/** GET / — plain HTML string. No framework, no external scripts, no external CSS. */ import type { MetricKey, Spike } from "./spike"; import { formatRatio } from "./spike"; export function escapeHtml(s: string): string { return s .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """); } export function fmtNum(n: number | undefined): string { if (n === undefined) return "–"; return Number.isInteger(n) ? n.toLocaleString("en-US") : n.toLocaleString("en-US", { maximumFractionDigits: 1 }); } export interface PageModel { /** Ascending, oldest first; the last one is today. */ dates: string[]; table: Map>; spikes: Spike[]; /** ISO timestamp of the newest collected_at, or null when the table is empty. */ lastCollected: string | null; } /** * Same gauge mark as the hosted Usage Guard (my-open-project apps/b-inbox/public/favicon.svg, 2026-09-15): * blue 270° ring + purple needle on a dark tile. Inlined as a data URI so the Worker ships no static assets. */ export const FAVICON_SVG = `usage-guard-collector`; export function faviconHref(): string { return `data:image/svg+xml,${encodeURIComponent(FAVICON_SVG)}`; } const CSS = `body{font:14px/1.5 -apple-system,system-ui,sans-serif;max-width:64rem;margin:2rem auto;padding:0 1rem;color:#222} table{border-collapse:collapse;width:100%}th,td{padding:.3rem .5rem;border-bottom:1px solid #ddd;text-align:right;white-space:nowrap} th:first-child,td:first-child{text-align:left}th{font-weight:600}.spike{background:#fff3e0}.muted{color:#777}code{font-size:.9em}`; export function renderPage(m: PageModel): string { const spikeKeys = new Set(m.spikes.map((s) => s.metric)); const head = m.dates.map((d) => `${escapeHtml(d.slice(5))}`).join(""); const metrics = [...m.table.keys()].sort(); const body = metrics.length === 0 ? `No rows yet. The Cron runs every 6 hours; trigger one with curl -X POST http://127.0.0.1:8787/__scheduled under wrangler dev --test-scheduled.` : metrics .map((k) => { const byDate = m.table.get(k) as Map; const cells = m.dates.map((d) => `${fmtNum(byDate.get(d))}`).join(""); return `${escapeHtml(k)}${cells}`; }) .join(""); const spikes = m.spikes.length === 0 ? `

No spikes today (today ≥ 10× the 7-day median and above the per-metric floor).

` : `
    ${m.spikes .map( (s) => `
  • ${escapeHtml(s.metric)}: ${fmtNum(s.today)} today vs. median ${fmtNum(s.baseline)} (${escapeHtml(formatRatio(s.ratio))})
  • `, ) .join("")}
`; return ` usage-guard-collector

Cloudflare usage, last ${m.dates.length} days

Account-wide daily totals from the GraphQL Analytics API (UTC days; today is partial). ${m.lastCollected ? `Last collected ${escapeHtml(m.lastCollected)}.` : "Not collected yet."} These are analytics counts, not the invoice.

Spikes

${spikes}

Daily totals

${head}${body}
metric

Read-only. Source: github.com/HowardZlh/usage-guard-collector.

`; }