UNPKG

@paykit-sdk/stripe

Version:

Stripe provider for PayKit

214 lines (209 loc) 7.84 kB
// src/index.ts import { validateEnvVars } from "@paykit-sdk/core"; // src/stripe-provider.ts import { toPaykitEvent, headersExtractor, stringifyObjectValues as stringifyObjectValues2 } from "@paykit-sdk/core"; import Stripe from "stripe"; // lib/mapper.ts import { stringifyObjectValues } from "@paykit-sdk/core"; var toPaykitCheckout = (checkout) => { return { id: checkout.id, customer_id: checkout.customer, session_type: checkout.mode === "subscription" ? "recurring" : "one_time", // todo: handle `setup` mode payment_url: checkout.url, products: checkout.line_items.data.map((item) => ({ id: item.price.id, quantity: item.quantity })), currency: checkout.currency, amount: checkout.amount_total, metadata: checkout.metadata }; }; var toPaykitCustomer = (customer) => { return { id: customer.id, email: customer.email ?? void 0, name: customer.name ?? void 0, metadata: stringifyObjectValues(customer.metadata ?? {}) }; }; var toPaykitSubscriptionStatus = (status) => { if (["active", "trialing"].includes(status)) return "active"; if (["incomplete_expired", "incomplete", "past_due"].includes(status)) return "past_due"; if (["canceled"].includes(status)) return "canceled"; if (["expired"].includes(status)) return "expired"; throw new Error(`Unknown status: ${status}`); }; var toPaykitSubscription = (subscription) => { return { id: subscription.id, customer_id: subscription.customer?.toString(), status: toPaykitSubscriptionStatus(subscription.status), current_period_start: new Date(subscription.start_date), current_period_end: new Date(subscription.cancel_at), metadata: stringifyObjectValues(subscription.metadata ?? {}) }; }; var toPaykitInvoice = (invoice) => { return { id: invoice.id, amount: invoice.amount_paid, currency: invoice.currency, metadata: stringifyObjectValues(invoice.metadata ?? {}), customer_id: invoice.customer?.toString() ?? "", billing_mode: invoice.billingMode }; }; // src/stripe-provider.ts var StripeProvider = class { constructor(config) { /** * Checkout management */ this.createCheckout = async (params) => { const { customer_id, item_id, metadata, session_type, provider_metadata } = params; const checkout = await this.stripe.checkout.sessions.create({ customer: customer_id, mode: session_type === "one_time" ? "payment" : "subscription", ...session_type == "one_time" && { metadata }, ...session_type == "recurring" && { subscription_data: { metadata } }, line_items: [{ price: item_id }], ...provider_metadata }); return toPaykitCheckout(checkout); }; this.retrieveCheckout = async (id) => { const checkout = await this.stripe.checkout.sessions.retrieve(id); return toPaykitCheckout(checkout); }; /** * Customer management */ this.createCustomer = async (params) => { const customer = await this.stripe.customers.create(params); return toPaykitCustomer(customer); }; this.updateCustomer = async (id, params) => { const customer = await this.stripe.customers.update(id, params); return toPaykitCustomer(customer); }; this.deleteCustomer = async (id) => { await this.stripe.customers.del(id); return null; }; this.retrieveCustomer = async (id) => { const customer = await this.stripe.customers.retrieve(id); if ("deleted" in customer) return null; return toPaykitCustomer(customer); }; /** * Subscription management */ this.cancelSubscription = async (id) => { await this.stripe.subscriptions.cancel(id); return null; }; this.updateSubscription = async (id, params) => { const subscription = await this.stripe.subscriptions.update(id, { metadata: params.metadata }); return toPaykitSubscription(subscription); }; this.retrieveSubscription = async (id) => { const subscription = await this.stripe.subscriptions.retrieve(id); return toPaykitSubscription(subscription); }; /** * Webhook management */ this.handleWebhook = async (params) => { const { body, headers, webhookSecret } = params; const stripeHeaders = headersExtractor(headers, ["x-stripe-signature"]); const signature = stripeHeaders[0].value; const event = this.stripe.webhooks.constructEvent(body, signature, webhookSecret); const webhookHandlers = { /** * Invoice */ "checkout.session.completed": (event2) => { const data = event2.data.object; if (data.mode !== "payment") return null; return toPaykitEvent({ type: "$invoicePaid", created: event2.created, id: event2.id, data: { id: data.id, amount: data.amount_total ?? 0, currency: data.currency ?? "", metadata: stringifyObjectValues2({ ...data.metadata ?? {}, $mode: data.mode }), customer_id: data.customer?.toString() ?? "", billing_mode: "one_time" } }); }, "invoice.paid": (event2) => { const data = event2.data.object; if (data.status !== "paid" && !["subscription_create", "subscription_cycle"].includes(data.billing_reason)) { return null; } return toPaykitEvent({ type: "$invoicePaid", created: event2.created, id: event2.id, data: toPaykitInvoice({ ...data, billingMode: "recurring" }) }); }, /** * Customer */ "customer.created": (event2) => { const data = event2.data.object; return toPaykitEvent({ type: "$customerCreated", created: event2.created, id: event2.id, data: toPaykitCustomer(data) }); }, "customer.updated": (event2) => { const data = event2.data.object; return toPaykitEvent({ type: "$customerUpdated", created: event2.created, id: event2.id, data: toPaykitCustomer(data) }); }, "customer.deleted": (event2) => { return toPaykitEvent({ type: "$customerDeleted", created: event2.created, id: event2.id, data: null }); }, /** * Subscription */ "customer.subscription.created": (event2) => { const data = event2.data.object; return toPaykitEvent({ type: "$subscriptionCreated", created: event2.created, id: event2.id, data: toPaykitSubscription(data) }); }, "customer.subscription.updated": (event2) => { const data = event2.data.object; return toPaykitEvent({ type: "$subscriptionUpdated", created: event2.created, id: event2.id, data: toPaykitSubscription(data) }); }, "customer.subscription.deleted": (event2) => { return toPaykitEvent({ type: "$subscriptionCancelled", created: event2.created, id: event2.id, data: null }); } }; const handler = webhookHandlers[event.type]; if (!handler) throw new Error(`Unhandled event type: ${event.type}`); const result = handler(event); if (!result) throw new Error(`Unhandled event type: ${event.type}`); return result; }; const { debug, apiKey, ...rest } = config; this.stripe = new Stripe(apiKey, rest); } }; // src/index.ts var createStripe = (config) => { return new StripeProvider(config); }; var stripe = () => { const envVars = validateEnvVars(["STRIPE_API_KEY"], process.env); const isDev = process.env.NODE_ENV === "development"; return createStripe({ apiKey: envVars.STRIPE_API_KEY, debug: isDev, apiVersion: "2025-07-30.basil" }); }; export { createStripe, stripe };