Five-minute quickstart
Open a recoverable surface
This path uses the production factory, a typed protocol, strict origin settings, synced state, and the new readiness session.
1. Serve the worker
Copy public/modulon-shared-worker.js from the SDK to the web root. The CLI can scaffold this:
npx modulon init my-app --template react-vite
cd my-app
npm install
npm run dev
2. Create the host
Your host page needs an inline element such as <section id="orders">Orders</section>.
import {
createModulonHost,
defineModulonProtocol,
} from "@modulonengine/sdk";
type Methods = {
"orders.get": {
params: { id: string };
result: { id: string; status: string };
};
};
const isRecord = (v: unknown): v is Record<string, unknown> =>
!!v && typeof v === "object" && !Array.isArray(v);
const protocol = defineModulonProtocol<Methods>({
methods: {
"orders.get": {
params: (v) => isRecord(v) && typeof v.id === "string",
result: (v) => isRecord(v) && typeof v.id === "string" && typeof v.status === "string",
},
},
});
const runtime = createModulonHost<Methods>({
appId: "orders-app",
namespace: "orders-app.v1",
protocol,
busSecurity: { mode: "strict" },
adapterOptions: {
detachedUrl: "/popout.html",
detachedUrlParams: { ns: "orders-app.v1" },
targetOrigin: location.origin,
allowedOrigins: [location.origin],
},
windows: [{ id: "orders", title: "Orders", isDetachable: true }],
syncedState: { id: "app", initial: { selectedId: "A-100" } },
});
runtime.bus.handle("orders.get", ({ id }) => ({ id, status: "open" }));
document.querySelector("#open")?.addEventListener("click", async () => {
const opened = await runtime.surfaces.open({ windowId: "orders" });
if (!opened.ok) {
console.error(opened.error.code, opened.error.remediation);
return;
}
const ready = await opened.value.ready;
console.log(ready.ok ? opened.value.snapshot() : ready.error);
});
3. Create the popout route
import { createModulonPopout } from "@modulonengine/sdk";
import { protocol } from "./protocol";
const runtime = createModulonPopout({
appId: "orders-app",
namespace: "orders-app.v1",
protocol,
busSecurity: { mode: "strict" },
syncedState: { id: "app" },
});
await runtime.syncState?.ready;
document.body.textContent =
`Connected ${runtime.ctx.windowId} via ${runtime.surface.transport}`;
4. Verify production behavior
- Open from a user click and confirm the session becomes
connected. - Refresh the popout and confirm the same session reconnects.
- Temporarily disable the worker and confirm BroadcastChannel reports
degraded. - Run
diagnoseModulon()and exportruntime.createSupportBundle().
React
Import ModulonProvider, useSurfaceSession, useSyncedState, and useModulonInspect from @modulonengine/sdk/react. React remains an optional peer and is not included in the core graph.