diff options
Diffstat (limited to 'packages/throughput-store/src/store.ts')
| -rw-r--r-- | packages/throughput-store/src/store.ts | 100 |
1 files changed, 50 insertions, 50 deletions
diff --git a/packages/throughput-store/src/store.ts b/packages/throughput-store/src/store.ts index 94675b1..7c5991b 100644 --- a/packages/throughput-store/src/store.ts +++ b/packages/throughput-store/src/store.ts @@ -3,18 +3,18 @@ import { aggregateSamples, type ModelThroughput, type ThroughputSample } from ". import { dayKeyOf, type Period, resolvePeriod } from "./period.js"; export interface ThroughputReport { - readonly period: Period; - readonly date: string; - /** Inclusive start, epoch-ms. */ - readonly start: number; - /** Exclusive end, epoch-ms. */ - readonly end: number; - readonly models: readonly ModelThroughput[]; + readonly period: Period; + readonly date: string; + /** Inclusive start, epoch-ms. */ + readonly start: number; + /** Exclusive end, epoch-ms. */ + readonly end: number; + readonly models: readonly ModelThroughput[]; } export interface ThroughputQuery { - readonly period: Period; - readonly date: string; + readonly period: Period; + readonly date: string; } /** @@ -24,15 +24,15 @@ export interface ThroughputQuery { * key so a period query addresses only its own day buckets. */ export interface ThroughputStore { - readonly record: (sample: ThroughputSample) => Promise<void>; - readonly aggregate: (query: ThroughputQuery) => Promise<ThroughputReport>; + readonly record: (sample: ThroughputSample) => Promise<void>; + readonly aggregate: (query: ThroughputQuery) => Promise<ThroughputReport>; } export interface ThroughputStoreDeps { - readonly storage: StorageNamespace; - readonly logger?: Logger; - /** Injectable unique-id generator (default crypto.randomUUID). */ - readonly newId?: () => string; + readonly storage: StorageNamespace; + readonly logger?: Logger; + /** Injectable unique-id generator (default crypto.randomUUID). */ + readonly newId?: () => string; } /** Thrown when a query's `(period, date)` is malformed. */ @@ -41,43 +41,43 @@ export class ThroughputQueryError extends Error {} const SAMPLE_PREFIX = "sample"; export function createThroughputStore(deps: ThroughputStoreDeps): ThroughputStore { - const newId = deps.newId ?? (() => crypto.randomUUID()); + const newId = deps.newId ?? (() => crypto.randomUUID()); - return { - async record(sample) { - // Per-sample key under the local-day bucket → write is a single set - // (no read-modify-write, so concurrent turns can't lose a sample). - const day = dayKeyOf(sample.ts); - const key = `${SAMPLE_PREFIX}:${day}:${sample.ts}:${newId()}`; - await deps.storage.set(key, JSON.stringify(sample)); - }, + return { + async record(sample) { + // Per-sample key under the local-day bucket → write is a single set + // (no read-modify-write, so concurrent turns can't lose a sample). + const day = dayKeyOf(sample.ts); + const key = `${SAMPLE_PREFIX}:${day}:${sample.ts}:${newId()}`; + await deps.storage.set(key, JSON.stringify(sample)); + }, - async aggregate(query) { - const resolved = resolvePeriod(query.period, query.date); - if (!resolved.ok) throw new ThroughputQueryError(resolved.error); + async aggregate(query) { + const resolved = resolvePeriod(query.period, query.date); + if (!resolved.ok) throw new ThroughputQueryError(resolved.error); - const samples: ThroughputSample[] = []; - for (const day of resolved.dayKeys) { - const keys = await deps.storage.keys(`${SAMPLE_PREFIX}:${day}:`); - for (const k of keys) { - const raw = await deps.storage.get(k); - if (raw === null) continue; - try { - samples.push(JSON.parse(raw) as ThroughputSample); - } catch { - // Skip a malformed row rather than failing the whole query. - } - } - } + const samples: ThroughputSample[] = []; + for (const day of resolved.dayKeys) { + const keys = await deps.storage.keys(`${SAMPLE_PREFIX}:${day}:`); + for (const k of keys) { + const raw = await deps.storage.get(k); + if (raw === null) continue; + try { + samples.push(JSON.parse(raw) as ThroughputSample); + } catch { + // Skip a malformed row rather than failing the whole query. + } + } + } - const models = aggregateSamples(samples, resolved.start, resolved.end); - return { - period: query.period, - date: resolved.date, - start: resolved.start, - end: resolved.end, - models, - }; - }, - }; + const models = aggregateSamples(samples, resolved.start, resolved.end); + return { + period: query.period, + date: resolved.date, + start: resolved.start, + end: resolved.end, + models, + }; + }, + }; } |
