Rebasely Beta: data may be purged

examples/storefront Public

TypeScript · 49 lines · 1.8 KiB · at c6a00ae

// 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>;  // True when the intent is cancelled, false when it can no longer be (it succeeded, or a  // payment is processing). In that case the webhook settles the order.  cancelIntent(intentId: string): Promise<boolean>;}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);        return true;      } catch (e) {        if (e instanceof Stripe.errors.StripeInvalidRequestError && e.code === "payment_intent_unexpected_state") return false;        throw e;      }    },  };}