// The worker half of the standalone deployment (improvise-9x6): strings only, // every decision in Rust. The two rules it must not break: context/code/clients.md. import init, { start } from "./worker-pkg/improvise_worker_server.js"; import { serialize } from "./serial.js"; const params = new URLSearchParams(self.location.search); const DOC = params.get("doc") || "demo.improv"; // Where the first copy of the document comes from on a fresh origin: fetched // and WRITTEN through the VFS, never injected past storage. const SEED = params.get("seed") || "demo.improv"; // Fetch the seed if there is one to fetch. A missing seed is not an error: // with none, the worker creates an empty model under DOC instead. async function seedBytes() { try { const res = await fetch(SEED); if (!res.ok) return undefined; return new Uint8Array(await res.arrayBuffer()); } catch (_) { return undefined; } } let server = null; function post(replies) { for (const reply of replies) self.postMessage(reply); } async function handle(data) { const replies = server.on_message(data); post(replies); await server.flush(); } // Startup, and the head of the chain: frames arrive before this settles, and // chaining onto it holds them in arrival order with no queue to drain. const started = (async () => { await init(); server = await start(DOC, await seedBytes()); })(); started.catch((err) => { console.error("improvise worker: failed to start", err); }); // One frame at a time, in arrival order, and the listener is deliberately NOT // `async`: the chaining is `serial.js`'s and is tested there. const onFrame = serialize( started, async (data) => { // `start()` failed. There is nothing to answer with, and the main // thread's handshake watchdog is what tells the user. if (!server) return; await handle(data); }, // An unhandled rejection here reaches the devtools console and nothing // else. Caught, so one bad frame does not poison every later one. (err, data) => console.error("improvise worker: frame rejected", data, err), ); self.onmessage = (event) => { onFrame(event.data); };