Plain operations: last write wins, hash-keyed events, simpler composite
CI / Node 22 (pull_request) Successful in 12s
CI / Node 26 (pull_request) Successful in 13s
CI / Node 24 (pull_request) Successful in 14s

- KV: one write primitive, write(changes) with { key, value? }; writeIfAbsent removed.
  The server executes exactly what clients send and never reads values, so they can be
  encrypted end to end. Adds setFields/getFields on the base class.
- HTTP: no server history or event ids; SSE relays every change (own writes included) and
  the client emits resync when a dropped stream reconnects.
- Composite: writes apply locally, then go to the source (undone locally if refused);
  pushed changes are applied and announced only where they differ from local values;
  offline writes go to a queue store (any KV storage); sync() = replay, diff, replay.
  Removes KVReplicaSet, KVOutbox, KeyCounter, SerialQueue and RetryTimer.
- Events: id = <time>_<sha256(time + canonical data)>, so concurrent appends never
  collide and retries can't duplicate; no versions or ConcurrencyError.
- Event-sourced documents: read, resolve, append, apply; catchUp folds in foreign events;
  getAt takes an event id.

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 13:33:07 +00:00
parent 1f82ec9110
commit 631c75428b
34 changed files with 814 additions and 1387 deletions
+23 -26
View File
@@ -15,14 +15,14 @@ export function runKVStorageConformance(name: string, make: () => BaseKVStorage
describe('primitives', () => {
beforeEach(async () => {
await db.writeMany([
['b', 2],
['a/2', { n: 'a2' }],
['c', [3]],
['a', 1],
['a/1', 'a1'],
['a0', null],
['10', 10],
['9', 9],
{ key: 'b', value: 2 },
{ key: 'a/2', value: { n: 'a2' } },
{ key: 'c', value: [3] },
{ key: 'a', value: 1 },
{ key: 'a/1', value: 'a1' },
{ key: 'a0', value: null },
{ key: '10', value: 10 },
{ key: '9', value: 9 },
])
})
@@ -48,16 +48,9 @@ export function runKVStorageConformance(name: string, make: () => BaseKVStorage
expect(await db.readMany(['b', 'c'])).toEqual([undefined, [3]])
})
it('writeIfAbsent writes only absent keys, and only one concurrent claim wins', async () => {
expect(
await db.writeIfAbsent([
['a', 'x'],
['new', 'y'],
]),
).toEqual([false, true])
expect(await db.readMany(['a', 'new'])).toEqual([1, 'y'])
const results = await Promise.all([1, 2, 3].map((n) => db.writeIfAbsent([['claim', n]])))
expect(results.flat().filter(Boolean)).toHaveLength(1)
it('writes and removes in one batch', async () => {
await db.writeMany([{ key: 'b' }, { key: 'new', value: 'y' }, { key: 'a', value: 'x' }])
expect(await db.readMany(['a', 'b', 'new'])).toEqual(['x', undefined, 'y'])
})
it('keeps scanning correctly when keys change mid-scan', async () => {
@@ -74,22 +67,18 @@ export function runKVStorageConformance(name: string, make: () => BaseKVStorage
it('emits change events for writes and removals', async () => {
const events: unknown[] = []
const off = db.on('change', (event) => events.push(event))
await db.writeMany([['x', 1]])
await db.writeMany([{ key: 'x', value: 1 }])
await db.removeMany(['x'])
await db.writeIfAbsent([
['a', 'no'],
['y', 2],
])
await db.writeMany([])
off()
expect(events).toEqual([
{ changes: [{ key: 'x', value: 1 }], origin: 'local' },
{ changes: [{ key: 'x' }], origin: 'local' },
{ changes: [{ key: 'y', value: 2 }], origin: 'local' },
])
})
it('stores bigint and Uint8Array values', async () => {
await db.writeMany([['bin', { n: 10n ** 20n, bytes: new Uint8Array([0, 255]) }]])
await db.writeMany([{ key: 'bin', value: { n: 10n ** 20n, bytes: new Uint8Array([0, 255]) } }])
expect(await db.readMany(['bin'])).toEqual([{ n: 10n ** 20n, bytes: new Uint8Array([0, 255]) }])
})
@@ -123,6 +112,14 @@ export function runKVStorageConformance(name: string, make: () => BaseKVStorage
expect(await n.getMany(['a', 'b'])).toEqual([undefined, 2])
})
it('sets and gets direct children as fields', async () => {
const user = db.child('users').child('1')
await user.setFields({ name: 'Ada', hobby: 'chess', skipped: undefined })
await user.child('address').set('city', 'Paris')
expect(await user.get('hobby')).toBe('chess')
expect(await user.getFields()).toEqual({ hobby: 'chess', name: 'Ada' })
})
it('keeps own values and children independent', async () => {
const user = db.child('users').child('1')
await user.set('own')
@@ -157,7 +154,7 @@ export function runKVStorageConformance(name: string, make: () => BaseKVStorage
await n.set('c', 3)
await n.child('c').child('x').set('y', 1)
await n.set('a-1', 4)
await db.writeMany([['n/~e/000000000001', {}]])
await db.writeMany([{ key: 'n/~e/000000000001', value: {} }])
expect(await collect(n.keys())).toEqual(['a', 'a-1', 'b', 'c'])
expect(await collect(n.keys({ reverse: true }))).toEqual(['c', 'b', 'a-1', 'a'])
expect(await collect(n.keys({ after: 'a', limit: 2 }))).toEqual(['a-1', 'b'])