Runtime topology
& co-hosting.
The Hono trunk is the top-level server: it hosts the SPA as static assets, the JSON-RPC capability surface, auth, MCP, and an embedded collaboration server — all on one owned port. This document fixes that decision and the four production-attach blockers it leaves open.
01 Decision
Adopt a single-process trunk. The HTTP server, the static SPA assets, the /auth and /mcp mounts, the event-rendered published HTML, and the embedded Hocuspocus collaboration server co-host on one http.Server instance. No second framework hosts the collaboration WebSocket.
onAuthenticate. A rolled-back SQL transaction must never leave a mutation resident in the live Y.Doc once clients attach.02 Co-hosting mechanism
The trunk owns the server; raw ws in noServer mode receives the upgrade and hands the connection to Hocuspocus. Static assets are served from the SPA build directory; everything else routes through the capability surface.
// one owned http.Server — all surfaces co-host server.on("upgrade", async (req, socket, head) => { const principal = await resolver.fromCookie(req); if (!principal) return socket.destroy(); ws.handleUpgrade(req, socket, head, (conn) => hocuspocus.handleConnection(conn, req, { principal }) ); });
03 Open blockers
- Role-aware read / write at
onAuthenticate, not the tenant-only floor. - An
Origincheck on the WebSocket upgrade. - Revocation freshness on the upgrade-time principal snapshot.
- Enforce the
onAuthenticateinvariant by construction, not by convention.