mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-21 22:32:22 +03:00
Um `ALL_TARGETS_SKIPPED` 503 que não diz qual janela esgotou é opaco justamente no momento em que o operador mais precisa saber. Alinhar os rótulos de janela AUTH com os da API de uso fecha a outra metade: dois nomes para a mesma coisa fazem o dashboard e o erro parecerem discordar. Revalidei sobre o tip: **6/6**, typecheck:core limpo, check-file-size OK. **Dois consertos meus na sua branch.** 1. `typecheck:core` falhava com `TS2345` em `comboAttemptLoop.ts` (linhas 130 e 416): o `QuotaSkipTarget` declarava `connectionId?: string`, mas o `ResolvedComboTarget` carrega `string | null` para alvo não-pinado. Alarguei para `string | null` no tipo de diagnóstico em vez de estreitar o call site — o módulo só **lê** o campo e a linha 29 já narrowa com `typeof === "string"`, então null não custa nada ali. Isso apareceu porque o `comboAttemptLoop` mudou de forma no #12746/#12811, mergeados nesta mesma campanha depois que você cortou a branch. 2. O `roundRobinCombo.ts` foi de 1198 para 1205 e cruzou o teto de 1200 para arquivo novo. Congelei com justificativa: o arquivo já nasceu em 1198 quando o #12811 o levantou de dentro do `combo.ts`, e os diagnósticos em si vivem no `quotaSkipDiagnostics.ts`, sob o cap. Registrei que a próxima extração natural é o corpo do attempt loop, mas que ele acabou de ser movido e deve assentar antes de ser cortado de novo.
74 lines
2.6 KiB
TypeScript
74 lines
2.6 KiB
TypeScript
/**
|
|
* Shared duration-aware quota window labels for AUTH preflight and /api/usage.
|
|
* Routing keys (`session`, `weekly`) stay position-based; only the display
|
|
* string follows the real window length so a 30-day primary window is not
|
|
* reported as "session (5h)".
|
|
*/
|
|
|
|
const SESSION_MAX_SECONDS = 6 * 3600;
|
|
const WEEKLY_MAX_SECONDS = 8 * 24 * 3600;
|
|
const MONTHLY_MAX_SECONDS = 40 * 24 * 3600;
|
|
const GENERIC_FAMILY = new Set(["session", "weekly", "monthly"]);
|
|
|
|
export type QuotaWindowLabelInput = {
|
|
key: string;
|
|
displayName?: string | null;
|
|
windowSeconds?: number | null;
|
|
};
|
|
|
|
function toPositiveSeconds(value: unknown): number | null {
|
|
if (typeof value === "number" && Number.isFinite(value) && value > 0) return value;
|
|
if (typeof value === "string" && value.trim().length > 0) {
|
|
const parsed = Number(value);
|
|
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function formatWindowDuration(windowSeconds: number): string {
|
|
if (windowSeconds % 86400 === 0) return `${windowSeconds / 86400}d`;
|
|
if (windowSeconds % 3600 === 0) return `${windowSeconds / 3600}h`;
|
|
return `${Math.round(windowSeconds)}s`;
|
|
}
|
|
|
|
export function inferWindowFamilyLabel(windowSeconds: number): string | undefined {
|
|
if (windowSeconds <= SESSION_MAX_SECONDS) return "Session";
|
|
if (windowSeconds <= WEEKLY_MAX_SECONDS) return "Weekly";
|
|
if (windowSeconds <= MONTHLY_MAX_SECONDS) return "Monthly";
|
|
return undefined;
|
|
}
|
|
|
|
function normalizeFamily(value: string): string {
|
|
return value.trim().toLowerCase();
|
|
}
|
|
|
|
/**
|
|
* Prefer a duration-aware label. When usage already stamped a generic family
|
|
* (`Weekly`) on a 30-day window, replace it with Monthly so AUTH and the
|
|
* usage API agree on the reset window.
|
|
*/
|
|
export function formatQuotaWindowLabel(input: QuotaWindowLabelInput): string {
|
|
const seconds = toPositiveSeconds(input.windowSeconds);
|
|
const duration = seconds != null ? formatWindowDuration(seconds) : null;
|
|
const inferred = seconds != null ? inferWindowFamilyLabel(seconds) : undefined;
|
|
const named = typeof input.displayName === "string" ? input.displayName.trim() : "";
|
|
const key = typeof input.key === "string" && input.key.trim() ? input.key.trim() : "quota";
|
|
|
|
let base = named || inferred || key;
|
|
if (inferred && named && GENERIC_FAMILY.has(normalizeFamily(named)) && inferred !== named) {
|
|
base = inferred;
|
|
}
|
|
|
|
if (duration && !base.toLowerCase().includes(duration.toLowerCase())) {
|
|
return `${base} (${duration})`;
|
|
}
|
|
return base;
|
|
}
|
|
|
|
export function formatQuotaUsageReason(
|
|
input: QuotaWindowLabelInput,
|
|
usedPercentage: number
|
|
): string {
|
|
return `${formatQuotaWindowLabel(input)} usage ${Math.round(usedPercentage)}%`;
|
|
}
|