UNPKG

@paykit-sdk/polar

Version:
202 lines (197 loc) 7.58 kB
// src/index.ts import { validateEnvVars } from "@paykit-sdk/core"; // src/polar-provider.ts import { toPaykitEvent, headersExtractor } from "@paykit-sdk/core"; import { Polar, ServerList } from "@polar-sh/sdk"; import { validateEvent } from "@polar-sh/sdk/webhooks"; // lib/mapper.ts import { stringifyObjectValues } from "@paykit-sdk/core"; var toPaykitCheckout = (checkout) => { return { id: checkout.id, payment_url: checkout.url, customer_id: checkout.customerId, session_type: checkout.subscriptionId ? "recurring" : "one_time", products: checkout.products.map((product) => ({ id: product.id, quantity: 1 })), metadata: checkout.metadata ?? null, currency: checkout.currency, amount: checkout.amount }; }; var toPaykitCustomer = (customer) => { return { id: customer.id, email: customer.email, name: customer.name ?? void 0 }; }; var toPaykitSubscriptionStatus = (status) => { if (status === "active") return "active"; if (status === "past_due" || status === "incomplete") return "past_due"; if (status === "canceled" || status === "unpaid") return "canceled"; if (status === "incomplete_expired") return "expired"; throw new Error(`Unhandled status: ${status}`); }; var toPaykitSubscription = (subscription) => { return { id: subscription.id, customer_id: subscription.customerId, status: toPaykitSubscriptionStatus(subscription.status), current_period_start: new Date(subscription.currentPeriodStart), current_period_end: new Date(subscription.currentPeriodEnd), metadata: stringifyObjectValues({ ...subscription.metadata ?? {}, $customFieldData: subscription.customFieldData }) }; }; var toPaykitInvoice = (invoice) => { return { id: invoice.id, amount: invoice.totalAmount, currency: invoice.currency, metadata: stringifyObjectValues({ ...invoice.metadata ?? {}, $customFieldData: invoice.customFieldData }), customer_id: invoice.customerId, billing_mode: invoice.billingMode }; }; // src/polar-provider.ts var PolarProvider = class { constructor(config) { this.config = config; this.productionURL = ServerList["production"]; this.sandboxURL = ServerList["sandbox"]; /** * Checkout management */ this.createCheckout = async (params) => { const { metadata, item_id, provider_metadata } = params; const response = await this.polar.checkouts.create({ metadata, products: [item_id], ...provider_metadata }); return toPaykitCheckout(response); }; this.retrieveCheckout = async (id) => { const response = await this.polar.checkouts.get({ id }); return toPaykitCheckout(response); }; /** * Customer management */ this.createCustomer = async (params) => { const { email, name, metadata } = params; const response = await this.polar.customers.create({ email, name, ...metadata && { metadata } }); return toPaykitCustomer(response); }; this.updateCustomer = async (id, params) => { const { email, name, metadata } = params; const response = await this.polar.customers.update({ id, customerUpdate: { ...email && { email }, ...name && { name }, ...metadata && { metadata } } }); return toPaykitCustomer(response); }; this.retrieveCustomer = async (id) => { const response = await this.polar.customers.get({ id }); return toPaykitCustomer(response); }; /** * Subscription management */ this.cancelSubscription = async (id) => { await this.polar.subscriptions.revoke({ id }); return null; }; this.retrieveSubscription = async (id) => { const response = await this.polar.subscriptions.get({ id }); return toPaykitSubscription(response); }; this.updateSubscription = async (id, params) => { const response = await this.polar.subscriptions.update({ id, subscriptionUpdate: { ...params.metadata } }); return toPaykitSubscription(response); }; /** * Webhook management */ this.handleWebhook = async (params) => { const { body, headers, webhookSecret } = params; const webhookHeaders = headersExtractor(headers, ["webhook-id", "webhook-timestamp", "webhook-signature"]).reduce( (acc, kv) => { acc[kv.key] = Array.isArray(kv.value) ? kv.value.join(",") : kv.value; return acc; }, {} ); const { data, type } = validateEvent(body, webhookHeaders, webhookSecret); const id = webhookHeaders["webhook-id"]; const timestamp = webhookHeaders["webhook-timestamp"]; const webhookHandlers = { /** * Invoice */ "order.paid": (data2) => { const { status, metadata } = data2; if (status !== "paid") return null; return toPaykitEvent({ type: "$invoicePaid", created: parseInt(timestamp), id, data: toPaykitInvoice({ ...data2, metadata: { ...metadata ?? {} }, billingMode: "one_time" }) }); }, "order.created": (data2) => { const { billingReason, metadata, status } = data2; if (["subscription_create", "subscription_cycle"].includes(billingReason)) { return toPaykitEvent({ type: "$invoicePaid", created: parseInt(timestamp), id, data: toPaykitInvoice({ ...data2, metadata: { ...metadata ?? {} }, billingMode: "recurring" }) }); } return null; }, /** * Customer */ "customer.created": (data2) => { return toPaykitEvent({ type: "$customerCreated", created: parseInt(timestamp), id, data: toPaykitCustomer(data2) }); }, "customer.updated": (data2) => { return toPaykitEvent({ type: "$customerUpdated", created: parseInt(timestamp), id, data: toPaykitCustomer(data2) }); }, "customer.deleted": () => { return toPaykitEvent({ type: "$customerDeleted", created: parseInt(timestamp), id, data: null }); }, /** * Subscription */ "subscription.updated": (data2) => { return toPaykitEvent({ type: "$subscriptionUpdated", created: parseInt(timestamp), id, data: toPaykitSubscription(data2) }); }, "subscription.created": (data2) => { return toPaykitEvent({ type: "$subscriptionCreated", created: parseInt(timestamp), id, data: toPaykitSubscription(data2) }); }, "subscription.revoked": (data2) => { return toPaykitEvent({ type: "$subscriptionCancelled", created: parseInt(timestamp), id, data: toPaykitSubscription(data2) }); } }; const handler = webhookHandlers[type]; if (!handler) throw new Error(`Unhandled event type: ${type}`); const result = handler(data); if (!result) throw new Error(`Unhandled event type: ${type}`); return result; }; const { accessToken, server, ...rest } = config; this.polar = new Polar({ accessToken, serverURL: server === "sandbox" ? this.sandboxURL : this.productionURL, ...rest }); } }; // src/index.ts var createPolar = (config) => { return new PolarProvider(config); }; var polar = () => { const envVars = validateEnvVars(["POLAR_ACCESS_TOKEN"], process.env); const isDev = process.env.NODE_ENV === "development"; return createPolar({ debug: true, accessToken: envVars.POLAR_ACCESS_TOKEN, server: isDev ? "sandbox" : "production" }); }; export { createPolar, polar };