fix(usage): share SDK helpers and bound source cache

This commit is contained in:
Mohamed Boudra
2026-09-26 20:52:37 +02:00
parent abf2646e18
commit d0cb4e6be8
10 changed files with 153 additions and 25 deletions
+38
View File
@@ -0,0 +1,38 @@
import { expect, test } from "vitest";
import {
balanceToneFromRemaining,
toneFromUsedPct,
usedPctOf,
windowFromUsedPct,
} from "./usage.js";
test("shared usage tones preserve the app threshold contract", () => {
expect([null, 69.9, 70, 90, 90.1].map(toneFromUsedPct)).toEqual([
"default",
"ok",
"warning",
"warning",
"danger",
]);
expect([null, 0, 0.01].map(balanceToneFromRemaining)).toEqual(["default", "danger", "ok"]);
});
test("shared windows retain percentage, reset time, and optional headline", () => {
expect(windowFromUsedPct({ id: "a", label: "A", utilizationPct: 30, headline: true })).toEqual({
id: "a",
label: "A",
usedPct: 30,
remainingPct: 70,
resetsAt: null,
headline: true,
});
expect(windowFromUsedPct({ id: "b", label: "B", utilizationPct: null })).toEqual({
id: "b",
label: "B",
usedPct: null,
remainingPct: null,
resetsAt: null,
});
expect(usedPctOf(25, 100)).toBe(25);
expect(usedPctOf(25, 0)).toBeNull();
});
+58
View File
@@ -49,3 +49,61 @@ export interface UsageSourceRegistration {
fetch(input: unknown): Promise<UsageReport>;
discover?(): Promise<JsonValue[]>;
}
export function windowFromUsedPct(input: {
id: string;
label: string;
utilizationPct: number | null | undefined;
resetsAt?: string | null;
tone?: UsageWindow["tone"];
headline?: boolean;
}): UsageWindow {
const usedPct = typeof input.utilizationPct === "number" ? input.utilizationPct : null;
const window: UsageWindow = {
id: input.id,
label: input.label,
usedPct,
remainingPct: usedPct === null ? null : Math.max(0, 100 - usedPct),
resetsAt: input.resetsAt ?? null,
};
if (input.tone) window.tone = input.tone;
if (input.headline) window.headline = true;
return window;
}
/**
* The tone scale for anything measured against a known limit, windows and balances alike.
*
* Thresholds match `deriveTone` in the app's provider-usage/tone.ts, which is what the
* client falls back to when a window arrives without a tone. Healthy is "ok" rather than
* "default" because that is what every provider setting a tone has always sent, and it is
* what the bars render today below their thresholds.
*/
export function toneFromUsedPct(usedPct: number | null | undefined): UsageWindow["tone"] {
if (typeof usedPct !== "number") return "default";
if (usedPct > 90) return "danger";
if (usedPct >= 70) return "warning";
return "ok";
}
/**
* Tone for a balance with no known limit, where a percentage cannot be computed and the
* only signal is whether anything is left. Prefer `toneFromUsedPct` when a limit exists:
* this one stays "ok" until the balance is completely spent.
*/
export function balanceToneFromRemaining(
remaining: number | null | undefined,
): UsageBalance["tone"] {
if (typeof remaining !== "number") return "default";
if (remaining <= 0) return "danger";
return "ok";
}
/** Percentage of a limit consumed, or null when either side is unknown. */
export function usedPctOf(
used: number | null | undefined,
limit: number | null | undefined,
): number | null {
if (typeof used !== "number" || typeof limit !== "number" || limit <= 0) return null;
return (used / limit) * 100;
}