Sync / foldkit-durable
Using Durable directly
Without Sync, a Journal needs an operation codec, a snapshot codec, an empty snapshot, and a pure reducer:
ts
import { Effect, Schema } from 'effect'
import { ActorId, Cursor, DocumentId, Journal, OpId } from 'foldkit-durable'
const Operation = Schema.Struct({ opId: Schema.String, title: Schema.String })
const Snapshot = Schema.Struct({ todos: Schema.Array(Schema.String) })
type Principal = { readonly actorId: string }
const program = Effect.gen(function* () {
const journal = yield* Journal.make({
file: 'journal.sqlite',
operation: Operation,
snapshot: Snapshot,
empty: () => ({ todos: [] }),
reduce: (snapshot, operation) => ({ todos: [...snapshot.todos, operation.title] }),
opId: operation => OpId.make(operation.opId),
actorId: (principal: Principal) => ActorId.make(principal.actorId),
})
const todos = DocumentId.make('todos')
yield* journal.append(todos, { opId: 'tab-1:1', title: 'Milk' }, { actorId: 'alice' })
const { snapshot, cursor } = yield* journal.load(todos)
const since = yield* journal.read(todos, Cursor.make(0))
return { snapshot, cursor, since }
}).pipe(Effect.scoped)The operation schema decides what append accepts: its encoded side, so a
transforming schema is checked at the call site rather than degrading the
boundary to unknown. A payload that does not decode is an InvalidOperationError.