Setup
waitForRestore() resolves once all IndexedDB reads triggered by handle creation have completed. Call it after declaring every handle you need, not before.
How it works
On reconnect the server sends a
Sync delta that merges authoritatively on top of the cached state — the cache is never stale for long.
The visibilitychange flush covers most crash and background-kill scenarios: when the browser moves a tab to the background (mobile app switch, tab minimise) the queue is persisted immediately, before the process may be suspended or killed.
Offline mode
Passoffline: true to never auto-connect. The client operates entirely from the local cache. Call client.connect() explicitly when you want to go online.
Custom storage adapter
BothStateStorage (async) and SyncStateStorage (sync) are plain interfaces — implement them to use any backend:
Storage adapters
Multi-tab sync
PasstabSync: true to keep all open tabs in the same namespace in sync instantly — without each tab waiting for its own server round-trip:
BroadcastChannel is available in all modern browsers and in Node.js 18+. The SDK checks typeof BroadcastChannel !== "undefined" at construction time and silently skips tab sync if the API is absent.Caveats
- Awareness — ephemeral by design. Offline updates are dropped silently since awareness data is time-sensitive and not persisted.
- SSR / Node —
indexedDbStateStoragerejects gracefully ifindexedDBis not available.localStorageSyncOpsAdapteris a no-op iflocalStorageis unavailable. - Token rotation — snapshot keys include the
client_idfrom the token. If you issue a new token with a differentclient_id, the previous cache is ignored (not deleted automatically). - Long offline sessions — the server GCs RGA and Tree tombstones after 24 hours (configurable via
MERIDIAN_CRDT_GC_GRACE_MS). Clients offline longer than this grace period may not receive delete deltas for GC’d tombstones on reconnect.