import { describe, expect, it, vi } from "vitest"; import type { AllowanceSource, SourceResult } from "../meter.js"; import { OPENCODE_GO_PROVIDER_ID, createOpenCodeGoProvider, } from "./opencode-go.js"; const USAGE_URL = "https://opencode.ai/zen/go/v1/usage"; const API_KEY = "synthetic-api-key"; const RESET_ROLLING = "2026-08-12T06:00:00.000Z"; const RESET_WEEKLY = "2026-08-17T00:00:00.000Z"; const RESET_MONTHLY = "2026-09-12T00:00:00.000Z"; type ResolvedAuth = { readonly auth: { readonly apiKey?: string } } | undefined; function source(options: { readonly fetch?: typeof globalThis.fetch; readonly resolveAuth?: () => Promise; }): AllowanceSource { const provider = createOpenCodeGoProvider({ resolveAuth: options.resolveAuth ?? (async () => ({ auth: { apiKey: API_KEY } })), ...(options.fetch ? { fetch: options.fetch } : {}), }); if (provider.support !== "live") throw new Error("Expected live provider"); return provider.source; } function windowPayload( status: unknown = "ok", percent: unknown = 12, resetsAt: unknown = RESET_ROLLING, ): Record { return { status, percent, resetsAt }; } function usagePayload( options: { readonly rolling?: unknown; readonly weekly?: unknown; readonly monthly?: unknown; readonly extraUsageKey?: boolean; readonly extraTopLevelKey?: boolean; } = {}, ): unknown { const usage: Record = { rolling: "rolling" in options ? options.rolling : windowPayload("ok", 12, RESET_ROLLING), weekly: "weekly" in options ? options.weekly : windowPayload("ok", 8, RESET_WEEKLY), monthly: "monthly" in options ? options.monthly : windowPayload("ok", 35, RESET_MONTHLY), }; if (options.extraUsageKey) { usage.yearly = windowPayload("ok", 1, RESET_MONTHLY); } const payload: Record = { usage }; if (options.extraTopLevelKey) { payload.meta = "extra"; } return payload; } function jsonResponse( payload: unknown, status = 200, headers?: Record, ): Response { return new Response(JSON.stringify(payload), { status, headers }); } async function readWith( allowanceSource: AllowanceSource, signal = new AbortController().signal, ): Promise { return allowanceSource.read(signal); } describe("OpenCode Go provider", () => { it("creates the evidence-backed live provider definition", () => { const provider = createOpenCodeGoProvider({ resolveAuth: async () => undefined, fetch: vi.fn(), }); expect(provider).toMatchObject({ support: "live", id: OPENCODE_GO_PROVIDER_ID, displayName: "OpenCode Go", evidence: "first-party-source", }); expect(OPENCODE_GO_PROVIDER_ID).toBe("opencode-go"); }); it("performs no auth or network I/O until read is called", async () => { const resolveAuth = vi.fn(async () => ({ auth: { apiKey: API_KEY } })); const fetchMock = vi .fn() .mockResolvedValue(jsonResponse(usagePayload())); const provider = createOpenCodeGoProvider({ resolveAuth, fetch: fetchMock }); expect(resolveAuth).not.toHaveBeenCalled(); expect(fetchMock).not.toHaveBeenCalled(); if (provider.support !== "live") throw new Error("Expected live provider"); await provider.source.read(new AbortController().signal); expect(resolveAuth).toHaveBeenCalledTimes(1); expect(fetchMock).toHaveBeenCalledTimes(1); }); it("issues one exact GET with bearer auth and normalizes all three windows", async () => { const fetchMock = vi .fn() .mockResolvedValue(jsonResponse(usagePayload())); const signal = new AbortController().signal; const result = await readWith(source({ fetch: fetchMock }), signal); expect(fetchMock).toHaveBeenCalledTimes(1); const [url, init] = fetchMock.mock.calls[0] ?? []; expect(url).toBe(USAGE_URL); expect(init).toMatchObject({ method: "GET" }); expect(init?.signal).toBe(signal); expect(init?.body).toBeUndefined(); expect(init?.headers).toEqual({ Accept: "application/json", Authorization: `Bearer ${API_KEY}`, }); expect(result).toEqual({ kind: "success", observation: { windows: [ { id: "rolling", label: "5 hour", usedPercent: 12, windowMinutes: 300, resetsAt: new Date(RESET_ROLLING), }, { id: "weekly", label: "Weekly", usedPercent: 8, windowMinutes: 10_080, resetsAt: new Date(RESET_WEEKLY), }, { id: "monthly", label: "Monthly", usedPercent: 35, resetsAt: new Date(RESET_MONTHLY), }, ], }, }); expect(JSON.stringify(result)).not.toMatch( /synthetic-api-key|authorization|bearer|api[_-]?key|opencode\.ai|secret|private|detail/i, ); }); it("accepts boundary percent values of 0 and 100", async () => { const result = await readWith( source({ fetch: vi.fn().mockResolvedValue( jsonResponse( usagePayload({ rolling: windowPayload("ok", 0, RESET_ROLLING), weekly: windowPayload("ok", 100, RESET_WEEKLY), }), ), ), }), ); expect(result).toMatchObject({ kind: "success", observation: { windows: [ { id: "rolling", usedPercent: 0 }, { id: "weekly", usedPercent: 100 }, { id: "monthly", usedPercent: 35 }, ], }, }); }); it("treats rate-limited windows as successful observations", async () => { const result = await readWith( source({ fetch: vi.fn().mockResolvedValue( jsonResponse( usagePayload({ rolling: windowPayload("rate-limited", 100, RESET_ROLLING), weekly: windowPayload("rate-limited", 100, RESET_WEEKLY), }), ), ), }), ); expect(result).toEqual({ kind: "success", observation: { windows: [ { id: "rolling", label: "5 hour", usedPercent: 100, windowMinutes: 300, resetsAt: new Date(RESET_ROLLING), }, { id: "weekly", label: "Weekly", usedPercent: 100, windowMinutes: 10_080, resetsAt: new Date(RESET_WEEKLY), }, { id: "monthly", label: "Monthly", usedPercent: 35, resetsAt: new Date(RESET_MONTHLY), }, ], }, }); }); it.each([ [ "missing auth", async (): Promise => undefined, ], [ "missing key", async (): Promise => ({ auth: {} }), ], [ "blank key", async (): Promise => ({ auth: { apiKey: "" } }), ], [ "whitespace-only key", async (): Promise => ({ auth: { apiKey: " \t " } }), ], [ "embedded-space key", async (): Promise => ({ auth: { apiKey: "unsafe credential" }, }), ], [ "unsafe newline key", async (): Promise => ({ auth: { apiKey: "unsafe\ncredential" }, }), ], [ "unsafe control key", async (): Promise => ({ auth: { apiKey: "unsafe\u001b[2Jcredential" }, }), ], ] as const)("returns not-configured for %s without fetching", async (_, resolveAuth) => { const fetchMock = vi.fn(); await expect( readWith(source({ resolveAuth, fetch: fetchMock })), ).resolves.toEqual({ kind: "failure", failure: { reason: "not-configured" }, }); expect(fetchMock).not.toHaveBeenCalled(); }); it("maps auth resolution failure to a sanitized network failure", async () => { const fetchMock = vi.fn(); const result = await readWith( source({ resolveAuth: async () => { throw new Error("secret auth refresh detail"); }, fetch: fetchMock, }), ); expect(result).toEqual({ kind: "failure", failure: { reason: "network" }, }); expect(JSON.stringify(result)).not.toContain("secret auth refresh detail"); expect(fetchMock).not.toHaveBeenCalled(); }); it.each([401, 403])("maps HTTP %i to unauthorized", async (status) => { const result = await readWith( source({ fetch: vi.fn().mockResolvedValue( new Response("private body", { status }), ), }), ); expect(result).toEqual({ kind: "failure", failure: { reason: "unauthorized" }, }); expect(JSON.stringify(result)).not.toContain("private body"); }); it.each([404, 429, 500, 503] as const)( "maps HTTP %i to network without retryAt", async (status) => { const result = await readWith( source({ fetch: vi.fn().mockResolvedValue( new Response("private body", { status, headers: status === 429 ? { "Retry-After": "30" } : undefined, }), ), }), ); expect(result).toEqual({ kind: "failure", failure: { reason: "network" }, }); expect(JSON.stringify(result)).not.toContain("private body"); }, ); it("maps transport rejection to network and abort to timeout", async () => { const network = await readWith( source({ fetch: vi .fn() .mockRejectedValue(new Error("socket secret")), }), ); expect(network).toEqual({ kind: "failure", failure: { reason: "network" }, }); const controller = new AbortController(); controller.abort(); const aborted = await readWith( source({ fetch: vi .fn() .mockRejectedValue(new DOMException("aborted", "AbortError")), }), controller.signal, ); expect(aborted).toEqual({ kind: "failure", failure: { reason: "timeout" }, }); expect(JSON.stringify([network, aborted])).not.toMatch( /socket secret|aborted/i, ); }); it("maps malformed JSON to invalid-response", async () => { const result = await readWith( source({ fetch: vi .fn() .mockResolvedValue(new Response("{")), }), ); expect(result).toEqual({ kind: "failure", failure: { reason: "invalid-response" }, }); }); it("rejects the legacy pre-d4704347 flat response shape", async () => { const result = await readWith( source({ fetch: vi.fn().mockResolvedValue( jsonResponse({ useBalance: 100, rollingUsage: windowPayload("ok", 12, RESET_ROLLING), weeklyUsage: windowPayload("ok", 8, RESET_WEEKLY), monthlyUsage: windowPayload("ok", 35, RESET_MONTHLY), }), ), }), ); expect(result).toEqual({ kind: "failure", failure: { reason: "invalid-response" }, }); }); it.each([ ["null payload", null], ["string payload", "usage"], ["array payload", []], ["empty record", {}], ["usage null", { usage: null }], ["usage array", { usage: [] }], ["usage empty", { usage: {} }], [ "missing monthly window", { usage: { rolling: windowPayload("ok", 12, RESET_ROLLING), weekly: windowPayload("ok", 8, RESET_WEEKLY), }, }, ], [ "extra window key", { usage: { rolling: windowPayload("ok", 12, RESET_ROLLING), weekly: windowPayload("ok", 8, RESET_WEEKLY), monthly: windowPayload("ok", 35, RESET_MONTHLY), yearly: windowPayload("ok", 1, RESET_MONTHLY), }, }, ], [ "extra top-level key", usagePayload({ extraTopLevelKey: true }), ], [ "extra usage key", usagePayload({ extraUsageKey: true }), ], ] as const)("rejects missing, extra, or non-record usage shape %s", async (_, payload) => { const result = await readWith( source({ fetch: vi .fn() .mockResolvedValue(jsonResponse(payload)), }), ); expect(result).toEqual({ kind: "failure", failure: { reason: "invalid-response" }, }); }); it.each([ ["null window", usagePayload({ rolling: null })], ["array window", usagePayload({ rolling: [] })], ["string window", usagePayload({ rolling: "ok" })], [ "missing status", usagePayload({ rolling: { percent: 12, resetsAt: RESET_ROLLING } }), ], [ "invalid status", usagePayload({ rolling: windowPayload("paused", 12, RESET_ROLLING) }), ], [ "uppercase status", usagePayload({ rolling: windowPayload("OK", 12, RESET_ROLLING) }), ], [ "missing percent", usagePayload({ rolling: { status: "ok", resetsAt: RESET_ROLLING } }), ], [ "negative percent", usagePayload({ rolling: windowPayload("ok", -1, RESET_ROLLING) }), ], [ "percent above 100", usagePayload({ rolling: windowPayload("ok", 101, RESET_ROLLING) }), ], [ "fractional percent", usagePayload({ rolling: windowPayload("ok", 12.5, RESET_ROLLING) }), ], [ "string percent", usagePayload({ rolling: windowPayload("ok", "12", RESET_ROLLING) }), ], [ "unsafe integer percent", usagePayload({ rolling: windowPayload("ok", Number.MAX_SAFE_INTEGER + 1, RESET_ROLLING), }), ], [ "missing resetsAt", usagePayload({ rolling: { status: "ok", percent: 12 } }), ], [ "non-string resetsAt", usagePayload({ rolling: windowPayload("ok", 12, 1_234_567_890) }), ], [ "unparseable resetsAt", usagePayload({ rolling: windowPayload("ok", 12, "not-a-date") }), ], [ "date-only resetsAt", usagePayload({ rolling: windowPayload("ok", 12, "2026-08-12") }), ], [ "zone-less resetsAt", usagePayload({ rolling: windowPayload("ok", 12, "2026-08-12T06:00:00") }), ], [ "impossible calendar date", usagePayload({ rolling: windowPayload("ok", 12, "2026-02-31T12:00:00.000Z"), }), ], [ "out-of-range offset", usagePayload({ rolling: windowPayload("ok", 12, "2026-08-12T06:00:00+24:00"), }), ], [ "extra window field", usagePayload({ rolling: { status: "ok", percent: 12, resetsAt: RESET_ROLLING, extra: true, }, }), ], ] as const)("rejects malformed window %s", async (_, payload) => { const result = await readWith( source({ fetch: vi .fn() .mockResolvedValue(jsonResponse(payload)), }), ); expect(result).toEqual({ kind: "failure", failure: { reason: "invalid-response" }, }); }); });