Skip to content

Browser boot

This is the network sequence a fresh browser tab goes through to reach "Matrix client connected, app rendered" state.

Sequence

1. GET /apps/chat/                            → index.html (from chat.http asset endpoint)
2. GET /apps/chat/assets/index-abc123.js      → main bundle (asset endpoint)
3. GET /apps/chat/assets/style-def456.css     → stylesheet (asset endpoint)
4. GET /api/bootstrap                         → bootstrap JSON (gateway-direct)
5. WS  /nats-ws (CONNECT after upgrade)       → NATS WebSocket (gateway upgrade or Caddy)
6. RR  on local NATS: subscribe, mount actors, register components
7. First app render with live data

Steps 1-3 are static asset fetches handled by MatrixHttpAssetEndpointActor in the package's runtime, relayed through the gateway.

Step 4 is the dynamic edge — the gateway's own platform endpoint.

Step 5 is the WebSocket upgrade to NATS.

Steps 6+ happen entirely over NATS; the gateway is no longer involved.

Step 1: index.html

The browser navigates to /apps/chat/. The gateway resolves it as a static-app route, asks chat.http for index.html, and returns the bytes.

The HTML typically contains:

html
<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="/apps/chat/assets/style-def456.css">
  <script type="module" src="/apps/chat/assets/index-abc123.js"></script>
</head>
<body>
  <div id="app"></div>
</body>
</html>

References use absolute paths because:

  • The package's build emits absolute /apps/chat/... URLs.
  • For Space routes (/<routeKey>/chat/...), the gateway rewrites these prefixes at serve time (rewriteWebappHtmlResponse) so the URLs in the rendered HTML match the user-visible URL.

Step 2-3: hashed asset bundles

Most package builds (Vite-based) emit content-hashed asset names: index-abc123.js, style-def456.css. The hash changes when content changes, so the browser's cache works correctly even with the gateway's cache-control: no-cache (the URL itself is the version).

For non-hashed assets, the no-cache header forces the browser to revalidate on each load. See Cache and invalidation.

Step 4: /api/bootstrap

The browser fetches /api/bootstrap to get the dynamic configuration:

json
{
  "natsWsUrl": "wss://hivecast.ai/nats-ws",
  "root": "COM.NIMBLETEC.RICHARD-SANTOMAURO",
  "transportPlan": {
    "wsPath": "/nats-ws",
    "authMode": "jwt",
    "authEndpoint": "/api/nats-jwt"
  },
  "principal": { "principalId": "...", "displayName": "Richard" },
  "busToken": "..."
}

This response is per-request, derived from cookies/session/host config. See App bootstrap.

Step 5: NATS WebSocket

The browser uses the bootstrap result to open a WebSocket. For authMode: 'jwt', it first calls authEndpoint (/api/nats-jwt) to fetch a NATS-protocol JWT. Then it opens wss://<origin>/nats-ws, sends the NATS CONNECT frame with the JWT, and is connected.

After CONNECT, NATS protocol takes over. The gateway sees only the WebSocket upgrade; it does not parse NATS frames.

Step 6: Mount components

The browser-side Matrix runtime instantiates a MatrixRuntime, which:

  • Creates a unique runtimeId (browser-tab-scoped).
  • Subscribes to its <runtimeId>.$inbox subject.
  • Mounts the package's browser-side components (e.g. chat.ui).
  • Registers each component as a provider in system.registry.
  • Begins heartbeating on the registry.

The gateway is not involved in any of this. It happens entirely over NATS.

Step 7: First render

The browser-side component fetches initial data via Matrix RR:

typescript
await RequestReply.execute(context, 'chat', 'chat.thread.list', {});
// → { ok, threads: [...] }

The headless chat actor (in the package's runtime) responds. The browser renders.

Total round trips

For a fresh load with cold caches:

  • 1× HTML
  • N× JS/CSS bundles (depends on the app)
  • 1× /api/bootstrap
  • 1× WebSocket upgrade + 1× NATS auth
  • 1× first data RR

For a cached SPA navigation within the same session, only the data RR runs.

Failure surfaces

StepFailureSymptom
1404 from gatewayWrong appName or runtime down
4500 from /api/bootstrapGateway misconfig; check logs
5WS handshake failsNATS WS port unreachable; check transport.nats.wsPort
5NATS CONNECT auth failsJWT/token mismatch; check session and credentialsRef
6Components don't mountbus permissions; check NATS account permissions

See also

Source: projects/matrix-3/packages/system-gateway-http/src/host-platform-http-surface.ts:480-580.