/** * Persisted quota ledger — pure persistence + keying helpers, no quota * decision logic (that lives in `quota-governor.ts`). * * Layout: `.bober/seo/quota-ledger.json`. * * Every write is atomic via temp-file + rename (mirrors * `src/incident/timeline.ts:86-92` atomicWriteJson / `src/state/run-state.ts:41-52`). * * Concurrent read-modify-write calls to the SAME resolved path are serialized * via a module-scoped per-path promise-chain mutex (mirrors * `src/telemetry/emit.ts:57,85-86`) so two `SeoQuotaGovernor` instances * sharing a ledger path never lose an update. * * Fail-closed discrimination: a MISSING ledger (ENOENT) is a fresh, empty * ledger (offline / first-run => allow). An EXISTING-but-unparseable or * unreadable ledger is the `"corrupt"` sentinel (fail-closed => at-ceiling). * This is deliberately NOT the blanket catch used by `readRunState` * (`src/state/run-state.ts:61-68`), which collapses both cases to `null`. * * Sprint 7 — spec-20260715-ultimate-seo-suite. */ import type { SeoQuotaLedger } from "./types.js"; /** `YYYY-MM-DD` date key; daily counters reset on this boundary. */ export declare function dateKey(now: Date): string; /** Composite per-site/per-user scope key (`${siteUrl}|${userId}`). */ export declare function scopeKey(scope: { siteUrl?: string; userId?: string; }): string; /** * Read the ledger from disk. * * - Missing file (ENOENT) => fresh empty ledger `{}` (offline/first-run, NOT corrupt). * - Existing-but-unreadable (permissions, etc.) or unparseable JSON => `"corrupt"` * sentinel so the caller can fail closed (treat spend as at-ceiling). */ export declare function readLedger(path: string): Promise; /** * Atomically overwrite the ledger: write a unique temp file, then rename * (POSIX-atomic) so a crash mid-write can never leave a torn/corrupt file. */ export declare function writeLedgerAtomic(path: string, ledger: SeoQuotaLedger): Promise; /** * Run `fn` exclusively with respect to any other `withLedgerLock` call on * the same resolved path. Chains onto the previous run regardless of * whether it resolved or rejected, so one failure never wedges the chain. */ export declare function withLedgerLock(path: string, fn: () => Promise): Promise; //# sourceMappingURL=quota-ledger.d.ts.map