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 = 'Toggle detailed error view'; 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 ? '' : ''; const cleanedHTML = document.documentElement.outerHTML .replace(/]*>.*?<\\/nuxt-error-overlay>/gs, '') .replace(/]*>.*?<\\/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("", `