Live
Live is Anyknown’s realtime/collaborative Capability — multiple Visitors editing, watching, or reacting to the same state in a shared room, conflict-resolved with a CRDT (Yjs) underneath.
Live is split today: the client path works, the server path does not. The browser can open a WebSocket to a room and send/receive ops right now. sdk.live.room() — the server-side handle a handler would use to apply ops, read a snapshot, or push events from your own backend code — throws NotAvailableInV1Error unconditionally in a deployed App. Read this page for what you can build against now, and treat the server half as not-yet-shipped.
What works: the client connection
Section titled “What works: the client connection”liveConnect (exported as connect from @anyknown/app-client) opens a WebSocket to your App’s live gateway at /_anyknown/live/<room> and gives you an event-driven connection object. This is real, running infrastructure — app-runtime routes the WebSocket to a per-room Durable Object (ROOM_DO) that holds the CRDT document, ack’s ops, and fans out to every connected client.
import { liveConnect } from "@anyknown/app-client"
const room = liveConnect("my-room-id", { lastSeenVersion: 0, onUnauthenticated: () => { /* redirect to sign-in, etc. */ },})
room.on("op", (envelope) => { // apply envelope.op to local state})room.on("presence", ({ clientId, state }) => { // another client's awareness state changed})room.on("error", ({ code, message, retryAfter }) => { // e.g. code === "RATE_LIMITED"})
room.send({ opId: crypto.randomUUID(), clientId: myClientId, parentVersion: currentVersion, op: myChange,})
room.setPresence({ cursor: { x, y } })
// laterroom.disconnect()function liveConnect(roomId: string, opts?: ClientLiveOpts): ClientLiveConnection
type ClientLiveOpts = { lastSeenVersion?: number onUnauthenticated?: () => void}
type ClientLiveConnection = { send(input: { opId: string clientId: string parentVersion: number op: unknown ts?: number }): void setPresence(state: unknown): void disconnect(): void on<K extends "op" | "ack" | "presence" | "error" | "close" | "replay-done">( event: K, handler: (data: ClientLiveEventMap[K]) => void, ): () => void // returns an unsubscribe function}The connection reconnects automatically with exponential backoff (capped, up to 12 attempts) on a dropped socket, and replays missed ops from lastSeenVersion on reconnect — you do not need to write your own reconnect or replay logic. A "close" event fires only when you call disconnect() yourself, or after retries are exhausted; an "UNAUTHORIZED" error stops reconnection entirely and calls onUnauthenticated.
Events you can listen for:
| Event | Fires when |
|---|---|
op | A remote op was applied to the room and reached this client |
ack | An op this client sent was accepted and assigned a version |
presence | Another client’s awareness state changed |
error | The gateway rejected something (rate limit, disabled room, etc.) |
close | The connection was deliberately closed or exhausted its retries |
replay-done | Missed-op replay from lastSeenVersion finished on (re)connect |
What does not work: server-side sdk.live.room()
Section titled “What does not work: server-side sdk.live.room()”The server-side room API is retired in v1 — realtime is client-only, via liveConnect. sdk.live.room() has been removed from the public SDK type, so newly built Apps cannot even compile a call to it. Older bundles built before the removal hit a runtime tombstone instead:
NotAvailableInV1Error: server-side sdk.live is retired in v1 (client-only realtime via liveConnect); ROOM_DO binding is not configured in deployed AppsThis is not a runtime fluke or a misconfiguration you can fix from your App, and it is not unlockable through any plan or App-level setting — it is the intentional v1 posture. Bringing the server half back needs a cloud-api binding change and a tenant-auth design that has not shipped. Do not write handler code that calls sdk.live.room().
Using Live today
Section titled “Using Live today”Build realtime features entirely from the browser side with liveConnect. Multiple Visitors connecting to the same roomId share state through the CRDT-backed room; your handler code does not need to (and currently cannot) participate server-side. This covers collaborative cursors, live presence, shared editing surfaces, and similar client-to-client patterns — anything that does not require your own backend to originate or validate ops.
Things to know
Section titled “Things to know”-
sdk.live.room()throws today — do not build against it. The clientliveConnectpath is the only working surface. Treat the server-side room API as a documented future contract, not something you can call. -
The client path is real infrastructure, not a mock.
/_anyknown/live/<room>routes to a liveROOM_DODurable Object with CRDT conflict resolution, ack’d ops, presence/awareness, and automatic reconnect-with-replay. -
No client SDK ergonomics beyond
liveConnectyet. There is no framework-specific wrapper (e.g. a React hook) shipped today — you own theon/sendevent wiring in your component. -
A room can reject ops. Watch for
errorevents withcode: "RATE_LIMITED","ROOM_DISABLED", or a storage-cap condition, and handle them rather than assuming everysendsucceeds.