159 lines · 5.6 KB
import { env } from "cloudflare:workers";
import { repoDb } from "../scoped-db";
import { ownerSiteScopes } from "./store";
import { addCounter, counterTotals } from "../counters";
import { SCRATCH_LIMITS } from "./config";
import { meterSiteRequest } from "./metering";
import type { SiteMeta } from "./config";

const FLAG_TTL_SECONDS = 2 * 24 * 60 * 60;
const HTTP_SWITCHING = 101;

export type UsageDelta = { requests?: number; cpuMs?: number; bytesOut?: number };

export type AccountUsage = {
  day: string;
  requests: number;
  cpuMs: number;
  bytesOut: number;
};

export function usageDay(now = Date.now()): string {
  return new Date(now).toISOString().slice(0, 10);
}

function overKey(siteId: string, day: string): string {
  return `sites:over:${siteId}:${day}`;
}

/**
 * Adds to a site's daily usage through its Counters object (D1's `site_usage` row follows within seconds). Unclaimed scratch sites (no account) are the free tier: once a daily cap is
 * crossed a KV flag makes the dispatcher refuse further requests until the next UTC day.
 */
export async function recordUsage(
  meta: Pick<SiteMeta, "id" | "ownerId" | "scratch">,
  delta: UsageDelta,
): Promise<void> {
  const day = usageDay();
  const [requests, cpuMs, bytesOut] = await addCounter(
    "site-usage",
    meta.id,