UNPKG

@beignet/core

Version:

Core framework primitives for Beignet

230 lines 7.93 kB
/** * @beignet/core/payments * * Provider-neutral payments primitives for Beignet applications. */ import { createProvider, createProviderInstrumentation, } from "../providers/index.js"; /** * Error thrown by payment helpers and provider adapters. */ export class PaymentProviderError extends Error { /** * Provider name when known. */ provider; /** * Operation that failed. */ operation; /** * Provider error code when known. */ code; /** * Original provider error when available. */ cause; constructor(args) { super(args.message); this.name = "PaymentProviderError"; this.provider = args.provider; this.operation = args.operation; this.code = args.code; this.cause = args.cause; } } function defaultMemoryId(prefix) { return `${prefix}_${crypto.randomUUID()}`; } function cloneMetadata(metadata) { return metadata ? { ...metadata } : undefined; } function cloneCheckoutInput(input) { return { ...input, lineItems: input.lineItems.map((item) => ({ ...item })), metadata: cloneMetadata(input.metadata), }; } function cloneRefundInput(input) { return { ...input, metadata: cloneMetadata(input.metadata), }; } /** * Create an in-memory payments port for tests, local development, and * examples. * * The memory adapter does not contact a payment provider or validate webhook * signatures. Queue webhook events explicitly with `queueWebhookEvent(...)`. */ export function createMemoryPayments(options = {}) { const checkoutSessions = []; const billingPortalSessions = []; const refunds = []; const webhookEvents = []; const queuedWebhookEvents = []; const now = options.now ?? (() => new Date()); const id = options.id ?? defaultMemoryId; return { get checkoutSessions() { return checkoutSessions; }, get billingPortalSessions() { return billingPortalSessions; }, get refunds() { return refunds; }, get webhookEvents() { return webhookEvents; }, async createCheckoutSession(input) { const session = { id: id("checkout"), provider: "memory", mode: input.mode, url: `https://payments.example.test/checkout/${id("url")}`, customerId: input.customerId, metadata: cloneMetadata(input.metadata), input: cloneCheckoutInput(input), createdAt: now(), }; checkoutSessions.push(session); await options.onCheckoutSessionCreated?.(session); return session; }, async createBillingPortalSession(input) { const session = { id: id("portal"), provider: "memory", url: `https://payments.example.test/portal/${id("url")}`, customerId: input.customerId, input: { ...input }, createdAt: now(), }; billingPortalSessions.push(session); await options.onBillingPortalSessionCreated?.(session); return session; }, async createRefund(input) { const refund = { id: id("refund"), provider: "memory", paymentId: input.paymentId, amount: input.amount, status: "succeeded", metadata: cloneMetadata(input.metadata), input: cloneRefundInput(input), createdAt: now(), }; refunds.push(refund); await options.onRefundCreated?.(refund); return refund; }, async verifyWebhook() { const event = queuedWebhookEvents.shift(); if (!event) { throw new PaymentProviderError({ provider: "memory", operation: "payments.verifyWebhook", message: "No memory payment webhook event is queued. Call queueWebhookEvent(...) before verifyWebhook(...).", }); } webhookEvents.push(event); await options.onWebhookVerified?.(event); return event; }, queueWebhookEvent(event) { queuedWebhookEvents.push(event); }, clear() { checkoutSessions.length = 0; billingPortalSessions.length = 0; refunds.length = 0; webhookEvents.length = 0; queuedWebhookEvents.length = 0; }, }; } /** * Create a provider that contributes an in-memory payments port. */ export function createMemoryPaymentsProvider(options = {}) { const { name = "memory-payments", onCheckoutSessionCreated, onBillingPortalSessionCreated, onRefundCreated, onWebhookVerified, ...paymentsOptions } = options; return createProvider({ name, metadata: { ports: ["payments"], watchers: ["payments"], }, setup({ ports }) { const instrumentation = createProviderInstrumentation(ports, { providerName: name, watcher: "payments", }); const payments = createMemoryPayments({ ...paymentsOptions, async onCheckoutSessionCreated(session) { instrumentation.custom({ name: "payments.checkout.created", label: "Checkout session created", summary: session.id, details: { id: session.id, mode: session.mode, customerId: session.customerId, }, }); await onCheckoutSessionCreated?.(session); }, async onBillingPortalSessionCreated(session) { instrumentation.custom({ name: "payments.portal.created", label: "Billing portal session created", summary: session.id, details: { id: session.id, customerId: session.customerId, }, }); await onBillingPortalSessionCreated?.(session); }, async onRefundCreated(refund) { instrumentation.custom({ name: "payments.refund.created", label: "Refund created", summary: refund.id, details: { id: refund.id, paymentId: refund.paymentId, amount: refund.amount, status: refund.status, }, }); await onRefundCreated?.(refund); }, async onWebhookVerified(event) { instrumentation.custom({ name: "payments.webhook.verified", label: "Payment webhook verified", summary: event.type, details: { id: event.id, eventType: event.type, livemode: event.livemode, }, }); await onWebhookVerified?.(event); }, }); return { ports: { payments, }, }; }, }); } //# sourceMappingURL=index.js.map