@cronwatch/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +69 -0
  2. package/dist/anthropic.cjs +84 -0
  3. package/dist/anthropic.cjs.map +1 -0
  4. package/dist/anthropic.d.cts +35 -0
  5. package/dist/anthropic.d.ts +35 -0
  6. package/dist/anthropic.js +78 -0
  7. package/dist/anthropic.js.map +1 -0
  8. package/dist/discord.cjs +42 -0
  9. package/dist/discord.cjs.map +1 -0
  10. package/dist/discord.d.cts +11 -0
  11. package/dist/discord.d.ts +11 -0
  12. package/dist/discord.js +40 -0
  13. package/dist/discord.js.map +1 -0
  14. package/dist/index.cjs +1317 -0
  15. package/dist/index.cjs.map +1 -0
  16. package/dist/index.d.cts +219 -0
  17. package/dist/index.d.ts +219 -0
  18. package/dist/index.js +1302 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/postgres.cjs +142 -0
  21. package/dist/postgres.cjs.map +1 -0
  22. package/dist/postgres.d.cts +19 -0
  23. package/dist/postgres.d.ts +19 -0
  24. package/dist/postgres.js +136 -0
  25. package/dist/postgres.js.map +1 -0
  26. package/dist/slack.cjs +44 -0
  27. package/dist/slack.cjs.map +1 -0
  28. package/dist/slack.d.cts +12 -0
  29. package/dist/slack.d.ts +12 -0
  30. package/dist/slack.js +42 -0
  31. package/dist/slack.js.map +1 -0
  32. package/dist/sqlite.cjs +151 -0
  33. package/dist/sqlite.cjs.map +1 -0
  34. package/dist/sqlite.d.cts +17 -0
  35. package/dist/sqlite.d.ts +17 -0
  36. package/dist/sqlite.js +144 -0
  37. package/dist/sqlite.js.map +1 -0
  38. package/dist/types-BQ1P8z55.d.cts +159 -0
  39. package/dist/types-BQ1P8z55.d.ts +159 -0
  40. package/dist/webhook.cjs +24 -0
  41. package/dist/webhook.cjs.map +1 -0
  42. package/dist/webhook.d.cts +20 -0
  43. package/dist/webhook.d.ts +20 -0
  44. package/dist/webhook.js +22 -0
  45. package/dist/webhook.js.map +1 -0
  46. package/package.json +114 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/duration.ts","../src/schedule.ts","../src/stats.ts","../src/evaluate.ts","../src/format.ts","../src/http.ts","../src/output.ts","../src/job.ts","../src/serialize.ts","../src/routes/html.ts","../src/routes/index.ts","../src/stores/memory.ts","../src/client.ts","../src/index.ts"],"names":["graceMs","constantTimeEqual"],"mappings":"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","file":"index.js","sourcesContent":["import type { Duration } from \"./types.js\";\n\nconst UNIT_MS: Record<string, number> = {\n ms: 1,\n s: 1000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n w: 604_800_000,\n};\n\n/**\n * \"15m\" -> 900000. Accepts a plain number of milliseconds, and compound\n * strings such as \"1h30m\". Whitespace between parts is fine.\n */\nexport function parseDuration(value: Duration, label = \"duration\"): number {\n if (typeof value === \"number\") {\n if (!Number.isFinite(value) || value < 0) throw new Error(`${label} must be a non-negative number of milliseconds`);\n return value;\n }\n const text = value.trim().toLowerCase();\n if (text === \"\") throw new Error(`${label} is empty`);\n const re = /(\\d+(?:\\.\\d+)?)\\s*(ms|s|m|h|d|w)/g;\n let total = 0;\n let consumed = \"\";\n let match: RegExpExecArray | null;\n while ((match = re.exec(text)) !== null) {\n total += parseFloat(match[1]!) * UNIT_MS[match[2]!]!;\n consumed += match[0];\n }\n if (consumed.replace(/\\s+/g, \"\") !== text.replace(/\\s+/g, \"\")) {\n throw new Error(`${label} \"${value}\" is not a duration like \"15m\", \"1h30m\" or \"90s\"`);\n }\n return Math.round(total);\n}\n\n/** 90000 -> \"1m 30s\". For messages, not for parsing back. */\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms)) return \"?\";\n if (ms < 1000) return `${Math.round(ms)}ms`;\n const parts: string[] = [];\n let rest = Math.round(ms / 1000);\n const units: [string, number][] = [[\"d\", 86_400], [\"h\", 3_600], [\"m\", 60], [\"s\", 1]];\n for (const [unit, size] of units) {\n if (rest >= size) {\n const n = Math.floor(rest / size);\n rest -= n * size;\n parts.push(`${n}${unit}`);\n }\n if (parts.length === 2) break;\n }\n return parts.join(\" \") || \"0s\";\n}\n\n/** \"5 minutes ago\", \"in 2h\". Relative to `now`. */\nexport function formatRelative(at: number, now: number): string {\n const diff = at - now;\n const abs = Math.abs(diff);\n const text = abs < 5_000 ? \"now\" : formatDuration(abs);\n if (abs < 5_000) return text;\n return diff < 0 ? `${text} ago` : `in ${text}`;\n}\n","import { Cron } from \"croner\";\nimport { parseDuration } from \"./duration.js\";\n\nexport interface ParsedSchedule {\n kind: \"cron\" | \"interval\";\n source: string;\n /** For intervals, the period in milliseconds. */\n everyMs?: number;\n cron?: Cron;\n}\n\nconst cache = new Map<string, ParsedSchedule>();\n\n/**\n * \"0 2 * * *\" (cron, five or six fields), \"@hourly\", or \"every 5m\".\n * Parsed once per (schedule, timezone) pair and cached. The croner instance\n * gets no callback, so it schedules nothing; it is only used to compute fire\n * times. Without a timezone the expression is read in the process timezone,\n * like crontab. Vercel and GitHub Actions run their crons in UTC, so pass\n * timezone: \"UTC\" for those.\n */\nexport function parseSchedule(schedule: string, timezone?: string): ParsedSchedule {\n const key = `${timezone ?? \"\"}|${schedule}`;\n const hit = cache.get(key);\n if (hit) return hit;\n\n const text = schedule.trim();\n const every = /^every\\s+(.+)$/i.exec(text);\n let parsed: ParsedSchedule;\n if (every) {\n const everyMs = parseDuration(every[1]!, \"schedule interval\");\n if (everyMs < 1000) throw new Error(`schedule \"${schedule}\" is shorter than one second`);\n parsed = { kind: \"interval\", source: text, everyMs };\n } else {\n let cron: Cron;\n try {\n cron = new Cron(text, timezone ? { timezone } : {});\n } catch (error) {\n throw new Error(`schedule \"${schedule}\" is not a cron expression or \"every <duration>\": ${(error as Error).message}`);\n }\n parsed = { kind: \"cron\", source: text, cron };\n }\n cache.set(key, parsed);\n return parsed;\n}\n\n/** The next time the cron fires strictly after `from`. */\nexport function nextFire(parsed: ParsedSchedule, from: number, lastRunAt: number | null): number | null {\n if (parsed.kind === \"interval\") {\n const base = lastRunAt ?? from;\n return base + parsed.everyMs!;\n }\n const next = parsed.cron!.nextRun(new Date(from));\n return next ? next.getTime() : null;\n}\n\n/**\n * The most recent time the cron fired at or before `now`, or null when the\n * expression never fires in the year before `now`.\n *\n * croner only looks forward, so this searches: widen a window behind `now`\n * until a fire time falls inside it, then bisect on the window's start for\n * the latest start whose next fire is still at or before `now`.\n */\nexport function previousFire(parsed: ParsedSchedule, now: number): number | null {\n if (parsed.kind !== \"cron\") throw new Error(\"previousFire is for cron schedules\");\n const cron = parsed.cron!;\n // nextRun(from) is strictly after `from`, so start one millisecond behind.\n const fireAtOrBefore = (from: number): number | null => {\n const next = cron.nextRun(new Date(from - 1));\n if (!next) return null;\n const t = next.getTime();\n return t <= now ? t : null;\n };\n\n const YEAR = 366 * 86_400_000;\n let step = 60_000;\n let lo: number | null = null;\n while (step <= YEAR) {\n if (fireAtOrBefore(now - step) !== null) {\n lo = now - step;\n break;\n }\n step *= 2;\n }\n if (lo === null) return null;\n\n // Invariant: fireAtOrBefore(lo) !== null. Find the largest start that still\n // has a fire at or before now; its fire is the previous one.\n let hi = now;\n while (hi - lo > 1) {\n const mid = Math.floor((lo + hi) / 2);\n if (fireAtOrBefore(mid) !== null) lo = mid;\n else hi = mid;\n }\n return fireAtOrBefore(lo);\n}\n\nexport interface Expectation {\n /** When the current period's run was due. */\n dueAt: number;\n /** Missed once now passes this. */\n deadline: number;\n}\n\n/**\n * What the schedule expects given the last run. Returns null when nothing is\n * due yet (a cron whose first fire since registration is still ahead, or an\n * interval that has not elapsed).\n */\nexport function expectation(\n parsed: ParsedSchedule,\n now: number,\n lastRunAt: number | null,\n registeredAt: number,\n graceMs: number,\n): Expectation | null {\n if (parsed.kind === \"interval\") {\n const dueAt = (lastRunAt ?? registeredAt) + parsed.everyMs!;\n return { dueAt, deadline: dueAt + graceMs };\n }\n const prev = previousFire(parsed, now);\n if (prev === null || prev < registeredAt) return null;\n return { dueAt: prev, deadline: prev + graceMs };\n}\n\n/**\n * Whether a run starting at `startedAt` covers the fire at `dueAt`. A minute of\n * slack before the tick absorbs schedulers that fire a touch early.\n */\nexport function runCovers(startedAt: number, dueAt: number): boolean {\n return startedAt >= dueAt - 60_000;\n}\n","export function percentile(values: number[], p: number): number | null {\n if (values.length === 0) return null;\n const sorted = [...values].sort((a, b) => a - b);\n const index = Math.min(sorted.length - 1, Math.max(0, Math.ceil((p / 100) * sorted.length) - 1));\n return sorted[index]!;\n}\n\nexport function median(values: number[]): number | null {\n if (values.length === 0) return null;\n const sorted = [...values].sort((a, b) => a - b);\n const mid = Math.floor(sorted.length / 2);\n return sorted.length % 2 === 0 ? (sorted[mid - 1]! + sorted[mid]!) / 2 : sorted[mid]!;\n}\n","/**\n * Pure decisions about a job's health. Each function takes the current state\n * and returns the new state plus the alerts that should go out. Nothing here\n * touches a store or a network, which is what makes it testable.\n */\nimport { formatDuration } from \"./duration.js\";\nimport { parseDuration } from \"./duration.js\";\nimport { expectation, parseSchedule, runCovers } from \"./schedule.js\";\nimport { median, percentile } from \"./stats.js\";\nimport type { Condition, JobDefinition, JobState, Run, StoredJob, StoredJobDefinition } from \"./types.js\";\n\nexport interface AlertDraft {\n type: Condition | \"recovered\";\n run: Run | null;\n details: Record<string, unknown>;\n}\n\nexport interface Evaluation {\n state: JobState;\n alerts: AlertDraft[];\n}\n\nexport const DEFAULT_GRACE_MS = 10 * 60_000;\nexport const DEFAULT_TIMEOUT_MS = 60 * 60_000;\n/** Runs faster than this are never called slow, whatever the baseline says. */\nexport const SLOW_FLOOR_MS = 10_000;\n/** How many earlier runs a baseline needs before it is trusted. */\nexport const BASELINE_MIN_RUNS = 5;\nexport const BASELINE_WINDOW = 20;\n\nexport function emptyState(job: string): JobState {\n return { job, open: {}, consecutiveFailures: 0, silencedUntil: null, lastAlertAt: null };\n}\n\nfunction cloneState(state: JobState): JobState {\n return { ...state, open: { ...state.open } };\n}\n\nfunction openCondition(state: JobState, condition: Condition, now: number): boolean {\n if (state.open[condition] !== undefined) return false;\n state.open[condition] = now;\n return true;\n}\n\nfunction closeCondition(state: JobState, condition: Condition): boolean {\n if (state.open[condition] === undefined) return false;\n delete state.open[condition];\n return true;\n}\n\nexport function openConditions(state: JobState): Condition[] {\n return Object.keys(state.open) as Condition[];\n}\n\nexport function graceMs(def: Pick<JobDefinition, \"grace\">): number {\n return def.grace === undefined ? DEFAULT_GRACE_MS : parseDuration(def.grace, \"grace\");\n}\n\nexport function timeoutMs(def: Pick<JobDefinition, \"timeout\">): number {\n return def.timeout === undefined ? DEFAULT_TIMEOUT_MS : parseDuration(def.timeout, \"timeout\");\n}\n\n/** Slow threshold for a successful run, or null when there is nothing to compare against yet. */\nexport function slowThreshold(def: Pick<JobDefinition, \"maxDuration\">, history: Run[]): { thresholdMs: number; basis: string } | null {\n if (def.maxDuration !== undefined) {\n return { thresholdMs: parseDuration(def.maxDuration, \"maxDuration\"), basis: \"maxDuration\" };\n }\n const durations = history\n .filter((r) => r.status === \"ok\" && r.durationMs !== null)\n .slice(0, BASELINE_WINDOW)\n .map((r) => r.durationMs!);\n if (durations.length < BASELINE_MIN_RUNS) return null;\n const p95 = percentile(durations, 95)!;\n return { thresholdMs: Math.max(2 * p95, SLOW_FLOOR_MS), basis: `twice the p95 of the last ${durations.length} runs (${formatDuration(p95)})` };\n}\n\nexport interface BudgetBreach {\n metric: string;\n value: number;\n limit: number;\n basis: string;\n}\n\nexport function budgetBreaches(def: Pick<JobDefinition, \"budget\">, run: Run, history: Run[]): BudgetBreach[] {\n const breaches: BudgetBreach[] = [];\n for (const [metric, value] of Object.entries(run.metrics)) {\n const ceiling = def.budget?.[metric];\n if (ceiling !== undefined) {\n if (value > ceiling) breaches.push({ metric, value, limit: ceiling, basis: \"budget\" });\n continue;\n }\n const past = history\n .filter((r) => r.status === \"ok\" && typeof r.metrics[metric] === \"number\")\n .slice(0, BASELINE_WINDOW)\n .map((r) => r.metrics[metric]!);\n if (past.length < BASELINE_MIN_RUNS) continue;\n const usual = median(past)!;\n if (usual > 0 && value > 3 * usual) {\n breaches.push({ metric, value, limit: 3 * usual, basis: `three times the usual ${formatNumber(usual)}` });\n }\n }\n return breaches;\n}\n\nexport function formatNumber(n: number): string {\n if (Number.isInteger(n)) return n.toLocaleString(\"en-US\");\n return n.toLocaleString(\"en-US\", { maximumFractionDigits: 4 });\n}\n\n/**\n * Called when a run starts. Missed and stuck are about the absence of a run,\n * so a run starting closes them without an alert. Returns which conditions\n * were open beforehand, for the recovered message at the end.\n */\nexport function onRunStart(state: JobState): { state: JobState; openBefore: Condition[] } {\n const next = cloneState(state);\n const openBefore = openConditions(next);\n closeCondition(next, \"missed\");\n closeCondition(next, \"stuck\");\n return { state: next, openBefore };\n}\n\n/**\n * Called when a run finishes with status ok, failed or timeout. `history` is\n * the job's earlier runs, newest first, not including this one.\n */\nexport function onRunFinish(\n def: JobDefinition | StoredJobDefinition,\n run: Run,\n state: JobState,\n history: Run[],\n openBefore: Condition[],\n now: number,\n): Evaluation {\n const next = cloneState(state);\n const alerts: AlertDraft[] = [];\n\n if (run.status === \"ok\") {\n next.consecutiveFailures = 0;\n closeCondition(next, \"failed\");\n closeCondition(next, \"missed\");\n closeCondition(next, \"stuck\");\n\n const slow = slowThreshold(def, history);\n if (slow && run.durationMs !== null && run.durationMs > slow.thresholdMs) {\n if (openCondition(next, \"slow\", now)) {\n alerts.push({ type: \"slow\", run, details: { durationMs: run.durationMs, thresholdMs: slow.thresholdMs, basis: slow.basis } });\n }\n } else {\n closeCondition(next, \"slow\");\n }\n\n const breaches = budgetBreaches(def, run, history);\n if (breaches.length > 0) {\n if (openCondition(next, \"over_budget\", now)) {\n alerts.push({ type: \"over_budget\", run, details: { breaches } });\n }\n } else {\n closeCondition(next, \"over_budget\");\n }\n\n const wasOpen = new Set([...openBefore, ...openConditions(state)]);\n if (wasOpen.size > 0 && openConditions(next).length === 0) {\n alerts.push({ type: \"recovered\", run, details: { after: [...wasOpen] } });\n }\n return { state: next, alerts };\n }\n\n // failed or timeout\n next.consecutiveFailures += 1;\n closeCondition(next, \"missed\");\n const threshold = Math.max(1, def.failuresBeforeAlert ?? 1);\n const condition: Condition = run.status === \"timeout\" ? \"stuck\" : \"failed\";\n if (next.consecutiveFailures >= threshold) {\n if (openCondition(next, condition, now)) {\n alerts.push({ type: condition, run, details: { consecutiveFailures: next.consecutiveFailures, threshold } });\n }\n }\n return { state: next, alerts };\n}\n\n/**\n * Called by check(). Decides whether the schedule has been missed. `lastRun`\n * is the most recent run of any status.\n */\nexport function onCheck(\n def: StoredJobDefinition,\n stored: StoredJob,\n lastRun: Run | null,\n state: JobState,\n now: number,\n): Evaluation & { nextExpectedAt: number | null; dueAt: number | null } {\n const next = cloneState(state);\n const alerts: AlertDraft[] = [];\n if (!def.schedule) return { state: next, alerts, nextExpectedAt: null, dueAt: null };\n\n const parsed = parseSchedule(def.schedule, def.timezone);\n const grace = graceMs(def);\n const exp = expectation(parsed, now, lastRun?.startedAt ?? null, stored.createdAt, grace);\n\n let nextExpectedAt: number | null = null;\n if (parsed.kind === \"interval\") {\n nextExpectedAt = (lastRun?.startedAt ?? stored.createdAt) + parsed.everyMs!;\n } else {\n const upcoming = parsed.cron!.nextRun(new Date(now));\n nextExpectedAt = upcoming ? upcoming.getTime() : null;\n }\n\n if (!exp) return { state: next, alerts, nextExpectedAt, dueAt: null };\n\n // For a cron, a run at or after the fire covers it. For an interval the due\n // time is computed from the last run itself, so only the deadline matters.\n const covered = parsed.kind === \"cron\" && lastRun !== null && runCovers(lastRun.startedAt, exp.dueAt);\n if (covered) {\n closeCondition(next, \"missed\");\n } else if (now > exp.deadline) {\n if (openCondition(next, \"missed\", now)) {\n alerts.push({\n type: \"missed\",\n run: lastRun,\n details: { dueAt: exp.dueAt, deadline: exp.deadline, graceMs: grace, lastRunAt: lastRun?.startedAt ?? null },\n });\n }\n }\n return { state: next, alerts, nextExpectedAt, dueAt: exp.dueAt };\n}\n\n/** Whether a running run has gone on longer than the job's timeout. */\nexport function isStuck(def: Pick<JobDefinition, \"timeout\">, run: Run, now: number): boolean {\n return run.status === \"running\" && now - run.startedAt > timeoutMs(def);\n}\n\n/**\n * While a job is silenced nothing new is recorded as an incident: conditions\n * may close (so a job that recovered during the silence shows as healthy) but\n * none may open, so the first problem after the silence ends alerts normally.\n */\nexport function muteOpens(previous: JobState, next: JobState): JobState {\n const muted = cloneState(next);\n for (const condition of openConditions(muted)) {\n if (previous.open[condition] === undefined) delete muted.open[condition];\n }\n return muted;\n}\n\nexport function isSilenced(state: JobState, now: number): boolean {\n return state.silencedUntil !== null && state.silencedUntil > now;\n}\n","import { formatDuration, formatRelative } from \"./duration.js\";\nimport type { AlertDraft, BudgetBreach } from \"./evaluate.js\";\nimport { formatNumber } from \"./evaluate.js\";\nimport type { Alert, StoredJobDefinition } from \"./types.js\";\n\nfunction when(at: number | null | undefined, now: number): string {\n if (at === null || at === undefined) return \"never\";\n return `${new Date(at).toISOString().replace(\"T\", \" \").slice(0, 19)} UTC (${formatRelative(at, now)})`;\n}\n\nfunction firstLines(text: string | null, n: number): string {\n if (!text) return \"\";\n return text.split(\"\\n\").slice(0, n).join(\"\\n\");\n}\n\nfunction tail(text: string | null, n: number): string {\n if (!text) return \"\";\n const lines = text.trimEnd().split(\"\\n\");\n return lines.slice(Math.max(0, lines.length - n)).join(\"\\n\");\n}\n\n/** Turns a draft into the title and message every channel shows. */\nexport function composeAlert(draft: AlertDraft, def: StoredJobDefinition, now: number): Alert {\n const name = def.name;\n const run = draft.run;\n const d = draft.details;\n let title: string;\n const lines: string[] = [];\n\n switch (draft.type) {\n case \"missed\": {\n title = `${name} missed its scheduled run`;\n lines.push(`Due ${when(d.dueAt as number, now)}, and no run had started by ${when(d.deadline as number, now)} (grace ${formatDuration(d.graceMs as number)}).`);\n lines.push(`Schedule: ${def.schedule}${def.timezone ? ` (${def.timezone})` : \"\"}.`);\n lines.push(`Last run: ${run ? `${run.status} ${when(run.startedAt, now)}` : \"never\"}.`);\n break;\n }\n case \"failed\": {\n title = `${name} failed`;\n const n = d.consecutiveFailures as number;\n if (n > 1) lines.push(`${n} consecutive failures.`);\n if (run) {\n lines.push(`Started ${when(run.startedAt, now)}${run.durationMs !== null ? `, ran ${formatDuration(run.durationMs)}` : \"\"}.`);\n if (run.error) lines.push(`Error: ${firstLines(run.error, 4)}`);\n const out = tail(run.output, 8);\n if (out) lines.push(`Output (tail):\\n${out}`);\n }\n break;\n }\n case \"stuck\": {\n title = `${name} is stuck`;\n if (run) {\n lines.push(`Started ${when(run.startedAt, now)} and never reported finishing. Marked as timed out after ${formatDuration(run.durationMs ?? now - run.startedAt)}.`);\n const out = tail(run.output, 8);\n if (out) lines.push(`Output so far (tail):\\n${out}`);\n }\n lines.push(`If the process was killed mid-run (a serverless timeout, a deploy), this is what that looks like.`);\n break;\n }\n case \"slow\": {\n title = `${name} was slow`;\n lines.push(`Took ${formatDuration(d.durationMs as number)}; the limit is ${formatDuration(d.thresholdMs as number)} (${d.basis}).`);\n if (run) lines.push(`Started ${when(run.startedAt, now)}.`);\n break;\n }\n case \"over_budget\": {\n title = `${name} went over budget`;\n for (const b of d.breaches as BudgetBreach[]) {\n lines.push(`${b.metric}: ${formatNumber(b.value)}, limit ${formatNumber(b.limit)} (${b.basis}).`);\n }\n if (run) lines.push(`Started ${when(run.startedAt, now)}.`);\n break;\n }\n case \"recovered\": {\n title = `${name} recovered`;\n const after = (d.after as string[]).map((c) => c.replace(\"_\", \" \")).join(\", \");\n lines.push(`A run ${run ? when(run.startedAt, now) : \"just now\"} succeeded${after ? ` after: ${after}` : \"\"}.`);\n if (run?.durationMs !== null && run?.durationMs !== undefined) lines.push(`Ran ${formatDuration(run.durationMs)}.`);\n break;\n }\n }\n\n return {\n type: draft.type,\n job: name,\n definition: def,\n run,\n title,\n message: lines.join(\"\\n\"),\n details: d,\n at: now,\n };\n}\n","export function json(body: unknown, status = 200, headers: Record<string, string> = {}): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { \"content-type\": \"application/json; charset=utf-8\", \"cache-control\": \"no-store\", ...headers },\n });\n}\n","/** Output is capped so a chatty job cannot fill the store. The tail is kept. */\nexport const OUTPUT_CAP = 16 * 1024;\n\nexport function capOutput(text: string): string {\n if (text.length <= OUTPUT_CAP) return text;\n return \"[earlier output trimmed]\\n\" + text.slice(text.length - OUTPUT_CAP);\n}\n\nexport function errorMessage(error: unknown): string {\n if (error instanceof Error) {\n const stack = error.stack ? `\\n${error.stack.split(\"\\n\").slice(1, 6).join(\"\\n\")}` : \"\";\n return `${error.name}: ${error.message}${stack}`;\n }\n if (typeof error === \"string\") return error;\n try {\n return JSON.stringify(error);\n } catch {\n return String(error);\n }\n}\n","import { capOutput } from \"./output.js\";\nimport type { Run } from \"./types.js\";\n\n/** What a job function receives. */\nexport interface JobContext {\n readonly name: string;\n readonly runId: string;\n readonly startedAt: number;\n /** Aborts when the job's timeout elapses. Honour it if the work can stop. */\n readonly signal: AbortSignal;\n /** Append a line of output. Kept with the run, capped at 16 KB, shown in alerts and the dashboard. */\n log(...parts: unknown[]): void;\n /** Report a number for this run: tokens, cost, rows, anything. Watched against budgets and baselines. */\n metric(name: string, value: number): void;\n metrics(values: Record<string, number>): void;\n}\n\nexport interface RunRecorder {\n context: JobContext;\n output(): string | null;\n metrics(): Record<string, number>;\n abort(): void;\n}\n\nfunction stringify(part: unknown): string {\n if (typeof part === \"string\") return part;\n if (part instanceof Error) return `${part.name}: ${part.message}`;\n try {\n return JSON.stringify(part);\n } catch {\n return String(part);\n }\n}\n\nexport function createRecorder(run: Run): RunRecorder {\n const lines: string[] = [];\n let size = 0;\n const metrics: Record<string, number> = {};\n const controller = new AbortController();\n\n const context: JobContext = {\n name: run.job,\n runId: run.id,\n startedAt: run.startedAt,\n signal: controller.signal,\n log(...parts) {\n const line = parts.map(stringify).join(\" \");\n lines.push(line);\n size += line.length + 1;\n // Drop from the front once well past the cap; capOutput trims exactly at the end.\n while (size > 64 * 1024 && lines.length > 1) {\n size -= lines.shift()!.length + 1;\n }\n },\n metric(name, value) {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new Error(`metric \"${name}\" must be a finite number`);\n }\n metrics[name] = value;\n },\n metrics(values) {\n for (const [k, v] of Object.entries(values)) context.metric(k, v);\n },\n };\n\n return {\n context,\n output: () => (lines.length === 0 ? null : capOutput(lines.join(\"\\n\"))),\n metrics: () => ({ ...metrics }),\n abort: () => controller.abort(),\n };\n}\n","import type { JobDefinition, StoredJobDefinition } from \"./types.js\";\n\n/** A definition as a store can hold it: `expect` becomes a description. */\nexport function toStored(def: JobDefinition): StoredJobDefinition {\n const { expect, ...rest } = def;\n const stored: StoredJobDefinition = { ...rest };\n if (expect !== undefined) {\n stored.expect =\n typeof expect === \"string\" ? `contains ${JSON.stringify(expect)}`\n : expect instanceof RegExp ? `matches ${expect.toString()}`\n : \"custom function\";\n }\n return stored;\n}\n\nexport function checkExpectation(expect: JobDefinition[\"expect\"], output: string | null): string | null {\n if (expect === undefined) return null;\n const text = output ?? \"\";\n if (typeof expect === \"string\") {\n return text.includes(expect) ? null : `Output did not contain ${JSON.stringify(expect)}`;\n }\n if (expect instanceof RegExp) {\n return expect.test(text) ? null : `Output did not match ${expect.toString()}`;\n }\n let ok = false;\n try {\n ok = expect(text);\n } catch (error) {\n return `Output check threw: ${(error as Error).message}`;\n }\n return ok ? null : \"Output did not pass the expect() check\";\n}\n","import { formatDuration, formatRelative } from \"../duration.js\";\nimport type { JobSummary, Run } from \"../types.js\";\n\nexport function escapeHtml(value: unknown): string {\n return String(value ?? \"\")\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n\nconst h = escapeHtml;\n\nconst CSS = `\n:root{--bg:#fbfbf9;--fg:#1b1b18;--muted:#6b6b64;--line:#e6e5df;--card:#fff;--ok:#1f8a4c;--warn:#b7791f;--bad:#c62828;--info:#2b5fb3;--pill:#f1f0ea;--mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;--sans:-apple-system,BlinkMacSystemFont,\"Segoe UI\",Inter,Roboto,sans-serif}\n@media(prefers-color-scheme:dark){:root{--bg:#121311;--fg:#ecece6;--muted:#9a9a91;--line:#2a2b27;--card:#1a1b18;--pill:#24251f}}\n*{box-sizing:border-box}html{-webkit-text-size-adjust:100%}\nbody{margin:0;background:var(--bg);color:var(--fg);font:15px/1.5 var(--sans)}\na{color:inherit}main{max-width:1080px;margin:0 auto;padding:24px 16px 64px}\nheader{display:flex;align-items:baseline;justify-content:space-between;gap:16px;flex-wrap:wrap;margin-bottom:20px}\nheader h1{font-size:18px;margin:0;letter-spacing:-.01em}header h1 a{text-decoration:none}\nheader .meta{color:var(--muted);font-size:13px}\n.card{background:var(--card);border:1px solid var(--line);border-radius:10px;overflow:hidden}\ntable{width:100%;border-collapse:collapse;font-size:14px}\nth{text-align:left;font-weight:600;color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.04em;padding:10px 12px;border-bottom:1px solid var(--line);white-space:nowrap}\ntd{padding:10px 12px;border-bottom:1px solid var(--line);vertical-align:top}\ntr:last-child td{border-bottom:0}\n.name{font-weight:600;white-space:nowrap}.name a{text-decoration:none}.name a:hover{text-decoration:underline}\n.mono{font-family:var(--mono);font-size:13px}.muted{color:var(--muted)}.nowrap{white-space:nowrap}\n.pill{display:inline-flex;align-items:center;gap:6px;padding:2px 9px;border-radius:999px;background:var(--pill);font-size:12px;font-weight:600;white-space:nowrap}\n.pill::before{content:\"\";width:7px;height:7px;border-radius:50%;background:currentColor}\n.ok{color:var(--ok)}.warn{color:var(--warn)}.bad{color:var(--bad)}.info{color:var(--info)}.mutedpill{color:var(--muted)}\n.spark{display:block}\nform.inline{display:inline}\nbutton,select{font:inherit;font-size:13px;padding:5px 10px;border:1px solid var(--line);border-radius:7px;background:var(--card);color:var(--fg);cursor:pointer}\nbutton:hover{border-color:var(--muted)}\n.actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}\n.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin:0 0 20px}\n.stat{padding:12px 14px}.stat .k{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}.stat .v{font-size:20px;font-weight:600;margin-top:2px}\npre{margin:0;padding:10px 12px;background:var(--pill);border-radius:8px;font:12.5px/1.45 var(--mono);white-space:pre-wrap;word-break:break-word;max-height:320px;overflow:auto}\ndetails summary{cursor:pointer;color:var(--muted);font-size:13px}details{margin-top:6px}\n.empty{padding:40px 16px;text-align:center;color:var(--muted)}\ndl{display:grid;grid-template-columns:max-content 1fr;gap:6px 16px;margin:0;padding:14px 16px;font-size:14px}dt{color:var(--muted)}dd{margin:0}\nfooter{margin-top:28px;color:var(--muted);font-size:12px}\n@media(max-width:720px){.hide-sm{display:none}main{padding:16px 16px 48px}}\n`;\n\nexport function layout(title: string, body: string, options: { refresh?: number } = {}): string {\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">\n<meta name=\"robots\" content=\"noindex,nofollow\">\n${options.refresh ? `<meta http-equiv=\"refresh\" content=\"${options.refresh}\">` : \"\"}\n<title>${h(title)}</title>\n<style>${CSS}</style>\n</head>\n<body><main>${body}</main></body>\n</html>`;\n}\n\nfunction healthPill(job: JobSummary): string {\n const map: Record<JobSummary[\"health\"], [string, string]> = {\n healthy: [\"ok\", \"healthy\"],\n late: [\"warn\", \"late\"],\n failing: [\"bad\", \"failing\"],\n stuck: [\"bad\", \"stuck\"],\n silenced: [\"mutedpill\", \"silenced\"],\n never_ran: [\"info\", \"never ran\"],\n };\n const [cls, label] = map[job.health];\n const extras = job.open.filter((c) => ![\"missed\", \"failed\", \"stuck\"].includes(c)).map((c) => c.replace(\"_\", \" \"));\n return `<span class=\"pill ${cls}\">${label}</span>${extras.length ? ` <span class=\"pill warn\">${h(extras.join(\", \"))}</span>` : \"\"}`;\n}\n\nfunction runPill(run: Run): string {\n const cls = run.status === \"ok\" ? \"ok\" : run.status === \"running\" ? \"info\" : \"bad\";\n return `<span class=\"pill ${cls}\">${h(run.status)}</span>`;\n}\n\nfunction sparkline(runs: Run[]): string {\n const points = [...runs].reverse().filter((r) => r.durationMs !== null).slice(-20);\n if (points.length < 2) return \"\";\n const w = 96, hgt = 22;\n const max = Math.max(...points.map((r) => r.durationMs!), 1);\n const step = w / (points.length - 1);\n const path = points.map((r, i) => `${i === 0 ? \"M\" : \"L\"}${(i * step).toFixed(1)},${(hgt - 2 - (r.durationMs! / max) * (hgt - 4)).toFixed(1)}`).join(\" \");\n const dots = points.map((r, i) => r.status === \"ok\" ? \"\" : `<circle cx=\"${(i * step).toFixed(1)}\" cy=\"${(hgt - 2 - (r.durationMs! / max) * (hgt - 4)).toFixed(1)}\" r=\"2.2\" fill=\"var(--bad)\"/>`).join(\"\");\n return `<svg class=\"spark\" width=\"${w}\" height=\"${hgt}\" viewBox=\"0 0 ${w} ${hgt}\" aria-hidden=\"true\"><path d=\"${path}\" fill=\"none\" stroke=\"var(--muted)\" stroke-width=\"1.5\"/>${dots}</svg>`;\n}\n\nfunction stamp(at: number | null, now: number): string {\n if (at === null) return `<span class=\"muted\">never</span>`;\n const iso = new Date(at).toISOString().replace(\"T\", \" \").slice(0, 19);\n return `<span class=\"nowrap\" title=\"${iso} UTC\">${h(formatRelative(at, now))}</span>`;\n}\n\nexport function dashboardPage(jobs: JobSummary[], runsByJob: Map<string, Run[]>, now: number, base: string, checkedAt: number | null): string {\n const rows = jobs.map((job) => {\n const last = job.lastRun;\n return `<tr>\n<td class=\"name\"><a href=\"${h(base)}/jobs/${encodeURIComponent(job.name)}\">${h(job.name)}</a>${job.definition.description ? `<div class=\"muted\" style=\"font-weight:400;font-size:13px;white-space:normal\">${h(job.definition.description)}</div>` : \"\"}</td>\n<td>${healthPill(job)}</td>\n<td class=\"mono nowrap\">${h(job.definition.schedule ?? \"\")}<span class=\"muted\">${job.definition.schedule ? \"\" : \"no schedule\"}</span></td>\n<td class=\"nowrap\">${last ? `${runPill(last)} ${stamp(last.startedAt, now)}${last.durationMs !== null ? ` <span class=\"muted\">${h(formatDuration(last.durationMs))}</span>` : \"\"}` : `<span class=\"muted\">never</span>`}</td>\n<td class=\"nowrap hide-sm\">${stamp(job.nextExpectedAt, now)}</td>\n<td class=\"hide-sm\">${sparkline(runsByJob.get(job.name) ?? [])}</td>\n</tr>`;\n }).join(\"\\n\");\n\n const body = `\n<header>\n <h1><a href=\"${h(base)}/\">CronWatch</a></h1>\n <div class=\"actions\">\n <span class=\"meta\">${jobs.length} job${jobs.length === 1 ? \"\" : \"s\"}${checkedAt ? `, checked ${h(formatRelative(checkedAt, now))}` : \"\"}</span>\n <form class=\"inline\" method=\"post\" action=\"${h(base)}/check\"><button type=\"submit\">Run check now</button></form>\n </div>\n</header>\n<div class=\"card\">\n${jobs.length === 0 ? `<div class=\"empty\">No jobs yet. Declare one with <code class=\"mono\">cw.job(\"name\", { schedule: \"0 2 * * *\" })</code> and run it once.</div>` : `<table>\n<thead><tr><th>Job</th><th>Health</th><th>Schedule</th><th>Last run</th><th class=\"hide-sm\">Next due</th><th class=\"hide-sm\">Durations</th></tr></thead>\n<tbody>${rows}</tbody></table>`}\n</div>\n<footer>Refreshes every minute. <a href=\"${h(base)}/api/jobs\">JSON</a></footer>`;\n return layout(\"CronWatch\", body, { refresh: 60 });\n}\n\nexport function jobPage(job: JobSummary, runs: Run[], now: number, base: string): string {\n const d = job.definition;\n const okRate = `${Math.round(job.stats.okRate * 100)}%`;\n const runRows = runs.map((run) => {\n const detail = [\n run.error ? `<details open><summary>error</summary><pre>${h(run.error)}</pre></details>` : \"\",\n run.output ? `<details${run.status === \"ok\" ? \"\" : \" open\"}><summary>output</summary><pre>${h(run.output)}</pre></details>` : \"\",\n ].join(\"\");\n const metrics = Object.entries(run.metrics).map(([k, v]) => `<span class=\"pill mutedpill\">${h(k)} ${h(Number.isInteger(v) ? v : v.toFixed(4))}</span>`).join(\" \");\n return `<tr>\n<td class=\"nowrap\">${runPill(run)}</td>\n<td class=\"nowrap\">${stamp(run.startedAt, now)}</td>\n<td class=\"nowrap\">${run.durationMs !== null ? h(formatDuration(run.durationMs)) : `<span class=\"muted\">running</span>`}</td>\n<td class=\"hide-sm\">${metrics}</td>\n<td class=\"mono hide-sm muted\">${h(run.trigger)}</td>\n</tr>${detail ? `<tr><td colspan=\"5\" style=\"padding-top:0\">${detail}</td></tr>` : \"\"}`;\n }).join(\"\\n\");\n\n const silenced = job.silencedUntil !== null && job.silencedUntil > now;\n const body = `\n<header>\n <h1><a href=\"${h(base)}/\">CronWatch</a> <span class=\"muted\">/</span> ${h(job.name)}</h1>\n <div class=\"actions\">\n ${healthPill(job)}\n ${silenced\n ? `<form class=\"inline\" method=\"post\" action=\"${h(base)}/jobs/${encodeURIComponent(job.name)}/unsilence\"><button type=\"submit\">Unsilence (until ${h(formatRelative(job.silencedUntil!, now))})</button></form>`\n : `<form class=\"inline\" method=\"post\" action=\"${h(base)}/jobs/${encodeURIComponent(job.name)}/silence\"><select name=\"for\"><option value=\"1h\">1 hour</option><option value=\"4h\">4 hours</option><option value=\"1d\">1 day</option><option value=\"7d\">1 week</option></select> <button type=\"submit\">Silence</button></form>`}\n <form class=\"inline\" method=\"post\" action=\"${h(base)}/jobs/${encodeURIComponent(job.name)}/forget\" onsubmit=\"return confirm('Remove this job and its runs from the store?')\"><button type=\"submit\">Forget</button></form>\n </div>\n</header>\n<div class=\"grid\">\n <div class=\"card stat\"><div class=\"k\">Last run</div><div class=\"v\">${job.lastRun ? h(formatRelative(job.lastRun.startedAt, now)) : \"never\"}</div></div>\n <div class=\"card stat\"><div class=\"k\">Next due</div><div class=\"v\">${job.nextExpectedAt ? h(formatRelative(job.nextExpectedAt, now)) : \"no schedule\"}</div></div>\n <div class=\"card stat\"><div class=\"k\">Success, last ${job.stats.runs}</div><div class=\"v\">${okRate}</div></div>\n <div class=\"card stat\"><div class=\"k\">p50 / p95</div><div class=\"v\">${job.stats.p50Ms !== null ? h(formatDuration(job.stats.p50Ms)) : \"?\"} <span class=\"muted\">/</span> ${job.stats.p95Ms !== null ? h(formatDuration(job.stats.p95Ms)) : \"?\"}</div></div>\n</div>\n<div class=\"card\" style=\"margin-bottom:20px\">\n<dl>\n <dt>Schedule</dt><dd class=\"mono\">${d.schedule ? h(d.schedule) + (d.timezone ? ` <span class=\"muted\">${h(d.timezone)}</span>` : \"\") : `<span class=\"muted\">none</span>`}</dd>\n <dt>Grace</dt><dd class=\"mono\">${h(d.grace ?? \"10m\")}</dd>\n <dt>Timeout</dt><dd class=\"mono\">${h(d.timeout ?? \"1h\")}</dd>\n ${d.maxDuration ? `<dt>Max duration</dt><dd class=\"mono\">${h(d.maxDuration)}</dd>` : \"\"}\n ${d.budget ? `<dt>Budget</dt><dd class=\"mono\">${h(Object.entries(d.budget).map(([k, v]) => `${k} ≤ ${v}`).join(\", \"))}</dd>` : \"\"}\n ${d.expect ? `<dt>Expect</dt><dd class=\"mono\">${h(d.expect)}</dd>` : \"\"}\n ${d.failuresBeforeAlert && d.failuresBeforeAlert > 1 ? `<dt>Alert after</dt><dd>${d.failuresBeforeAlert} consecutive failures</dd>` : \"\"}\n ${d.description ? `<dt>Description</dt><dd>${h(d.description)}</dd>` : \"\"}\n ${d.tags?.length ? `<dt>Tags</dt><dd>${d.tags.map((t) => `<span class=\"pill mutedpill\">${h(t)}</span>`).join(\" \")}</dd>` : \"\"}\n ${job.open.length ? `<dt>Open</dt><dd>${job.open.map((c) => `<span class=\"pill warn\">${h(c.replace(\"_\", \" \"))}</span>`).join(\" \")}</dd>` : \"\"}\n ${job.consecutiveFailures > 0 ? `<dt>Consecutive failures</dt><dd>${job.consecutiveFailures}</dd>` : \"\"}\n</dl>\n</div>\n<div class=\"card\">\n${runs.length === 0 ? `<div class=\"empty\">No runs yet.</div>` : `<table>\n<thead><tr><th>Status</th><th>Started</th><th>Duration</th><th class=\"hide-sm\">Metrics</th><th class=\"hide-sm\">Trigger</th></tr></thead>\n<tbody>${runRows}</tbody></table>`}\n</div>\n<footer><a href=\"${h(base)}/api/jobs/${encodeURIComponent(job.name)}\">JSON</a></footer>`;\n return layout(`${job.name}: CronWatch`, body, { refresh: 60 });\n}\n\nexport function messagePage(title: string, message: string, base: string): string {\n return layout(title, `<header><h1><a href=\"${h(base)}/\">CronWatch</a></h1></header><div class=\"card\"><div class=\"empty\"><strong>${h(title)}</strong><br>${h(message)}</div></div>`);\n}\n","import type { CronWatch } from \"../client.js\";\nimport { json } from \"../http.js\";\nimport { parseDuration } from \"../duration.js\";\nimport type { Run } from \"../types.js\";\nimport { dashboardPage, jobPage, messagePage } from \"./html.js\";\n\nexport interface RoutesOptions {\n /**\n * Required to reach anything. Send it as `Authorization: Bearer <token>`,\n * or open the dashboard once with `?token=<token>` and a cookie is set.\n * Defaults to process.env.CRONWATCH_TOKEN. With no token at all, the routes\n * are open in development and refuse to serve in production.\n *\n * The check endpoint (/api/check) also accepts the client's cronSecret, so\n * a platform cron that sends `Authorization: Bearer <CRON_SECRET>` can\n * trigger checks without knowing the dashboard token.\n */\n token?: string | null;\n /** Where the routes are mounted, so links resolve. Default \"/cronwatch\". */\n basePath?: string;\n}\n\nexport type FetchHandler = (request: Request) => Promise<Response>;\n\nexport interface Routes {\n handler: FetchHandler;\n GET: FetchHandler;\n POST: FetchHandler;\n DELETE: FetchHandler;\n}\n\nconst COOKIE = \"cronwatch_token\";\n\nfunction constantTimeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n return diff === 0;\n}\n\nfunction readCookie(request: Request, name: string): string | null {\n const header = request.headers.get(\"cookie\");\n if (!header) return null;\n for (const part of header.split(\";\")) {\n const [k, ...rest] = part.trim().split(\"=\");\n if (k === name) return decodeURIComponent(rest.join(\"=\"));\n }\n return null;\n}\n\nfunction stripBase(pathname: string, base: string): string {\n let path = pathname.startsWith(base) ? pathname.slice(base.length) : pathname;\n if (path === \"\") path = \"/\";\n if (path.length > 1 && path.endsWith(\"/\")) path = path.slice(0, -1);\n return path;\n}\n\nasync function readBody(request: Request): Promise<Record<string, string>> {\n const type = request.headers.get(\"content-type\") ?? \"\";\n try {\n if (type.includes(\"application/json\")) {\n const data = await request.json();\n return typeof data === \"object\" && data !== null ? Object.fromEntries(Object.entries(data).map(([k, v]) => [k, String(v)])) : {};\n }\n if (type.includes(\"application/x-www-form-urlencoded\") || type.includes(\"multipart/form-data\")) {\n const form = await request.formData();\n const out: Record<string, string> = {};\n for (const [k, v] of form.entries()) out[k] = String(v);\n return out;\n }\n } catch {\n return {};\n }\n return {};\n}\n\n/**\n * A fetch-style handler serving the dashboard and a small JSON API. Mount it\n * in a Next.js app at app/cronwatch/[[...path]]/route.ts:\n *\n * export const { GET, POST, DELETE } = cw.routes();\n */\nexport function createRoutes(cw: CronWatch, options: RoutesOptions = {}): Routes {\n const token = options.token === undefined ? (process.env.CRONWATCH_TOKEN ?? null) : options.token;\n const base = (options.basePath ?? \"/cronwatch\").replace(/\\/+$/, \"\");\n const production = process.env.NODE_ENV === \"production\";\n\n const handler: FetchHandler = async (request) => {\n const url = new URL(request.url);\n const path = stripBase(url.pathname, base);\n const wantsHtml = !path.startsWith(\"/api\");\n const method = request.method.toUpperCase();\n\n if (!token && production) {\n return wantsHtml\n ? html(messagePage(\"CronWatch routes are locked\", \"Set CRONWATCH_TOKEN (or pass token to cw.routes()) to use them in production.\", base), 503)\n : json({ ok: false, error: \"CRONWATCH_TOKEN is not set\" }, 503);\n }\n\n if (token) {\n const bearer = request.headers.get(\"authorization\")?.replace(/^Bearer\\s+/i, \"\") ?? null;\n const query = url.searchParams.get(\"token\");\n const cookie = readCookie(request, COOKIE);\n const presented = bearer ?? query ?? cookie;\n const isCheck = path === \"/api/check\";\n const cronSecretOk = isCheck && bearer !== null && cw.cronSecret !== null && constantTimeEqual(bearer, cw.cronSecret);\n if (!cronSecretOk && (presented === null || !constantTimeEqual(presented, token))) {\n return wantsHtml\n ? html(messagePage(\"Sign in\", `Open this page with ?token=<your CRONWATCH_TOKEN> once and it will stay signed in.`, base), 401)\n : json({ ok: false, error: \"Unauthorized\" }, 401);\n }\n if (query !== null && wantsHtml && method === \"GET\") {\n // Move the token from the URL into a cookie so it is not in history or logs.\n url.searchParams.delete(\"token\");\n const secure = url.protocol === \"https:\" ? \"; Secure\" : \"\";\n return new Response(null, {\n status: 303,\n headers: {\n location: url.pathname + (url.search || \"\"),\n \"set-cookie\": `${COOKIE}=${encodeURIComponent(token)}; Path=${base || \"/\"}; HttpOnly; SameSite=Lax; Max-Age=${60 * 60 * 24 * 30}${secure}`,\n },\n });\n }\n }\n\n const redirectBack = () => {\n const referer = request.headers.get(\"referer\") ?? \"\";\n const location = referer.startsWith(url.origin + \"/\") ? referer : `${base}/`;\n return new Response(null, { status: 303, headers: { location } });\n };\n const jobName = (segment: string | undefined) => (segment ? decodeURIComponent(segment) : \"\");\n const parts = path.split(\"/\").filter(Boolean);\n\n // HTML\n if (method === \"GET\" && path === \"/\") {\n const jobs = await cw.jobs();\n const runsByJob = new Map<string, Run[]>();\n for (const job of jobs) runsByJob.set(job.name, await cw.runs(job.name, 20));\n return html(dashboardPage(jobs, runsByJob, cw.now(), base, null));\n }\n if (method === \"GET\" && parts[0] === \"jobs\" && parts.length === 2) {\n const job = await cw.jobSummary(jobName(parts[1]));\n if (!job) return html(messagePage(\"No such job\", `${jobName(parts[1])} is not in the store.`, base), 404);\n return html(jobPage(job, await cw.runs(job.name, 50), cw.now(), base));\n }\n if (method === \"POST\" && path === \"/check\") {\n await cw.check();\n return redirectBack();\n }\n if (method === \"POST\" && parts[0] === \"jobs\" && parts.length === 3) {\n const name = jobName(parts[1]);\n const body = await readBody(request);\n if (parts[2] === \"silence\") await cw.silence(name, safeDuration(body.for, \"1h\"));\n else if (parts[2] === \"unsilence\") await cw.unsilence(name);\n else if (parts[2] === \"forget\") {\n await cw.forget(name);\n return new Response(null, { status: 303, headers: { location: `${base}/` } });\n } else return html(messagePage(\"Not found\", path, base), 404);\n return redirectBack();\n }\n\n // JSON API\n if (parts[0] === \"api\") {\n const rest = parts.slice(1);\n if (method === \"GET\" && rest[0] === \"jobs\" && rest.length === 1) {\n return json({ ok: true, jobs: await cw.jobs() });\n }\n if (rest[0] === \"jobs\" && rest.length === 2) {\n const name = jobName(rest[1]);\n if (method === \"GET\") {\n const job = await cw.jobSummary(name);\n if (!job) return json({ ok: false, error: \"No such job\" }, 404);\n const limit = Number(url.searchParams.get(\"runs\") ?? 20);\n return json({ ok: true, job, runs: await cw.runs(name, Number.isFinite(limit) ? limit : 20) });\n }\n if (method === \"DELETE\") {\n await cw.forget(name);\n return json({ ok: true });\n }\n }\n if (method === \"POST\" && rest[0] === \"jobs\" && rest.length === 3) {\n const name = jobName(rest[1]);\n if (!(await cw.jobSummary(name))) return json({ ok: false, error: \"No such job\" }, 404);\n const body = await readBody(request);\n if (rest[2] === \"silence\") return json({ ok: true, state: await cw.silence(name, safeDuration(body.for ?? url.searchParams.get(\"for\"), \"1h\")) });\n if (rest[2] === \"unsilence\") return json({ ok: true, state: await cw.unsilence(name) });\n }\n if ((method === \"GET\" || method === \"POST\") && rest[0] === \"check\" && rest.length === 1) {\n const result = await cw.check();\n return json({ ok: true, ...result });\n }\n if (method === \"GET\" && rest[0] === \"runs\" && rest.length === 2) {\n const run = await cw.getRun(rest[1]!);\n return run ? json({ ok: true, run }) : json({ ok: false, error: \"No such run\" }, 404);\n }\n return json({ ok: false, error: \"Not found\" }, 404);\n }\n\n return html(messagePage(\"Not found\", path, base), 404);\n };\n\n return { handler, GET: handler, POST: handler, DELETE: handler };\n}\n\nfunction safeDuration(value: string | null | undefined, fallback: string): string {\n if (!value) return fallback;\n try {\n parseDuration(value);\n return value;\n } catch {\n return fallback;\n }\n}\n\nfunction html(body: string, status = 200): Response {\n return new Response(body, {\n status,\n headers: { \"content-type\": \"text/html; charset=utf-8\", \"cache-control\": \"no-store\", \"x-robots-tag\": \"noindex\" },\n });\n}\n","import type { JobState, Run, Store, StoredJob, StoredJobDefinition } from \"../types.js\";\n\n/**\n * Keeps everything in process memory. The default when no store is given,\n * good for tests and for trying the library out. State is gone on restart,\n * so a missed run cannot be noticed across one.\n */\nexport function memory(): Store {\n const jobs = new Map<string, StoredJob>();\n const runs = new Map<string, Run>();\n const order = new Map<string, number>();\n const states = new Map<string, JobState>();\n let seq = 0;\n\n const clone = <T>(v: T): T => JSON.parse(JSON.stringify(v));\n\n return {\n async upsertJob(definition: StoredJobDefinition, now: number) {\n const existing = jobs.get(definition.name);\n jobs.set(definition.name, {\n name: definition.name,\n definition: clone(definition),\n createdAt: existing?.createdAt ?? now,\n updatedAt: now,\n });\n },\n async getJob(name) {\n const j = jobs.get(name);\n return j ? clone(j) : null;\n },\n async listJobs() {\n return [...jobs.values()].map(clone).sort((a, b) => a.name.localeCompare(b.name));\n },\n async deleteJob(name) {\n jobs.delete(name);\n states.delete(name);\n for (const [id, run] of runs) if (run.job === name) { runs.delete(id); order.delete(id); }\n },\n async insertRun(run) {\n runs.set(run.id, clone(run));\n order.set(run.id, ++seq);\n },\n async updateRun(run) {\n runs.set(run.id, clone(run));\n },\n async getRun(id) {\n const r = runs.get(id);\n return r ? clone(r) : null;\n },\n async listRuns(job, limit) {\n return [...runs.values()]\n .filter((r) => r.job === job)\n .sort((a, b) => b.startedAt - a.startedAt || order.get(b.id)! - order.get(a.id)!)\n .slice(0, limit)\n .map(clone);\n },\n async lastRun(job) {\n const list = await this.listRuns(job, 1);\n return list[0] ?? null;\n },\n async runningRuns() {\n return [...runs.values()].filter((r) => r.status === \"running\").map(clone);\n },\n async getState(job) {\n const s = states.get(job);\n return s ? clone(s) : null;\n },\n async setState(state) {\n states.set(state.job, clone(state));\n },\n async prune(before) {\n let n = 0;\n for (const [id, run] of runs) {\n if (run.status !== \"running\" && run.startedAt < before) {\n runs.delete(id);\n order.delete(id);\n n++;\n }\n }\n return n;\n },\n };\n}\n","import { parseDuration } from \"./duration.js\";\nimport {\n BASELINE_WINDOW,\n emptyState,\n isSilenced,\n isStuck,\n muteOpens,\n onCheck,\n onRunFinish,\n onRunStart,\n openConditions,\n timeoutMs,\n} from \"./evaluate.js\";\nimport type { AlertDraft, Evaluation } from \"./evaluate.js\";\nimport { composeAlert } from \"./format.js\";\nimport { json } from \"./http.js\";\nimport { createRecorder } from \"./job.js\";\nimport type { JobContext } from \"./job.js\";\nimport { errorMessage } from \"./output.js\";\nimport { parseSchedule } from \"./schedule.js\";\nimport { checkExpectation, toStored } from \"./serialize.js\";\nimport { percentile } from \"./stats.js\";\nimport { createRoutes } from \"./routes/index.js\";\nimport type { Routes, RoutesOptions } from \"./routes/index.js\";\nimport { memory } from \"./stores/memory.js\";\nimport type {\n Alert,\n AlertChannel,\n CheckResult,\n Condition,\n Duration,\n JobDefinition,\n JobOptions,\n JobState,\n JobSummary,\n Run,\n Store,\n StoredJob,\n StoredJobDefinition,\n TriageFn,\n} from \"./types.js\";\n\nexport type JobFn<T> = (job: JobContext) => Promise<T> | T;\nexport type HandlerFn<T> = (job: JobContext, request: Request) => Promise<T> | T;\n\nexport interface HandlerOptions {\n /**\n * Callers must send `Authorization: Bearer <secret>`. Defaults to the\n * client's cronSecret, which defaults to process.env.CRON_SECRET (what\n * Vercel sends its cron requests with). Pass null to allow anyone.\n */\n secret?: string | null;\n}\n\nexport interface JobHandle {\n readonly name: string;\n readonly definition: JobDefinition;\n /** Run the function now, recording the run. Rethrows whatever the function throws. */\n run<T>(fn: JobFn<T>, options?: { trigger?: string }): Promise<T>;\n /** A fetch-style request handler (Next.js route, Hono, Bun, Deno) that runs the function and records the run. */\n handler<T>(fn: HandlerFn<T>, options?: HandlerOptions): (request: Request) => Promise<Response>;\n}\n\nexport interface CronWatchOptions {\n /** Where jobs, runs and state live. Defaults to an in-memory store that forgets on restart. */\n store?: Store;\n /** Where alerts go. Defaults to the console. */\n alerts?: AlertChannel[];\n /** Adds a short diagnosis to failure alerts. See @cronwatch/sdk/anthropic. */\n triage?: TriageFn;\n /** Shared secret that handler() requests must carry. Defaults to process.env.CRON_SECRET. */\n cronSecret?: string | null;\n /** How long finished runs are kept. Default \"30d\". */\n retention?: Duration;\n /** Applied to every job unless the job sets its own. */\n defaults?: Pick<JobOptions, \"grace\" | \"timeout\" | \"timezone\" | \"failuresBeforeAlert\">;\n /** Called with anything that goes wrong outside a job: an alert channel failing, a triage timeout. */\n onError?: (error: unknown, where: string) => void;\n /** The clock. Tests use this. */\n now?: () => number;\n}\n\nexport interface ExecuteResult<T> {\n run: Run;\n result: T | undefined;\n error: unknown;\n threw: boolean;\n}\n\nconst NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,119}$/;\nconst TRIAGE_TIMEOUT_MS = 25_000;\nconst PRUNE_INTERVAL_MS = 60 * 60_000;\n\nfunction constantTimeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n let diff = 0;\n for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);\n return diff === 0;\n}\n\nexport class CronWatch {\n readonly store: Store;\n readonly alerts: AlertChannel[];\n readonly triage: TriageFn | undefined;\n readonly cronSecret: string | null;\n readonly retentionMs: number;\n readonly now: () => number;\n readonly onError: (error: unknown, where: string) => void;\n private readonly defaults: NonNullable<CronWatchOptions[\"defaults\"]>;\n private readonly definitions = new Map<string, JobDefinition>();\n private readonly synced = new Set<string>();\n private ready: Promise<void> | null = null;\n private checking: Promise<CheckResult> | null = null;\n private lastPruneAt = 0;\n private timer: ReturnType<typeof setInterval> | null = null;\n private usingDefaultStore = false;\n\n constructor(options: CronWatchOptions = {}) {\n this.store = options.store ?? (this.usingDefaultStore = true, memory());\n this.alerts = options.alerts ?? [consoleChannel()];\n this.triage = options.triage;\n this.cronSecret = options.cronSecret === undefined ? (process.env.CRON_SECRET ?? null) : options.cronSecret;\n this.retentionMs = parseDuration(options.retention ?? \"30d\", \"retention\");\n this.defaults = options.defaults ?? {};\n this.now = options.now ?? (() => Date.now());\n this.onError = options.onError ?? ((error, where) => console.error(`[cronwatch] ${where}:`, error));\n }\n\n /** Declare a job. Call it once, at module level, and keep the handle. */\n job(name: string, options: JobOptions = {}): JobHandle {\n if (!NAME_RE.test(name)) {\n throw new Error(`job name \"${name}\" must be 1 to 120 characters of letters, digits, \".\", \"_\", \":\" or \"-\"`);\n }\n const definition: JobDefinition = { ...this.defaults, ...options, name };\n if (definition.schedule) parseSchedule(definition.schedule, definition.timezone);\n if (definition.grace !== undefined) parseDuration(definition.grace, \"grace\");\n if (definition.timeout !== undefined) parseDuration(definition.timeout, \"timeout\");\n if (definition.maxDuration !== undefined) parseDuration(definition.maxDuration, \"maxDuration\");\n this.definitions.set(name, definition);\n this.synced.delete(name);\n return this.handle(definition);\n }\n\n /** Run a job by name without keeping a handle. Defines it on first use. */\n run<T>(name: string, fn: JobFn<T>): Promise<T>;\n run<T>(name: string, options: JobOptions, fn: JobFn<T>): Promise<T>;\n run<T>(name: string, optionsOrFn: JobOptions | JobFn<T>, maybeFn?: JobFn<T>): Promise<T> {\n const fn = typeof optionsOrFn === \"function\" ? optionsOrFn : maybeFn!;\n const options = typeof optionsOrFn === \"function\" ? undefined : optionsOrFn;\n const handle = options || !this.definitions.has(name) ? this.job(name, options) : this.handle(this.definitions.get(name)!);\n return handle.run(fn);\n }\n\n /** The definitions declared in this process. */\n definedJobs(): JobDefinition[] {\n return [...this.definitions.values()];\n }\n\n private handle(definition: JobDefinition): JobHandle {\n const self = this;\n return {\n name: definition.name,\n definition,\n async run<T>(fn: JobFn<T>, options?: { trigger?: string }): Promise<T> {\n const outcome = await self.execute(definition, fn, options?.trigger ?? \"run\");\n if (outcome.threw) throw outcome.error;\n return outcome.result as T;\n },\n handler<T>(fn: HandlerFn<T>, options?: HandlerOptions) {\n const secret = options?.secret === undefined ? self.cronSecret : options.secret;\n return async (request: Request): Promise<Response> => {\n if (secret) {\n const header = request.headers.get(\"authorization\") ?? \"\";\n if (!constantTimeEqual(header, `Bearer ${secret}`)) {\n return json({ ok: false, error: \"Unauthorized\" }, 401);\n }\n }\n const outcome = await self.execute(definition, (job) => fn(job, request), \"handler\");\n if (outcome.result instanceof Response) return outcome.result;\n const body = {\n ok: outcome.run.status === \"ok\",\n job: definition.name,\n run: outcome.run.id,\n status: outcome.run.status,\n durationMs: outcome.run.durationMs,\n ...(outcome.run.error ? { error: outcome.run.error.split(\"\\n\")[0] } : {}),\n };\n return json(body, outcome.run.status === \"ok\" ? 200 : 500);\n };\n },\n };\n }\n\n private async ensureReady(): Promise<void> {\n if (!this.ready) {\n this.ready = (async () => {\n if (this.store.init) await this.store.init();\n if (this.usingDefaultStore && process.env.NODE_ENV === \"production\") {\n console.warn(\"[cronwatch] using the in-memory store: runs and state are lost on restart. Pass a store from @cronwatch/sdk/sqlite or @cronwatch/sdk/postgres.\");\n }\n })();\n }\n await this.ready;\n }\n\n private async sync(definition: JobDefinition): Promise<void> {\n await this.ensureReady();\n if (this.synced.has(definition.name)) return;\n await this.store.upsertJob(toStored(definition), this.now());\n this.synced.add(definition.name);\n }\n\n /** Runs a function as a recorded run. Never throws for the job's own error; see `threw`. */\n async execute<T>(definition: JobDefinition, fn: JobFn<T>, trigger: string): Promise<ExecuteResult<T>> {\n await this.sync(definition);\n const startedAt = this.now();\n const run: Run = {\n id: crypto.randomUUID(),\n job: definition.name,\n status: \"running\",\n startedAt,\n finishedAt: null,\n durationMs: null,\n error: null,\n output: null,\n metrics: {},\n trigger,\n };\n await this.store.insertRun(run);\n\n const before = (await this.store.getState(definition.name)) ?? emptyState(definition.name);\n const started = onRunStart(before);\n if (openConditions(started.state).length !== openConditions(before).length) {\n await this.store.setState(started.state);\n }\n\n const recorder = createRecorder(run);\n const timer = setTimeout(() => recorder.abort(), timeoutMs(definition));\n if (typeof timer === \"object\" && \"unref\" in timer) timer.unref();\n\n let result: T | undefined;\n let error: unknown;\n let threw = false;\n try {\n result = await fn(recorder.context);\n } catch (e) {\n error = e;\n threw = true;\n } finally {\n clearTimeout(timer);\n }\n\n const finishedAt = this.now();\n run.finishedAt = finishedAt;\n run.durationMs = Math.max(0, finishedAt - startedAt);\n run.metrics = recorder.metrics();\n run.output = recorder.output() ?? (typeof result === \"string\" ? result : null);\n\n if (threw) {\n run.status = \"failed\";\n run.error = errorMessage(error);\n } else if (result instanceof Response && result.status >= 400) {\n run.status = \"failed\";\n run.error = `HTTP ${result.status}${result.statusText ? ` ${result.statusText}` : \"\"}`;\n } else {\n const unmet = checkExpectation(definition.expect, run.output);\n if (unmet) {\n run.status = \"failed\";\n run.error = unmet;\n } else {\n run.status = \"ok\";\n }\n }\n await this.store.updateRun(run);\n\n try {\n const history = (await this.store.listRuns(definition.name, BASELINE_WINDOW + 5)).filter((r) => r.id !== run.id);\n const state = (await this.store.getState(definition.name)) ?? emptyState(definition.name);\n const evaluation = onRunFinish(definition, run, state, history, started.openBefore, finishedAt);\n await this.settle(state, evaluation, toStored(definition), finishedAt);\n } catch (e) {\n this.onError(e, `evaluating ${definition.name}`);\n }\n\n return { run, result, error, threw };\n }\n\n /**\n * Look for missed and stuck runs across every job, send alerts, and prune\n * old runs. Call it from an interval (start()), a cron hitting the mounted\n * routes, or by hand. Concurrent calls share one check.\n */\n check(): Promise<CheckResult> {\n if (!this.checking) {\n this.checking = this.runCheck().finally(() => {\n this.checking = null;\n });\n }\n return this.checking;\n }\n\n private async runCheck(): Promise<CheckResult> {\n await this.ensureReady();\n for (const definition of this.definitions.values()) await this.sync(definition);\n const now = this.now();\n const alerts: Alert[] = [];\n\n // Runs that never reported back.\n for (const run of await this.store.runningRuns()) {\n const stored = await this.store.getJob(run.job);\n const declared = this.definitions.get(run.job);\n const definition = declared ? toStored(declared) : stored?.definition;\n if (!definition || !isStuck(definition, run, now)) continue;\n run.status = \"timeout\";\n run.finishedAt = now;\n run.durationMs = now - run.startedAt;\n run.error = `Still running after ${Math.round(timeoutMs(definition) / 60_000)} minutes; marked as timed out`;\n await this.store.updateRun(run);\n const history = (await this.store.listRuns(run.job, BASELINE_WINDOW + 5)).filter((r) => r.id !== run.id);\n const state = (await this.store.getState(run.job)) ?? emptyState(run.job);\n const evaluation = onRunFinish(definition, run, state, history, [], now);\n alerts.push(...(await this.settle(state, evaluation, definition, now)));\n }\n\n const jobs: JobSummary[] = [];\n for (const stored of await this.store.listJobs()) {\n const definition = stored.definition;\n const lastRun = await this.store.lastRun(stored.name);\n const state = (await this.store.getState(stored.name)) ?? emptyState(stored.name);\n const evaluation = onCheck(definition, stored, lastRun, state, now);\n alerts.push(...(await this.settle(state, evaluation, definition, now)));\n jobs.push(await this.summarize(stored, lastRun, evaluation.state, evaluation.nextExpectedAt, now));\n }\n\n let pruned = 0;\n if (now - this.lastPruneAt > PRUNE_INTERVAL_MS) {\n this.lastPruneAt = now;\n try {\n pruned = await this.store.prune(now - this.retentionMs);\n } catch (e) {\n this.onError(e, \"pruning\");\n }\n }\n\n return { checkedAt: now, jobs, alerts, pruned };\n }\n\n /** Every job the store knows about, with its health. Does not send alerts. */\n async jobs(): Promise<JobSummary[]> {\n await this.ensureReady();\n for (const definition of this.definitions.values()) await this.sync(definition);\n const now = this.now();\n const out: JobSummary[] = [];\n for (const stored of await this.store.listJobs()) {\n const lastRun = await this.store.lastRun(stored.name);\n const state = (await this.store.getState(stored.name)) ?? emptyState(stored.name);\n const { nextExpectedAt } = onCheck(stored.definition, stored, lastRun, state, now);\n out.push(await this.summarize(stored, lastRun, state, nextExpectedAt, now));\n }\n return out;\n }\n\n async jobSummary(name: string): Promise<JobSummary | null> {\n await this.ensureReady();\n const definition = this.definitions.get(name);\n if (definition) await this.sync(definition);\n const stored = await this.store.getJob(name);\n if (!stored) return null;\n const now = this.now();\n const lastRun = await this.store.lastRun(name);\n const state = (await this.store.getState(name)) ?? emptyState(name);\n const { nextExpectedAt } = onCheck(stored.definition, stored, lastRun, state, now);\n return this.summarize(stored, lastRun, state, nextExpectedAt, now);\n }\n\n async runs(name: string, limit = 50): Promise<Run[]> {\n await this.ensureReady();\n return this.store.listRuns(name, Math.min(500, Math.max(1, limit)));\n }\n\n async getRun(id: string): Promise<Run | null> {\n await this.ensureReady();\n return this.store.getRun(id);\n }\n\n /** Stop alerts for a job for a while. State keeps updating underneath. */\n async silence(name: string, duration: Duration): Promise<JobState> {\n await this.ensureReady();\n const state = (await this.store.getState(name)) ?? emptyState(name);\n state.silencedUntil = this.now() + parseDuration(duration, \"silence duration\");\n await this.store.setState(state);\n return state;\n }\n\n async unsilence(name: string): Promise<JobState> {\n await this.ensureReady();\n const state = (await this.store.getState(name)) ?? emptyState(name);\n state.silencedUntil = null;\n await this.store.setState(state);\n return state;\n }\n\n /** Remove a job and its runs from the store. A job still declared in code comes back on its next run. */\n async forget(name: string): Promise<void> {\n await this.ensureReady();\n this.definitions.delete(name);\n this.synced.delete(name);\n await this.store.deleteJob(name);\n }\n\n /** The dashboard and JSON API as fetch-style handlers. See createRoutes(). */\n routes(options?: RoutesOptions): Routes {\n return createRoutes(this, options);\n }\n\n /** Check on an interval, for long-running servers. Default every minute. */\n start(every: Duration = \"1m\"): void {\n if (this.timer) return;\n const ms = Math.max(5_000, parseDuration(every, \"check interval\"));\n const tick = () => this.check().catch((e) => this.onError(e, \"check\"));\n this.timer = setInterval(tick, ms);\n if (typeof this.timer === \"object\" && \"unref\" in this.timer) this.timer.unref();\n setTimeout(tick, 1_000).unref?.();\n }\n\n stop(): void {\n if (this.timer) clearInterval(this.timer);\n this.timer = null;\n }\n\n async close(): Promise<void> {\n this.stop();\n if (this.store.close) await this.store.close();\n }\n\n private async summarize(stored: StoredJob, lastRun: Run | null, state: JobState, nextExpectedAt: number | null, now: number): Promise<JobSummary> {\n const recent = await this.store.listRuns(stored.name, BASELINE_WINDOW);\n const finished = recent.filter((r) => r.status !== \"running\");\n const okDurations = recent.filter((r) => r.status === \"ok\" && r.durationMs !== null).map((r) => r.durationMs!);\n const open = openConditions(state);\n let health: JobSummary[\"health\"];\n if (state.silencedUntil !== null && state.silencedUntil > now) health = \"silenced\";\n else if (open.includes(\"stuck\") || (lastRun && isStuck(stored.definition, lastRun, now))) health = \"stuck\";\n else if (open.includes(\"failed\") || lastRun?.status === \"failed\" || lastRun?.status === \"timeout\") health = \"failing\";\n else if (open.includes(\"missed\")) health = \"late\";\n else if (!lastRun) health = \"never_ran\";\n else health = \"healthy\";\n return {\n name: stored.name,\n definition: stored.definition,\n health,\n open,\n lastRun,\n nextExpectedAt,\n consecutiveFailures: state.consecutiveFailures,\n silencedUntil: state.silencedUntil,\n stats: {\n runs: finished.length,\n okRate: finished.length === 0 ? 1 : finished.filter((r) => r.status === \"ok\").length / finished.length,\n p50Ms: percentile(okDurations, 50),\n p95Ms: percentile(okDurations, 95),\n },\n };\n }\n\n /** Save an evaluation's state, honouring silence, and send its alerts. */\n private async settle(previous: JobState, evaluation: Evaluation, definition: StoredJobDefinition, now: number): Promise<Alert[]> {\n if (isSilenced(previous, now)) {\n evaluation.state = muteOpens(previous, evaluation.state);\n evaluation.alerts = [];\n }\n if (JSON.stringify(evaluation.state) !== JSON.stringify(previous)) await this.store.setState(evaluation.state);\n return this.dispatch(evaluation.alerts, definition, evaluation.state, now);\n }\n\n private async dispatch(drafts: AlertDraft[], definition: StoredJobDefinition, state: JobState, now: number): Promise<Alert[]> {\n if (drafts.length === 0) return [];\n const sent: Alert[] = [];\n for (const draft of drafts) {\n const alert = composeAlert(draft, definition, now);\n if (this.triage && alert.type !== \"recovered\") {\n try {\n const recentRuns = await this.store.listRuns(alert.job, 5);\n const diagnosis = await withTimeout(this.triage({ alert, recentRuns }), TRIAGE_TIMEOUT_MS);\n if (diagnosis) alert.triage = diagnosis;\n } catch (e) {\n this.onError(e, `triage for ${alert.job}`);\n }\n }\n for (const channel of this.alerts) {\n try {\n await channel.send(alert);\n } catch (e) {\n this.onError(e, `alert channel ${channel.name}`);\n }\n }\n sent.push(alert);\n }\n state.lastAlertAt = now;\n await this.store.setState(state);\n return sent;\n }\n}\n\nfunction withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const t = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms);\n promise.then((v) => { clearTimeout(t); resolve(v); }, (e) => { clearTimeout(t); reject(e); });\n });\n}\n\n/** Writes alerts to the console. The default channel. */\nexport function consoleChannel(): AlertChannel {\n return {\n name: \"console\",\n async send(alert) {\n const line = `[cronwatch] ${alert.title}\\n${alert.message}${alert.triage ? `\\nTriage: ${alert.triage}` : \"\"}`;\n if (alert.type === \"recovered\") console.info(line);\n else console.error(line);\n },\n };\n}\n\n/** Wrap any function as an alert channel. */\nexport function custom(name: string, send: (alert: Alert) => Promise<void> | void): AlertChannel {\n return { name, send: async (alert) => { await send(alert); } };\n}\n\nexport type { Condition };\n","import { CronWatch } from \"./client.js\";\nimport type { CronWatchOptions } from \"./client.js\";\n\n/**\n * Create a CronWatch client. One per app, at module level:\n *\n * export const cw = cronwatch({ store: sqlite({ path: \"./data/cronwatch.db\" }), alerts: [slack({ webhookUrl })] });\n * export const nightly = cw.job(\"nightly-report\", { schedule: \"0 2 * * *\", grace: \"15m\" });\n */\nexport function cronwatch(options: CronWatchOptions = {}): CronWatch {\n return new CronWatch(options);\n}\n\nexport { CronWatch, consoleChannel, custom } from \"./client.js\";\nexport { json } from \"./http.js\";\nexport type { CronWatchOptions, HandlerFn, HandlerOptions, JobFn, JobHandle } from \"./client.js\";\nexport type { JobContext } from \"./job.js\";\nexport { memory } from \"./stores/memory.js\";\nexport { createRoutes } from \"./routes/index.js\";\nexport type { RoutesOptions, Routes } from \"./routes/index.js\";\nexport { parseDuration, formatDuration, formatRelative } from \"./duration.js\";\nexport { parseSchedule, previousFire, nextFire } from \"./schedule.js\";\nexport { composeAlert } from \"./format.js\";\nexport type {\n Alert,\n AlertChannel,\n AlertType,\n CheckResult,\n Condition,\n Duration,\n ExpectRule,\n JobDefinition,\n JobHealth,\n JobOptions,\n JobState,\n JobSummary,\n Run,\n RunStatus,\n Store,\n StoredJob,\n StoredJobDefinition,\n TriageContext,\n TriageFn,\n} from \"./types.js\";\n"]}
