The app's component runs inside the frame - #148
Merged
Conversation
mountApp keeps its shape; its internals change. frame.ts is now the in-frame runtime: on the one mount message from its embedder it instantiates the guest with polyengine in the frame's own realm, binds polyvisor:surface to that document's real DOM through the existing createDirectBackend (synchronously — no op array, no structured clone, no second validation pass), and serves the visor's calls into the guest's exports over a control port. Every OTHER import the app is granted is a proxy over its own MessagePort back to the visor-side implementation, with WIT errors crossing as @polyengine/protocol's cloneable form so a host `result` err arrives in the guest as err(payload), not a trap. The queued op protocol leaves the app path; frame-backend.ts is deleted. The applier and the queued/channel backends stay: the todomvc harness is their instrument, and the applier's re-validation is still what a trusted-territory backend needs. The frame's policy becomes the ruled one (#142, spikes 3–4): sandbox="allow-scripts allow-forms" — without allow-forms the submit event never fires at all, so <form onsubmit> is dead — and a meta CSP of default-src 'none' with the script hash, 'wasm-unsafe-eval' (the guest is compiled here now), img-src blob: data:, font-src blob:, media-src blob:, form-action 'none'. A form-action violation is an app that forgot preventDefault and is logged; every other violation is a fault. Suspension is two halves because neither suffices (#142 P1): `inert` on the iframe, and in the frame the runner's gate plus dropping focus. Height comes from a ResizeObserver. The mount message is accepted once and only from window.parent — sibling frames can reach this one's WindowProxy — with the transferred ports as the real authenticator. Linker rule this rests on, recorded in NOTES: an import that crosses a realm must be async-declared in the WIT. The guest then suspends through the component model's async ABI and the frame needs no JSPI — Firefox 144, which has none, runs the in-frame guest. No caller changed. frame.js grows from ~3 KB to 192 KB raw / 58 KB gzip (it carries the embedder), as spike 2 predicted. Gates: deno check (demo, spikes/todomvc); check-invariants 9/9, its seam scans now covering mount.ts + frame.ts + frame.html; spikes/todomvc e2e 5/5; demo e2e 36/36 with zero scenario edits; a direct probe in Chromium and Firefox (srcdoc, sandbox flags, the meta directives, in-frame fetch never reaching the server, a typed todo, inert on suspend, iframe gone on destroy). Out of scope, deliberately: the dioxus dialect's spike transport (spikes/todomvc/host/dioxus-frame.ts) stays until polyengine-dioxus's host runs in this frame runtime; where a framed app's route lives; a linker-side check that cross-realm imports are async-lowered.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Step B of #142's design; step A was #147.
mountAppkeeps its shape, its internals change, no caller changed.frame.tsis the in-frame runtime: polyengine instantiates the guest in the frame's realm;polyvisor:surfacebinds to the real DOM viacreateDirectBackend, synchronously; the visor's export calls ride a control port; every other granted import is a proxy over its ownMessagePort(errors as@polyengine/protocol's cloneable form — a hostresulterr arrives aserr(payload), not a trap).frame-backend.tsdeleted. Applier + queued/channel backends stay (harness; trusted-territory).sandbox="allow-scripts allow-forms"; metadefault-src 'none'; script-src 'sha256-…' 'wasm-unsafe-eval'; style-src 'unsafe-inline'; img-src blob: data:; font-src blob:; media-src blob:; form-action 'none'.form-actionviolations are logged; all others are faults.inerton the iframe + runner gate + focus drop in the frame (Spike: app-frame CSP without a dedicated origin — srcdoc + <meta> is network-dead, SWs never see sandboxed navigations, process-isolation matrix #142 P1). Height viaResizeObserver. Mount message accepted once, only fromwindow.parent; the transferred ports are the authenticator.frame.js: 3 KB → 192 KB raw / 58 KB gzip, as spike 2 predicted.Gates:
deno checkboth consumers;check-invariants.sh9/9 (seam scans nowmount.ts+frame.ts+frame.html); spikes/todomvc e2e 5/5; demo e2e 36/36, zero scenario edits; direct probe in Chromium and Firefox (12/12).Out of scope: the dioxus dialect's spike transport (until polyengine-dioxus's host runs in this frame runtime); where a framed app's route lives; a linker-side async-lowering check. Comments in
spikes/todomvc/{host/dioxus-frame.ts,README.md,e2e/tests/dioxus-frame.spec.ts}still nameframe-backend.ts; repoint with the dioxus follow-up.Automerge armed.