/** * Maps a CLIProxyAPI hub's `quota-scheduler/status` response onto the usage * limit windows the Limits view renders, one account per pooled auth file. * * The hub already normalises each upstream: Claude accounts carry * `five_hour` / `seven_day` / `fable`, Codex accounts `five_hour` / `weekly`. * Every window is `{ used_percent, reset_at?, known, hard_limited }`. * * @module usage/cliproxyUsageLimits */ import { ProviderDriverKind, type ServerProviderUsageLimits, type ServerProviderUsageWindow, type UsageLimitSourceAccount, } from "@t3tools/contracts"; import * as DateTime from "effect/DateTime"; import * as Option from "effect/Option"; import * as Schema from "effect/Schema"; import { codexPlanLabel } from "../provider/Layers/CodexProvider.ts"; import { clampPercent, makeUsageLimits } from "../provider/providerUsageLimits.ts"; const QuotaWindow = Schema.Struct({ used_percent: Schema.Number, reset_at: Schema.optional(Schema.String), known: Schema.optional(Schema.Boolean), hard_limited: Schema.optional(Schema.Boolean), }); const QuotaAccount = Schema.Struct({ provider: Schema.String, plan: Schema.optional(Schema.String), fetched_at: Schema.optional(Schema.String), five_hour: Schema.optional(QuotaWindow), seven_day: Schema.optional(QuotaWindow), weekly: Schema.optional(QuotaWindow), fable: Schema.optional(QuotaWindow), }); export const CliproxyQuotaStatus = Schema.Struct({ accounts: Schema.Record(Schema.String, QuotaAccount), }); export type CliproxyQuotaStatus = typeof CliproxyQuotaStatus.Type; export const decodeCliproxyQuotaStatus = Schema.decodeUnknownEffect(CliproxyQuotaStatus); const SESSION_MINS = 5 * 60; const WEEK_MINS = 7 * 24 * 60; /** Window ids match what the provider drivers emit, so rows read the same across sources. */ const WINDOWS: ReadonlyArray<{ readonly key: keyof Omit; readonly id: string; readonly kind: ServerProviderUsageWindow["kind"]; readonly label: string; readonly windowDurationMins: number; }> = [ { key: "five_hour", id: "five_hour", kind: "session", label: "Session", windowDurationMins: SESSION_MINS, }, { key: "seven_day", id: "seven_day", kind: "weekly", label: "Weekly", windowDurationMins: WEEK_MINS, }, { key: "weekly", id: "secondary", kind: "weekly", label: "Weekly", windowDurationMins: WEEK_MINS, }, { key: "fable", id: "seven_day_fable", kind: "weekly", label: "Weekly · Fable", windowDurationMins: WEEK_MINS, }, ]; const DRIVER_BY_HUB_PROVIDER: Readonly> = { claude: ProviderDriverKind.make("claudeAgent"), codex: ProviderDriverKind.make("codex"), }; function isoFromHub(value: string | undefined): string | undefined { if (!value) return undefined; const dt = DateTime.make(value); return Option.isSome(dt) ? DateTime.formatIso(dt.value) : undefined; } /** `claude-julius@ping.gg.json` → `julius@ping.gg`; `codex--x@y-pro.json` → `x@y`. */ export function accountEmailFromAuthFile(fileName: string): string | undefined { const stem = fileName.replace(/\.json$/i, ""); // Strip the provider prefix (and Codex's hash) rather than splitting on // `-`, so a hyphenated local part such as `first-last@` survives. return stem.match(/^(?:claude-|codex-[a-z0-9]+-)?([^\s/]+@[^\s/]+?)(?:-[a-z0-9]+)?$/i)?.[1]; } /** * The hub only reports a plan slug for Codex. Claude accounts carry no tier * in the scheduler status, so the row says what it is: a Claude subscription. */ function planLabel(account: typeof QuotaAccount.Type): string | undefined { if (account.provider === "codex") return codexPlanLabel(account.plan); if (account.provider === "claude") return "Claude Subscription"; return undefined; } export function cliproxyAccountToUsageLimits( account: typeof QuotaAccount.Type, checkedAt: string, ): ServerProviderUsageLimits { const windows: ServerProviderUsageWindow[] = []; for (const spec of WINDOWS) { const window = account[spec.key]; if (!window || window.known === false) continue; const resetsAt = isoFromHub(window.reset_at); windows.push({ id: spec.id, kind: spec.kind, label: spec.label, windowDurationMins: spec.windowDurationMins, // The hub flags a window it has seen a 429 on; the percent may lag. usedPercent: window.hard_limited ? 100 : clampPercent(window.used_percent), ...(resetsAt ? { resetsAt } : {}), }); } return makeUsageLimits({ checkedAt: isoFromHub(account.fetched_at) ?? checkedAt, windows }); } export function cliproxyStatusToAccounts( status: CliproxyQuotaStatus, checkedAt: string, ): ReadonlyArray { const accounts: UsageLimitSourceAccount[] = []; for (const [fileName, account] of Object.entries(status.accounts)) { const driver = DRIVER_BY_HUB_PROVIDER[account.provider]; if (!driver) continue; const email = accountEmailFromAuthFile(fileName); const plan = planLabel(account); accounts.push({ id: fileName, driver, ...(email ? { email } : {}), ...(plan ? { plan } : {}), usageLimits: cliproxyAccountToUsageLimits(account, checkedAt), }); } return accounts.toSorted( (left, right) => left.driver.localeCompare(right.driver) || left.id.localeCompare(right.id), ); }