import type { MeterId } from "./meters";
/**
* Plans are config-driven: `METERING_PLANS` (JSON, same shape as DEFAULT_PLANS) overrides these defaults.
* `included` is free per period; usage past it is billed (paid plans) or blocked (hard caps).
* `hardCaps` are enforced atomically by reserveUsage; every other meter is soft and only alerts.
*/
export type PlanId = "scratch" | "free" | "pro";
export type Plan = {
id: PlanId;
label: string;
included: Partial<Record<MeterId, number>>;
hardCaps: Partial<Record<MeterId, number>>;
/** Whether overage is billed; when false every included amount acts as a soft cap with alerts. */
billsOverage: boolean;
};
const GB = 1024 ** 3;
const HOUR = 3600;
const FREE_INCLUDED: Plan["included"] = {
"storage.artifacts": 1 * GB,
"storage.lfs": 1 * GB,
"storage.ci_cache": 0.5 * GB,
"storage.sites": 0.25 * GB,
"storage.r2": 0.25 * GB,
"compute.runner": 5 * HOUR,
"compute.runner_large": 0,
"compute.runner_xlarge": 0,
"compute.editor": 2 * HOUR,
"compute.site_requests": 100_000,
"compute.site_cpu": 1_000_000,
"network.lfs": 2 * GB,
"network.sites": 10 * GB,
"ai.calls": 50,
"ai.tokens": 200_000,
};
export const DEFAULT_PLANS: Record<PlanId, Plan> = {