Sync Ephemeral
TTL-scoped typed key/value store where all entries must have a time-to-live. Server version uses Redis, browser version runs entirely in-memory. Ideal for presence, sessions, and temporary state.
Typical Pattern: Snapshot + Stream
snapshot() → hydrate local state → reader({ after: cursor }).stream() → apply incremental eventsOn overflow event (cursor fell behind retention window), re-snapshot and restart the stream.
Decision Guide
- Create/update entry:
upsert({key, value})— resets TTL. - Extend TTL without changing value:
touch({key})— returns{ok: false}if key missing. - Explicit removal:
remove({key, reason?})— emitsdeleteevent. - Multi-tenant: pass
tenantIdon factory or per-operation override.
Gotchas
- Every entry MUST have a TTL (
ttlMson factory is required, > 0). This is not optional storage. maxEntriesdefault is 10,000.upsert()throwsEphemeralCapacityErrorwhen full.maxPayloadBytesdefault is 4,096.upsert()throwsEphemeralPayloadTooLargeErroron oversized JSON.- Logical key must be non-empty and <= 512 bytes.
snapshot()runs internal reconciliation (expiry cleanup) before returning — may be slow on first call with many stale entries.stream({wait: true})auto-retries transient transport errors internally. Do not wrap withretry().- Event stream retention default is 5 minutes (
eventRetentionMs). Slow consumers will getoverflow.
Browser
import { ephemeral, EphemeralCapacityError } from "@valentinkolb/sync/browser";Same API. Browser-specific notes:
- TTL expiration uses
setTimeoutcallbacks instead of Redis key expiry + reconciliation. - No reconciliation loop needed —
setTimeoutfires the expiry directly and emits theexpireevent. - Events use an in-memory
EventLoginstead of Redis Streams. snapshot()is instant (no reconciliation pass) since expired entries are removed eagerly by timers.- State is single-tab, lost on page refresh.
setTimeoutmay be throttled in background tabs — TTL precision is best-effort.
API Reference
Read full API/types/config/defaults in references/api.md.