Break KVStorageComposite into focused classes
- 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:
@@ -0,0 +1,36 @@
|
||||
import type { ScanOptions } from '../kv-storage/base-kv-storage.js'
|
||||
import { Keys } from './keys.js'
|
||||
|
||||
/**
|
||||
* A key and its whole subtree: `[prefix, prefix + '0')`. Escaping guarantees nothing else sorts
|
||||
* in that range (not even lookalikes such as `prefix-x`). The empty prefix is every key.
|
||||
*/
|
||||
export class KeyRange {
|
||||
/** Inclusive lower bound (`undefined` = unbounded). */
|
||||
readonly gte: string | undefined
|
||||
/** Exclusive upper bound (`undefined` = unbounded). */
|
||||
readonly lt: string | undefined
|
||||
|
||||
constructor(readonly prefix: string) {
|
||||
this.gte = prefix === '' ? undefined : prefix
|
||||
this.lt = prefix === '' ? undefined : prefix + Keys.afterSeparator
|
||||
}
|
||||
|
||||
contains(key: string): boolean {
|
||||
return this.prefix === '' || key === this.prefix || key.startsWith(this.prefix + Keys.separator)
|
||||
}
|
||||
|
||||
/** Whether a scan over `[gte, lt)` stays inside this range. */
|
||||
covers(gte: string | undefined, lt: string | undefined): boolean {
|
||||
if (this.prefix === '') return true
|
||||
return gte !== undefined && lt !== undefined && gte >= this.gte! && lt <= this.lt!
|
||||
}
|
||||
|
||||
/** Scan options narrowed to this range, or `undefined` if nothing is left. */
|
||||
clamp(options: ScanOptions): ScanOptions | undefined {
|
||||
const gte = this.gte !== undefined && (options.gte === undefined || options.gte < this.gte) ? this.gte : options.gte
|
||||
const lt = this.lt !== undefined && (options.lt === undefined || options.lt > this.lt) ? this.lt : options.lt
|
||||
if (gte !== undefined && lt !== undefined && gte >= lt) return undefined
|
||||
return { ...options, gte, lt }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user