1.7 KiB
1.7 KiB
Atomsync
Clojure/ClojureScript offline-first synced atom library backed by IndexedDB (CLJS) or SQLite (CLJ).
Async: use promesa, not core.async
This project uses promesa (funcool/promesa) for all async operations. Do not introduce core.async.
- Store protocol (
store.cljc): all methods return promesa promises- Sync operations (e.g. MemoryStore):
(p/resolved val) - Async operations (e.g. IDBStore):
(p/create (fn [resolve reject] ...))
- Sync operations (e.g. MemoryStore):
- HTTP / sync (
sync.cljc): CLJ usesp/vthread, CLJS returns native JS Promise chains - Core (
core.cljc):p/letfor sequential async,p/allfor parallel - Sync loop: platform timers (
setInterval/ScheduledExecutorService), not go-loop - Push coalescing: debounced with 50ms timer +
pushing?atom guard, not channels
Why not core.async
- Channels-as-one-shot-promises add ceremony (
chan+put!+close!) for what is conceptually a return value - promesa maps to native primitives: JS Promises on CLJS, CompletableFuture on CLJ
p/letreads cleaner thango+<!for sequential async- Timer-based sync loop is simpler than
go-loop+alts!for this use case
Project structure
src/atomsync/
store.cljc — PStore protocol (promises)
store/memory.cljc — in-memory store (testing/JVM)
store/idb.cljs — IndexedDB store (browser)
sync.cljc — HTTP pull/push, SSE, connectivity
core.cljc — SyncedAtom, sync loop, public API
transit.cljc — Transit encoding/decoding
db.clj — SQLite server storage (nippy)
server.clj — HTTP sync server (http-kit)
Running tests
clj -M:dev:test