@secondlayer/sdk 16.2.1 → 16.3.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.
@@ -60,9 +60,9 @@ declare function buildDoctorReport(input: {
60
60
  * The list page's own reduced detector: computed from `WebhookSummary` alone
61
61
  * (no deliveries, no dead-letter rows — the list endpoint returns neither,
62
62
  * and fetching per-row detail or deliveries here would fan out one request
63
- * per row). Only `status` and `circuitOpenedAt` distinguish a real problem
63
+ * per row). Only `status` and `pauseReason` distinguish a real problem
64
64
  * from a manual pause at this level; deliveries-based rules (rate limits,
65
65
  * downtime, rejects, slowness, lag) only ever show on the detail page.
66
66
  */
67
- declare function buildListIssue(webhook: Pick<WebhookSummary, "status" | "circuitOpenedAt" | "lastSuccessAt">): DoctorIssue | null;
67
+ declare function buildListIssue(webhook: Pick<WebhookSummary, "status" | "pauseReason" | "circuitOpenedAt" | "lastSuccessAt">): DoctorIssue | null;
68
68
  export { DOWN_MIN_CONSECUTIVE, DoctorEvidence, DoctorFix, DoctorIssue, DoctorIssueCode, DoctorReport, DoctorSeverity, buildDoctorReport, buildListIssue, isSuccessDelivery };
@@ -11,6 +11,7 @@ import {
11
11
  SLOW_TIMEOUT_RATIO,
12
12
  SLOW_WINDOW
13
13
  } from "@secondlayer/shared/insights/thresholds";
14
+ import { pauseReasonOf } from "@secondlayer/shared/webhooks/health";
14
15
  function isSuccessDelivery(row) {
15
16
  return row.statusCode !== null && row.statusCode >= 200 && row.statusCode < 300;
16
17
  }
@@ -297,16 +298,17 @@ function buildDoctorReport(input) {
297
298
  };
298
299
  }
