UNPKG

acp-handler

Version:

Vercel handler for Agentic Commerce Protocol (ACP) - Build checkout APIs that AI agents like ChatGPT can use to complete purchases

66 lines (64 loc) 2.22 kB
//#region src/checkout/crypto.ts function timingSafeEqual(a, b) { if (a.length !== b.length) return false; let res = 0; for (let i = 0; i < a.length; i++) res |= a[i] ^ b[i]; return res === 0; } async function hmacSign(body, secret) { const key = await crypto.subtle.importKey("raw", new TextEncoder().encode(secret), { name: "HMAC", hash: "SHA-256" }, false, ["sign"]); const sig = await crypto.subtle.sign("HMAC", key, new TextEncoder().encode(body)); return Buffer.from(new Uint8Array(sig)).toString("hex"); } async function hmacVerify({ body, secret, signature }) { const expected = await hmacSign(body, secret); return timingSafeEqual(Buffer.from(signature, "hex"), Buffer.from(expected, "hex")); } function assertFreshTimestamp(ts, { skewSec = 300 } = {}) { if (!ts) throw new Error("missing timestamp"); const now = Math.floor(Date.now() / 1e3); if (Math.abs(now - ts) > skewSec) throw new Error("stale or future timestamp"); } //#endregion //#region src/checkout/webhooks/outbound.ts /** * Creates an outbound webhook sender with HMAC signing * * This is the baseline implementation. For production, consider: * - Wrapping with Next.js `after()` to avoid blocking responses * - Using a queue (Vercel Queues, Upstash, etc.) for retry logic * - Logging failures to a monitoring service */ function createOutboundWebhook(config) { async function sendWebhook(evt) { const body = JSON.stringify(evt); const signature = await hmacSign(body, config.secret); const timestamp = Math.floor(Date.now() / 1e3); const response = await fetch(config.webhookUrl, { method: "POST", headers: { "Content-Type": "application/json", [`${config.merchantName || "Merchant"}-Signature`]: signature, "X-Timestamp": String(timestamp) }, body }); if (!response.ok) throw new Error(`Webhook failed: ${response.status} ${await response.text()}`); } return { orderCreated: (evt) => sendWebhook({ ...evt, event: "order_created" }), orderUpdated: (evt) => sendWebhook({ ...evt, event: "order_updated" }) }; } //#endregion export { assertFreshTimestamp, createOutboundWebhook, hmacSign, hmacVerify, timingSafeEqual }; //# sourceMappingURL=outbound-DPQQzjHi.js.map