Files
PotentialStorage/src/utils/key-range.ts
T
Claude 1f82ec9110
CI / Node 22 (pull_request) Successful in 11s
CI / Node 24 (pull_request) Successful in 12s
CI / Node 26 (pull_request) Successful in 12s
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
2026-10-23 12:43:49 +00:00

37 lines
1.5 KiB
TypeScript

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 }
}
}