Modulon Popout SDK 0.5.0
Production multi-window runtime
Build external browser windows that recover from refresh and transport loss, remain typed and observable, and work with vanilla TypeScript or React.
What 0.5.0 adds
- Versioned
SurfaceSessionreadiness, lifecycle states, cleanup, and refresh recovery. - Automatic opener → SharedWorker → same-origin BroadcastChannel resolution with capability reporting.
- Typed protocols, optional validators, cancellation, message limits, and strict security mode.
@modulonengine/sdk/react, runtime manifests, Screen Details primitives, support bundles, and a richer debug panel.
API map
Host and popout
createModulonHost() returns adapter, bus, surfaces, optional syncState, inspect(), events, and createSupportBundle(). createModulonPopout() selects transport, starts the surface handshake, and optionally connects synced state.
Sessions and transport
surfaces.open(), get(), list(), subscribe(), and discover(); createAutoTransport(); createBroadcastChannelTransport(); TransportCapabilities.
Protocol and state
defineModulonProtocol(), typed bus.request/handle/emit/on, runtime validators, AbortSignal, strict limits, and schema-versioned createSyncedState().
React, manifests, and screens
ModulonProvider, useSurfaceSession, useSyncedState, useModulonInspect; defineWorkspaceManifest(), validateWorkspaceManifest(), registerManifestWindows(); ScreenDetailsProvider.
Browser and capability matrix
| Capability | Chromium | Firefox | Safari/WebKit |
|---|---|---|---|
| Basic popouts + opener RPC/state | Supported | Supported | Supported |
| SharedWorker hub, locks, authority | Supported | Supported | Context-dependent |
| BroadcastChannel degraded fallback | Supported | Supported | Supported |
| Window Management / Screen Details | Progressive enhancement | One-screen fallback | One-screen fallback |
Popup policy always applies: call surfaces.open() directly from a user gesture. Screen Details is optional; basic popouts do not depend on it.
Security
- Use exact
targetOriginandallowedOriginsvalues in production. - Messages are routed by the actual detached
Windowsource; do not build routing around a payload-providedwindowId. - Enable
busSecurity: { mode: "strict" }with protocol validators at untrusted boundaries. - Keep BroadcastChannel fallback same-origin and treat payloads as untrusted application input.
- Set a message-size limit and keep support bundles redacted unless a user explicitly opts in.
- CSP must allow your popout routes, modules, and the local SharedWorker asset.
Migrate from 0.4
0.5 is additive. Existing adapter.detachWindow(), bus, synced state, and URL helpers remain available.
- Deploy host and popout bundles together; the handshake reports protocol or SDK mismatches.
- Adopt
runtime.surfaces.open()where readiness/recovery matters. Keep direct adapter calls where legacy behavior is intentional. - Define a protocol and add validators incrementally before enabling strict mode.
- React users can move integration code behind
@modulonengine/sdk/react; the core remains framework-free.
Troubleshooting decision tree
Popup did not open
Check for blocked_by_popup_blocker. Call open from a click/keydown and allow popups for the site.
Session stays handshaking
Confirm the popout route calls createModulonPopout(), namespace matches, and both pages use the same SDK build.
Session is degraded
BroadcastChannel is active. RPC/events/state work; SharedWorker-only locks and authority do not. Verify the worker URL and CSP.
State stopped updating after refresh
Inspect transport capability/status, call surfaces.discover(), and export a support bundle. Run diagnoseModulon() for worker, origin, fallback, and version checks.
Architecture and product boundary
The SDK is a headless browser runtime: window lifecycle, local communication, synchronized state, transport resolution, browser metrics, and diagnostics. It intentionally does not provide docking chrome, automatic multi-monitor layouts, remote WebRTC/WebSocket sync, game-engine bindings, or autoscaling policy. Those remain separate Modulon products.