Rebasely Beta: data may be purged

examples/storefront Public

TypeScript · 47 lines · 1.7 KiB · at 582fe0a

// The payment provider, behind the two calls checkout needs. Stripe in production; tests pass// their own Payments.import Stripe from "stripe";export type Charge = { order_id: string; amount_cents: number; currency: string; email: string };export type Intent = { id: string; client_secret: string };export interface Payments {  // Creates the PaymentIntent the shopper pays in the browser. Calling it again for the same  // order returns the same intent.  createIntent(charge: Charge): Promise<Intent>;  cancelIntent(intentId: string): Promise<void>;}export function stripePayments(secretKey: string, fetchFn?: typeof fetch): Payments {  const stripe = new Stripe(secretKey, {    httpClient: Stripe.createFetchHttpClient(fetchFn),    maxNetworkRetries: 2,    timeout: 10_000,  });  return {    async createIntent(c) {      const intent = await stripe.paymentIntents.create(        {          amount: c.amount_cents,          currency: c.currency,          receipt_email: c.email,          automatic_payment_methods: { enabled: true },          metadata: { order_id: c.order_id },        },        { idempotencyKey: `order-${c.order_id}` },      );      if (!intent.client_secret) throw new Error(`PaymentIntent ${intent.id} has no client_secret`);      return { id: intent.id, client_secret: intent.client_secret };    },    async cancelIntent(intentId) {      try {        await stripe.paymentIntents.cancel(intentId);      } catch (e) {        // Already canceled, or paid in the meantime: the webhook settles the order either way.        if (e instanceof Stripe.errors.StripeInvalidRequestError && e.code === "payment_intent_unexpected_state") return;        throw e;      }    },  };}