From dd1d497cc6531c89ea054c7e3d0c3d6b749b3a00 Mon Sep 17 00:00:00 2001 From: Michael Ramos Date: Thu, 27 Aug 2026 08:18:40 -0700 Subject: [PATCH 1/7] feat(ui): load the HTML viewer bridge by URL with a protocol version and ready timeout Add an opt-in bridgeScriptUrl prop to HtmlViewer: the srcdoc document then loads the bridge through a classic `); + expect(srcdoc).not.toContain(BRIDGE_SCRIPT); + // The sandbox is unchanged by the delivery path. + expect(iframe.getAttribute('sandbox')).toBe('allow-scripts'); + }); + + test('without the prop the srcdoc inlines the bridge, as before', async () => { + const { iframe, banner } = await mount({}); + const srcdoc = iframe.getAttribute('srcdoc') ?? ''; + expect(srcdoc).toContain(``); + expect(srcdoc).not.toContain('`; + } + if (!BRIDGE_SCRIPT) { + // Only reachable when a host aliased `./bridge-script` to the generated + // `bridge-script.lite` module (which stubs the inline literal) and then + // rendered an HtmlViewer without `bridgeScriptUrl`: an empty inline + // script would be a silently dead surface, so fail loudly instead. + throw new Error( + "@plannotator/ui HtmlViewer: the inline bridge script is stubbed out " + + "(bridge-script.lite alias) but no bridgeScriptUrl was passed.", + ); + } + return ``; } /** The ``; + return `${buildBridgeScriptTag(bridgeScriptUrl)}`; } /** @@ -126,6 +167,12 @@ export function buildSrcdocInjection({ * script and disables annotation entirely. The iframe `sandbox` attribute is * the security boundary for the annotate surface; the page's CSP was written * for its standalone context, so it is removed before injection. + * + * The package itself never adds a CSP `` to the srcdoc document (the + * injection is one `