import { badRequest, forbidden } from "../errors"; 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); 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); let name: string; try { name = decodeURIComponent(org); } catch { throw badRequest("Invalid organization name"); } const account = await billingAccountFor(ctx.viewer, name); if (!account.canView) throw forbidden("Only owners can view usage for this organization"); return Response.json(await usageSummary(account.accountId, periodParam(ctx))); }