/** * Transport-agnostic presence — the one place the local-first → cloud-optional * gradient is encoded. * * Presence is ephemeral and self-healing; it is never written to the causal op * log. That makes the *transport* a free choice, and this helper picks it by * intent rather than hardcoding a hub: * * - no `relayUrl` → {@link BroadcastChannelTransport}: cross-tab, $0, no * socket, works with the network killed. This is the free / local tier and * the default. (Telos principle 7: kill the network, presence across tabs * still works — you just stop seeing remote peers.) * - `relayUrl` set → {@link DurableObjectRelayTransport}: a hosted relay room. * This opens a socket, so per the ecosystem economics it is a *paid* tier. * - `transport` → bring your own (tests, or an Iroh gossip transport at * Boulder 2) — the escape hatch that keeps the seam honest. * * Frameworks consume this inside their room hooks, e.g. Svelte: * * import { createRoom } from 'trellis/svelte'; * import { joinPresence } from 'trellis/realtime'; * * const { presence, others, destroy } = createRoom(() => * joinPresence({ peerId, room: 'doc:42', initialPresence: { name, color } }), * ); */ import { BroadcastChannelTransport } from './broadcast-channel-transport.js'; import { DurableObjectRelayTransport } from './durable-object-relay-transport.js'; import { RealtimeRoom } from './room.js'; import type { PresenceState, RealtimeTransport } from './types.js'; export interface PresenceOptions
{
/** Local peer identity (stable per tab/device). */
peerId: string;
/** Logical room — peers sharing it see each other. */
room: string;
/** Initial local presence (name, color, cursor, …). */
initialPresence?: P;
/**
* Hosted relay base URL. When set, presence syncs cross-device through the
* relay (paid tier). When omitted, presence stays local/cross-tab (free).
*/
relayUrl?: string;
/** Auth token for the hosted relay. */
auth?: string;
/**
* Explicit transport — overrides the `relayUrl`/local selection entirely.
* Use for tests or an alternative transport (e.g. future Iroh gossip).
*/
transport?: RealtimeTransport;
/** Heartbeat interval (ms). Default 2000 (see {@link RealtimeRoom}). */
heartbeatMs?: number;
/** Peer expiry after no heartbeat (ms). Default 6000. */
timeoutMs?: number;
/** Injectable clock for tests. */
now?: () => number;
/** Injectable WebSocket (hosted relay) for tests / non-browser hosts. */
WebSocketImpl?: ConstructorParameters (opts: PresenceOptions ): RealtimeRoom ;
//# sourceMappingURL=presence.d.ts.map