@voyant-travel/realtime. The React hooks live in @voyant-travel/realtime-react. This page covers both, plus how they relate to the managed Voyant realtime service.
The core idea: hints, not records
The realtime layer does not stream changed records over channels. It streams invalidation hints, small{ event, entity, id } envelopes that say “this thing changed, refetch it.” The React layer reacts by invalidating matching React Query keys, which then refetch over the existing authenticated HTTP path.
This design has three consequences worth understanding:
- HTTP stays the source of truth. A channel never carries entity data, so it never leaks state through channel capabilities.
- At-most-once delivery is acceptable. A missed hint self-heals on the next refetch or
staleTimetick. - The transaction that emitted the event is never blocked by a publish.
If a channel ever needs at-least-once delivery, that is a durable channel-push pattern (write an intent row, drain it from a workflow), not this module. The realtime module ships the at-most-once tier by design.
The provider interface
The transport is injected throughRealtimeProvider. Voyant is one implementation; any pub/sub backend (a hosted vendor, a self-hosted WebSocket or SSE service) can satisfy the same interface.
mintClientToken is the abstraction line. Every vendor mints tokens differently, but the token-mint route never knows the vendor. The package ships two built-in providers:
To bring your own backend, implement
RealtimeProvider and pass it through. No framework change is required.
Wiring the module
@voyant-travel/realtime is part of the standard product graph. It owns no schema, is stateless, and contributes its runtime ports through the runtime entry in its voyant.package.v1 manifest, so the token-mint route and the deferred event bridge are resolved into the application rather than assembled by hand.
What you do configure is the provider and the bridge routes that fan domain events out to channels:
POST /v1/admin/realtime/token and POST /v1/public/realtime/token. With no provider configured, the token route returns 503 and no bridge subscribers register.
The event bridge
bridgeRoutes is a declarative table from event name to channels and an optional hint. At bootstrap, the module registers one deferred event subscriber per route. Because the subscribers are deferred (inline: false), they run after the HTTP response via the runtime scheduler and never block the emitting transaction. Publish failures are swallowed and routed to onPublishError, because a dropped hint is self-healing.
The module also exports the lower-level pieces: createRealtimeService, resolveRealtimeCapabilities, and the route helpers (createRealtimeRoutes, buildRealtimeRouteRuntime) for that path.
Channel conventions
Channels and the capabilities that grant them follow a stable convention.The operator pattern on the client
@voyant-travel/realtime-react makes existing screens live without rewriting their data layer. The transport is injected as a RealtimeConnector, so the React layer stays vendor-agnostic too.
Wrap the app once. createRealtimeChannelConnector adapts the Voyant RealtimeChannel into a connector, but any vendor works by implementing RealtimeConnector directly.
useLiveQueries. It subscribes to channels and translates each invalidation hint into queryClient.invalidateQueries calls. The operator pattern is exactly this: subscribe to the admin channel and map each hint’s entity to a query-key root.
staleTime: 60_000 as a floor. A missed hint self-heals on the next stale tick, so a slow polling fallback remains a safe net under the hint-driven path.
For finer control, the package also exports useChannel(channel, options) to subscribe to a single channel with auto token-mint, reconnect, and sinceId resume, and usePresence(channel, profile) for member lists (“Ana is viewing this booking”). Custom hint-to-key mapping is available through resolveInvalidationKeys and the HintToQueryKeys type from @voyant-travel/realtime-react/query-keys.
Framework realtime versus Cloud realtime
These are two layers, and they cooperate.- Framework realtime (
@voyant-travel/realtimeand@voyant-travel/realtime-react) is the deployment-side contract: the provider interface, the event bridge, the token-mint route, and the React hooks. It is vendor-agnostic. - Cloud realtime is the managed pub/sub transport: channels, presence, history, and
RealtimeChannel. It is one implementation behind the provider interface, wired in throughcreateVoyantCloudRealtimeProvider.
Next steps
Events
The fire-and-forget event bus the realtime bridge subscribes to.
Cloud realtime
The managed pub/sub transport behind the Voyant provider.
Caching
The HTTP path that hints invalidate, and its staleness model.
API routes
Where the token-mint route mounts and how surfaces are split.