fix(usage): parse numeric-string quota reset timestamps as Unix sec/ms (#4493)

Rebuilt onto release/v3.8.33 (squash-base-stale). Integrated into release/v3.8.33.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-21 14:06:05 -03:00
committed by GitHub
parent 4279751abd
commit cd45943015
4 changed files with 38 additions and 9 deletions

View File

@@ -75,6 +75,7 @@ _In development — bullets added per PR; finalized at release._
- **fix(command-code): pass `reasoning` / `thinking` fields through to upstream params** — Command Code requests carrying `reasoning`/`thinking` controls had those fields dropped before the upstream call, so reasoning-effort and extended-thinking settings were silently ignored; they are now forwarded to the upstream params. ([#4473](https://github.com/diegosouzapw/OmniRoute/pull/4473) — thanks @adivekar-utexas)
- **fix(usage): keep Kiro overage-enabled accounts routable after base quota hits zero** — a Kiro account with overage enabled was excluded from routing once its base quota reached zero, even though overage billing should keep it serving; such accounts now stay routable past base-quota exhaustion. ([#4469](https://github.com/diegosouzapw/OmniRoute/issues/4469) — thanks @heaven321357 / @CleanDev-Fix)
- **fix(providers): model-aware `supportsRedactedThinking` for mixed-format providers** — the redacted-thinking capability was resolved per provider rather than per model, so a mixed-format provider (some models support redacted thinking, others don't) got the wrong answer for some models; the check is now model-aware. ([#4479](https://github.com/diegosouzapw/OmniRoute/pull/4479) — thanks @TF0rd)
- **fix(usage): parse numeric-string quota reset timestamps as Unix seconds/ms** — when a provider returned the quota reset timestamp as a numeric string (e.g. `"1700000000"`), `parseResetTime` passed it straight to `new Date(str)`, which returned `Invalid Date` and dropped the reset entirely (UI showed no reset). Numeric strings are now detected and treated as Unix timestamps with the same `< 1e12` seconds-vs-ms heuristic already applied to numeric values; ISO/parseable strings are untouched. Applied symmetrically in `codexUsageQuotas.parseResetTime`. (Inspired by upstream [decolua/9router#768](https://github.com/decolua/9router/pull/768) — thanks @DEYLNN)
### 🔒 Security

View File

@@ -41,14 +41,20 @@ function toNumber(value: unknown, fallback = 0): number {
function parseResetTime(resetValue: unknown): string | null {
if (!resetValue) return null;
try {
const date =
resetValue instanceof Date
? resetValue
: typeof resetValue === "number"
? new Date(resetValue < 1e12 ? resetValue * 1000 : resetValue)
: typeof resetValue === "string"
? new Date(resetValue)
: null;
let date: Date | null = null;
if (resetValue instanceof Date) {
date = resetValue;
} else if (typeof resetValue === "number") {
date = new Date(resetValue < 1e12 ? resetValue * 1000 : resetValue);
} else if (typeof resetValue === "string") {
// Numeric strings are Unix timestamps too (seconds or milliseconds).
if (/^\d+$/.test(resetValue)) {
const ts = Number(resetValue);
date = new Date(ts < 1e12 ? ts * 1000 : ts);
} else {
date = new Date(resetValue);
}
}
if (!date || date.getTime() <= 0) return null;
return date.toISOString();
} catch {

View File

@@ -1625,7 +1625,14 @@ function parseResetTime(resetValue: unknown): string | null {
} else if (typeof resetValue === "number") {
date = new Date(resetValue < 1e12 ? resetValue * 1000 : resetValue);
} else if (typeof resetValue === "string") {
date = new Date(resetValue);
// Numeric strings are Unix timestamps too (seconds or milliseconds).
// `new Date("1700000000")` otherwise returns Invalid Date.
if (/^\d+$/.test(resetValue)) {
const ts = Number(resetValue);
date = new Date(ts < 1e12 ? ts * 1000 : ts);
} else {
date = new Date(resetValue);
}
} else {
return null;
}

View File

@@ -60,6 +60,21 @@ describe("parseResetTime", () => {
it("returns null for invalid date strings", () => {
assert.equal(__testing.parseResetTime("not-a-date"), null);
});
// Inspired-by upstream decolua/9router#768 — provider APIs sometimes return
// the reset timestamp as a numeric string. Without explicit detection,
// `new Date("1700000000")` returns Invalid Date and the value is lost.
it("parses a numeric string in seconds (value < 1e12)", () => {
const sec = "1700000000";
const out = __testing.parseResetTime(sec);
assert.equal(out, new Date(Number(sec) * 1000).toISOString());
});
it("parses a numeric string already in milliseconds (value >= 1e12)", () => {
const ms = "1700000000000";
const out = __testing.parseResetTime(ms);
assert.equal(out, new Date(Number(ms)).toISOString());
});
});
/* ------------------------------------------------------------------ */