299
300
  function buildListIssue(webhook) {
300
- if (webhook.status !== "paused")
301
+ const reason = pauseReasonOf(webhook);
302
+ if (reason === null)
301
303
  return null;
302
- if (webhook.circuitOpenedAt) {
304
+ if (reason === "circuit") {
303
305
  return {
304
306
  code: "circuit",
305
307
  severity: "bad",
306
308
  evidence: [
307
309
  {
308
310
  label: "circuit opened",
309
- value: formatShortDate(webhook.circuitOpenedAt)
311
+ value: webhook.circuitOpenedAt ? formatShortDate(webhook.circuitOpenedAt) : "unknown"
310
312
  },
311
313
  {
312
314
  label: "last success",
@@ -328,5 +330,5 @@ export {
328
330
  isSuccessDelivery
329
331
  };
330
332
 
331
- //# debugId=44661C072105706964756E2164756E21
333
+ //# debugId=DAB3EDEBA7F6064164756E2164756E21
332
334
  //# sourceMappingURL=doctor.js.map
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["src/webhooks/doctor.ts"],
4
4
  "sourcesContent": [
5
- "import {\n\tDOWN_MIN_CONSECUTIVE,\n\tLAG_MIN_SAMPLES,\n\tLAG_THRESHOLD_MS,\n\tLAG_WINDOW,\n\tRATE_LIMITED_MIN_ATTEMPTS,\n\tRATE_LIMITED_MIN_RATIO,\n\tREJECTS_MIN_CONSECUTIVE,\n\tSLOW_MIN_SAMPLES,\n\tSLOW_TIMEOUT_RATIO,\n\tSLOW_WINDOW,\n} from \"@secondlayer/shared/insights/thresholds\";\nimport type {\n\tDeadRow,\n\tDeliveryRow,\n\tWebhookDetail,\n\tWebhookSummary,\n} from \"@secondlayer/shared/schemas/webhooks\";\n\n/**\n * Webhook diagnosis, shared by `secondlayer webhooks doctor` and the\n * dashboard's webhook detail page. Moved out of the CLI (unchanged behavior)\n * so the web can build the same judgment without printing CLI-command text.\n *\n * Five deterministic, numbers-only detectors sit on top of the\n * existing flag checks: no model, no history beyond the deliveries window\n * already fetched. Thresholds are named constants below, conservative on\n * purpose — a wrong insight costs more trust than a missed one.\n */\n\nexport function isSuccessDelivery(row: DeliveryRow): boolean {\n\treturn (\n\t\trow.statusCode !== null && row.statusCode >= 200 && row.statusCode < 300\n\t);\n}\n\nexport type DoctorSeverity = \"bad\" | \"warn\" | \"calm\";\n\nexport interface DoctorEvidence {\n\tlabel: string;\n\tvalue: string;\n}\n\nexport interface DoctorFix {\n\ttext: string;\n\t/** A `secondlayer webhooks ...` command the reader can copy. */\n\tcommand?: string;\n\t/** Anchor into the docs' webhooks troubleshooting section. */\n\tdocsPath?: string;\n}\n\nexport type DoctorIssueCode =\n\t| \"warning\"\n\t| \"paused\"\n\t| \"last_error\"\n\t| \"circuit\"\n\t| \"dead_letters\"\n\t| \"no_deliveries\"\n\t| \"receiver_rate_limited\"\n\t| \"receiver_down\"\n\t| \"receiver_rejects\"\n\t| \"receiver_slow\"\n\t| \"delivery_lag\";\n\nexport interface DoctorIssue {\n\tcode: DoctorIssueCode;\n\tdetail?: string;\n\tseverity: DoctorSeverity;\n\t/** 2-4 numbers-only facts backing the issue. Only the five new detectors\n\t * and the list-summary circuit issue carry this — the older flag checks\n\t * keep their plain `detail` string. */\n\tevidence?: DoctorEvidence[];\n\tfix?: DoctorFix;\n}\n\nexport interface DoctorReport {\n\twebhook: WebhookDetail;\n\tdeliverySummary: {\n\t\ttotal: number;\n\t\tsuccessful: number;\n\t\tfailed: number;\n\t\tlast: DeliveryRow | null;\n\t};\n\tdeadCount: number;\n\t/** CLI-facing next steps, one per issue, in the same order as `issues`. */\n\thints: string[];\n\tissues: DoctorIssue[];\n\t/** The single most severe issue (bad > warn > calm, then rule priority),\n\t * or `null` when there are none. The UI leads with this and collapses\n\t * the rest underneath. */\n\tprimary: DoctorIssue | null;\n}\n\n// ── Detector thresholds ─────────────────────────────────────────────\n// Named constants, not config. Tune from real data; until then these stay\n// conservative.\n\n// Thresholds live in shared so the server-side insight rules use the same\n// numbers. `DOWN_MIN_CONSECUTIVE` is re-exported: the status pill's\n// \"auto-failing\" rule reuses it instead of duplicating the number.\nexport { DOWN_MIN_CONSECUTIVE };\nconst ERROR_SNIPPET_MAX = 200;\n\nfunction median(values: number[]): number {\n\tif (values.length === 0) return 0;\n\tconst sorted = [...values].sort((a, b) => a - b);\n\treturn sorted[Math.floor(sorted.length / 2)] ?? 0;\n}\n\nfunction percentile(values: number[], p: number): number {\n\tif (values.length === 0) return 0;\n\tconst sorted = [...values].sort((a, b) => a - b);\n\tconst idx = Math.min(sorted.length - 1, Math.floor(p * sorted.length));\n\treturn sorted[idx] ?? 0;\n}\n\nfunction formatMs(ms: number): string {\n\treturn ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${Math.round(ms)}ms`;\n}\n\n/** \"2026-04-23 00:00 UTC\" — date, hour:minute, and an explicit zone so an\n * evidence value never reads as local time. */\nfunction formatShortDate(iso: string): string {\n\treturn `${iso.slice(0, 10)} ${iso.slice(11, 16)} UTC`;\n}\n\n/** The longest run from the start of `rows` (newest-first) matching\n * `predicate` — the current losing (or rejecting) streak. */\nfunction consecutiveFromStart(\n\trows: DeliveryRow[],\n\tpredicate: (row: DeliveryRow) => boolean,\n): DeliveryRow[] {\n\tconst out: DeliveryRow[] = [];\n\tfor (const row of rows) {\n\t\tif (!predicate(row)) break;\n\t\tout.push(row);\n\t}\n\treturn out;\n}\n\nfunction summarizeStatusBreakdown(rows: DeliveryRow[]): string {\n\tconst counts = new Map<string, number>();\n\tfor (const row of rows) {\n\t\tconst key =\n\t\t\trow.statusCode === null ? \"timeout/no response\" : String(row.statusCode);\n\t\tcounts.set(key, (counts.get(key) ?? 0) + 1);\n\t}\n\treturn [...counts.entries()].map(([key, n]) => `${n}× ${key}`).join(\", \");\n}\n\nconst RETRY_AFTER_RE = /retry-after:?\\s*(\\d+)/i;\n\n/** The most recent 429's `Retry-After`, if the receiver's error text carried\n * one — we never invent a value the rows didn't report. */\nfunction extractRetryAfterSeconds(rows: DeliveryRow[]): string | null {\n\tfor (const row of rows) {\n\t\tif (row.statusCode !== 429 || !row.errorMessage) continue;\n\t\tconst match = row.errorMessage.match(RETRY_AFTER_RE);\n\t\tif (match?.[1]) return match[1];\n\t}\n\treturn null;\n}\n\n/** ≥10 attempts in the window, ≥50% of them 429 — the receiver is\n * rate-limiting us, not failing. */\nfunction detectReceiverRateLimited(\n\twebhook: WebhookDetail,\n\tdeliveries: DeliveryRow[],\n): DoctorIssue | null {\n\tif (deliveries.length < RATE_LIMITED_MIN_ATTEMPTS) return null;\n\tconst count429 = deliveries.filter((d) => d.statusCode === 429).length;\n\tif (count429 / deliveries.length < RATE_LIMITED_MIN_RATIO) return null;\n\n\tconst oldest = deliveries[deliveries.length - 1];\n\tconst newest = deliveries[0];\n\tconst evidence: DoctorEvidence[] = [\n\t\t{\n\t\t\tlabel: \"429 responses\",\n\t\t\tvalue: `${count429} of ${deliveries.length} attempts`,\n\t\t},\n\t\t{\n\t\t\tlabel: \"window\",\n\t\t\tvalue:\n\t\t\t\toldest && newest\n\t\t\t\t\t? `${formatShortDate(oldest.dispatchedAt)} → ${formatShortDate(newest.dispatchedAt)}`\n\t\t\t\t\t: \"unknown\",\n\t\t},\n\t];\n\tconst retryAfter = extractRetryAfterSeconds(deliveries);\n\tif (retryAfter) {\n\t\tevidence.push({ label: \"latest Retry-After\", value: `${retryAfter}s` });\n\t}\n\n\tconst suggestedConcurrency = Math.max(1, Math.floor(webhook.concurrency / 2));\n\treturn {\n\t\tcode: \"receiver_rate_limited\",\n\t\tseverity: \"warn\",\n\t\tevidence,\n\t\tfix: {\n\t\t\ttext: \"Lower concurrency, or honor the Retry-After header on your receiver.\",\n\t\t\tcommand: `secondlayer webhooks update ${webhook.id} --concurrency ${suggestedConcurrency}`,\n\t\t\tdocsPath: \"/docs/webhooks#receiver-rate-limited\",\n\t\t},\n\t};\n}\n\n/** ≥5 most recent attempts are 5xx or got no response at all (timeout /\n * connection failure) — the receiver looks down, not just slow. */\nfunction detectReceiverDown(\n\twebhook: WebhookDetail,\n\tdeliveries: DeliveryRow[],\n): DoctorIssue | null {\n\tconst streak = consecutiveFromStart(\n\t\tdeliveries,\n\t\t(d) => d.statusCode === null || d.statusCode >= 500,\n\t);\n\tif (streak.length < DOWN_MIN_CONSECUTIVE) return null;\n\n\treturn {\n\t\tcode: \"receiver_down\",\n\t\tseverity: \"bad\",\n\t\tevidence: [\n\t\t\t{ label: \"consecutive failures\", value: String(streak.length) },\n\t\t\t{ label: \"breakdown\", value: summarizeStatusBreakdown(streak) },\n\t\t\t{\n\t\t\t\tlabel: \"last success\",\n\t\t\t\tvalue: webhook.lastSuccessAt\n\t\t\t\t\t? formatShortDate(webhook.lastSuccessAt)\n\t\t\t\t\t: \"never\",\n\t\t\t},\n\t\t],\n\t\tfix: {\n\t\t\ttext: \"Check your receiver's health and logs, then send a test event.\",\n\t\t\tcommand: `secondlayer webhooks test ${webhook.id}`,\n\t\t\tdocsPath: \"/docs/webhooks#receiver-down\",\n\t\t},\n\t};\n}\n\n/** ≥5 most recent attempts are 4xx other than 429 — the receiver is\n * reachable but actively rejecting us (auth, signature, bad request). */\nfunction detectReceiverRejects(\n\twebhook: WebhookDetail,\n\tdeliveries: DeliveryRow[],\n): DoctorIssue | null {\n\tconst streak = consecutiveFromStart(\n\t\tdeliveries,\n\t\t(d) =>\n\t\t\td.statusCode !== null &&\n\t\t\td.statusCode >= 400 &&\n\t\t\td.statusCode < 500 &&\n\t\t\td.statusCode !== 429,\n\t);\n\tif (streak.length < REJECTS_MIN_CONSECUTIVE) return null;\n\n\tconst evidence: DoctorEvidence[] = [\n\t\t{ label: \"consecutive rejects\", value: String(streak.length) },\n\t\t{ label: \"breakdown\", value: summarizeStatusBreakdown(streak) },\n\t];\n\tconst withText = streak.find((d) => d.errorMessage || d.responseBody);\n\tconst snippet = withText\n\t\t? (withText.errorMessage ?? withText.responseBody ?? \"\").slice(\n\t\t\t\t0,\n\t\t\t\tERROR_SNIPPET_MAX,\n\t\t\t)\n\t\t: null;\n\tif (snippet) evidence.push({ label: \"first error\", value: snippet });\n\n\treturn {\n\t\tcode: \"receiver_rejects\",\n\t\tseverity: \"bad\",\n\t\tevidence,\n\t\tfix: {\n\t\t\ttext: \"Check your receiver's auth config or signature verification.\",\n\t\t\tcommand: `secondlayer webhooks test ${webhook.id}`,\n\t\t\tdocsPath: \"/docs/webhooks#receiver-rejects\",\n\t\t},\n\t};\n}\n\n/** Median response time of the newest 20 attempts is at least half the\n * webhook's timeout — deliveries are slow, not failing. */\nfunction detectReceiverSlow(\n\twebhook: WebhookDetail,\n\tdeliveries: DeliveryRow[],\n): DoctorIssue | null {\n\tconst durations = deliveries\n\t\t.slice(0, SLOW_WINDOW)\n\t\t.map((d) => d.durationMs)\n\t\t.filter((d): d is number => d !== null);\n\tif (durations.length < SLOW_MIN_SAMPLES) return null;\n\n\tconst med = median(durations);\n\tif (med < webhook.timeoutMs * SLOW_TIMEOUT_RATIO) return null;\n\n\treturn {\n\t\tcode: \"receiver_slow\",\n\t\tseverity: \"warn\",\n\t\tevidence: [\n\t\t\t{ label: \"median response time\", value: formatMs(med) },\n\t\t\t{\n\t\t\t\tlabel: \"p95 response time\",\n\t\t\t\tvalue: formatMs(percentile(durations, 0.95)),\n\t\t\t},\n\t\t\t{ label: \"timeout\", value: formatMs(webhook.timeoutMs) },\n\t\t],\n\t\tfix: {\n\t\t\ttext: \"Speed up your receiver, or raise the timeout (up to 30s hosted).\",\n\t\t\tcommand: `secondlayer webhooks update ${webhook.id} --timeout-ms 30000`,\n\t\t\tdocsPath: \"/docs/webhooks#receiver-slow\",\n\t\t},\n\t};\n}\n\n/** Median (dispatch time − block time) of the newest 20 attempts with a\n * known block time exceeds a minute — we're behind on delivery. This is\n * our-side latency, not something the receiver can fix, so it carries no\n * actionable command. */\nfunction detectDeliveryLag(deliveries: DeliveryRow[]): DoctorIssue | null {\n\tconst window = deliveries\n\t\t.slice(0, LAG_WINDOW)\n\t\t.filter(\n\t\t\t(d): d is DeliveryRow & { blockTime: string } => d.blockTime !== null,\n\t\t);\n\tif (window.length < LAG_MIN_SAMPLES) return null;\n\n\tconst lags = window.map(\n\t\t(d) => new Date(d.dispatchedAt).getTime() - new Date(d.blockTime).getTime(),\n\t);\n\tconst med = median(lags);\n\tif (med <= LAG_THRESHOLD_MS) return null;\n\n\tconst blockTimes = window.map((d) => d.blockTime).sort();\n\tconst oldest = blockTimes[0];\n\tconst newest = blockTimes[blockTimes.length - 1];\n\n\treturn {\n\t\tcode: \"delivery_lag\",\n\t\tseverity: \"warn\",\n\t\tevidence: [\n\t\t\t{ label: \"median lag\", value: formatMs(med) },\n\t\t\t{\n\t\t\t\tlabel: \"block time range\",\n\t\t\t\tvalue:\n\t\t\t\t\toldest && newest\n\t\t\t\t\t\t? `${formatShortDate(oldest)} → ${formatShortDate(newest)}`\n\t\t\t\t\t\t: \"unknown\",\n\t\t\t},\n\t\t],\n\t\tfix: {\n\t\t\ttext: \"We're behind on delivery; no action needed on your end.\",\n\t\t},\n\t};\n}\n\nconst SEVERITY_RANK: Record<DoctorSeverity, number> = {\n\tbad: 0,\n\twarn: 1,\n\tcalm: 2,\n};\n\n/** Tie-break within a severity tier when more than one issue fires at\n * once — most specific / most actionable first. */\nconst CODE_PRIORITY: DoctorIssueCode[] = [\n\t\"circuit\",\n\t\"receiver_down\",\n\t\"receiver_rejects\",\n\t\"dead_letters\",\n\t\"paused\",\n\t\"last_error\",\n\t\"warning\",\n\t\"receiver_rate_limited\",\n\t\"receiver_slow\",\n\t\"delivery_lag\",\n\t\"no_deliveries\",\n];\n\nfunction pickPrimary(issues: DoctorIssue[]): DoctorIssue | null {\n\tif (issues.length === 0) return null;\n\treturn (\n\t\t[...issues].sort((a, b) => {\n\t\t\tconst sevDiff = SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity];\n\t\t\tif (sevDiff !== 0) return sevDiff;\n\t\t\treturn CODE_PRIORITY.indexOf(a.code) - CODE_PRIORITY.indexOf(b.code);\n\t\t})[0] ?? null\n\t);\n}\n\nfunction hintFor(issue: DoctorIssue): string {\n\tif (!issue.fix) return issue.detail ?? issue.code;\n\treturn issue.fix.command\n\t\t? `${issue.fix.text} ${issue.fix.command}`\n\t\t: issue.fix.text;\n}\n\nexport function buildDoctorReport(input: {\n\twebhook: WebhookDetail;\n\tdeliveries: DeliveryRow[];\n\tdead: DeadRow[];\n}): DoctorReport {\n\tconst successful = input.deliveries.filter(isSuccessDelivery).length;\n\tconst failed = input.deliveries.length - successful;\n\n\tconst hints: string[] = [];\n\tconst issues: DoctorIssue[] = [];\n\tif (input.webhook.warning) {\n\t\thints.push(input.webhook.warning);\n\t\tissues.push({\n\t\t\tcode: \"warning\",\n\t\t\tdetail: input.webhook.warning,\n\t\t\tseverity: \"warn\",\n\t\t});\n\t}\n\tif (input.webhook.status === \"paused\") {\n\t\thints.push(\n\t\t\t`Resume when the receiver is healthy: secondlayer webhooks resume ${input.webhook.id}`,\n\t\t);\n\t\tissues.push({ code: \"paused\", severity: \"warn\" });\n\t}\n\tif (input.webhook.lastError) {\n\t\thints.push(\n\t\t\t\"Run secondlayer webhooks test to reproduce the receiver request.\",\n\t\t);\n\t\tissues.push({\n\t\t\tcode: \"last_error\",\n\t\t\tdetail: input.webhook.lastError,\n\t\t\tseverity: \"warn\",\n\t\t});\n\t}\n\tif (input.webhook.circuitOpenedAt || input.webhook.circuitFailures > 0) {\n\t\thints.push(\n\t\t\t\"Circuit breaker has failures; inspect receiver logs and delivery status codes.\",\n\t\t);\n\t\tissues.push({ code: \"circuit\", severity: \"bad\" });\n\t}\n\tif (input.dead.length > 0) {\n\t\thints.push(\n\t\t\t`Dead-letter rows exist; inspect with secondlayer webhooks dead ${input.webhook.id} and requeue selected rows.`,\n\t\t);\n\t\tissues.push({ code: \"dead_letters\", severity: \"bad\" });\n\t}\n\n\tfor (const detector of [\n\t\tdetectReceiverRateLimited,\n\t\tdetectReceiverDown,\n\t\tdetectReceiverRejects,\n\t\tdetectReceiverSlow,\n\t]) {\n\t\tconst issue = detector(input.webhook, input.deliveries);\n\t\tif (issue) {\n\t\t\tissues.push(issue);\n\t\t\thints.push(hintFor(issue));\n\t\t}\n\t}\n\tconst lagIssue = detectDeliveryLag(input.deliveries);\n\tif (lagIssue) {\n\t\tissues.push(lagIssue);\n\t\thints.push(hintFor(lagIssue));\n\t}\n\n\tif (input.deliveries.length === 0) {\n\t\thints.push(\n\t\t\t\"No deliveries yet; confirm a chain event matching one of the triggers has happened since the webhook was created.\",\n\t\t);\n\t\tissues.push({ code: \"no_deliveries\", severity: \"calm\" });\n\t}\n\tif (hints.length === 0) {\n\t\thints.push(\"No immediate action needed.\");\n\t}\n\n\treturn {\n\t\twebhook: input.webhook,\n\t\tdeliverySummary: {\n\t\t\ttotal: input.deliveries.length,\n\t\t\tsuccessful,\n\t\t\tfailed,\n\t\t\tlast: input.deliveries[0] ?? null,\n\t\t},\n\t\tdeadCount: input.dead.length,\n\t\thints,\n\t\tissues,\n\t\tprimary: pickPrimary(issues),\n\t};\n}\n\n/**\n * The list page's own reduced detector: computed from `WebhookSummary` alone\n * (no deliveries, no dead-letter rows — the list endpoint returns neither,\n * and fetching per-row detail or deliveries here would fan out one request\n * per row). Only `status` and `circuitOpenedAt` distinguish a real problem\n * from a manual pause at this level; deliveries-based rules (rate limits,\n * downtime, rejects, slowness, lag) only ever show on the detail page.\n */\nexport function buildListIssue(\n\twebhook: Pick<WebhookSummary, \"status\" | \"circuitOpenedAt\" | \"lastSuccessAt\">,\n): DoctorIssue | null {\n\tif (webhook.status !== \"paused\") return null;\n\tif (webhook.circuitOpenedAt) {\n\t\treturn {\n\t\t\tcode: \"circuit\",\n\t\t\tseverity: \"bad\",\n\t\t\tevidence: [\n\t\t\t\t{\n\t\t\t\t\tlabel: \"circuit opened\",\n\t\t\t\t\tvalue: formatShortDate(webhook.circuitOpenedAt),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"last success\",\n\t\t\t\t\tvalue: webhook.lastSuccessAt\n\t\t\t\t\t\t? formatShortDate(webhook.lastSuccessAt)\n\t\t\t\t\t\t: \"never\",\n\t\t\t\t},\n\t\t\t],\n\t\t\tfix: {\n\t\t\t\ttext: \"Check your receiver's health and logs, then send a test event.\",\n\t\t\t\tdocsPath: \"/docs/webhooks#receiver-down\",\n\t\t\t},\n\t\t};\n\t}\n\treturn { code: \"paused\", severity: \"warn\" };\n}\n"
5
+ "import {\n\tDOWN_MIN_CONSECUTIVE,\n\tLAG_MIN_SAMPLES,\n\tLAG_THRESHOLD_MS,\n\tLAG_WINDOW,\n\tRATE_LIMITED_MIN_ATTEMPTS,\n\tRATE_LIMITED_MIN_RATIO,\n\tREJECTS_MIN_CONSECUTIVE,\n\tSLOW_MIN_SAMPLES,\n\tSLOW_TIMEOUT_RATIO,\n\tSLOW_WINDOW,\n} from \"@secondlayer/shared/insights/thresholds\";\nimport type {\n\tDeadRow,\n\tDeliveryRow,\n\tWebhookDetail,\n\tWebhookSummary,\n} from \"@secondlayer/shared/schemas/webhooks\";\nimport { pauseReasonOf } from \"@secondlayer/shared/webhooks/health\";\n\n/**\n * Webhook diagnosis, shared by `secondlayer webhooks doctor` and the\n * dashboard's webhook detail page. Moved out of the CLI (unchanged behavior)\n * so the web can build the same judgment without printing CLI-command text.\n *\n * Five deterministic, numbers-only detectors sit on top of the\n * existing flag checks: no model, no history beyond the deliveries window\n * already fetched. Thresholds are named constants below, conservative on\n * purpose — a wrong insight costs more trust than a missed one.\n */\n\nexport function isSuccessDelivery(row: DeliveryRow): boolean {\n\treturn (\n\t\trow.statusCode !== null && row.statusCode >= 200 && row.statusCode < 300\n\t);\n}\n\nexport type DoctorSeverity = \"bad\" | \"warn\" | \"calm\";\n\nexport interface DoctorEvidence {\n\tlabel: string;\n\tvalue: string;\n}\n\nexport interface DoctorFix {\n\ttext: string;\n\t/** A `secondlayer webhooks ...` command the reader can copy. */\n\tcommand?: string;\n\t/** Anchor into the docs' webhooks troubleshooting section. */\n\tdocsPath?: string;\n}\n\nexport type DoctorIssueCode =\n\t| \"warning\"\n\t| \"paused\"\n\t| \"last_error\"\n\t| \"circuit\"\n\t| \"dead_letters\"\n\t| \"no_deliveries\"\n\t| \"receiver_rate_limited\"\n\t| \"receiver_down\"\n\t| \"receiver_rejects\"\n\t| \"receiver_slow\"\n\t| \"delivery_lag\";\n\nexport interface DoctorIssue {\n\tcode: DoctorIssueCode;\n\tdetail?: string;\n\tseverity: DoctorSeverity;\n\t/** 2-4 numbers-only facts backing the issue. Only the five new detectors\n\t * and the list-summary circuit issue carry this — the older flag checks\n\t * keep their plain `detail` string. */\n\tevidence?: DoctorEvidence[];\n\tfix?: DoctorFix;\n}\n\nexport interface DoctorReport {\n\twebhook: WebhookDetail;\n\tdeliverySummary: {\n\t\ttotal: number;\n\t\tsuccessful: number;\n\t\tfailed: number;\n\t\tlast: DeliveryRow | null;\n\t};\n\tdeadCount: number;\n\t/** CLI-facing next steps, one per issue, in the same order as `issues`. */\n\thints: string[];\n\tissues: DoctorIssue[];\n\t/** The single most severe issue (bad > warn > calm, then rule priority),\n\t * or `null` when there are none. The UI leads with this and collapses\n\t * the rest underneath. */\n\tprimary: DoctorIssue | null;\n}\n\n// ── Detector thresholds ─────────────────────────────────────────────\n// Named constants, not config. Tune from real data; until then these stay\n// conservative.\n\n// Thresholds live in shared so the server-side insight rules use the same\n// numbers. `DOWN_MIN_CONSECUTIVE` is re-exported: the status pill's\n// \"auto-failing\" rule reuses it instead of duplicating the number.\nexport { DOWN_MIN_CONSECUTIVE };\nconst ERROR_SNIPPET_MAX = 200;\n\nfunction median(values: number[]): number {\n\tif (values.length === 0) return 0;\n\tconst sorted = [...values].sort((a, b) => a - b);\n\treturn sorted[Math.floor(sorted.length / 2)] ?? 0;\n}\n\nfunction percentile(values: number[], p: number): number {\n\tif (values.length === 0) return 0;\n\tconst sorted = [...values].sort((a, b) => a - b);\n\tconst idx = Math.min(sorted.length - 1, Math.floor(p * sorted.length));\n\treturn sorted[idx] ?? 0;\n}\n\nfunction formatMs(ms: number): string {\n\treturn ms >= 1000 ? `${(ms / 1000).toFixed(1)}s` : `${Math.round(ms)}ms`;\n}\n\n/** \"2026-04-23 00:00 UTC\" — date, hour:minute, and an explicit zone so an\n * evidence value never reads as local time. */\nfunction formatShortDate(iso: string): string {\n\treturn `${iso.slice(0, 10)} ${iso.slice(11, 16)} UTC`;\n}\n\n/** The longest run from the start of `rows` (newest-first) matching\n * `predicate` — the current losing (or rejecting) streak. */\nfunction consecutiveFromStart(\n\trows: DeliveryRow[],\n\tpredicate: (row: DeliveryRow) => boolean,\n): DeliveryRow[] {\n\tconst out: DeliveryRow[] = [];\n\tfor (const row of rows) {\n\t\tif (!predicate(row)) break;\n\t\tout.push(row);\n\t}\n\treturn out;\n}\n\nfunction summarizeStatusBreakdown(rows: DeliveryRow[]): string {\n\tconst counts = new Map<string, number>();\n\tfor (const row of rows) {\n\t\tconst key =\n\t\t\trow.statusCode === null ? \"timeout/no response\" : String(row.statusCode);\n\t\tcounts.set(key, (counts.get(key) ?? 0) + 1);\n\t}\n\treturn [...counts.entries()].map(([key, n]) => `${n}× ${key}`).join(\", \");\n}\n\nconst RETRY_AFTER_RE = /retry-after:?\\s*(\\d+)/i;\n\n/** The most recent 429's `Retry-After`, if the receiver's error text carried\n * one — we never invent a value the rows didn't report. */\nfunction extractRetryAfterSeconds(rows: DeliveryRow[]): string | null {\n\tfor (const row of rows) {\n\t\tif (row.statusCode !== 429 || !row.errorMessage) continue;\n\t\tconst match = row.errorMessage.match(RETRY_AFTER_RE);\n\t\tif (match?.[1]) return match[1];\n\t}\n\treturn null;\n}\n\n/** ≥10 attempts in the window, ≥50% of them 429 — the receiver is\n * rate-limiting us, not failing. */\nfunction detectReceiverRateLimited(\n\twebhook: WebhookDetail,\n\tdeliveries: DeliveryRow[],\n): DoctorIssue | null {\n\tif (deliveries.length < RATE_LIMITED_MIN_ATTEMPTS) return null;\n\tconst count429 = deliveries.filter((d) => d.statusCode === 429).length;\n\tif (count429 / deliveries.length < RATE_LIMITED_MIN_RATIO) return null;\n\n\tconst oldest = deliveries[deliveries.length - 1];\n\tconst newest = deliveries[0];\n\tconst evidence: DoctorEvidence[] = [\n\t\t{\n\t\t\tlabel: \"429 responses\",\n\t\t\tvalue: `${count429} of ${deliveries.length} attempts`,\n\t\t},\n\t\t{\n\t\t\tlabel: \"window\",\n\t\t\tvalue:\n\t\t\t\toldest && newest\n\t\t\t\t\t? `${formatShortDate(oldest.dispatchedAt)} → ${formatShortDate(newest.dispatchedAt)}`\n\t\t\t\t\t: \"unknown\",\n\t\t},\n\t];\n\tconst retryAfter = extractRetryAfterSeconds(deliveries);\n\tif (retryAfter) {\n\t\tevidence.push({ label: \"latest Retry-After\", value: `${retryAfter}s` });\n\t}\n\n\tconst suggestedConcurrency = Math.max(1, Math.floor(webhook.concurrency / 2));\n\treturn {\n\t\tcode: \"receiver_rate_limited\",\n\t\tseverity: \"warn\",\n\t\tevidence,\n\t\tfix: {\n\t\t\ttext: \"Lower concurrency, or honor the Retry-After header on your receiver.\",\n\t\t\tcommand: `secondlayer webhooks update ${webhook.id} --concurrency ${suggestedConcurrency}`,\n\t\t\tdocsPath: \"/docs/webhooks#receiver-rate-limited\",\n\t\t},\n\t};\n}\n\n/** ≥5 most recent attempts are 5xx or got no response at all (timeout /\n * connection failure) — the receiver looks down, not just slow. */\nfunction detectReceiverDown(\n\twebhook: WebhookDetail,\n\tdeliveries: DeliveryRow[],\n): DoctorIssue | null {\n\tconst streak = consecutiveFromStart(\n\t\tdeliveries,\n\t\t(d) => d.statusCode === null || d.statusCode >= 500,\n\t);\n\tif (streak.length < DOWN_MIN_CONSECUTIVE) return null;\n\n\treturn {\n\t\tcode: \"receiver_down\",\n\t\tseverity: \"bad\",\n\t\tevidence: [\n\t\t\t{ label: \"consecutive failures\", value: String(streak.length) },\n\t\t\t{ label: \"breakdown\", value: summarizeStatusBreakdown(streak) },\n\t\t\t{\n\t\t\t\tlabel: \"last success\",\n\t\t\t\tvalue: webhook.lastSuccessAt\n\t\t\t\t\t? formatShortDate(webhook.lastSuccessAt)\n\t\t\t\t\t: \"never\",\n\t\t\t},\n\t\t],\n\t\tfix: {\n\t\t\ttext: \"Check your receiver's health and logs, then send a test event.\",\n\t\t\tcommand: `secondlayer webhooks test ${webhook.id}`,\n\t\t\tdocsPath: \"/docs/webhooks#receiver-down\",\n\t\t},\n\t};\n}\n\n/** ≥5 most recent attempts are 4xx other than 429 — the receiver is\n * reachable but actively rejecting us (auth, signature, bad request). */\nfunction detectReceiverRejects(\n\twebhook: WebhookDetail,\n\tdeliveries: DeliveryRow[],\n): DoctorIssue | null {\n\tconst streak = consecutiveFromStart(\n\t\tdeliveries,\n\t\t(d) =>\n\t\t\td.statusCode !== null &&\n\t\t\td.statusCode >= 400 &&\n\t\t\td.statusCode < 500 &&\n\t\t\td.statusCode !== 429,\n\t);\n\tif (streak.length < REJECTS_MIN_CONSECUTIVE) return null;\n\n\tconst evidence: DoctorEvidence[] = [\n\t\t{ label: \"consecutive rejects\", value: String(streak.length) },\n\t\t{ label: \"breakdown\", value: summarizeStatusBreakdown(streak) },\n\t];\n\tconst withText = streak.find((d) => d.errorMessage || d.responseBody);\n\tconst snippet = withText\n\t\t? (withText.errorMessage ?? withText.responseBody ?? \"\").slice(\n\t\t\t\t0,\n\t\t\t\tERROR_SNIPPET_MAX,\n\t\t\t)\n\t\t: null;\n\tif (snippet) evidence.push({ label: \"first error\", value: snippet });\n\n\treturn {\n\t\tcode: \"receiver_rejects\",\n\t\tseverity: \"bad\",\n\t\tevidence,\n\t\tfix: {\n\t\t\ttext: \"Check your receiver's auth config or signature verification.\",\n\t\t\tcommand: `secondlayer webhooks test ${webhook.id}`,\n\t\t\tdocsPath: \"/docs/webhooks#receiver-rejects\",\n\t\t},\n\t};\n}\n\n/** Median response time of the newest 20 attempts is at least half the\n * webhook's timeout — deliveries are slow, not failing. */\nfunction detectReceiverSlow(\n\twebhook: WebhookDetail,\n\tdeliveries: DeliveryRow[],\n): DoctorIssue | null {\n\tconst durations = deliveries\n\t\t.slice(0, SLOW_WINDOW)\n\t\t.map((d) => d.durationMs)\n\t\t.filter((d): d is number => d !== null);\n\tif (durations.length < SLOW_MIN_SAMPLES) return null;\n\n\tconst med = median(durations);\n\tif (med < webhook.timeoutMs * SLOW_TIMEOUT_RATIO) return null;\n\n\treturn {\n\t\tcode: \"receiver_slow\",\n\t\tseverity: \"warn\",\n\t\tevidence: [\n\t\t\t{ label: \"median response time\", value: formatMs(med) },\n\t\t\t{\n\t\t\t\tlabel: \"p95 response time\",\n\t\t\t\tvalue: formatMs(percentile(durations, 0.95)),\n\t\t\t},\n\t\t\t{ label: \"timeout\", value: formatMs(webhook.timeoutMs) },\n\t\t],\n\t\tfix: {\n\t\t\ttext: \"Speed up your receiver, or raise the timeout (up to 30s hosted).\",\n\t\t\tcommand: `secondlayer webhooks update ${webhook.id} --timeout-ms 30000`,\n\t\t\tdocsPath: \"/docs/webhooks#receiver-slow\",\n\t\t},\n\t};\n}\n\n/** Median (dispatch time − block time) of the newest 20 attempts with a\n * known block time exceeds a minute — we're behind on delivery. This is\n * our-side latency, not something the receiver can fix, so it carries no\n * actionable command. */\nfunction detectDeliveryLag(deliveries: DeliveryRow[]): DoctorIssue | null {\n\tconst window = deliveries\n\t\t.slice(0, LAG_WINDOW)\n\t\t.filter(\n\t\t\t(d): d is DeliveryRow & { blockTime: string } => d.blockTime !== null,\n\t\t);\n\tif (window.length < LAG_MIN_SAMPLES) return null;\n\n\tconst lags = window.map(\n\t\t(d) => new Date(d.dispatchedAt).getTime() - new Date(d.blockTime).getTime(),\n\t);\n\tconst med = median(lags);\n\tif (med <= LAG_THRESHOLD_MS) return null;\n\n\tconst blockTimes = window.map((d) => d.blockTime).sort();\n\tconst oldest = blockTimes[0];\n\tconst newest = blockTimes[blockTimes.length - 1];\n\n\treturn {\n\t\tcode: \"delivery_lag\",\n\t\tseverity: \"warn\",\n\t\tevidence: [\n\t\t\t{ label: \"median lag\", value: formatMs(med) },\n\t\t\t{\n\t\t\t\tlabel: \"block time range\",\n\t\t\t\tvalue:\n\t\t\t\t\toldest && newest\n\t\t\t\t\t\t? `${formatShortDate(oldest)} → ${formatShortDate(newest)}`\n\t\t\t\t\t\t: \"unknown\",\n\t\t\t},\n\t\t],\n\t\tfix: {\n\t\t\ttext: \"We're behind on delivery; no action needed on your end.\",\n\t\t},\n\t};\n}\n\nconst SEVERITY_RANK: Record<DoctorSeverity, number> = {\n\tbad: 0,\n\twarn: 1,\n\tcalm: 2,\n};\n\n/** Tie-break within a severity tier when more than one issue fires at\n * once — most specific / most actionable first. */\nconst CODE_PRIORITY: DoctorIssueCode[] = [\n\t\"circuit\",\n\t\"receiver_down\",\n\t\"receiver_rejects\",\n\t\"dead_letters\",\n\t\"paused\",\n\t\"last_error\",\n\t\"warning\",\n\t\"receiver_rate_limited\",\n\t\"receiver_slow\",\n\t\"delivery_lag\",\n\t\"no_deliveries\",\n];\n\nfunction pickPrimary(issues: DoctorIssue[]): DoctorIssue | null {\n\tif (issues.length === 0) return null;\n\treturn (\n\t\t[...issues].sort((a, b) => {\n\t\t\tconst sevDiff = SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity];\n\t\t\tif (sevDiff !== 0) return sevDiff;\n\t\t\treturn CODE_PRIORITY.indexOf(a.code) - CODE_PRIORITY.indexOf(b.code);\n\t\t})[0] ?? null\n\t);\n}\n\nfunction hintFor(issue: DoctorIssue): string {\n\tif (!issue.fix) return issue.detail ?? issue.code;\n\treturn issue.fix.command\n\t\t? `${issue.fix.text} ${issue.fix.command}`\n\t\t: issue.fix.text;\n}\n\nexport function buildDoctorReport(input: {\n\twebhook: WebhookDetail;\n\tdeliveries: DeliveryRow[];\n\tdead: DeadRow[];\n}): DoctorReport {\n\tconst successful = input.deliveries.filter(isSuccessDelivery).length;\n\tconst failed = input.deliveries.length - successful;\n\n\tconst hints: string[] = [];\n\tconst issues: DoctorIssue[] = [];\n\tif (input.webhook.warning) {\n\t\thints.push(input.webhook.warning);\n\t\tissues.push({\n\t\t\tcode: \"warning\",\n\t\t\tdetail: input.webhook.warning,\n\t\t\tseverity: \"warn\",\n\t\t});\n\t}\n\tif (input.webhook.status === \"paused\") {\n\t\thints.push(\n\t\t\t`Resume when the receiver is healthy: secondlayer webhooks resume ${input.webhook.id}`,\n\t\t);\n\t\tissues.push({ code: \"paused\", severity: \"warn\" });\n\t}\n\tif (input.webhook.lastError) {\n\t\thints.push(\n\t\t\t\"Run secondlayer webhooks test to reproduce the receiver request.\",\n\t\t);\n\t\tissues.push({\n\t\t\tcode: \"last_error\",\n\t\t\tdetail: input.webhook.lastError,\n\t\t\tseverity: \"warn\",\n\t\t});\n\t}\n\tif (input.webhook.circuitOpenedAt || input.webhook.circuitFailures > 0) {\n\t\thints.push(\n\t\t\t\"Circuit breaker has failures; inspect receiver logs and delivery status codes.\",\n\t\t);\n\t\tissues.push({ code: \"circuit\", severity: \"bad\" });\n\t}\n\tif (input.dead.length > 0) {\n\t\thints.push(\n\t\t\t`Dead-letter rows exist; inspect with secondlayer webhooks dead ${input.webhook.id} and requeue selected rows.`,\n\t\t);\n\t\tissues.push({ code: \"dead_letters\", severity: \"bad\" });\n\t}\n\n\tfor (const detector of [\n\t\tdetectReceiverRateLimited,\n\t\tdetectReceiverDown,\n\t\tdetectReceiverRejects,\n\t\tdetectReceiverSlow,\n\t]) {\n\t\tconst issue = detector(input.webhook, input.deliveries);\n\t\tif (issue) {\n\t\t\tissues.push(issue);\n\t\t\thints.push(hintFor(issue));\n\t\t}\n\t}\n\tconst lagIssue = detectDeliveryLag(input.deliveries);\n\tif (lagIssue) {\n\t\tissues.push(lagIssue);\n\t\thints.push(hintFor(lagIssue));\n\t}\n\n\tif (input.deliveries.length === 0) {\n\t\thints.push(\n\t\t\t\"No deliveries yet; confirm a chain event matching one of the triggers has happened since the webhook was created.\",\n\t\t);\n\t\tissues.push({ code: \"no_deliveries\", severity: \"calm\" });\n\t}\n\tif (hints.length === 0) {\n\t\thints.push(\"No immediate action needed.\");\n\t}\n\n\treturn {\n\t\twebhook: input.webhook,\n\t\tdeliverySummary: {\n\t\t\ttotal: input.deliveries.length,\n\t\t\tsuccessful,\n\t\t\tfailed,\n\t\t\tlast: input.deliveries[0] ?? null,\n\t\t},\n\t\tdeadCount: input.dead.length,\n\t\thints,\n\t\tissues,\n\t\tprimary: pickPrimary(issues),\n\t};\n}\n\n/**\n * The list page's own reduced detector: computed from `WebhookSummary` alone\n * (no deliveries, no dead-letter rows — the list endpoint returns neither,\n * and fetching per-row detail or deliveries here would fan out one request\n * per row). Only `status` and `pauseReason` distinguish a real problem\n * from a manual pause at this level; deliveries-based rules (rate limits,\n * downtime, rejects, slowness, lag) only ever show on the detail page.\n */\nexport function buildListIssue(\n\twebhook: Pick<\n\t\tWebhookSummary,\n\t\t\"status\" | \"pauseReason\" | \"circuitOpenedAt\" | \"lastSuccessAt\"\n\t>,\n): DoctorIssue | null {\n\tconst reason = pauseReasonOf(webhook);\n\tif (reason === null) return null;\n\tif (reason === \"circuit\") {\n\t\treturn {\n\t\t\tcode: \"circuit\",\n\t\t\tseverity: \"bad\",\n\t\t\tevidence: [\n\t\t\t\t{\n\t\t\t\t\tlabel: \"circuit opened\",\n\t\t\t\t\tvalue: webhook.circuitOpenedAt\n\t\t\t\t\t\t? formatShortDate(webhook.circuitOpenedAt)\n\t\t\t\t\t\t: \"unknown\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"last success\",\n\t\t\t\t\tvalue: webhook.lastSuccessAt\n\t\t\t\t\t\t? formatShortDate(webhook.lastSuccessAt)\n\t\t\t\t\t\t: \"never\",\n\t\t\t\t},\n\t\t\t],\n\t\t\tfix: {\n\t\t\t\ttext: \"Check your receiver's health and logs, then send a test event.\",\n\t\t\t\tdocsPath: \"/docs/webhooks#receiver-down\",\n\t\t\t},\n\t\t};\n\t}\n\treturn { code: \"paused\", severity: \"warn\" };\n}\n"
6
6
  ],
7
- "mappings": "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",
8
- "debugId": "44661C072105706964756E2164756E21",
7
+ "mappings": "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",
8
+ "debugId": "DAB3EDEBA7F6064164756E2164756E21",
9
9
  "names": []
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@secondlayer/sdk",
3
- "version": "16.2.1",
3
+ "version": "16.3.0",
4
4
  "description": "Decoded Stacks data in your own database — stream rows into your schema, or query the tables you defined.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -68,9 +68,9 @@
68
68
  "prepublishOnly": "bun run build"
69
69
  },
70
70
  "dependencies": {
71
- "@secondlayer/shared": "^15.0.2",
71
+ "@secondlayer/shared": "^15.3.0",
72
72
  "@secondlayer/stacks": "^6.5.3",
73
- "@secondlayer/subgraphs": "^8.0.3"
73
+ "@secondlayer/subgraphs": "^8.1.0"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@openpkg-ts/cli": "^0.13.2",