Break KVStorageComposite into focused classes
CI / Node 22 (pull_request) Successful in 11s
CI / Node 24 (pull_request) Successful in 12s
CI / Node 26 (pull_request) Successful in 12s

- KVReplicaSet: seed, apply, local scan, diff against the source, sync meta
- KVOutbox: persisted offline queue with in-order replay (load() resumes it)
- utils: KeyRange (also used for server authorization), KeyCounter,
  SerialQueue (also used by KVStorageHttp and the event-sourced store),
  RetryTimer (separate timers for sync and replay; previously one shared
  timer could cancel the other's retry)

The composite now only orchestrates. Behaviour unchanged; new unit tests for
the building blocks and the outbox.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017Qxbkp4tA7G5SCWjzWuxmE
This commit is contained in:
Claude
2026-10-23 12:43:49 +00:00
parent a8c9539ad9
commit 1f82ec9110
14 changed files with 616 additions and 317 deletions
+12
View File
@@ -177,6 +177,18 @@ outbox `~q/o/<seq:12>`.
- `start()`, `synced()` (complete copy, all received changes applied), `queued` (outbox size),
`close()`.
**Structure.** The composite only orchestrates (what to read from, when to sync, whether to queue a
write). The work is done by small classes:
| Class | Job |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `KVReplicaSet` | the replicas of one `KeyRange`: seed the faster ones, apply changes, scan locally (hiding `~q/` bookkeeping), diff against the source, sync metadata |
| `KVOutbox` | the persisted offline queue (`~q/o/<seq>`), its pending-key counts, and in-order replay with backoff |
| `KeyRange` (utils) | a key plus its subtree: `contains`, `clamp` scan bounds, `covers` a scan; also used by the server's authorization |
| `KeyCounter` (utils) | per-key counts: pending outbox writes and expected echoes |
| `SerialQueue` (utils) | one-at-a-time tasks, optionally per key: applying remote changes, subscription updates, event-sourced writes |
| `RetryTimer` (utils) | backoff retries, one timer per job (full sync and outbox replay retry independently) |
## 5. Event storage
`BaseEventStorage` primitives over stream paths: `appendTo`, `readFrom`, `versionOf`, `streamsOf`.