examples/storefront Public
// 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; } }, };}