Rebasely Beta: data may be purged

examples/storefront Public

TypeScript · 54 lines · 2.3 KiB · at b748afa

// Stripe's webhook: verifies the signature, then settles the order the PaymentIntent belongs to.// Stripe retries any delivery that does not get a 2xx, for up to three days, so every outcome// here is either done or safe to repeat.import Stripe from "stripe";import type { Settled } from "../../../src/orders.ts";// storefront-api's OrdersService, as this Worker sees it through the ORDERS service binding.export interface Orders {  markPaid(orderId: string, paymentIntentId: string): Promise<Settled>;  cancel(orderId: string): Promise<Settled>;}export interface Env {  ORDERS: Orders;  STRIPE_WEBHOOK_SECRET: string;}const subtle = Stripe.createSubtleCryptoProvider();export async function handleWebhook(req: Request, env: Env): Promise<Response> {  if (new URL(req.url).pathname !== "/stripe/webhook") return text(404, "not found");  if (req.method !== "POST") return text(405, "POST only");  const signature = req.headers.get("stripe-signature");  if (!signature) return text(400, "missing stripe-signature");  let event: Stripe.Event;  try {    event = await Stripe.webhooks.constructEventAsync(await req.text(), signature, env.STRIPE_WEBHOOK_SECRET, undefined, subtle);  } catch {    return text(400, "bad signature");  }  if (event.type === "payment_intent.succeeded" || event.type === "payment_intent.canceled") {    const intent = event.data.object;    const orderId = intent.metadata.order_id;    if (!orderId) return text(200, "not a storefront payment");    const result = event.type === "payment_intent.succeeded" ? await env.ORDERS.markPaid(orderId, intent.id) : await env.ORDERS.cancel(orderId);    log(event, result);    if (event.type === "payment_intent.succeeded" && result.status === "cancelled") {      // The money arrived for an order we had already given up on. Someone has to refund it.      console.error(JSON.stringify({ msg: "payment for a cancelled order, refund it", order: orderId, payment_intent: intent.id }));    }  }  return text(200, "ok");}function log(event: Stripe.Event, r: Settled): void {  console.log(JSON.stringify({ msg: "stripe event", type: event.type, id: event.id, order: r.order_id, status: r.status, changed: r.changed }));}function text(status: number, body: string): Response {  return new Response(body, { status, headers: { "content-type": "text/plain; charset=utf-8" } });}