← All @molecule/* packages · App templates
@molecule/app-realtimeCore interface · realtime · App (browser) · v1.0.1 · Apache-2.0
Realtime client core interface for molecule.dev — WebSocket/SSE connections with rooms, presence, events, and auto-reconnection
npm install @molecule/app-realtime@molecule/app-realtime is the realtime core interface on the app (browser) side: the API your app calls, with no vendor inside.
Choose the implementation by bonding one of its 1 provider: @molecule/app-realtime-socketio.
import { setProvider, connect } from '@molecule/app-realtime'
import { provider } from '@molecule/app-realtime-socketio'
setProvider(provider)
const connection = await connect('wss://api.example.com', {
autoReconnect: true,
auth: { token: 'my-jwt' },
})
await connection.joinRoom('chat-room-1')
connection.on('message', (data) => console.log('Received:', data))
connection.sendTo('chat-room-1', 'message', { text: 'Hello!' })Providers (1): @molecule/app-realtime-socketio
Works with: @molecule/app-bond
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Realtime client core interface for molecule.dev.
Provides a framework-agnostic contract for WebSocket / SSE client connections
with rooms, presence tracking, events, and automatic reconnection. Bond a
provider (e.g. @molecule/app-realtime-socketio) at startup, then use
{@link connect} anywhere.
import { setProvider, connect } from '@molecule/app-realtime'
import { provider } from '@molecule/app-realtime-socketio'
setProvider(provider)
const connection = await connect('wss://api.example.com', {
autoReconnect: true,
auth: { token: 'my-jwt' },
})
await connection.joinRoom('chat-room-1')
connection.on('message', (data) => console.log('Received:', data))
connection.sendTo('chat-room-1', 'message', { text: 'Hello!' })
core
npm install @molecule/app-realtime @molecule/app-bond
ConnectionOptionsOptions for establishing a realtime connection.
interface ConnectionOptions {
/** Whether to automatically reconnect on disconnection. Defaults to `true`. */
autoReconnect?: boolean
/** Delay in milliseconds before attempting reconnection. Defaults to `1000`. */
reconnectDelay?: number
/** Maximum number of reconnection attempts. Defaults to `10`. */
maxRetries?: number
/** Authentication data sent during the handshake. */
auth?: Record<string, unknown>
}
PresenceInfoPresence information for a connected client in a room.
interface PresenceInfo {
/** The client's unique identifier. */
clientId: string
/** Arbitrary metadata attached to the client's presence (e.g. username, avatar). */
metadata?: Record<string, unknown>
}
RealtimeClientProviderContract that bond packages must implement to provide realtime client functionality.
interface RealtimeClientProvider {
/**
* Establishes a realtime connection to the given server URL.
*
* @param url - The server URL to connect to.
* @param options - Optional connection configuration.
* @returns A promise resolving to a live realtime connection.
*/
connect(url: string, options?: ConnectionOptions): Promise<RealtimeConnection>
}
RealtimeConnectionA live realtime connection exposing room, event, and presence methods.
interface RealtimeConnection {
// -- Rooms ---------------------------------------------------------------
/**
* Joins a room by id.
*
* @param roomId - The room to join.
*/
joinRoom(roomId: string): Promise<void>
/**
* Leaves a room by id.
*
* @param roomId - The room to leave.
*/
leaveRoom(roomId: string): Promise<void>
// -- Messaging -----------------------------------------------------------
/**
* Sends an event to the server (broadcast to the default channel).
*
* @param event - The event name.
* @param data - The event payload.
*/
send(event: string, data: unknown): void
/**
* Sends an event to a specific room.
*
* @param roomId - The target room.
* @param event - The event name.
* @param data - The event payload.
*/
sendTo(roomId: string, event: string, data: unknown): void
// -- Event listening -----------------------------------------------------
/**
* Registers a handler for an incoming event.
*
* @param event - The event name to listen for.
* @param handler - The handler callback.
*/
on(event: string, handler: RealtimeEventHandler): void
/**
* Removes a handler for an event. If no handler is provided, all handlers
* for that event are removed.
*
* @param event - The event name.
* @param handler - The specific handler to remove (optional).
*/
off(event: string, handler?: RealtimeEventHandler): void
// -- Presence ------------------------------------------------------------
/**
* Returns the current presence information for all clients in a room.
*
* @param roomId - The room to query.
* @returns Array of presence info for each connected client.
*/
getPresence(roomId: string): PresenceInfo[]
/**
* Registers a handler that fires when presence changes in any joined room.
* The handler receives the room id the update is for (see
* {@link PresenceChangeHandler}) — a single handler registered once still
* works correctly for a consumer joined to multiple rooms.
*
* @param handler - The presence change handler.
*/
onPresenceChange(handler: PresenceChangeHandler): void
// -- Connection lifecycle ------------------------------------------------
/**
* Disconnects from the server and cleans up resources.
*/
disconnect(): void
/**
* Returns whether the connection is currently active.
*
* @returns `true` if connected to the server.
*/
isConnected(): boolean
/**
* Returns the current connection state.
*
* @returns The current {@link ConnectionState}.
*/
getState(): ConnectionState
/**
* Registers a handler that fires on successful reconnection.
*
* @param handler - The reconnection handler.
*/
onReconnect(handler: () => void): void
/**
* Registers a handler that fires when the connection state changes.
*
* @param handler - The state change handler.
*/
onStateChange(handler: ConnectionStateHandler): void
}
ConnectionStatePossible states of a realtime connection.
type ConnectionState = 'connecting' | 'connected' | 'disconnected' | 'reconnecting'
ConnectionStateHandlerHandler invoked when the connection state changes.
type ConnectionStateHandler = (state: ConnectionState) => void
PresenceChangeHandlerHandler invoked when presence information changes for a room.
type PresenceChangeHandler = (presence: PresenceInfo[], roomId: string) => void
RealtimeEventHandlerHandler invoked when a realtime event is received.
type RealtimeEventHandler = (data: unknown) => void
connect(url, options)Establishes a realtime connection using the bonded provider.
function connect(url: string, options?: ConnectionOptions): Promise<RealtimeConnection>
url — The server URL to connect to.options — Optional connection configuration.Returns: A promise resolving to a live realtime connection.
getProvider()Retrieves the bonded realtime client provider, throwing if none is configured.
function getProvider(): RealtimeClientProvider
Returns: The bonded realtime client provider.
hasProvider()Checks whether a realtime client provider is currently bonded.
function hasProvider(): boolean
Returns: true if a realtime client provider is bonded.
setProvider(provider)Registers a realtime client provider as the active singleton. Called by bond
packages (e.g. @molecule/app-realtime-socketio) during app startup.
function setProvider(provider: RealtimeClientProvider): void
provider — The realtime client provider implementation to bond.| Provider | Package |
|---|---|
| Realtime | @molecule/app-realtime-socketio |
Peer dependencies:
@molecule/app-bond ^1.0.1@molecule/app-bond
The client needs a realtime SERVER counterpart. Wire the matching bond
pair across the stack — e.g. @molecule/app-realtime-socketio in the app
with @molecule/api-realtime-socketio in the API — and connect to YOUR
API's URL. A client bond alone has nothing to connect to.
Wiring the bond is NOT consuming. Setting the bond up in bonds.ts only
opens the connection — a screen must ALSO connect() → joinRoom(room) →
on(event, handler), or it receives nothing while the server broadcasts to
an empty room. The room and event names MUST match the server's
broadcast(room, event, …) EXACTLY — both are usually template literals
(e.g. `listing:${id}`), so build the identical string. A wrong (or
never-joined) room, or a wrong event name, is a SILENT no-op: nothing throws,
the events just never arrive. Confirm with the live two-session check below.
Clean up on unmount/screen change. Registering on(event, handler) in
a render/effect without the matching off(event, handler) (plus
leaveRoom/disconnect) re-registers on every re-render — events then
fire N times.
Anything a client sends is UNTRUSTED server-side: the API must validate
and authorize every event (room membership, ownership) — never trust
client-supplied ids or roles.
Pass credentials via ConnectionOptions.auth at connect time, never in
the URL query string (URLs leak into logs).
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual screens/flows, and check every box off one by one. A box you can't check is an integration bug to fix — not a skip: