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
| What | Storage | When saved | When loaded |
|---|---|---|---|
| CRDT snapshots | IndexedDB | After every server delta | On handle creation (lazy, async) |
| Pending op queue | localStorage | On close() and beforeunload | On MeridianClient.create() |
| Vector clocks | localStorage (opt-in) | On every observed op | On VectorClockTracker construction |
Sync delta that merges authoritatively on top of the cached state — the cache is never stale for long.
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
| Adapter | Interface | Use for |
|---|---|---|
indexedDbStateStorage(dbName?) | StateStorage (async) | CRDT snapshots — large data, no quota issues |
localStorageSyncOpsAdapter(prefix?) | SyncStateStorage (sync) | Pending op queue — must be sync for beforeunload safety |
memoryStateStorage | StateStorage (async) | Testing — in-memory, not persisted |
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).