Files
wasmeld/crates/wasmeld-console/web/src/primitives/create-frame-bridge.ts
T

50 lines
1.6 KiB
TypeScript
Raw Normal View History

import { createSignal, onCleanup, onMount } from "solid-js";
import type { View } from "../lib/model";
import { isHostMessage, type HostSharedState, type PageCommand } from "../sdk/protocol";
import { notifyReady, sendCommand } from "../sdk/page";
/**
* Connects one iframe document to the persistent Host Shell.
*
* A keep-alive document remains mounted while inactive and exposes that state
* through `active`. Removing the iframe still runs `onCleanup`, so an evicted
* document cannot continue to receive Host snapshots.
*/
export function createFrameBridge(view: View) {
const [state, setState] = createSignal<HostSharedState | null>(null);
const [active, setActive] = createSignal(false);
const receive = (event: MessageEvent<unknown>) => {
if (event.origin !== window.location.origin || event.source !== window.parent) return;
if (!isHostMessage(event.data)) return;
if (event.data.type === "state" && event.data.state.view === view) {
setState(event.data.state);
}
if (event.data.type === "lifecycle") {
const phase = event.data.phase;
setActive(phase === "activate");
window.dispatchEvent(
new CustomEvent("wasmeld:lifecycle", {
detail: { phase },
}),
);
window.dispatchEvent(new Event(`wasmeld:${phase}`));
}
};
onMount(() => {
window.addEventListener("message", receive);
notifyReady(view);
});
onCleanup(() => window.removeEventListener("message", receive));
return {
state,
active,
command(command: PageCommand) {
sendCommand(view, command);
},
};
}