import { injectIntoDocumentHead } from './html-document';
/**
* In-memory localStorage/sessionStorage shim, injected as the FIRST thing in the
* document so the page's own scripts see working storage.
*
* The interactive iframe is sandboxed `allow-scripts` WITHOUT `allow-same-origin`
* (intentional — combining them negates the sandbox for LLM-authored HTML). In a
* null-origin document, touching `window.localStorage` throws a SecurityError;
* many generated pages read/write storage in their setup code, so that throw
* crashes the script before anything renders → a blank/black widget. This shim
* replaces both storages with an in-memory implementation when the real ones are
* inaccessible, keeping the sandbox intact while letting storage-using pages run.
*/
const STORAGE_SHIM = ``;
/**
* Runtime-error capture, injected as the VERY FIRST script so it observes errors
* from the storage shim and every page script that follows. Generated interactive
* pages frequently die on a runtime error (a `JSON.parse` of malformed config, a
* reference to a CDN lib that failed to load, …) → the script aborts and the
* widget renders blank. The sandboxed (null-origin) iframe can't be read by the
* editor, but it CAN `postMessage` out: this forwards `window.onerror`, unhandled
* rejections and `console.error` to the parent, which stores them per scene and
* feeds them to the editor agent — so it can diagnose a blank page instead of
* guessing. Only touches `window.*` so it stays sandbox-safe and unit-testable.
*
* The most important errors (a `JSON.parse` that aborts setup) fire SYNCHRONOUSLY
* while srcDoc parses — potentially before the parent has subscribed its `message`
* listener (which it installs from a passive effect after inserting the iframe).
* To avoid losing exactly the errors this feature exists to surface, every post is
* also buffered, and the shim re-emits the whole buffer when the parent sends a
* `{ __maicErrorReplayRequest: true }` message once its listener is ready. The
* parent dedups, so the live + replayed copies collapse to one.
*/
const ERROR_CAPTURE_SHIM = ``;
/**
* Patch embedded HTML to display correctly inside an iframe.
*
* Injects a runtime-error capture shim + a storage shim (so sandboxed pages that
* use localStorage don't crash) plus CSS that ensures proper sizing and scrolling
* behavior when HTML content is rendered via srcDoc in an iframe. The shims are
* placed first so they run before the page's own scripts (error capture first, so
* it also observes the storage shim).
*/
export function patchHtmlForIframe(html: string, options: { offline?: boolean } = {}): string {
const iframeCss = ``;
// Desktop course packages are frozen before publication. Their interactive
// pages must therefore be self-contained: the local player blocks every
// network, parent, plugin and nested-frame capability while preserving inline
// scripts/styles, data/blob media and the existing sandboxed interaction UI.
const offlineCsp = options.offline
? ``
: '';
const injection = `\n${[offlineCsp, ERROR_CAPTURE_SHIM, STORAGE_SHIM, iframeCss].filter(Boolean).join('\n')}`;
return injectIntoDocumentHead(html, injection);
}