import { z } from 'zod'; import { type PathCtx } from '../config/paths.js'; import { type LeaseOptions } from '../session/lease.js'; import { type LimitProbeResult } from './limit-probe.js'; import { type RefreshOutcome } from './oauth-refresh.js'; declare const EntrySchema: z.ZodObject<{ fiveHour: z.ZodNullable; sevenDay: z.ZodNullable; fiveHourReset: z.ZodNullable; sevenDayReset: z.ZodNullable; /** Per-model weekly windows (Fable, ...). */ models: z.ZodOptional>; }, "strip", z.ZodTypeAny, { utilization: number; name: string; resetsAt?: number | null | undefined; }, { utilization: number; name: string; resetsAt?: number | null | undefined; }>, "many">>; /** When this entry was fetched (epoch ms). */ at: z.ZodNumber; }, "strip", z.ZodTypeAny, { at: number; fiveHour: number | null; sevenDay: number | null; fiveHourReset: number | null; sevenDayReset: number | null; models?: { utilization: number; name: string; resetsAt?: number | null | undefined; }[] | undefined; }, { at: number; fiveHour: number | null; sevenDay: number | null; fiveHourReset: number | null; sevenDayReset: number | null; models?: { utilization: number; name: string; resetsAt?: number | null | undefined; }[] | undefined; }>; declare const SnapshotSchema: z.ZodObject<{ accounts: z.ZodRecord; sevenDay: z.ZodNullable; fiveHourReset: z.ZodNullable; sevenDayReset: z.ZodNullable; /** Per-model weekly windows (Fable, ...). */ models: z.ZodOptional>; }, "strip", z.ZodTypeAny, { utilization: number; name: string; resetsAt?: number | null | undefined; }, { utilization: number; name: string; resetsAt?: number | null | undefined; }>, "many">>; /** When this entry was fetched (epoch ms). */ at: z.ZodNumber; }, "strip", z.ZodTypeAny, { at: number; fiveHour: number | null; sevenDay: number | null; fiveHourReset: number | null; sevenDayReset: number | null; models?: { utilization: number; name: string; resetsAt?: number | null | undefined; }[] | undefined; }, { at: number; fiveHour: number | null; sevenDay: number | null; fiveHourReset: number | null; sevenDayReset: number | null; models?: { utilization: number; name: string; resetsAt?: number | null | undefined; }[] | undefined; }>>; }, "strip", z.ZodTypeAny, { accounts: Record; }, { accounts: Record; }>; export type UsageEntry = z.infer; export type UsageSnapshot = z.infer; export declare const USAGE_TTL_MS: number; /** The cached snapshot; malformed or absent reads as empty (never throws). */ export declare function readUsageSnapshot(c?: PathCtx): UsageSnapshot; /** * Persist a snapshot. Exported so renaming an account can move its numbers with * it; without that, a rename looks like the usage history was thrown away. */ export declare function writeUsageSnapshot(snapshot: UsageSnapshot, c?: PathCtx): void; /** * How old the stored snapshot is, judged by its NEWEST entry; Infinity when * there is nothing. The newest entry rather than the oldest, because one * account that could not be probed (signed out, rate-limited) must not make a * fresh snapshot read as ancient and trigger refreshes that cannot help it. */ export declare function snapshotAgeMs(c?: PathCtx, now?: () => number): number; /** * Whose stored login answers for this account's usage. * * A running Claude keeps its own copy of the login fresher than the profile's, * so a leased account is normally read from the session directory. That is only * right while the session is signed in AS this account. * * Sessions used to share one directory, so the login sitting in it belonged to * whichever account started last, and reading it filed THAT account's usage * under this one. Measured here: an account with 21% of its week used and 35% * of its Fable was recorded at 57% with Fable spent, and then routed around as * out of room while its own numbers said it was fine. * * Only falls back on positive evidence of a mismatch. An identity nobody has * recorded is not a mismatch, and refusing the session copy then would give a * staler answer for no reason. */ export declare function usageCredentialDir(account: { dir: string; email?: string; }, leaseConfigDir: string | undefined): string; export interface RefreshableAccount { name: string; dir: string; /** * Who this profile is registered for. Carried so the sibling check can tell a * genuine duplicate of ONE account from two different accounts that have * ended up holding the same token, and only copy a renewal across the first. */ email?: string; } export interface RefreshUsageOptions { maxAgeMs?: number; now?: () => number; /** Injected in tests; defaults to the real API probe. */ probe?: (credentialsFile: string) => Promise; /** Delay between account fetches, to stay inside the endpoint's budget. */ gapMs?: number; /** Injected in tests: how "is a session using this account" is answered. */ leaseOptions?: LeaseOptions; /** * Renew an account's token before reading its usage. An account you are not * using goes stale within hours, and a stale token cannot report usage, which * would hide exactly the accounts rotation wants to move to. */ renew?: (accountDir: string) => Promise; } /** * Refresh stale entries (older than the TTL) with one minimal probe each, in * parallel, and persist the merged snapshot. Fresh entries are not refetched. * A failed probe stores nulls WITH a timestamp so a broken network is retried * once per TTL, not every tick. */ export declare function refreshUsage(accounts: RefreshableAccount[], c?: PathCtx, options?: RefreshUsageOptions): Promise; export {};