import { badRequest } from "../errors"; import { limitBrowse } from "../limits"; import { billingAccountFor } from "../metering/access"; import { periodOf } from "../metering/record"; import { usageSummary } from "../metering/summary"; import { requireAccountScope } from "./http"; import type { ApiContext } from "./http"; const PERIOD = /^\d{4}-(0[1-9]|1[0-2])$/; function periodParam(ctx: ApiContext): string { const period = ctx.url.searchParams.get("period") ?? periodOf(); if (!PERIOD.test(period)) throw badRequest("period must be YYYY-MM"); return period; } /** Billing data is account-level: repo-scoped tokens (fine-grained PATs, agent tokens) may not read it (INT-A15/AZ-A5). */ export async function getUserUsage(ctx: ApiContext): Promise { requireAccountScope(ctx); await limitBrowse(ctx.viewer); const account = await billingAccountFor(ctx.viewer, null); return Response.json(await usageSummary(account.accountId, periodParam(ctx))); } export async function getOrgUsage(ctx: ApiContext, org: string): Promise { requireAccountScope(ctx); await limitBrowse(ctx.viewer); let name: string; try { name = decodeURIComponent(org); } catch { throw badRequest("Invalid organization name"); } const account = await billingAccountFor(ctx.viewer, name); return Response.json(await usageSummary(account.accountId, periodParam(ctx))); }