import { AsyncLocalStorage } from "node:async_hooks";
/**
* Per-unit-of-work cost accounting for hotspot detection. Every request, queue batch, cron task and Durable
* Object alarm runs inside `withPerf`, which counts the D1 statements and scoped-object (RepoState /
* AccountState) calls it makes and how long they took, then reports one PostHog event:
*
* - `server_request`: `route` (a template, never names; lib/route-template.ts), `method`, `status`, `surface`.
* - `server_job`: `job` (cron task, queue, alarm name).
*
* Both carry `duration_ms`, `d1_queries`, `d1_ms`, `d1_replica_queries`, `d1_rows_read`, `d1_rows_written`,
* `do_calls`, `do_ms`, `do_rows_read`, `do_rows_written`, `cold_start` and `sample_weight` (rows are what D1 and
* Durable Object SQL bill by). Slow or expensive units are always sent; the rest are sampled (PERF_SAMPLE_RATE, default 2%)
* and carry `sample_weight` = 1 / rate so sums and counts in PostHog estimate the true totals. No person
* profile, no account ids, no paths.
*/
export type PerfCounters = {
d1Queries: number;
d1Ms: number;
d1ReplicaQueries: number;
doCalls: number;
doMs: number;
doRowsRead: number;
doRowsWritten: number;
d1RowsRead: number;
d1RowsWritten: number;
};
type PerfScope = PerfCounters & { startedAt: number; coldStart: boolean };
const storage = new AsyncLocalStorage<PerfScope>();
const SLOW_MS = 1000;
const HEAVY_D1 = 25;
const HEAVY_DO = 25;
const DEFAULT_SAMPLE_RATE = 0.02;
let coldStart = true;
type Reporter = (event: string, properties: Record<string, string | number | boolean | null>) => void;