elearning/Frontend-Learner/node_modules/@nuxt/nitro-server/dist/runtime/utils/dev.js
2026-01-13 10:48:02 +07:00

334 lines
9.2 KiB
JavaScript

const iframeStorageBridge = (nonce) => (
/* js */
`
(function() {
const memoryStore = {};
const NONCE = ${JSON.stringify(nonce)}
const mockStorage = {
getItem: function(key) {
return memoryStore[key] !== undefined ? memoryStore[key] : null;
},
setItem: function(key, value) {
memoryStore[key] = String(value);
window.parent.postMessage({
type: 'storage-set',
key: key,
value: String(value),
nonce: NONCE
}, '*');
},
removeItem: function(key) {
delete memoryStore[key];
window.parent.postMessage({
type: 'storage-remove',
key: key,
nonce: NONCE
}, '*');
},
clear: function() {
for (const key in memoryStore) {
delete memoryStore[key];
}
window.parent.postMessage({
type: 'storage-clear',
nonce: NONCE
}, '*');
},
key: function(index) {
const keys = Object.keys(memoryStore);
return keys[index] !== undefined ? keys[index] : null;
},
get length() {
return Object.keys(memoryStore).length;
}
};
try {
Object.defineProperty(window, 'localStorage', {
value: mockStorage,
writable: false,
configurable: true
});
} catch (e) {
window.localStorage = mockStorage;
}
window.addEventListener('message', function(event) {
if (event.data.type === 'storage-sync-data' && event.data.nonce === NONCE) {
const data = event.data.data;
for (const key in data) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
memoryStore[key] = data[key];
}
}
if (typeof window.initTheme === 'function') {
window.initTheme();
}
window.dispatchEvent(new Event('storage-ready'));
}
});
window.parent.postMessage({
type: 'storage-sync-request',
nonce: NONCE
}, '*');
})();
`
);
const parentStorageBridge = (nonce) => (
/* js */
`
(function() {
const host = document.querySelector('nuxt-error-overlay');
if (!host) return;
// Wait for shadow root to be attached
const checkShadow = setInterval(function() {
if (host.shadowRoot) {
clearInterval(checkShadow);
const iframe = host.shadowRoot.getElementById('frame');
if (!iframe) return;
const NONCE = ${JSON.stringify(nonce)}
window.addEventListener('message', function(event) {
if (!event.data || event.data.nonce !== NONCE) return;
const data = event.data;
if (data.type === 'storage-set') {
localStorage.setItem(data.key, data.value);
} else if (data.type === 'storage-remove') {
localStorage.removeItem(data.key);
} else if (data.type === 'storage-clear') {
localStorage.clear();
} else if (data.type === 'storage-sync-request') {
const allData = {};
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
allData[key] = localStorage.getItem(key);
}
iframe.contentWindow.postMessage({
type: 'storage-sync-data',
data: allData,
nonce: NONCE
}, '*');
}
});
}
}, 10);
})();
`
);
const errorCSS = (
/* css */
`
:host {
--preview-width: 240px;
--preview-height: 180px;
--base-width: 1200px;
--base-height: 900px;
--z-base: 999999998;
all: initial;
display: contents;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
#frame {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
border: none;
z-index: var(--z-base);
}
#frame[inert] {
right: 5px;
bottom: 5px;
left: auto;
top: auto;
width: var(--base-width);
height: var(--base-height);
transform: scale(calc(240 / 1200));
transform-origin: bottom right;
overflow: hidden;
border-radius: calc(1200 * 8px / 240);
}
#preview {
position: fixed;
right: 5px;
bottom: 5px;
width: var(--preview-width);
height: var(--preview-height);
overflow: hidden;
border-radius: 8px;
pointer-events: none;
z-index: var(--z-base);
background: white;
display: none;
}
#frame:not([inert]) + #preview {
display: block;
}
#toggle {
position: fixed;
right: 5px;
bottom: 5px;
width: var(--preview-width);
height: var(--preview-height);
background: none;
border: 3px solid #00DC82;
border-radius: 8px;
cursor: pointer;
opacity: 0.8;
transition: opacity 0.2s, box-shadow 0.2s;
z-index: calc(var(--z-base) + 1);
}
#toggle:hover,
#toggle:focus {
opacity: 1;
box-shadow: 0 0 20px rgba(0, 220, 130, 0.6);
}
#toggle:focus-visible {
outline: 3px solid #00DC82;
outline-offset: 3px;
box-shadow: 0 0 24px rgba(0, 220, 130, 0.8);
}
@media (prefers-reduced-motion: reduce) {
#toggle {
transition: none;
}
}
`
);
function webComponentScript(base64HTML, startMinimized) {
return (
/* js */
`
(function() {
try {
const host = document.querySelector('nuxt-error-overlay');
if (!host) return;
const shadow = host.attachShadow({ mode: 'open' });
// Create elements
const style = document.createElement('style');
style.textContent = ${JSON.stringify(errorCSS)};
const iframe = document.createElement('iframe');
iframe.id = 'frame';
iframe.src = 'data:text/html;base64,${base64HTML}';
iframe.title = 'Detailed error stack trace';
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
const preview = document.createElement('div');
preview.id = 'preview';
const button = document.createElement('button');
button.id = 'toggle';
button.setAttribute('aria-expanded', 'true');
button.setAttribute('type', 'button');
button.innerHTML = '<span class="sr-only">Toggle detailed error view</span>';
const liveRegion = document.createElement('div');
liveRegion.setAttribute('role', 'status');
liveRegion.setAttribute('aria-live', 'polite');
liveRegion.className = 'sr-only';
// Update preview snapshot
function updatePreview() {
try {
let previewIframe = preview.querySelector('iframe');
if (!previewIframe) {
previewIframe = document.createElement('iframe');
previewIframe.style.cssText = 'width: 1200px; height: 900px; transform: scale(0.2); transform-origin: top left; border: none;';
previewIframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
preview.appendChild(previewIframe);
}
const doctype = document.doctype ? '<!DOCTYPE ' + document.doctype.name + '>' : '';
const cleanedHTML = document.documentElement.outerHTML
.replace(/<nuxt-error-overlay[^>]*>.*?<\\/nuxt-error-overlay>/gs, '')
.replace(/<script[^>]*>.*?<\\/script>/gs, '');
const iframeDoc = previewIframe.contentDocument || previewIframe.contentWindow.document;
iframeDoc.open();
iframeDoc.write(doctype + cleanedHTML);
iframeDoc.close();
} catch (error) {
console.error('Failed to update preview:', error);
}
}
function toggleView() {
const isMinimized = iframe.hasAttribute('inert');
if (isMinimized) {
updatePreview();
iframe.removeAttribute('inert');
button.setAttribute('aria-expanded', 'true');
liveRegion.textContent = 'Showing detailed error view';
setTimeout(function() {
try { iframe.contentWindow.focus(); } catch {}
}, 100);
} else {
iframe.setAttribute('inert', '');
button.setAttribute('aria-expanded', 'false');
liveRegion.textContent = 'Showing error page';
button.focus();
}
}
button.onclick = toggleView;
document.addEventListener('keydown', function(e) {
if ((e.key === 'Escape' || e.key === 'Esc') && !iframe.hasAttribute('inert')) {
toggleView();
}
});
// Append to shadow DOM
shadow.appendChild(style);
shadow.appendChild(liveRegion);
shadow.appendChild(iframe);
shadow.appendChild(preview);
shadow.appendChild(button);
if (${startMinimized}) {
iframe.setAttribute('inert', '');
button.setAttribute('aria-expanded', 'false');
}
// Initialize preview
setTimeout(updatePreview, 100);
} catch (error) {
console.error('Failed to initialize Nuxt error overlay:', error);
}
})();
`
);
}
export function generateErrorOverlayHTML(html, options) {
const nonce = Array.from(crypto.getRandomValues(new Uint8Array(16)), (b) => b.toString(16).padStart(2, "0")).join("");
const errorPage = html.replace("<head>", `<head><script>${iframeStorageBridge(nonce)}<\/script>`);
const base64HTML = Buffer.from(errorPage, "utf8").toString("base64");
return `
<script>${parentStorageBridge(nonce)}<\/script>
<nuxt-error-overlay></nuxt-error-overlay>
<script>${webComponentScript(base64HTML, options?.startMinimized ?? false)}<\/script>
`;
}