@@ -0,0 +1,142 @@
1
+ 'use strict';
2
+
3
+ var pg = require('pg');
4
+
5
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
+
7
+ var pg__default = /*#__PURE__*/_interopDefault(pg);
8
+
9
+ // src/stores/postgres.ts
10
+ var num = (v) => v === null ? null : Number(v);
11
+ function rowToRun(r) {
12
+ return {
13
+ id: r.id,
14
+ job: r.job,
15
+ status: r.status,
16
+ startedAt: Number(r.started_at),
17
+ finishedAt: num(r.finished_at),
18
+ durationMs: num(r.duration_ms),
19
+ error: r.error,
20
+ output: r.output,
21
+ metrics: r.metrics ?? {},
22
+ trigger: r.trigger
23
+ };
24
+ }
25
+ function postgres(options = {}) {
26
+ const owned = !options.pool;
27
+ const pool = options.pool ?? new pg__default.default.Pool({ connectionString: options.connectionString ?? process.env.DATABASE_URL });
28
+ const p = (options.prefix ?? "cronwatch_").replace(/[^a-z0-9_]/gi, "");
29
+ const JOBS = `${p}jobs`, RUNS = `${p}runs`, STATE = `${p}state`;
30
+ return {
31
+ async init() {
32
+ await pool.query(`
33
+ CREATE TABLE IF NOT EXISTS ${JOBS} (
34
+ name TEXT PRIMARY KEY,
35
+ definition JSONB NOT NULL,
36
+ created_at BIGINT NOT NULL,
37
+ updated_at BIGINT NOT NULL
38
+ );
39
+ CREATE TABLE IF NOT EXISTS ${RUNS} (
40
+ seq BIGSERIAL,
41
+ id TEXT PRIMARY KEY,
42
+ job TEXT NOT NULL,
43
+ status TEXT NOT NULL,
44
+ started_at BIGINT NOT NULL,
45
+ finished_at BIGINT,
46
+ duration_ms BIGINT,
47
+ error TEXT,
48
+ output TEXT,
49
+ metrics JSONB NOT NULL DEFAULT '{}'::jsonb,
50
+ trigger TEXT NOT NULL DEFAULT 'run'
51
+ );
52
+ CREATE INDEX IF NOT EXISTS ${RUNS}_job_started ON ${RUNS} (job, started_at DESC);
53
+ CREATE INDEX IF NOT EXISTS ${RUNS}_running ON ${RUNS} (status) WHERE status = 'running';
54
+ CREATE TABLE IF NOT EXISTS ${STATE} (
55
+ job TEXT PRIMARY KEY,
56
+ state JSONB NOT NULL
57
+ );
58
+ `);
59
+ },
60
+ async upsertJob(definition, now) {
61
+ await pool.query(
62
+ `INSERT INTO ${JOBS} (name, definition, created_at, updated_at) VALUES ($1, $2, $3, $3)
63
+ ON CONFLICT (name) DO UPDATE SET definition = EXCLUDED.definition, updated_at = EXCLUDED.updated_at`,
64
+ [definition.name, JSON.stringify(definition), now]
65
+ );
66
+ },
67
+ async getJob(name) {
68
+ const { rows } = await pool.query(`SELECT * FROM ${JOBS} WHERE name = $1`, [name]);
69
+ const r = rows[0];
70
+ return r ? { name: r.name, definition: r.definition, createdAt: Number(r.created_at), updatedAt: Number(r.updated_at) } : null;
71
+ },
72
+ async listJobs() {
73
+ const { rows } = await pool.query(`SELECT * FROM ${JOBS} ORDER BY name`);
74
+ return rows.map((r) => ({ name: r.name, definition: r.definition, createdAt: Number(r.created_at), updatedAt: Number(r.updated_at) }));
75
+ },
76
+ async deleteJob(name) {
77
+ const client = await pool.connect();
78
+ try {
79
+ await client.query("BEGIN");
80
+ await client.query(`DELETE FROM ${RUNS} WHERE job = $1`, [name]);
81
+ await client.query(`DELETE FROM ${STATE} WHERE job = $1`, [name]);
82
+ await client.query(`DELETE FROM ${JOBS} WHERE name = $1`, [name]);
83
+ await client.query("COMMIT");
84
+ } catch (e) {
85
+ await client.query("ROLLBACK");
86
+ throw e;
87
+ } finally {
88
+ client.release();
89
+ }
90
+ },
91
+ async insertRun(run) {
92
+ await pool.query(
93
+ `INSERT INTO ${RUNS} (id, job, status, started_at, finished_at, duration_ms, error, output, metrics, trigger)
94
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,
95
+ [run.id, run.job, run.status, run.startedAt, run.finishedAt, run.durationMs, run.error, run.output, JSON.stringify(run.metrics), run.trigger]
96
+ );
97
+ },
98
+ async updateRun(run) {
99
+ await pool.query(
100
+ `UPDATE ${RUNS} SET status = $1, finished_at = $2, duration_ms = $3, error = $4, output = $5, metrics = $6 WHERE id = $7`,
101
+ [run.status, run.finishedAt, run.durationMs, run.error, run.output, JSON.stringify(run.metrics), run.id]
102
+ );
103
+ },
104
+ async getRun(id) {
105
+ const { rows } = await pool.query(`SELECT * FROM ${RUNS} WHERE id = $1`, [id]);
106
+ return rows[0] ? rowToRun(rows[0]) : null;
107
+ },
108
+ async listRuns(job, limit) {
109
+ const { rows } = await pool.query(`SELECT * FROM ${RUNS} WHERE job = $1 ORDER BY started_at DESC, seq DESC LIMIT $2`, [job, limit]);
110
+ return rows.map(rowToRun);
111
+ },
112
+ async lastRun(job) {
113
+ const { rows } = await pool.query(`SELECT * FROM ${RUNS} WHERE job = $1 ORDER BY started_at DESC, seq DESC LIMIT 1`, [job]);
114
+ return rows[0] ? rowToRun(rows[0]) : null;
115
+ },
116
+ async runningRuns() {
117
+ const { rows } = await pool.query(`SELECT * FROM ${RUNS} WHERE status = 'running' ORDER BY started_at`);
118
+ return rows.map(rowToRun);
119
+ },
120
+ async getState(job) {
121
+ const { rows } = await pool.query(`SELECT state FROM ${STATE} WHERE job = $1`, [job]);
122
+ return rows[0]?.state ?? null;
123
+ },
124
+ async setState(state) {
125
+ await pool.query(
126
+ `INSERT INTO ${STATE} (job, state) VALUES ($1, $2) ON CONFLICT (job) DO UPDATE SET state = EXCLUDED.state`,
127
+ [state.job, JSON.stringify(state)]
128
+ );
129
+ },
130
+ async prune(before) {
131
+ const result = await pool.query(`DELETE FROM ${RUNS} WHERE status <> 'running' AND started_at < $1`, [before]);
132
+ return result.rowCount ?? 0;
133
+ },
134
+ async close() {
135
+ if (owned) await pool.end();
136
+ }
137
+ };
138
+ }
139
+
140
+ exports.postgres = postgres;
141
+ //# sourceMappingURL=postgres.cjs.map
142
+ //# sourceMappingURL=postgres.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stores/postgres.ts"],"names":["pg"],"mappings":"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","file":"postgres.cjs","sourcesContent":["import pg from \"pg\";\nimport type { JobState, Run, Store, StoredJob, StoredJobDefinition } from \"../types.js\";\n\nexport interface PostgresOptions {\n /** postgres://... Defaults to process.env.DATABASE_URL. */\n connectionString?: string;\n /** Bring your own pool instead. It is not closed by close(). */\n pool?: pg.Pool;\n /** Table name prefix. Default \"cronwatch_\". */\n prefix?: string;\n}\n\ninterface JobRow { name: string; definition: StoredJobDefinition; created_at: string | number; updated_at: string | number }\ninterface RunRow {\n id: string; job: string; status: Run[\"status\"]; started_at: string | number; finished_at: string | number | null;\n duration_ms: string | number | null; error: string | null; output: string | null; metrics: Record<string, number>; trigger: string;\n}\n\nconst num = (v: string | number | null): number | null => (v === null ? null : Number(v));\n\nfunction rowToRun(r: RunRow): Run {\n return {\n id: r.id, job: r.job, status: r.status, startedAt: Number(r.started_at), finishedAt: num(r.finished_at),\n durationMs: num(r.duration_ms), error: r.error, output: r.output, metrics: r.metrics ?? {}, trigger: r.trigger,\n };\n}\n\n/**\n * Keeps everything in Postgres through the `pg` driver. For apps on Vercel,\n * Neon, Supabase, Railway and the like, where there is no disk to keep a\n * SQLite file on. Times are stored as BIGINT epoch milliseconds.\n */\nexport function postgres(options: PostgresOptions = {}): Store {\n const owned = !options.pool;\n const pool = options.pool ?? new pg.Pool({ connectionString: options.connectionString ?? process.env.DATABASE_URL });\n const p = (options.prefix ?? \"cronwatch_\").replace(/[^a-z0-9_]/gi, \"\");\n const JOBS = `${p}jobs`, RUNS = `${p}runs`, STATE = `${p}state`;\n\n return {\n async init() {\n await pool.query(`\n CREATE TABLE IF NOT EXISTS ${JOBS} (\n name TEXT PRIMARY KEY,\n definition JSONB NOT NULL,\n created_at BIGINT NOT NULL,\n updated_at BIGINT NOT NULL\n );\n CREATE TABLE IF NOT EXISTS ${RUNS} (\n seq BIGSERIAL,\n id TEXT PRIMARY KEY,\n job TEXT NOT NULL,\n status TEXT NOT NULL,\n started_at BIGINT NOT NULL,\n finished_at BIGINT,\n duration_ms BIGINT,\n error TEXT,\n output TEXT,\n metrics JSONB NOT NULL DEFAULT '{}'::jsonb,\n trigger TEXT NOT NULL DEFAULT 'run'\n );\n CREATE INDEX IF NOT EXISTS ${RUNS}_job_started ON ${RUNS} (job, started_at DESC);\n CREATE INDEX IF NOT EXISTS ${RUNS}_running ON ${RUNS} (status) WHERE status = 'running';\n CREATE TABLE IF NOT EXISTS ${STATE} (\n job TEXT PRIMARY KEY,\n state JSONB NOT NULL\n );\n `);\n },\n async upsertJob(definition, now) {\n await pool.query(\n `INSERT INTO ${JOBS} (name, definition, created_at, updated_at) VALUES ($1, $2, $3, $3)\n ON CONFLICT (name) DO UPDATE SET definition = EXCLUDED.definition, updated_at = EXCLUDED.updated_at`,\n [definition.name, JSON.stringify(definition), now],\n );\n },\n async getJob(name) {\n const { rows } = await pool.query<JobRow>(`SELECT * FROM ${JOBS} WHERE name = $1`, [name]);\n const r = rows[0];\n return r ? { name: r.name, definition: r.definition, createdAt: Number(r.created_at), updatedAt: Number(r.updated_at) } : null;\n },\n async listJobs(): Promise<StoredJob[]> {\n const { rows } = await pool.query<JobRow>(`SELECT * FROM ${JOBS} ORDER BY name`);\n return rows.map((r) => ({ name: r.name, definition: r.definition, createdAt: Number(r.created_at), updatedAt: Number(r.updated_at) }));\n },\n async deleteJob(name) {\n const client = await pool.connect();\n try {\n await client.query(\"BEGIN\");\n await client.query(`DELETE FROM ${RUNS} WHERE job = $1`, [name]);\n await client.query(`DELETE FROM ${STATE} WHERE job = $1`, [name]);\n await client.query(`DELETE FROM ${JOBS} WHERE name = $1`, [name]);\n await client.query(\"COMMIT\");\n } catch (e) {\n await client.query(\"ROLLBACK\");\n throw e;\n } finally {\n client.release();\n }\n },\n async insertRun(run) {\n await pool.query(\n `INSERT INTO ${RUNS} (id, job, status, started_at, finished_at, duration_ms, error, output, metrics, trigger)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)`,\n [run.id, run.job, run.status, run.startedAt, run.finishedAt, run.durationMs, run.error, run.output, JSON.stringify(run.metrics), run.trigger],\n );\n },\n async updateRun(run) {\n await pool.query(\n `UPDATE ${RUNS} SET status = $1, finished_at = $2, duration_ms = $3, error = $4, output = $5, metrics = $6 WHERE id = $7`,\n [run.status, run.finishedAt, run.durationMs, run.error, run.output, JSON.stringify(run.metrics), run.id],\n );\n },\n async getRun(id) {\n const { rows } = await pool.query<RunRow>(`SELECT * FROM ${RUNS} WHERE id = $1`, [id]);\n return rows[0] ? rowToRun(rows[0]) : null;\n },\n async listRuns(job, limit) {\n const { rows } = await pool.query<RunRow>(`SELECT * FROM ${RUNS} WHERE job = $1 ORDER BY started_at DESC, seq DESC LIMIT $2`, [job, limit]);\n return rows.map(rowToRun);\n },\n async lastRun(job) {\n const { rows } = await pool.query<RunRow>(`SELECT * FROM ${RUNS} WHERE job = $1 ORDER BY started_at DESC, seq DESC LIMIT 1`, [job]);\n return rows[0] ? rowToRun(rows[0]) : null;\n },\n async runningRuns() {\n const { rows } = await pool.query<RunRow>(`SELECT * FROM ${RUNS} WHERE status = 'running' ORDER BY started_at`);\n return rows.map(rowToRun);\n },\n async getState(job) {\n const { rows } = await pool.query<{ state: JobState }>(`SELECT state FROM ${STATE} WHERE job = $1`, [job]);\n return rows[0]?.state ?? null;\n },\n async setState(state) {\n await pool.query(\n `INSERT INTO ${STATE} (job, state) VALUES ($1, $2) ON CONFLICT (job) DO UPDATE SET state = EXCLUDED.state`,\n [state.job, JSON.stringify(state)],\n );\n },\n async prune(before) {\n const result = await pool.query(`DELETE FROM ${RUNS} WHERE status <> 'running' AND started_at < $1`, [before]);\n return result.rowCount ?? 0;\n },\n async close() {\n if (owned) await pool.end();\n },\n };\n}\n"]}
@@ -0,0 +1,19 @@
1
+ import pg from 'pg';
2
+ import { S as Store } from './types-BQ1P8z55.cjs';
3
+
4
+ interface PostgresOptions {
5
+ /** postgres://... Defaults to process.env.DATABASE_URL. */
6
+ connectionString?: string;
7
+ /** Bring your own pool instead. It is not closed by close(). */
8
+ pool?: pg.Pool;
9
+ /** Table name prefix. Default "cronwatch_". */
10
+ prefix?: string;
11
+ }
12
+ /**
13
+ * Keeps everything in Postgres through the `pg` driver. For apps on Vercel,
14
+ * Neon, Supabase, Railway and the like, where there is no disk to keep a
15
+ * SQLite file on. Times are stored as BIGINT epoch milliseconds.
16
+ */
17
+ declare function postgres(options?: PostgresOptions): Store;
18
+
19
+ export { type PostgresOptions, postgres };
@@ -0,0 +1,19 @@
1
+ import pg from 'pg';
2
+ import { S as Store } from './types-BQ1P8z55.js';
3
+
4
+ interface PostgresOptions {
5
+ /** postgres://... Defaults to process.env.DATABASE_URL. */
6
+ connectionString?: string;
7
+ /** Bring your own pool instead. It is not closed by close(). */
8
+ pool?: pg.Pool;
9
+ /** Table name prefix. Default "cronwatch_". */
10
+ prefix?: string;
11
+ }
12
+ /**
13
+ * Keeps everything in Postgres through the `pg` driver. For apps on Vercel,
14
+ * Neon, Supabase, Railway and the like, where there is no disk to keep a
15
+ * SQLite file on. Times are stored as BIGINT epoch milliseconds.
16
+ */
17
+ declare function postgres(options?: PostgresOptions): Store;
18
+
19
+ export { type PostgresOptions, postgres };