client.offline
See the Offline guide for concepts and patterns. Offline support is on by default in browsers and a no-op in Node, serverless runtimes and SSR.
Properties
Section titled “Properties”status
Section titled “status”client.offline.status: "online" | "offline" | "syncing"Current connectivity, fused from navigator.onLine, real request outcomes, and
the websocket lifecycle. "syncing" means the durable write queue is draining
after a reconnect.
enabled
Section titled “enabled”client.offline.enabled: booleantrue in a browser with IndexedDB + the Cache API; false otherwise (all
methods become no-ops / return empty).
Methods
Section titled “Methods”onStatusChange(cb)
Section titled “onStatusChange(cb)”onStatusChange(cb: (status: "online" | "offline" | "syncing") => void): () => voidSubscribe to connectivity changes. Returns an unsubscribe function. Status
changes are also emitted on EventCore (ONLINE, OFFLINE, SYNCING,
SYNC_PROGRESS, SYNC_COMPLETE, SYNC_ERROR).
resume()
Section titled “resume()”resume(): Promise<void>Replay the durable write queue now, as a reconnect does, if the queue holds
anything. Writes kept after a payment refusal (see below) go out this way. It
does nothing when offline support is off or the queue is empty. The SDK calls it
for you each time client.app.access() reports the app
allowed; call it yourself only if you have another reason to think a refusal has
cleared.
Sync events
Section titled “Sync events”The durable queue replays writes in clock order when the connection returns.
Progress is reported on EventCore, with these payloads:
| Event | Payload |
|---|---|
SYNC_PROGRESS | { domain, method } — one queued write was accepted. |
SYNC_COMPLETE | {} — the drain finished. |
SYNC_ERROR | { domain, method, error, dropped } — dropped: true means the server permanently refused the write (a 4xx) and it was discarded; a transient failure stops the drain and keeps the rest for the next reconnect. |
A write refused for payment (PaymentRequiredError: the app takes paid plans only,
or someone’s payment is past due) is kept, not dropped. SYNC_ERROR carries
dropped: false and the refusal’s code, and the drain stops there, keeping
order. It resumes on the next reconnect or when client.offline.resume() runs.
App-state snapshots — client.offline.snapshot
Section titled “App-state snapshots — client.offline.snapshot”An encrypted cache for UI/view state that never leaves the device. Encrypted at rest with the
identity-derived key; reads return null while the client is locked.
save(name, state)
Section titled “save(name, state)”save<T>(name: string, state: T): Promise<void>Persist state under name (encrypted). Throws OfflineLockedError if the
identity isn’t unlocked. The latest save wins. No-op when offline support is off.
load(name)
Section titled “load(name)”load<T>(name: string): Promise<T | null>Decrypt and return the snapshot, or null if absent or the client is locked.
delete(name) / list()
Section titled “delete(name) / list()”delete(name: string): Promise<void>list(): Promise<string[]>Remove a snapshot; list all snapshot names for the current user.
Client options
Section titled “Client options”new Client({ offline }) accepts enabled and store. It also declares
cacheShards and maxQueueBytes, but the SDK does not currently read either:
file-shard caching is on whenever offline support is on and the Cache API
exists, and the queue has no size cap.
Related
Section titled “Related”space.cachedMessages()— decode the locally-cached message log (offline hydrate).- The
offlineoption onnew Client(...)— enable/disable or supply a custom store.
Errors
Section titled “Errors”OfflineLockedError
Section titled “OfflineLockedError”Thrown when an encrypted offline read/write needs the user’s identity but the
client is locked (typically right after a reload, before unlock()). Distinct
from the generic “not signed in” error so apps can prompt to unlock specifically.