Offline Actions
Use a custom action when KalamDB is not the only write path. The table stays replicaOnly, the backend remains authoritative, and kalam_sync owns the optimistic overlay plus a durable outbox.
kalam_sync_generator writes the JSON codec, namespaced action definition, and typed queue. Drift still owns table row types. Direct create/update/delete uses one generic DML envelope — the generator does not emit three extra models per table.
Generate a queue
Add the generator as a dev dependency, then annotate an immutable payload and executor module:
dev_dependencies:build_runner: ^2.15.1kalam_sync_generator: ^0.6.0-rc.0That generates chat.sendMessage, the codec, and ChatActionsQueue.sendMessage().
Open with action definitions
Enqueue with an optimistic row
The generated queue method commits the optimistic row, sidecar sync state, and serialized action together. On connectivity, the executor calls the backend with the stable action UUID. The row becomes synced only after the backend’s KalamDB write arrives and is committed locally.
orderingKey keeps related actions FIFO (one conversation, one queue). Different keys can flush in parallel.
Calling messages.insert(...) on a replicaOnly table throws. Send and read receipts go through the generated queue.
Named steps
context.step(...) runs a sub-operation at most once across retries and process restarts. A completed named step is persisted and reused. Every remote endpoint must still honor the supplied idempotency key, because a response can be lost after the server commits.
context.idempotencyKey is the action UUID. Step callbacks receive '$actionId/$stepName'.
FILE uploads
Multipart FILE("placeholder") uploads use the same step machinery. Persist the step result, not the file bytes:
Retrying the action reuses a completed upload instead of sending the multipart body again.
Generation boundary
| Owner | Generates |
|---|---|
kalam schema gen --languages dart | Row classes and KalamTableSpec values |
kalam_sync_generator / build_runner | Action payload codecs, definitions, and queues |
| Drift | Table row / companion types when you own a custom database |
kalam_sync runtime | One generic DML envelope for bidirectional insert / update / delete |
Do not hand-write duplicate row models. Edit schema.sql, regenerate, then bind KalamTables.*.
The complete offline-first chat app, REST engine, schema, and live-server use-case tests live in the kalam_sync example. Conversations use bidirectional DML; messages stay replicaOnly and sync through generated sendMessage / markMsgRead actions.