91 lines · 2.7 KB
import { accountDb } from "../scoped-db";
import { notifyQuietly, quiet } from "./deliver";
import { accountAdmins } from "./recipients";

const FULL_PERCENT = 100;

export type QuotaThresholdInput = {
  accountId: string;
  /** e.g. "lfs_storage", "lfs_bandwidth", "ci_minutes", "budget" */
  metric: string;
  label: string;
  /** 50, 80 or 100 */
  percent: number;
  used: string;
  limit: string;
  url: string;
  /** When set (e.g. "2026-10"), each metric and threshold notifies at most once per period. */
  period?: string;
};

/**
 * Notifies the account owner (or an org's owners) that usage crossed a threshold. Callers dedupe per
 * period; this uses the "quota" category prefs, the account access check and the email budget.
 */
async function notifyQuotaThresholdUnsafe(input: QuotaThresholdInput): Promise<void> {
  if (input.period) {
    const claimed = await accountDb(input.accountId).run(
      `INSERT OR IGNORE INTO quota_notices (account_id, metric, period, threshold, notified_at) VALUES (?, ?, ?, ?, ?)`,
      input.accountId,
      input.metric,
      input.period,
      input.percent,
      Date.now(),
    );
    if (claimed.meta.changes === 0) return;
  }
  const recipients = await accountAdmins(input.accountId);
  const over = input.percent >= FULL_PERCENT;
  await notifyQuietly({
    category: "quota",