import type { MetricsClient } from './connection'; import { type MetricsKeys } from './keys'; export interface Retention { /** Days of minute-level detail. Doubles as the recorder's catch-up window. */ minutes: number; /** Days of hourly rollup. */ hours: number; /** Days of daily totals, which is what the shipped charts read. */ days: number; } export declare class HistoryStore { private readonly redis; private readonly keys; readonly retention: Retention; constructor(opts: { redis: MetricsClient; keys: MetricsKeys; retention: Retention; }); upsertMinute(queue: string, metric: string, minute: number, value: number): Promise; /** * Raw HMGET of the totals hash: `null` means the day was never recorded, a present * string (including `'0'`) means it was. Distinguishing "missing" from "stored zero" * matters for callers deciding between empty history vs. a zero-backfilled series. */ readDailyTotalsRaw(queue: string, metric: string, days: string[]): Promise<(string | null)[]>; readDayMinutes(queue: string, metric: string, day: string): Promise>; /** * Hourly buckets for one day, keyed by absolute hour index. * * Falls back to folding the minute hash when the hourly rollup is absent, which covers * days recorded before the rollup existed. Once those minute hashes age out, the days * they cover are already outside the minute window anyway. */ readDayHours(queue: string, metric: string, day: string): Promise>; private readNumericHash; }