Opt-in bridgeScriptUrl on HtmlViewer so multi-chunk hosts can serve the 185 KB bridge as a hashed asset instead of an inlined string; the inline bridge stays the default and Plannotator's own builds, the Pi and OpenCode copies, and the live-app proxy are unchanged apart from a protocolVersion field on the bridge's ready message. The parent checks the version (one warning naming both versions; on the URL path a dismissible banner plus onBridgeUnavailable while the old bridge keeps working), arms a ready timeout on the URL path only, and resolves the URL against the parent document before it reaches the frame so a page's own base href cannot redirect the load. A prepack-generated bridge-script.asset.js (byte-for-byte the inline string) and a bridge-script.lite.ts alias target ship in the tarball. CSP and CORP requirements for hosts are documented.
AI-assisted (Claude) under maintainer direction.
A document carrying its own <meta http-equiv=Content-Security-Policy> (including
Plannotator's own portable guided-review exports, which embed default-src 'none')
blocked the injected inline bridge script, disabling annotation entirely for that
file. The iframe sandbox attribute is the annotate surface's security boundary;
the page's CSP was authored for its standalone context, so injectIntoHead now
strips CSP meta tags (order/quote/case tolerant) before splicing the bridge.
Pre-existing bug, surfaced during v0.26.8 manual QA. Mutation-verified test.
HtmlViewer injected host-app state into rendered documents: ~26 bare
theme tokens (--muted, --background, ...) written into :root and
re-applied inline on the author's documentElement on every host theme
flip, a `light` class toggled on the author's root, an asymmetric
color-scheme:light injection, and unconditional ins/del diff styles.
Documents defining the same token names rendered with wrong colors in
both Plannotator and @plannotator/ui consumers.
Arbitrary documents now render exactly as in a standalone tab:
- Host tokens are pushed only under the viewer-owned --pn-* prefix;
annotation CSS and the bridge read only var(--pn-*, fallback). The
bridge refuses non---pn- writes and never touches the root class
list unless the document opts in.
- Host theme-following is opt-in per document via
<meta name="plannotator-theme" content="host">, which restores the
bare-token push, the light class, and a symmetric color-scheme sync.
The visual-explainer skill now emits the tag in generated artifacts.
- Diff CSS is injected only while the version-diff view is active and
scoped to ins/del.plannotator-diff, which htmlDiff now emits on its
generated wrappers; author <ins>/<del> markup is never restyled.
The srcdoc injection logic moves to a pure module (srcdoc.ts) with
tests pinning the neutrality contract, including a DOM test that runs
the actual bridge script and asserts a theme flip lands nothing on the
author's root except --pn-* properties.
Claude-Session: https://claude.ai/code/session_01MDqD8jdgTbdjiXcVVigzV2