For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /reference/CLIENT-SUBSCRIPTIONS.md.

Realtime browser messages

Centrifugo with Protobuf is the browser update transport. Contexts publish typed messages to an explicit domain or security audience. The API calculates every channel from the authenticated principal's current authority. Browsers neither name nor select channels.

Run applications have a separate Project-private serving gateway. It forwards application HTTP, SSE and WebSocket traffic with continuously checked member authority. Platform projections and notifications use the rules in this document.

Audiences and permissions

DeliveryTarget permits one audience:

TargetPurposeChannel derived by the gateway
Project IDState shared with connections currently authorised for a Projectpharos:project:<canonical-id>
Party IDState shared with a Partypharos:party:<canonical-id>
Principal subjectPrivate asynchronous outcome for one authenticated subjectpharos:principal:<base64url-subject>

Project and Party are domain audiences. Principal is the authenticated security subject used for private messages, including recorded command rejections and a per-principal projection. A Run is Project-owned, so Run state uses the Project target. Its payload remains a typed execution_core/run message with the Run ID and revision. SSH Access writes one principal-targeted publication for every actor that acts as the member.

The connect proxy authenticates the session and asks an application outbound port for the principal's current authorised realtime audiences. The API adaptor composes published owner queries from Party Governance and Project: Party Governance maps the security principal to the Party authority it may exercise, and Project decides which Projects that Party may currently access. The API maps the returned canonical IDs to server-side Centrifugo subscriptions. It does not reproduce either context's access rules.

The principal target is included for ordinary authorised connections. A limited API-owned session awaiting AUP receives only its own Party readiness channel. Invalid or unavailable session/Party authority fails closed. The connection carries a server-only audience fingerprint. Refresh asks the owners again and expires the connection when that fingerprint changes; the client reconnects to receive the new subscription set. Limited sessions use the canonical Party already revalidated by authentication. The registered Party payload is currently readiness only; adding other Party projections requires reviewing limited-session delivery authority. Once AUP is current, party.Audiences asks GetCurrentParty and traverses ListPartyProjectAudiences, whose Project owner checks runs.view for the exact API Party actor and authentication generation. A page may contain no allowed Projects and still supply a continuation cursor. Refresh retains its one-minute maximum and is capped by the earliest absolute valid_until returned by Beto. Expired, malformed or incomplete authority closes the connection. Development operator/CLI sessions without canonical Party authority retain only their principal channel.

The connect grant starts before owner reads to preserve the logout fence. If those reads exhaust its lifetime, the API refuses the attempt with retryable disconnect code 4001; a fresh attempt checks authority again. Invalid sessions and unresolved audiences retain terminal code 4501. Expired grants supply no subscriptions.

The dashboard navigation qualification records the regression and live authentication results.

Publishing

The aggregate transaction records its current state, receipt, outgoing message bytes and dispatch intent atomically. Each message supplies a RealtimeTarget and a context-owned typed snapshot. The relay sends only the encoded publication and its idempotency key:

{"b64data":"<protobuf bytes>","idempotency_key":"<event id>"}

The restricted gateway authenticates the publisher, verifies the envelope owner and permitted target kinds, derives the channel and forwards the original bytes to Centrifugo. Publisher code has no channel parameter. Execution Core may publish Project-targeted Run messages. Support publishes principal-targeted Ticket and TicketMessage messages, each to its owner. Party Governance publishes PartyProfileProjection to the owning principal, including private profiles. Profile data never uses the Party readiness channel available to limited sessions. The API records technical session-readiness notifications atomically in its owned Valkey state; its session credential can publish only the typed Party-targeted notification described in the authentication guide. Beto and Themelio expose the same typed RealtimeMessage/RealtimeTarget application API; Support and Party Governance explicitly enable their context-owned browser delivery in composition.

Metallo constructs Run changes with application.realtime.run_change, which selects RealtimeTarget.project(run.project_id). Beto publishers use application.ProjectTarget, PartyTarget or PrincipalTarget. Themelio uses the corresponding RealtimeTarget class methods. Rejection messages require a principal target in both technical foundations.

SSH Access records its typed projection with every committed root revision, including Site results and propagation completion. Its actor mapping creates one principal-targeted envelope per actor; a member with no actor receives no publication. The ssh_access publisher credential is accepted only for principal targets.

Frontend API

The new web application owns the connection in RealtimeProvider. Feature code observes connection state and typed messages through hooks:

const connection = useRealtimeConnection();

useRealtimeMessage(realtimeMessageTypes.runChanged, message => {
  applyIfNewer(message.run.runId, message.revision, message.run);
});

useRealtimeMessage registers a local typed handler. It does not subscribe to a Centrifugo channel. messages.ts decodes the common envelope and its registered payload, checks the target against payload identity and rejects unknown contracts. The checked-in protobufjs schema is generated from the Protobuf sources by pnpm generate:contracts.

The retained web keeps its Run connection in the authenticated RunNoticeProvider. It observes every server-authorised Project while the member navigates between pages. Resource managers select their Project's refresh counter; consent notices remain one per Run for its initiating member, including on the dashboard. Replacing the canonical member closes the old connection and clears its notices.

An authorised current-state read remains the initial source of truth. A feature applies only newer revisions and tolerates duplicate delivery. Recoverable Centrifugo history resumes by epoch and offset. An unrecoverable gap requires one fresh owner query before later messages are applied.

The SSH Access view registers a recovery callback with RealtimeProvider. The principal channel's first subscription reads GET /api/v1/ssh-access/sites/{siteId}/projection; recovered history needs no second read, and loss of history triggers one reconciliation. A view mounted after the principal subscription is ready receives its initial read immediately. Views mounted during an outage read once on the next subscription, including when existing views resume from recovered history.

Browser HTTP reads use the generated OpenAPI client. The initial Project directory is loaded once after session establishment; it is not a polling source or a substitute for an owner-authorised realtime audience.

Security rules

  • Client publish, client-selected subscriptions, polling, SSE and raw WebSocket business transports are prohibited. The one exception is the Run log panel, which polls its logs route every 5 seconds for now (decision).
  • Publisher credentials are context-scoped and never reach the browser.
  • The gateway forwards exact persisted Protobuf bytes; it does not reconstruct a later snapshot.
  • Realtime delivery carries committed state or an outcome. It grants no business authority.
  • Session revocation disconnects every connection for that principal. Connect authority is short-lived and refreshed through the authenticated API proxy.

The browser edge serves /auth, /api/v1 and /connection/websocket at https://platform.localtest.me. Internal proxy, diagnostics and Centrifugo administration endpoints remain private.

Page source

Source snapshot ยท Revision f928834c8.