Sync / foldkit-durable

Limits

  • SQLite is the only database: through @effect/sql-sqlite-node (Node 22) for Journal.make, or any effect/sql SQLite client for the core Journal.layer (foldkit-durable/core), such as @effect/sql-sqlite-wasm in a browser or @effect/sql-d1 on Cloudflare (with d1: true). vacuum reclaims a file's space and checkpoints its write-ahead log, which an in-memory database has nothing of; on D1 it is a no-op (see above).
  • reduce, validate, and authorize hold the write lock. Keep them pure, fast, and service-free.
  • One Journal handle per file. Uniqueness of [key, op_id] and [key, sequence] is enforced by the database, but the intended deployment is one authoritative writer.
  • Payloads compacted before schema 3 have no canonical hash, so only those rows cannot reject a key-reordered retry.
  • recover is application-driven; there is no background worker and no atomic append-and-enqueue.

Older spellings

makeJournal, makeJournalLayer, and journalMetrics are Journal.make, Journal.layer, and Journal.metrics; documentId, opId, actorId, sequence, and cursor are the branded .make constructors. JournalService(key) still works, but its generic arguments are supplied again at each use site with nothing tying them to the layer; Journal.define fixes both together. A codec given as a function pair is accepted wherever a Schema.Codec is.

See also

  • Replicated state: both halves end to end, including the exchange handler over this journal.
  • Editing server data through a journal: a table as this journal's read model, edits laid over Remote's rows.
  • foldkit-sync: the client half; journalContract() supplies the codecs, reducer, initial state, replica binding, and compiled authorization.
  • examples/sync: a SQLite journal, several replicas, server policy, compaction, and the effect ledger, with a test per failure.