@paykit-sdk/stripe
Version:
Stripe provider for PayKit
214 lines (209 loc) • 7.84 kB
JavaScript
// 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
};