/**
 * IframeManager
 *
 * Creates and manages a hidden cross-origin iframe for the PrivacyBoost
 * key vault. The iframe is invisible and sandboxed.
 */
function validateIframeUrl(url) {
    const parsed = new URL(url);
    if (parsed.protocol === 'https:') {
        return;
    }
    if (parsed.protocol === 'http:' &&
        (parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1')) {
        return;
    }
    throw new Error(`Iframe URL must use https:, or http: with localhost. Got: ${parsed.protocol}//${parsed.hostname}`);
}
export class IframeManager {
    url;
    iframe = null;
    constructor(url) {
        this.url = url;
        validateIframeUrl(url);
    }
    async create() {
        if (this.iframe) {
            return;
        }
        const iframeOrigin = new URL(this.url).origin;
        if (iframeOrigin === window.location.origin) {
            throw new Error(`Iframe URL must be cross-origin for isolation. Got same origin: ${iframeOrigin}. ` +
                'Use the default PrivacyBoost-hosted iframe or host on a different origin.');
        }
        return new Promise((resolve, reject) => {
            const iframe = document.createElement('iframe');
            const iframeUrl = new URL(this.url);
            iframeUrl.searchParams.set('parentOrigin', window.location.origin);
            iframe.src = iframeUrl.toString();
            iframe.style.display = 'none';
            iframe.style.width = '0';
            iframe.style.height = '0';
            iframe.style.border = 'none';
            iframe.style.position = 'absolute';
            iframe.style.top = '-9999px';
            iframe.style.left = '-9999px';
            // allow-scripts: required for WASM execution.
            // allow-same-origin: required for the iframe's own localStorage/IndexedDB
            //   (key persistence). This combination neutralises the sandbox for the
            //   iframe's own origin, but does NOT weaken the cross-origin boundary.
            //   The real isolation is enforced above: the iframe MUST be loaded from
            //   a different origin than the parent, so the browser's same-origin
            //   policy prevents any access to the parent's DOM, storage, or credentials.
            iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin');
            iframe.setAttribute('aria-hidden', 'true');
            iframe.setAttribute('tabindex', '-1');
            const timeout = setTimeout(() => {
                iframe.remove();
                this.iframe = null;
                reject(new Error('Iframe load timed out'));
            }, 30_000);
            iframe.onload = () => {
                clearTimeout(timeout);
                resolve();
            };
            iframe.onerror = () => {
                clearTimeout(timeout);
                iframe.remove();
                this.iframe = null;
                reject(new Error(`Failed to load iframe from ${this.url}`));
            };
            document.body.appendChild(iframe);
            this.iframe = iframe;
        });
    }
    get contentWindow() {
        if (!this.iframe?.contentWindow) {
            throw new Error('Iframe not ready');
        }
        return this.iframe.contentWindow;
    }
    get origin() {
        return new URL(this.url).origin;
    }
    destroy() {
        if (this.iframe) {
            this.iframe.remove();
            this.iframe = null;
        }
    }
}
//# sourceMappingURL=iframe-manager.js.map