@parsrun/payments 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +184 -0
- package/dist/billing/index.d.ts +121 -0
- package/dist/billing/index.js +1082 -0
- package/dist/billing/index.js.map +1 -0
- package/dist/billing-service-LsAFesou.d.ts +578 -0
- package/dist/dunning/index.d.ts +310 -0
- package/dist/dunning/index.js +2677 -0
- package/dist/dunning/index.js.map +1 -0
- package/dist/index.d.ts +185 -0
- package/dist/index.js +7698 -0
- package/dist/index.js.map +1 -0
- package/dist/providers/index.d.ts +5 -0
- package/dist/providers/index.js +1396 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/iyzico.d.ts +250 -0
- package/dist/providers/iyzico.js +469 -0
- package/dist/providers/iyzico.js.map +1 -0
- package/dist/providers/paddle.d.ts +66 -0
- package/dist/providers/paddle.js +437 -0
- package/dist/providers/paddle.js.map +1 -0
- package/dist/providers/stripe.d.ts +122 -0
- package/dist/providers/stripe.js +586 -0
- package/dist/providers/stripe.js.map +1 -0
- package/dist/schema-C5Zcju_j.d.ts +4191 -0
- package/dist/types.d.ts +388 -0
- package/dist/types.js +74 -0
- package/dist/types.js.map +1 -0
- package/dist/usage/index.d.ts +2674 -0
- package/dist/usage/index.js +2916 -0
- package/dist/usage/index.js.map +1 -0
- package/dist/webhooks/index.d.ts +89 -0
- package/dist/webhooks/index.js +188 -0
- package/dist/webhooks/index.js.map +1 -0
- package/package.json +91 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/providers/stripe.ts","../src/providers/paddle.ts","../src/providers/iyzico.ts","../src/webhooks/index.ts","../src/billing/types.ts","../src/billing/provider-strategy.ts","../src/billing/fallback-executor.ts","../src/billing/billing-service.ts","../src/usage/types.ts","../src/usage/memory-storage.ts","../src/usage/drizzle-storage.ts","../src/usage/schema.ts","../src/usage/quota-manager.ts","../src/usage/usage-tracker.ts","../src/usage/lifecycle-hooks.ts","../src/usage/usage-service.ts","../src/usage/billing-integration.ts","../src/usage/usage-meter.ts","../src/dunning/dunning-sequence.ts","../src/dunning/payment-retry.ts","../src/dunning/dunning-manager.ts","../src/dunning/dunning-scheduler.ts","../src/dunning/memory-storage.ts","../src/dunning/drizzle-storage.ts","../src/dunning/schema.ts","../src/index.ts"],"sourcesContent":["/**\n * @parsrun/payments - Type Definitions\n * Payment types and interfaces\n */\n\n// Re-export types from @parsrun/types for convenience\nexport {\n type,\n currencyCode,\n money,\n paymentCustomer,\n createCustomerRequest,\n cardDetails,\n paymentMethod,\n paymentIntentStatus,\n paymentIntent as parsPaymentIntent,\n createPaymentIntentRequest,\n subscriptionStatus as parsSubscriptionStatus,\n priceInterval,\n price as parsPrice,\n subscription as parsSubscription,\n createSubscriptionRequest,\n refundStatus,\n refund,\n createRefundRequest,\n webhookEventType,\n webhookEvent,\n stripeConfig,\n paddleConfig,\n iyzicoConfig,\n paymentsConfig,\n type CurrencyCode as ParsCurrencyCode,\n type Money,\n type PaymentCustomer,\n type CreateCustomerRequest as ParsCreateCustomerRequest,\n type CardDetails,\n type PaymentMethod as ParsPaymentMethod,\n type PaymentIntentStatus,\n type PaymentIntent as ParsPaymentIntentType,\n type CreatePaymentIntentRequest,\n type SubscriptionStatus as ParsSubscriptionStatus,\n type PriceInterval,\n type Price as ParsPrice,\n type Subscription as ParsSubscription,\n type CreateSubscriptionRequest as ParsCreateSubscriptionRequest,\n type RefundStatus,\n type Refund,\n type CreateRefundRequest,\n type WebhookEventType as ParsWebhookEventType,\n type WebhookEvent as ParsWebhookEvent,\n type StripeConfig,\n type PaddleConfig,\n type IyzicoConfig,\n type PaymentsConfig,\n} from \"@parsrun/types\";\n\n/**\n * Payment provider type\n */\nexport type PaymentProviderType = \"stripe\" | \"paddle\" | \"iyzico\";\n\n/**\n * Currency code (ISO 4217)\n */\nexport type CurrencyCode = \"USD\" | \"EUR\" | \"GBP\" | \"TRY\" | \"JPY\" | \"CAD\" | \"AUD\" | string;\n\n/**\n * Payment status\n */\nexport type PaymentStatus =\n | \"pending\"\n | \"processing\"\n | \"succeeded\"\n | \"failed\"\n | \"canceled\"\n | \"refunded\"\n | \"partially_refunded\";\n\n/**\n * Subscription status\n */\nexport type SubscriptionStatus =\n | \"active\"\n | \"past_due\"\n | \"unpaid\"\n | \"canceled\"\n | \"incomplete\"\n | \"incomplete_expired\"\n | \"trialing\"\n | \"paused\";\n\n/**\n * Billing interval\n */\nexport type BillingInterval = \"day\" | \"week\" | \"month\" | \"year\";\n\n// ============================================================================\n// Customer\n// ============================================================================\n\n/**\n * Customer data\n */\nexport interface Customer {\n /** Provider customer ID */\n id: string;\n /** Customer email */\n email: string;\n /** Customer name */\n name?: string | undefined;\n /** Phone number */\n phone?: string | undefined;\n /** Billing address */\n address?: Address | undefined;\n /** Custom metadata */\n metadata?: Record<string, string> | undefined;\n /** Provider-specific data */\n providerData?: unknown;\n}\n\n/**\n * Address\n */\nexport interface Address {\n line1?: string | undefined;\n line2?: string | undefined;\n city?: string | undefined;\n state?: string | undefined;\n postalCode?: string | undefined;\n country?: string | undefined;\n}\n\n/**\n * Create customer options\n */\nexport interface CreateCustomerOptions {\n email: string;\n name?: string | undefined;\n phone?: string | undefined;\n address?: Address | undefined;\n metadata?: Record<string, string> | undefined;\n}\n\n// ============================================================================\n// Products & Prices\n// ============================================================================\n\n/**\n * Product\n */\nexport interface Product {\n /** Provider product ID */\n id: string;\n /** Product name */\n name: string;\n /** Description */\n description?: string | undefined;\n /** Active status */\n active: boolean;\n /** Custom metadata */\n metadata?: Record<string, string> | undefined;\n /** Provider-specific data */\n providerData?: unknown;\n}\n\n/**\n * Price\n */\nexport interface Price {\n /** Provider price ID */\n id: string;\n /** Product ID */\n productId: string;\n /** Price in smallest currency unit (cents) */\n unitAmount: number;\n /** Currency */\n currency: CurrencyCode;\n /** Recurring billing details */\n recurring?: {\n interval: BillingInterval;\n intervalCount: number;\n } | undefined;\n /** Active status */\n active: boolean;\n /** Custom metadata */\n metadata?: Record<string, string> | undefined;\n /** Provider-specific data */\n providerData?: unknown;\n}\n\n// ============================================================================\n// Checkout\n// ============================================================================\n\n/**\n * Checkout line item\n */\nexport interface CheckoutLineItem {\n /** Price ID */\n priceId: string;\n /** Quantity */\n quantity: number;\n}\n\n/**\n * Create checkout options\n */\nexport interface CreateCheckoutOptions {\n /** Customer ID (optional, creates new if not provided) */\n customerId?: string | undefined;\n /** Customer email (for new customers) */\n customerEmail?: string | undefined;\n /** Line items */\n lineItems: CheckoutLineItem[];\n /** Success redirect URL */\n successUrl: string;\n /** Cancel redirect URL */\n cancelUrl: string;\n /** Checkout mode */\n mode: \"payment\" | \"subscription\" | \"setup\";\n /** Allow promotion codes */\n allowPromotionCodes?: boolean | undefined;\n /** Trial period days (subscription only) */\n trialDays?: number | undefined;\n /** Custom metadata */\n metadata?: Record<string, string> | undefined;\n /** Tenant ID for multi-tenant */\n tenantId?: string | undefined;\n}\n\n/**\n * Checkout session\n */\nexport interface CheckoutSession {\n /** Provider session ID */\n id: string;\n /** Checkout URL */\n url: string;\n /** Customer ID */\n customerId?: string | undefined;\n /** Payment status */\n status: \"open\" | \"complete\" | \"expired\";\n /** Mode */\n mode: \"payment\" | \"subscription\" | \"setup\";\n /** Amount total */\n amountTotal?: number | undefined;\n /** Currency */\n currency?: CurrencyCode | undefined;\n /** Provider-specific data */\n providerData?: unknown;\n}\n\n// ============================================================================\n// Subscriptions\n// ============================================================================\n\n/**\n * Subscription\n */\nexport interface Subscription {\n /** Provider subscription ID */\n id: string;\n /** Customer ID */\n customerId: string;\n /** Status */\n status: SubscriptionStatus;\n /** Price ID */\n priceId: string;\n /** Product ID */\n productId?: string | undefined;\n /** Current period start */\n currentPeriodStart: Date;\n /** Current period end */\n currentPeriodEnd: Date;\n /** Cancel at period end */\n cancelAtPeriodEnd: boolean;\n /** Canceled at */\n canceledAt?: Date | undefined;\n /** Trial start */\n trialStart?: Date | undefined;\n /** Trial end */\n trialEnd?: Date | undefined;\n /** Custom metadata */\n metadata?: Record<string, string> | undefined;\n /** Provider-specific data */\n providerData?: unknown;\n}\n\n/**\n * Create subscription options\n */\nexport interface CreateSubscriptionOptions {\n /** Customer ID */\n customerId: string;\n /** Price ID */\n priceId: string;\n /** Trial period days */\n trialDays?: number | undefined;\n /** Custom metadata */\n metadata?: Record<string, string> | undefined;\n /** Payment behavior */\n paymentBehavior?: \"default_incomplete\" | \"error_if_incomplete\" | \"allow_incomplete\" | undefined;\n}\n\n/**\n * Update subscription options\n */\nexport interface UpdateSubscriptionOptions {\n /** New price ID */\n priceId?: string | undefined;\n /** Cancel at period end */\n cancelAtPeriodEnd?: boolean | undefined;\n /** Custom metadata */\n metadata?: Record<string, string> | undefined;\n /** Proration behavior */\n prorationBehavior?: \"create_prorations\" | \"none\" | \"always_invoice\" | undefined;\n}\n\n// ============================================================================\n// Payments & Invoices\n// ============================================================================\n\n/**\n * Payment intent\n */\nexport interface PaymentIntent {\n /** Provider payment ID */\n id: string;\n /** Amount */\n amount: number;\n /** Currency */\n currency: CurrencyCode;\n /** Status */\n status: PaymentStatus;\n /** Customer ID */\n customerId?: string | undefined;\n /** Provider-specific data */\n providerData?: unknown;\n}\n\n/**\n * Invoice\n */\nexport interface Invoice {\n /** Provider invoice ID */\n id: string;\n /** Customer ID */\n customerId: string;\n /** Subscription ID */\n subscriptionId?: string | undefined;\n /** Status */\n status: \"draft\" | \"open\" | \"paid\" | \"void\" | \"uncollectible\";\n /** Amount due */\n amountDue: number;\n /** Amount paid */\n amountPaid: number;\n /** Currency */\n currency: CurrencyCode;\n /** Invoice URL */\n hostedInvoiceUrl?: string | undefined;\n /** PDF URL */\n invoicePdf?: string | undefined;\n /** Due date */\n dueDate?: Date | undefined;\n /** Provider-specific data */\n providerData?: unknown;\n}\n\n// ============================================================================\n// Portal\n// ============================================================================\n\n/**\n * Customer portal session\n */\nexport interface PortalSession {\n /** Portal URL */\n url: string;\n /** Return URL */\n returnUrl: string;\n}\n\n/**\n * Create portal options\n */\nexport interface CreatePortalOptions {\n /** Customer ID */\n customerId: string;\n /** Return URL */\n returnUrl: string;\n}\n\n// ============================================================================\n// Webhooks\n// ============================================================================\n\n/**\n * Webhook event types\n */\nexport type WebhookEventType =\n // Checkout\n | \"checkout.session.completed\"\n | \"checkout.session.expired\"\n // Customer\n | \"customer.created\"\n | \"customer.updated\"\n | \"customer.deleted\"\n // Subscription\n | \"subscription.created\"\n | \"subscription.updated\"\n | \"subscription.deleted\"\n | \"subscription.trial_will_end\"\n // Payment\n | \"payment.succeeded\"\n | \"payment.failed\"\n // Invoice\n | \"invoice.created\"\n | \"invoice.paid\"\n | \"invoice.payment_failed\"\n | \"invoice.upcoming\"\n // Refund\n | \"refund.created\"\n | \"refund.updated\";\n\n/**\n * Webhook event\n */\nexport interface WebhookEvent<T = unknown> {\n /** Event ID */\n id: string;\n /** Event type */\n type: WebhookEventType;\n /** Event data */\n data: T;\n /** Created timestamp */\n created: Date;\n /** Provider type */\n provider: PaymentProviderType;\n /** Raw event data */\n raw: unknown;\n}\n\n/**\n * Webhook handler\n */\nexport type WebhookHandler<T = unknown> = (\n event: WebhookEvent<T>\n) => void | Promise<void>;\n\n// ============================================================================\n// Provider Interface\n// ============================================================================\n\n/**\n * Payment provider interface\n */\nexport interface PaymentProvider {\n /** Provider type */\n readonly type: PaymentProviderType;\n\n // Customer\n createCustomer(options: CreateCustomerOptions): Promise<Customer>;\n getCustomer(customerId: string): Promise<Customer | null>;\n updateCustomer(customerId: string, options: Partial<CreateCustomerOptions>): Promise<Customer>;\n deleteCustomer(customerId: string): Promise<void>;\n\n // Checkout\n createCheckout(options: CreateCheckoutOptions): Promise<CheckoutSession>;\n getCheckout(sessionId: string): Promise<CheckoutSession | null>;\n\n // Subscriptions\n createSubscription(options: CreateSubscriptionOptions): Promise<Subscription>;\n getSubscription(subscriptionId: string): Promise<Subscription | null>;\n updateSubscription(subscriptionId: string, options: UpdateSubscriptionOptions): Promise<Subscription>;\n cancelSubscription(subscriptionId: string, cancelAtPeriodEnd?: boolean): Promise<Subscription>;\n listSubscriptions(customerId: string): Promise<Subscription[]>;\n\n // Portal\n createPortalSession(options: CreatePortalOptions): Promise<PortalSession>;\n\n // Webhooks\n verifyWebhook(payload: string | Uint8Array, signature: string): Promise<WebhookEvent | null>;\n\n // Products & Prices (optional)\n getProduct?(productId: string): Promise<Product | null>;\n getPrice?(priceId: string): Promise<Price | null>;\n listPrices?(productId?: string): Promise<Price[]>;\n}\n\n// ============================================================================\n// Provider Config\n// ============================================================================\n\n/**\n * Stripe provider config\n */\nexport interface StripeProviderConfig {\n /** Stripe secret key */\n secretKey: string;\n /** Webhook signing secret */\n webhookSecret?: string | undefined;\n /** API version */\n apiVersion?: string | undefined;\n}\n\n/**\n * Paddle provider config\n */\nexport interface PaddleProviderConfig {\n /** Paddle API key */\n apiKey: string;\n /** Paddle environment */\n environment?: \"sandbox\" | \"production\" | undefined;\n /** Webhook secret key */\n webhookSecret?: string | undefined;\n /** Seller ID */\n sellerId?: string | undefined;\n}\n\n// ============================================================================\n// Service Config\n// ============================================================================\n\n/**\n * Payment service config\n */\nexport interface PaymentServiceConfig {\n /** Payment provider */\n provider: PaymentProvider;\n /** Enable debug logging */\n debug?: boolean | undefined;\n}\n\n// ============================================================================\n// Errors\n// ============================================================================\n\n/**\n * Payment error\n */\nexport class PaymentError extends Error {\n constructor(\n message: string,\n public readonly code: string,\n public readonly cause?: unknown\n ) {\n super(message);\n this.name = \"PaymentError\";\n }\n}\n\n/**\n * Common payment error codes\n */\nexport const PaymentErrorCodes = {\n INVALID_CONFIG: \"INVALID_CONFIG\",\n CUSTOMER_NOT_FOUND: \"CUSTOMER_NOT_FOUND\",\n SUBSCRIPTION_NOT_FOUND: \"SUBSCRIPTION_NOT_FOUND\",\n CHECKOUT_FAILED: \"CHECKOUT_FAILED\",\n PAYMENT_FAILED: \"PAYMENT_FAILED\",\n WEBHOOK_VERIFICATION_FAILED: \"WEBHOOK_VERIFICATION_FAILED\",\n API_ERROR: \"API_ERROR\",\n RATE_LIMITED: \"RATE_LIMITED\",\n} as const;\n","/**\n * @parsrun/payments - Stripe Provider\n * Edge-compatible Stripe provider using fetch API\n */\n\nimport type {\n CheckoutSession,\n CreateCheckoutOptions,\n CreateCustomerOptions,\n CreatePortalOptions,\n CreateSubscriptionOptions,\n Customer,\n PaymentProvider,\n PortalSession,\n Price,\n Product,\n StripeProviderConfig,\n Subscription,\n SubscriptionStatus,\n UpdateSubscriptionOptions,\n WebhookEvent,\n WebhookEventType,\n} from \"../types.js\";\nimport { PaymentError, PaymentErrorCodes } from \"../types.js\";\n\n/**\n * Stripe Payment Provider\n * Edge-compatible using fetch API\n *\n * @example\n * ```typescript\n * const stripe = new StripeProvider({\n * secretKey: process.env.STRIPE_SECRET_KEY,\n * webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,\n * });\n *\n * const checkout = await stripe.createCheckout({\n * lineItems: [{ priceId: 'price_xxx', quantity: 1 }],\n * successUrl: 'https://example.com/success',\n * cancelUrl: 'https://example.com/cancel',\n * mode: 'subscription',\n * });\n * ```\n */\nexport class StripeProvider implements PaymentProvider {\n readonly type = \"stripe\" as const;\n\n private secretKey: string;\n private webhookSecret: string | undefined;\n private baseUrl = \"https://api.stripe.com/v1\";\n private apiVersion: string;\n\n constructor(config: StripeProviderConfig) {\n this.secretKey = config.secretKey;\n this.webhookSecret = config.webhookSecret;\n this.apiVersion = config.apiVersion ?? \"2024-12-18.acacia\";\n }\n\n private async request<T>(\n endpoint: string,\n options: {\n method?: string;\n body?: Record<string, unknown>;\n } = {}\n ): Promise<T> {\n const { method = \"GET\", body } = options;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.secretKey}`,\n \"Stripe-Version\": this.apiVersion,\n };\n\n const fetchOptions: RequestInit = {\n method,\n headers,\n };\n\n if (body) {\n headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n fetchOptions.body = this.encodeFormData(body);\n }\n\n const response = await fetch(`${this.baseUrl}${endpoint}`, fetchOptions);\n\n const data = await response.json() as T & { error?: { message: string; type: string; code?: string } };\n\n if (!response.ok || data.error) {\n const errorMessage = data.error?.message ?? `HTTP ${response.status}`;\n throw new PaymentError(\n `Stripe API error: ${errorMessage}`,\n data.error?.code ?? PaymentErrorCodes.API_ERROR,\n data.error\n );\n }\n\n return data;\n }\n\n private encodeFormData(obj: Record<string, unknown>, prefix = \"\"): string {\n const parts: string[] = [];\n\n for (const [key, value] of Object.entries(obj)) {\n if (value === undefined || value === null) continue;\n\n const fullKey = prefix ? `${prefix}[${key}]` : key;\n\n if (typeof value === \"object\" && !Array.isArray(value)) {\n parts.push(this.encodeFormData(value as Record<string, unknown>, fullKey));\n } else if (Array.isArray(value)) {\n value.forEach((item, index) => {\n if (typeof item === \"object\") {\n parts.push(this.encodeFormData(item as Record<string, unknown>, `${fullKey}[${index}]`));\n } else {\n parts.push(`${encodeURIComponent(`${fullKey}[${index}]`)}=${encodeURIComponent(String(item))}`);\n }\n });\n } else {\n parts.push(`${encodeURIComponent(fullKey)}=${encodeURIComponent(String(value))}`);\n }\n }\n\n return parts.filter(Boolean).join(\"&\");\n }\n\n // ============================================================================\n // Customer\n // ============================================================================\n\n async createCustomer(options: CreateCustomerOptions): Promise<Customer> {\n const body: Record<string, unknown> = {\n email: options.email,\n };\n\n if (options.name) body[\"name\"] = options.name;\n if (options.phone) body[\"phone\"] = options.phone;\n if (options.metadata) body[\"metadata\"] = options.metadata;\n if (options.address) {\n body[\"address\"] = {\n line1: options.address.line1,\n line2: options.address.line2,\n city: options.address.city,\n state: options.address.state,\n postal_code: options.address.postalCode,\n country: options.address.country,\n };\n }\n\n const result = await this.request<StripeCustomer>(\"/customers\", {\n method: \"POST\",\n body,\n });\n\n return this.mapCustomer(result);\n }\n\n async getCustomer(customerId: string): Promise<Customer | null> {\n try {\n const result = await this.request<StripeCustomer>(`/customers/${customerId}`);\n return this.mapCustomer(result);\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"resource_missing\") {\n return null;\n }\n throw err;\n }\n }\n\n async updateCustomer(\n customerId: string,\n options: Partial<CreateCustomerOptions>\n ): Promise<Customer> {\n const body: Record<string, unknown> = {};\n\n if (options.email) body[\"email\"] = options.email;\n if (options.name) body[\"name\"] = options.name;\n if (options.phone) body[\"phone\"] = options.phone;\n if (options.metadata) body[\"metadata\"] = options.metadata;\n if (options.address) {\n body[\"address\"] = {\n line1: options.address.line1,\n line2: options.address.line2,\n city: options.address.city,\n state: options.address.state,\n postal_code: options.address.postalCode,\n country: options.address.country,\n };\n }\n\n const result = await this.request<StripeCustomer>(`/customers/${customerId}`, {\n method: \"POST\",\n body,\n });\n\n return this.mapCustomer(result);\n }\n\n async deleteCustomer(customerId: string): Promise<void> {\n await this.request(`/customers/${customerId}`, { method: \"DELETE\" });\n }\n\n private mapCustomer(stripe: StripeCustomer): Customer {\n return {\n id: stripe.id,\n email: stripe.email ?? \"\",\n name: stripe.name ?? undefined,\n phone: stripe.phone ?? undefined,\n address: stripe.address\n ? {\n line1: stripe.address.line1 ?? undefined,\n line2: stripe.address.line2 ?? undefined,\n city: stripe.address.city ?? undefined,\n state: stripe.address.state ?? undefined,\n postalCode: stripe.address.postal_code ?? undefined,\n country: stripe.address.country ?? undefined,\n }\n : undefined,\n metadata: stripe.metadata ?? undefined,\n providerData: stripe,\n };\n }\n\n // ============================================================================\n // Checkout\n // ============================================================================\n\n async createCheckout(options: CreateCheckoutOptions): Promise<CheckoutSession> {\n const body: Record<string, unknown> = {\n mode: options.mode,\n success_url: options.successUrl,\n cancel_url: options.cancelUrl,\n line_items: options.lineItems.map((item) => ({\n price: item.priceId,\n quantity: item.quantity,\n })),\n };\n\n if (options.customerId) body[\"customer\"] = options.customerId;\n if (options.customerEmail) body[\"customer_email\"] = options.customerEmail;\n if (options.allowPromotionCodes) body[\"allow_promotion_codes\"] = true;\n if (options.metadata) body[\"metadata\"] = options.metadata;\n\n if (options.mode === \"subscription\" && options.trialDays) {\n body[\"subscription_data\"] = {\n trial_period_days: options.trialDays,\n };\n }\n\n const result = await this.request<StripeCheckoutSession>(\"/checkout/sessions\", {\n method: \"POST\",\n body,\n });\n\n return this.mapCheckoutSession(result);\n }\n\n async getCheckout(sessionId: string): Promise<CheckoutSession | null> {\n try {\n const result = await this.request<StripeCheckoutSession>(\n `/checkout/sessions/${sessionId}`\n );\n return this.mapCheckoutSession(result);\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"resource_missing\") {\n return null;\n }\n throw err;\n }\n }\n\n private mapCheckoutSession(stripe: StripeCheckoutSession): CheckoutSession {\n return {\n id: stripe.id,\n url: stripe.url ?? \"\",\n customerId: stripe.customer ?? undefined,\n status: stripe.status as \"open\" | \"complete\" | \"expired\",\n mode: stripe.mode as \"payment\" | \"subscription\" | \"setup\",\n amountTotal: stripe.amount_total ?? undefined,\n currency: stripe.currency ?? undefined,\n providerData: stripe,\n };\n }\n\n // ============================================================================\n // Subscriptions\n // ============================================================================\n\n async createSubscription(options: CreateSubscriptionOptions): Promise<Subscription> {\n const body: Record<string, unknown> = {\n customer: options.customerId,\n items: [{ price: options.priceId }],\n };\n\n if (options.trialDays) body[\"trial_period_days\"] = options.trialDays;\n if (options.metadata) body[\"metadata\"] = options.metadata;\n if (options.paymentBehavior) body[\"payment_behavior\"] = options.paymentBehavior;\n\n const result = await this.request<StripeSubscription>(\"/subscriptions\", {\n method: \"POST\",\n body,\n });\n\n return this.mapSubscription(result);\n }\n\n async getSubscription(subscriptionId: string): Promise<Subscription | null> {\n try {\n const result = await this.request<StripeSubscription>(\n `/subscriptions/${subscriptionId}`\n );\n return this.mapSubscription(result);\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"resource_missing\") {\n return null;\n }\n throw err;\n }\n }\n\n async updateSubscription(\n subscriptionId: string,\n options: UpdateSubscriptionOptions\n ): Promise<Subscription> {\n const body: Record<string, unknown> = {};\n\n if (options.cancelAtPeriodEnd !== undefined) {\n body[\"cancel_at_period_end\"] = options.cancelAtPeriodEnd;\n }\n if (options.metadata) body[\"metadata\"] = options.metadata;\n if (options.prorationBehavior) body[\"proration_behavior\"] = options.prorationBehavior;\n\n // Price change requires updating subscription items\n if (options.priceId) {\n // Get current subscription to find item ID\n const current = await this.request<StripeSubscription>(\n `/subscriptions/${subscriptionId}`\n );\n const itemId = current.items.data[0]?.id;\n if (itemId) {\n body[\"items\"] = [{ id: itemId, price: options.priceId }];\n }\n }\n\n const result = await this.request<StripeSubscription>(\n `/subscriptions/${subscriptionId}`,\n { method: \"POST\", body }\n );\n\n return this.mapSubscription(result);\n }\n\n async cancelSubscription(\n subscriptionId: string,\n cancelAtPeriodEnd = true\n ): Promise<Subscription> {\n if (cancelAtPeriodEnd) {\n return this.updateSubscription(subscriptionId, { cancelAtPeriodEnd: true });\n }\n\n const result = await this.request<StripeSubscription>(\n `/subscriptions/${subscriptionId}`,\n { method: \"DELETE\" }\n );\n\n return this.mapSubscription(result);\n }\n\n async listSubscriptions(customerId: string): Promise<Subscription[]> {\n const result = await this.request<{ data: StripeSubscription[] }>(\n `/subscriptions?customer=${customerId}`\n );\n\n return result.data.map((sub) => this.mapSubscription(sub));\n }\n\n private mapSubscription(stripe: StripeSubscription): Subscription {\n const item = stripe.items.data[0];\n\n return {\n id: stripe.id,\n customerId: typeof stripe.customer === \"string\" ? stripe.customer : stripe.customer.id,\n status: stripe.status as SubscriptionStatus,\n priceId: item?.price.id ?? \"\",\n productId: typeof item?.price.product === \"string\" ? item.price.product : item?.price.product?.id,\n currentPeriodStart: new Date(stripe.current_period_start * 1000),\n currentPeriodEnd: new Date(stripe.current_period_end * 1000),\n cancelAtPeriodEnd: stripe.cancel_at_period_end,\n canceledAt: stripe.canceled_at ? new Date(stripe.canceled_at * 1000) : undefined,\n trialStart: stripe.trial_start ? new Date(stripe.trial_start * 1000) : undefined,\n trialEnd: stripe.trial_end ? new Date(stripe.trial_end * 1000) : undefined,\n metadata: stripe.metadata ?? undefined,\n providerData: stripe,\n };\n }\n\n // ============================================================================\n // Portal\n // ============================================================================\n\n async createPortalSession(options: CreatePortalOptions): Promise<PortalSession> {\n const result = await this.request<{ url: string }>(\"/billing_portal/sessions\", {\n method: \"POST\",\n body: {\n customer: options.customerId,\n return_url: options.returnUrl,\n },\n });\n\n return {\n url: result.url,\n returnUrl: options.returnUrl,\n };\n }\n\n // ============================================================================\n // Products & Prices\n // ============================================================================\n\n async getProduct(productId: string): Promise<Product | null> {\n try {\n const result = await this.request<StripeProduct>(`/products/${productId}`);\n return this.mapProduct(result);\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"resource_missing\") {\n return null;\n }\n throw err;\n }\n }\n\n async getPrice(priceId: string): Promise<Price | null> {\n try {\n const result = await this.request<StripePrice>(`/prices/${priceId}`);\n return this.mapPrice(result);\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"resource_missing\") {\n return null;\n }\n throw err;\n }\n }\n\n async listPrices(productId?: string): Promise<Price[]> {\n let endpoint = \"/prices?active=true&limit=100\";\n if (productId) {\n endpoint += `&product=${productId}`;\n }\n\n const result = await this.request<{ data: StripePrice[] }>(endpoint);\n return result.data.map((price) => this.mapPrice(price));\n }\n\n private mapProduct(stripe: StripeProduct): Product {\n return {\n id: stripe.id,\n name: stripe.name,\n description: stripe.description ?? undefined,\n active: stripe.active,\n metadata: stripe.metadata ?? undefined,\n providerData: stripe,\n };\n }\n\n private mapPrice(stripe: StripePrice): Price {\n return {\n id: stripe.id,\n productId: typeof stripe.product === \"string\" ? stripe.product : stripe.product.id,\n unitAmount: stripe.unit_amount ?? 0,\n currency: stripe.currency.toUpperCase(),\n recurring: stripe.recurring\n ? {\n interval: stripe.recurring.interval as \"day\" | \"week\" | \"month\" | \"year\",\n intervalCount: stripe.recurring.interval_count,\n }\n : undefined,\n active: stripe.active,\n metadata: stripe.metadata ?? undefined,\n providerData: stripe,\n };\n }\n\n // ============================================================================\n // Webhooks\n // ============================================================================\n\n async verifyWebhook(\n payload: string | Uint8Array,\n signature: string\n ): Promise<WebhookEvent | null> {\n if (!this.webhookSecret) {\n throw new PaymentError(\n \"Webhook secret not configured\",\n PaymentErrorCodes.INVALID_CONFIG\n );\n }\n\n const payloadString = typeof payload === \"string\" ? payload : new TextDecoder().decode(payload);\n\n // Parse signature header\n const signatureParts = signature.split(\",\").reduce((acc, part) => {\n const [key, value] = part.split(\"=\");\n if (key && value) {\n acc[key] = value;\n }\n return acc;\n }, {} as Record<string, string>);\n\n const timestamp = signatureParts[\"t\"];\n const expectedSignature = signatureParts[\"v1\"];\n\n if (!timestamp || !expectedSignature) {\n return null;\n }\n\n // Check timestamp (within 5 minutes)\n const timestampSeconds = parseInt(timestamp, 10);\n const now = Math.floor(Date.now() / 1000);\n if (Math.abs(now - timestampSeconds) > 300) {\n return null;\n }\n\n // Compute expected signature\n const signedPayload = `${timestamp}.${payloadString}`;\n const computedSignature = await this.computeHmacSignature(\n signedPayload,\n this.webhookSecret\n );\n\n // Constant-time comparison\n if (!this.secureCompare(computedSignature, expectedSignature)) {\n return null;\n }\n\n // Parse event\n const event = JSON.parse(payloadString) as StripeWebhookEvent;\n\n return {\n id: event.id,\n type: this.mapEventType(event.type),\n data: event.data.object,\n created: new Date(event.created * 1000),\n provider: \"stripe\",\n raw: event,\n };\n }\n\n private async computeHmacSignature(payload: string, secret: string): Promise<string> {\n const encoder = new TextEncoder();\n const keyData = encoder.encode(secret);\n const messageData = encoder.encode(payload);\n\n const cryptoKey = await crypto.subtle.importKey(\n \"raw\",\n keyData,\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n\n const signature = await crypto.subtle.sign(\"HMAC\", cryptoKey, messageData);\n const signatureArray = new Uint8Array(signature);\n\n return Array.from(signatureArray)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n }\n\n private secureCompare(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n }\n\n private mapEventType(stripeType: string): WebhookEventType {\n const mapping: Record<string, WebhookEventType> = {\n \"checkout.session.completed\": \"checkout.session.completed\",\n \"checkout.session.expired\": \"checkout.session.expired\",\n \"customer.created\": \"customer.created\",\n \"customer.updated\": \"customer.updated\",\n \"customer.deleted\": \"customer.deleted\",\n \"customer.subscription.created\": \"subscription.created\",\n \"customer.subscription.updated\": \"subscription.updated\",\n \"customer.subscription.deleted\": \"subscription.deleted\",\n \"customer.subscription.trial_will_end\": \"subscription.trial_will_end\",\n \"payment_intent.succeeded\": \"payment.succeeded\",\n \"payment_intent.payment_failed\": \"payment.failed\",\n \"invoice.created\": \"invoice.created\",\n \"invoice.paid\": \"invoice.paid\",\n \"invoice.payment_failed\": \"invoice.payment_failed\",\n \"invoice.upcoming\": \"invoice.upcoming\",\n \"charge.refunded\": \"refund.created\",\n \"refund.created\": \"refund.created\",\n \"refund.updated\": \"refund.updated\",\n };\n\n return mapping[stripeType] ?? (\"unknown\" as WebhookEventType);\n }\n\n // ============================================================================\n // Usage Reporting (Metered Billing)\n // ============================================================================\n\n /**\n * Report usage for metered billing\n *\n * @example\n * ```typescript\n * // Report 100 API calls for a subscription item\n * await stripe.reportUsage({\n * subscriptionItemId: \"si_xxx\",\n * quantity: 100,\n * action: \"increment\", // or \"set\" to replace\n * });\n * ```\n */\n async reportUsage(record: {\n subscriptionItemId: string;\n quantity: number;\n timestamp?: Date;\n action?: \"increment\" | \"set\";\n idempotencyKey?: string;\n }): Promise<void> {\n const body: Record<string, unknown> = {\n quantity: record.quantity,\n action: record.action ?? \"increment\",\n };\n\n if (record.timestamp) {\n body[\"timestamp\"] = Math.floor(record.timestamp.getTime() / 1000);\n }\n\n const headers: Record<string, string> = {};\n if (record.idempotencyKey) {\n headers[\"Idempotency-Key\"] = record.idempotencyKey;\n }\n\n await this.request<StripeUsageRecord>(\n `/subscription_items/${record.subscriptionItemId}/usage_records`,\n {\n method: \"POST\",\n body,\n }\n );\n }\n\n /**\n * Report multiple usage records (batch)\n * Note: Stripe doesn't have a batch API, so this is sequential\n */\n async reportUsageBatch(records: Array<{\n subscriptionItemId: string;\n quantity: number;\n timestamp?: Date;\n action?: \"increment\" | \"set\";\n idempotencyKey?: string;\n }>): Promise<void> {\n for (const record of records) {\n await this.reportUsage(record);\n }\n }\n\n /**\n * Get subscription item ID for a subscription and price\n */\n async getSubscriptionItemId(\n subscriptionId: string,\n priceId: string\n ): Promise<string | null> {\n const subscription = await this.request<StripeSubscription>(\n `/subscriptions/${subscriptionId}`\n );\n\n const item = subscription.items.data.find((i) => i.price.id === priceId);\n return item?.id ?? null;\n }\n\n /**\n * Get usage records for a subscription item\n */\n async getUsageRecords(\n subscriptionItemId: string,\n options?: {\n startingAfter?: string;\n endingBefore?: string;\n limit?: number;\n }\n ): Promise<{\n data: Array<{\n id: string;\n quantity: number;\n timestamp: Date;\n subscriptionItem: string;\n }>;\n hasMore: boolean;\n }> {\n let endpoint = `/subscription_items/${subscriptionItemId}/usage_record_summaries?`;\n\n if (options?.limit) {\n endpoint += `limit=${options.limit}&`;\n }\n if (options?.startingAfter) {\n endpoint += `starting_after=${options.startingAfter}&`;\n }\n if (options?.endingBefore) {\n endpoint += `ending_before=${options.endingBefore}&`;\n }\n\n const result = await this.request<{\n data: StripeUsageRecordSummary[];\n has_more: boolean;\n }>(endpoint);\n\n return {\n data: result.data.map((r) => ({\n id: r.id,\n quantity: r.total_usage,\n timestamp: new Date(r.period.start * 1000),\n subscriptionItem: r.subscription_item,\n })),\n hasMore: result.has_more,\n };\n }\n\n /**\n * Get current period usage total for a subscription item\n */\n async getCurrentUsage(subscriptionItemId: string): Promise<number> {\n const result = await this.getUsageRecords(subscriptionItemId, { limit: 1 });\n return result.data[0]?.quantity ?? 0;\n }\n}\n\n// ============================================================================\n// Stripe API Types\n// ============================================================================\n\ninterface StripeCustomer {\n id: string;\n email: string | null;\n name: string | null;\n phone: string | null;\n address: {\n line1: string | null;\n line2: string | null;\n city: string | null;\n state: string | null;\n postal_code: string | null;\n country: string | null;\n } | null;\n metadata: Record<string, string> | null;\n}\n\ninterface StripeCheckoutSession {\n id: string;\n url: string | null;\n customer: string | null;\n status: string;\n mode: string;\n amount_total: number | null;\n currency: string | null;\n}\n\ninterface StripeSubscription {\n id: string;\n customer: string | { id: string };\n status: string;\n items: {\n data: Array<{\n id: string;\n price: StripePrice;\n }>;\n };\n current_period_start: number;\n current_period_end: number;\n cancel_at_period_end: boolean;\n canceled_at: number | null;\n trial_start: number | null;\n trial_end: number | null;\n metadata: Record<string, string> | null;\n}\n\ninterface StripeProduct {\n id: string;\n name: string;\n description: string | null;\n active: boolean;\n metadata: Record<string, string> | null;\n}\n\ninterface StripePrice {\n id: string;\n product: string | { id: string };\n unit_amount: number | null;\n currency: string;\n recurring: {\n interval: string;\n interval_count: number;\n } | null;\n active: boolean;\n metadata: Record<string, string> | null;\n}\n\ninterface StripeWebhookEvent {\n id: string;\n type: string;\n created: number;\n data: {\n object: unknown;\n };\n}\n\ninterface StripeUsageRecord {\n id: string;\n object: \"usage_record\";\n quantity: number;\n subscription_item: string;\n timestamp: number;\n}\n\ninterface StripeUsageRecordSummary {\n id: string;\n object: \"usage_record_summary\";\n invoice: string | null;\n period: {\n start: number;\n end: number;\n };\n subscription_item: string;\n total_usage: number;\n}\n\n/**\n * Create a Stripe provider\n */\nexport function createStripeProvider(config: StripeProviderConfig): StripeProvider {\n return new StripeProvider(config);\n}\n","/**\n * @parsrun/payments - Paddle Provider\n * Edge-compatible Paddle provider using fetch API (Paddle Billing API v2)\n */\n\nimport type {\n CheckoutSession,\n CreateCheckoutOptions,\n CreateCustomerOptions,\n CreatePortalOptions,\n CreateSubscriptionOptions,\n Customer,\n PaddleProviderConfig,\n PaymentProvider,\n PortalSession,\n Price,\n Product,\n Subscription,\n SubscriptionStatus,\n UpdateSubscriptionOptions,\n WebhookEvent,\n WebhookEventType,\n} from \"../types.js\";\nimport { PaymentError, PaymentErrorCodes } from \"../types.js\";\n\n/**\n * Paddle Payment Provider\n * Edge-compatible using fetch API (Paddle Billing API v2)\n *\n * @example\n * ```typescript\n * const paddle = new PaddleProvider({\n * apiKey: process.env.PADDLE_API_KEY,\n * environment: 'sandbox', // or 'production'\n * webhookSecret: process.env.PADDLE_WEBHOOK_SECRET,\n * });\n *\n * const checkout = await paddle.createCheckout({\n * lineItems: [{ priceId: 'pri_xxx', quantity: 1 }],\n * successUrl: 'https://example.com/success',\n * cancelUrl: 'https://example.com/cancel',\n * mode: 'subscription',\n * });\n * ```\n */\nexport class PaddleProvider implements PaymentProvider {\n readonly type = \"paddle\" as const;\n\n private apiKey: string;\n private webhookSecret: string | undefined;\n private baseUrl: string;\n\n constructor(config: PaddleProviderConfig) {\n this.apiKey = config.apiKey;\n this.webhookSecret = config.webhookSecret;\n this.baseUrl =\n config.environment === \"production\"\n ? \"https://api.paddle.com\"\n : \"https://sandbox-api.paddle.com\";\n }\n\n private async request<T>(\n endpoint: string,\n options: {\n method?: string;\n body?: Record<string, unknown>;\n } = {}\n ): Promise<T> {\n const { method = \"GET\", body } = options;\n\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n \"Content-Type\": \"application/json\",\n };\n\n const fetchOptions: RequestInit = {\n method,\n headers,\n };\n\n if (body) {\n fetchOptions.body = JSON.stringify(body);\n }\n\n const response = await fetch(`${this.baseUrl}${endpoint}`, fetchOptions);\n\n const data = await response.json() as {\n data?: T;\n error?: { type: string; code: string; detail: string };\n };\n\n if (!response.ok || data.error) {\n const errorMessage = data.error?.detail ?? `HTTP ${response.status}`;\n throw new PaymentError(\n `Paddle API error: ${errorMessage}`,\n data.error?.code ?? PaymentErrorCodes.API_ERROR,\n data.error\n );\n }\n\n return data.data as T;\n }\n\n // ============================================================================\n // Customer\n // ============================================================================\n\n async createCustomer(options: CreateCustomerOptions): Promise<Customer> {\n const body: Record<string, unknown> = {\n email: options.email,\n };\n\n if (options.name) body[\"name\"] = options.name;\n if (options.metadata) body[\"custom_data\"] = options.metadata;\n\n const result = await this.request<PaddleCustomer>(\"/customers\", {\n method: \"POST\",\n body,\n });\n\n return this.mapCustomer(result);\n }\n\n async getCustomer(customerId: string): Promise<Customer | null> {\n try {\n const result = await this.request<PaddleCustomer>(`/customers/${customerId}`);\n return this.mapCustomer(result);\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"not_found\") {\n return null;\n }\n throw err;\n }\n }\n\n async updateCustomer(\n customerId: string,\n options: Partial<CreateCustomerOptions>\n ): Promise<Customer> {\n const body: Record<string, unknown> = {};\n\n if (options.email) body[\"email\"] = options.email;\n if (options.name) body[\"name\"] = options.name;\n if (options.metadata) body[\"custom_data\"] = options.metadata;\n\n const result = await this.request<PaddleCustomer>(`/customers/${customerId}`, {\n method: \"PATCH\",\n body,\n });\n\n return this.mapCustomer(result);\n }\n\n async deleteCustomer(_customerId: string): Promise<void> {\n // Paddle doesn't support customer deletion via API\n // Customers can only be archived\n throw new PaymentError(\n \"Paddle does not support customer deletion\",\n PaymentErrorCodes.API_ERROR\n );\n }\n\n private mapCustomer(paddle: PaddleCustomer): Customer {\n return {\n id: paddle.id,\n email: paddle.email,\n name: paddle.name ?? undefined,\n metadata: paddle.custom_data ?? undefined,\n providerData: paddle,\n };\n }\n\n // ============================================================================\n // Checkout\n // ============================================================================\n\n async createCheckout(options: CreateCheckoutOptions): Promise<CheckoutSession> {\n const items = options.lineItems.map((item) => ({\n price_id: item.priceId,\n quantity: item.quantity,\n }));\n\n const body: Record<string, unknown> = {\n items,\n };\n\n if (options.customerId) body[\"customer_id\"] = options.customerId;\n if (options.customerEmail) {\n body[\"customer\"] = { email: options.customerEmail };\n }\n if (options.metadata) body[\"custom_data\"] = options.metadata;\n\n // Paddle handles return URLs differently - they're configured in dashboard\n // or passed as settings\n body[\"settings\"] = {\n success_url: options.successUrl,\n };\n\n const result = await this.request<PaddleTransaction>(\"/transactions\", {\n method: \"POST\",\n body,\n });\n\n return {\n id: result.id,\n url: result.checkout?.url ?? \"\",\n customerId: result.customer_id ?? undefined,\n status: result.status === \"completed\" ? \"complete\" : \"open\",\n mode: result.subscription_id ? \"subscription\" : \"payment\",\n amountTotal: this.parsePaddleAmount(result.details?.totals?.total),\n currency: result.currency_code,\n providerData: result,\n };\n }\n\n async getCheckout(sessionId: string): Promise<CheckoutSession | null> {\n try {\n const result = await this.request<PaddleTransaction>(`/transactions/${sessionId}`);\n\n return {\n id: result.id,\n url: result.checkout?.url ?? \"\",\n customerId: result.customer_id ?? undefined,\n status: result.status === \"completed\" ? \"complete\" : \"open\",\n mode: result.subscription_id ? \"subscription\" : \"payment\",\n amountTotal: this.parsePaddleAmount(result.details?.totals?.total),\n currency: result.currency_code,\n providerData: result,\n };\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"not_found\") {\n return null;\n }\n throw err;\n }\n }\n\n // ============================================================================\n // Subscriptions\n // ============================================================================\n\n async createSubscription(_options: CreateSubscriptionOptions): Promise<Subscription> {\n // Paddle subscriptions are created through the checkout flow\n // Direct subscription creation is not supported\n throw new PaymentError(\n \"Paddle subscriptions must be created through checkout\",\n PaymentErrorCodes.API_ERROR\n );\n }\n\n async getSubscription(subscriptionId: string): Promise<Subscription | null> {\n try {\n const result = await this.request<PaddleSubscription>(\n `/subscriptions/${subscriptionId}`\n );\n return this.mapSubscription(result);\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"not_found\") {\n return null;\n }\n throw err;\n }\n }\n\n async updateSubscription(\n subscriptionId: string,\n options: UpdateSubscriptionOptions\n ): Promise<Subscription> {\n const body: Record<string, unknown> = {};\n\n if (options.priceId) {\n body[\"items\"] = [{ price_id: options.priceId, quantity: 1 }];\n }\n if (options.metadata) body[\"custom_data\"] = options.metadata;\n if (options.prorationBehavior) {\n body[\"proration_billing_mode\"] =\n options.prorationBehavior === \"none\" ? \"do_not_bill\" : \"prorated_immediately\";\n }\n\n const result = await this.request<PaddleSubscription>(\n `/subscriptions/${subscriptionId}`,\n { method: \"PATCH\", body }\n );\n\n return this.mapSubscription(result);\n }\n\n async cancelSubscription(\n subscriptionId: string,\n cancelAtPeriodEnd = true\n ): Promise<Subscription> {\n const body: Record<string, unknown> = {\n effective_from: cancelAtPeriodEnd ? \"next_billing_period\" : \"immediately\",\n };\n\n const result = await this.request<PaddleSubscription>(\n `/subscriptions/${subscriptionId}/cancel`,\n { method: \"POST\", body }\n );\n\n return this.mapSubscription(result);\n }\n\n async listSubscriptions(customerId: string): Promise<Subscription[]> {\n const result = await this.request<PaddleSubscription[]>(\n `/subscriptions?customer_id=${customerId}`\n );\n\n return result.map((sub) => this.mapSubscription(sub));\n }\n\n private mapSubscription(paddle: PaddleSubscription): Subscription {\n const item = paddle.items?.[0];\n\n const statusMap: Record<string, SubscriptionStatus> = {\n active: \"active\",\n canceled: \"canceled\",\n past_due: \"past_due\",\n paused: \"paused\",\n trialing: \"trialing\",\n };\n\n return {\n id: paddle.id,\n customerId: paddle.customer_id,\n status: statusMap[paddle.status] ?? \"active\",\n priceId: item?.price?.id ?? \"\",\n productId: item?.price?.product_id,\n currentPeriodStart: new Date(paddle.current_billing_period?.starts_at ?? Date.now()),\n currentPeriodEnd: new Date(paddle.current_billing_period?.ends_at ?? Date.now()),\n cancelAtPeriodEnd: paddle.scheduled_change?.action === \"cancel\",\n canceledAt: paddle.canceled_at ? new Date(paddle.canceled_at) : undefined,\n trialStart: paddle.started_at ? new Date(paddle.started_at) : undefined,\n trialEnd: paddle.first_billed_at ? new Date(paddle.first_billed_at) : undefined,\n metadata: paddle.custom_data ?? undefined,\n providerData: paddle,\n };\n }\n\n // ============================================================================\n // Portal\n // ============================================================================\n\n async createPortalSession(options: CreatePortalOptions): Promise<PortalSession> {\n // Paddle uses customer portal links that are generated per customer\n // Get customer to retrieve portal session\n const customer = await this.getCustomer(options.customerId);\n if (!customer) {\n throw new PaymentError(\n \"Customer not found\",\n PaymentErrorCodes.CUSTOMER_NOT_FOUND\n );\n }\n\n // In Paddle Billing, you need to create a portal session\n // This creates a session link for the customer portal\n const result = await this.request<{ urls: { general: { overview: string } } }>(\n `/customers/${options.customerId}/portal-sessions`,\n { method: \"POST\" }\n );\n\n return {\n url: result.urls.general.overview,\n returnUrl: options.returnUrl,\n };\n }\n\n // ============================================================================\n // Products & Prices\n // ============================================================================\n\n async getProduct(productId: string): Promise<Product | null> {\n try {\n const result = await this.request<PaddleProduct>(`/products/${productId}`);\n return this.mapProduct(result);\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"not_found\") {\n return null;\n }\n throw err;\n }\n }\n\n async getPrice(priceId: string): Promise<Price | null> {\n try {\n const result = await this.request<PaddlePrice>(`/prices/${priceId}`);\n return this.mapPrice(result);\n } catch (err) {\n if (err instanceof PaymentError && err.code === \"not_found\") {\n return null;\n }\n throw err;\n }\n }\n\n async listPrices(productId?: string): Promise<Price[]> {\n let endpoint = \"/prices?status=active\";\n if (productId) {\n endpoint += `&product_id=${productId}`;\n }\n\n const result = await this.request<PaddlePrice[]>(endpoint);\n return result.map((price) => this.mapPrice(price));\n }\n\n private mapProduct(paddle: PaddleProduct): Product {\n return {\n id: paddle.id,\n name: paddle.name,\n description: paddle.description ?? undefined,\n active: paddle.status === \"active\",\n metadata: paddle.custom_data ?? undefined,\n providerData: paddle,\n };\n }\n\n private mapPrice(paddle: PaddlePrice): Price {\n const amount = paddle.unit_price?.amount\n ? parseInt(paddle.unit_price.amount, 10)\n : 0;\n\n return {\n id: paddle.id,\n productId: paddle.product_id,\n unitAmount: amount,\n currency: paddle.unit_price?.currency_code ?? \"USD\",\n recurring: paddle.billing_cycle\n ? {\n interval: paddle.billing_cycle.interval as \"day\" | \"week\" | \"month\" | \"year\",\n intervalCount: paddle.billing_cycle.frequency,\n }\n : undefined,\n active: paddle.status === \"active\",\n metadata: paddle.custom_data ?? undefined,\n providerData: paddle,\n };\n }\n\n private parsePaddleAmount(amount?: string): number | undefined {\n if (!amount) return undefined;\n return parseInt(amount, 10);\n }\n\n // ============================================================================\n // Webhooks\n // ============================================================================\n\n async verifyWebhook(\n payload: string | Uint8Array,\n signature: string\n ): Promise<WebhookEvent | null> {\n if (!this.webhookSecret) {\n throw new PaymentError(\n \"Webhook secret not configured\",\n PaymentErrorCodes.INVALID_CONFIG\n );\n }\n\n const payloadString = typeof payload === \"string\" ? payload : new TextDecoder().decode(payload);\n\n // Parse Paddle signature header (ts=xxx;h1=xxx)\n const signatureParts = signature.split(\";\").reduce((acc, part) => {\n const [key, value] = part.split(\"=\");\n if (key && value) {\n acc[key] = value;\n }\n return acc;\n }, {} as Record<string, string>);\n\n const timestamp = signatureParts[\"ts\"];\n const expectedSignature = signatureParts[\"h1\"];\n\n if (!timestamp || !expectedSignature) {\n return null;\n }\n\n // Compute expected signature\n const signedPayload = `${timestamp}:${payloadString}`;\n const computedSignature = await this.computeHmacSignature(\n signedPayload,\n this.webhookSecret\n );\n\n // Constant-time comparison\n if (!this.secureCompare(computedSignature, expectedSignature)) {\n return null;\n }\n\n // Parse event\n const event = JSON.parse(payloadString) as PaddleWebhookEvent;\n\n return {\n id: event.event_id,\n type: this.mapEventType(event.event_type),\n data: event.data,\n created: new Date(event.occurred_at),\n provider: \"paddle\",\n raw: event,\n };\n }\n\n private async computeHmacSignature(payload: string, secret: string): Promise<string> {\n const encoder = new TextEncoder();\n const keyData = encoder.encode(secret);\n const messageData = encoder.encode(payload);\n\n const cryptoKey = await crypto.subtle.importKey(\n \"raw\",\n keyData,\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"]\n );\n\n const signature = await crypto.subtle.sign(\"HMAC\", cryptoKey, messageData);\n const signatureArray = new Uint8Array(signature);\n\n return Array.from(signatureArray)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n }\n\n private secureCompare(a: string, b: string): boolean {\n if (a.length !== b.length) return false;\n\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n }\n\n private mapEventType(paddleType: string): WebhookEventType {\n const mapping: Record<string, WebhookEventType> = {\n \"transaction.completed\": \"checkout.session.completed\",\n \"customer.created\": \"customer.created\",\n \"customer.updated\": \"customer.updated\",\n \"subscription.created\": \"subscription.created\",\n \"subscription.updated\": \"subscription.updated\",\n \"subscription.canceled\": \"subscription.deleted\",\n \"subscription.past_due\": \"subscription.updated\",\n \"subscription.activated\": \"subscription.created\",\n \"transaction.payment_failed\": \"payment.failed\",\n \"adjustment.created\": \"refund.created\",\n };\n\n return mapping[paddleType] ?? (\"unknown\" as WebhookEventType);\n }\n}\n\n// ============================================================================\n// Paddle API Types\n// ============================================================================\n\ninterface PaddleCustomer {\n id: string;\n email: string;\n name: string | null;\n custom_data: Record<string, string> | null;\n}\n\ninterface PaddleTransaction {\n id: string;\n status: string;\n customer_id: string | null;\n subscription_id: string | null;\n currency_code: string;\n checkout?: {\n url: string;\n };\n details?: {\n totals?: {\n total: string;\n };\n };\n}\n\ninterface PaddleSubscription {\n id: string;\n customer_id: string;\n status: string;\n items?: Array<{\n price: {\n id: string;\n product_id: string;\n };\n }>;\n current_billing_period?: {\n starts_at: string;\n ends_at: string;\n };\n scheduled_change?: {\n action: string;\n };\n started_at: string | null;\n first_billed_at: string | null;\n canceled_at: string | null;\n custom_data: Record<string, string> | null;\n}\n\ninterface PaddleProduct {\n id: string;\n name: string;\n description: string | null;\n status: string;\n custom_data: Record<string, string> | null;\n}\n\ninterface PaddlePrice {\n id: string;\n product_id: string;\n status: string;\n unit_price?: {\n amount: string;\n currency_code: string;\n };\n billing_cycle?: {\n interval: string;\n frequency: number;\n };\n custom_data: Record<string, string> | null;\n}\n\ninterface PaddleWebhookEvent {\n event_id: string;\n event_type: string;\n occurred_at: string;\n data: unknown;\n}\n\n/**\n * Create a Paddle provider\n */\nexport function createPaddleProvider(config: PaddleProviderConfig): PaddleProvider {\n return new PaddleProvider(config);\n}\n","/**\n * @parsrun/payments - iyzico Provider\n * Edge-compatible iyzico provider using fetch API\n */\n\nimport type {\n CheckoutSession,\n CreateCheckoutOptions,\n CreateCustomerOptions,\n CreatePortalOptions,\n CreateSubscriptionOptions,\n Customer,\n PaymentProvider,\n PortalSession,\n Subscription,\n UpdateSubscriptionOptions,\n WebhookEvent,\n WebhookEventType,\n} from \"../types.js\";\nimport { PaymentError, PaymentErrorCodes } from \"../types.js\";\n\n/**\n * iyzico provider config\n */\nexport interface IyzicoProviderConfig {\n /** iyzico API key */\n apiKey: string;\n /** iyzico secret key */\n secretKey: string;\n /** Environment */\n environment?: \"sandbox\" | \"production\" | undefined;\n /** Base URL override */\n baseUrl?: string | undefined;\n}\n\n/**\n * iyzico basket item\n */\nexport interface IyzicoBasketItem {\n id: string;\n name: string;\n category1: string;\n category2?: string | undefined;\n itemType: \"PHYSICAL\" | \"VIRTUAL\";\n price: string; // Decimal string like \"1.0\"\n}\n\n/**\n * iyzico buyer info\n */\nexport interface IyzicoBuyer {\n id: string;\n name: string;\n surname: string;\n email: string;\n gsmNumber?: string | undefined;\n identityNumber: string;\n registrationAddress: string;\n city: string;\n country: string;\n ip: string;\n}\n\n/**\n * iyzico address\n */\nexport interface IyzicoAddress {\n contactName: string;\n city: string;\n country: string;\n address: string;\n}\n\n/**\n * Extended checkout options for iyzico\n */\nexport interface IyzicoCheckoutOptions extends CreateCheckoutOptions {\n /** Buyer information (required for iyzico) */\n buyer: IyzicoBuyer;\n /** Billing address */\n billingAddress: IyzicoAddress;\n /** Shipping address */\n shippingAddress: IyzicoAddress;\n /** Basket items */\n basketItems: IyzicoBasketItem[];\n /** Price (total amount as decimal string) */\n price: string;\n /** Paid price (can include installment fees) */\n paidPrice: string;\n /** Currency (TRY, USD, EUR, GBP, IRR) */\n currency: \"TRY\" | \"USD\" | \"EUR\" | \"GBP\" | \"IRR\";\n /** Installment options */\n enabledInstallments?: number[] | undefined;\n /** Force 3D Secure */\n force3ds?: boolean | undefined;\n /** Conversation ID for tracking */\n conversationId?: string | undefined;\n}\n\n/**\n * iyzico Payment Provider\n * Edge-compatible using fetch API\n *\n * @example\n * ```typescript\n * const iyzico = new IyzicoProvider({\n * apiKey: process.env.IYZICO_API_KEY,\n * secretKey: process.env.IYZICO_SECRET_KEY,\n * environment: 'sandbox',\n * });\n *\n * const checkout = await iyzico.createCheckoutForm({\n * price: '100.00',\n * paidPrice: '100.00',\n * currency: 'TRY',\n * basketItems: [...],\n * buyer: {...},\n * billingAddress: {...},\n * shippingAddress: {...},\n * callbackUrl: 'https://example.com/callback',\n * });\n * ```\n */\nexport class IyzicoProvider implements PaymentProvider {\n readonly type = \"iyzico\" as const;\n\n private apiKey: string;\n private secretKey: string;\n private baseUrl: string;\n\n constructor(config: IyzicoProviderConfig) {\n this.apiKey = config.apiKey;\n this.secretKey = config.secretKey;\n this.baseUrl =\n config.baseUrl ??\n (config.environment === \"production\"\n ? \"https://api.iyzipay.com\"\n : \"https://sandbox-api.iyzipay.com\");\n }\n\n private async request<T>(\n endpoint: string,\n body: Record<string, unknown>\n ): Promise<T> {\n const randomString = this.generateRandomString(8);\n\n // Generate authorization header\n const authorizationString = await this.generateAuthorizationString(\n body,\n randomString\n );\n\n const response = await fetch(`${this.baseUrl}${endpoint}`, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n \"Content-Type\": \"application/json\",\n Authorization: authorizationString,\n \"x-iyzi-rnd\": randomString,\n },\n body: JSON.stringify(body),\n });\n\n const data = (await response.json()) as IyzicoResponse & T;\n\n if (data.status !== \"success\") {\n throw new PaymentError(\n `iyzico API error: ${data.errorMessage ?? \"Unknown error\"}`,\n data.errorCode ?? PaymentErrorCodes.API_ERROR,\n data\n );\n }\n\n return data as T;\n }\n\n private generateRandomString(length: number): string {\n const chars = \"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n let result = \"\";\n const randomValues = new Uint8Array(length);\n crypto.getRandomValues(randomValues);\n for (let i = 0; i < length; i++) {\n const randomValue = randomValues[i];\n if (randomValue !== undefined) {\n result += chars[randomValue % chars.length];\n }\n }\n return result;\n }\n\n private async generateAuthorizationString(\n body: Record<string, unknown>,\n randomString: string\n ): Promise<string> {\n // Sort and flatten the body for PKI string\n const pkiString = this.generatePkiString(body);\n\n // Create hash string\n const hashString = `${this.apiKey}${randomString}${this.secretKey}${pkiString}`;\n\n // SHA256 hash\n const encoder = new TextEncoder();\n const data = encoder.encode(hashString);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n const hashArray = new Uint8Array(hashBuffer);\n const hashBase64 = btoa(String.fromCharCode(...hashArray));\n\n // Create authorization\n const authorizationString = `${this.apiKey}:${hashBase64}`;\n const authorizationBase64 = btoa(authorizationString);\n\n return `IYZWS ${authorizationBase64}`;\n }\n\n private generatePkiString(obj: Record<string, unknown>): string {\n const parts: string[] = [];\n\n for (const [key, value] of Object.entries(obj)) {\n if (value === undefined || value === null) continue;\n\n if (Array.isArray(value)) {\n const arrayParts = value.map((item) => {\n if (typeof item === \"object\" && item !== null) {\n return this.generatePkiString(item as Record<string, unknown>);\n }\n return String(item);\n });\n parts.push(`${key}=[${arrayParts.join(\", \")}]`);\n } else if (typeof value === \"object\") {\n parts.push(\n `${key}=[${this.generatePkiString(value as Record<string, unknown>)}]`\n );\n } else {\n parts.push(`${key}=${value}`);\n }\n }\n\n return `[${parts.join(\",\")}]`;\n }\n\n // ============================================================================\n // Customer - iyzico uses buyer info per transaction, not stored customers\n // ============================================================================\n\n async createCustomer(_options: CreateCustomerOptions): Promise<Customer> {\n // iyzico doesn't have a separate customer API\n // Customers are identified by buyer info in each transaction\n throw new PaymentError(\n \"iyzico does not support stored customers. Use buyer info in checkout.\",\n PaymentErrorCodes.API_ERROR\n );\n }\n\n async getCustomer(_customerId: string): Promise<Customer | null> {\n return null;\n }\n\n async updateCustomer(\n _customerId: string,\n _options: Partial<CreateCustomerOptions>\n ): Promise<Customer> {\n throw new PaymentError(\n \"iyzico does not support stored customers\",\n PaymentErrorCodes.API_ERROR\n );\n }\n\n async deleteCustomer(_customerId: string): Promise<void> {\n throw new PaymentError(\n \"iyzico does not support stored customers\",\n PaymentErrorCodes.API_ERROR\n );\n }\n\n // ============================================================================\n // Checkout\n // ============================================================================\n\n async createCheckout(_options: CreateCheckoutOptions): Promise<CheckoutSession> {\n // For standard createCheckout, we need extended options\n throw new PaymentError(\n \"Use createCheckoutForm() with IyzicoCheckoutOptions for iyzico\",\n PaymentErrorCodes.INVALID_CONFIG\n );\n }\n\n /**\n * Create iyzico checkout form (iframe/popup)\n */\n async createCheckoutForm(options: IyzicoCheckoutOptions): Promise<IyzicoCheckoutResult> {\n const body: Record<string, unknown> = {\n locale: \"tr\",\n conversationId: options.conversationId ?? this.generateRandomString(16),\n price: options.price,\n paidPrice: options.paidPrice,\n currency: options.currency,\n basketId: options.metadata?.[\"basketId\"] ?? this.generateRandomString(16),\n paymentGroup: \"PRODUCT\",\n callbackUrl: options.successUrl,\n buyer: {\n id: options.buyer.id,\n name: options.buyer.name,\n surname: options.buyer.surname,\n gsmNumber: options.buyer.gsmNumber,\n email: options.buyer.email,\n identityNumber: options.buyer.identityNumber,\n registrationAddress: options.buyer.registrationAddress,\n ip: options.buyer.ip,\n city: options.buyer.city,\n country: options.buyer.country,\n },\n shippingAddress: {\n contactName: options.shippingAddress.contactName,\n city: options.shippingAddress.city,\n country: options.shippingAddress.country,\n address: options.shippingAddress.address,\n },\n billingAddress: {\n contactName: options.billingAddress.contactName,\n city: options.billingAddress.city,\n country: options.billingAddress.country,\n address: options.billingAddress.address,\n },\n basketItems: options.basketItems.map((item) => ({\n id: item.id,\n name: item.name,\n category1: item.category1,\n category2: item.category2,\n itemType: item.itemType,\n price: item.price,\n })),\n };\n\n if (options.enabledInstallments) {\n body[\"enabledInstallments\"] = options.enabledInstallments;\n }\n\n if (options.force3ds) {\n body[\"forceThreeDS\"] = 1;\n }\n\n const result = await this.request<IyzicoCheckoutFormResponse>(\n \"/payment/iyzi-pos/checkoutform/initialize/auth/ecom\",\n body\n );\n\n return {\n token: result.token,\n checkoutFormContent: result.checkoutFormContent,\n tokenExpireTime: result.tokenExpireTime,\n paymentPageUrl: result.paymentPageUrl,\n };\n }\n\n /**\n * Retrieve checkout form result\n */\n async retrieveCheckoutForm(token: string): Promise<IyzicoPaymentResult> {\n const body = {\n locale: \"tr\",\n conversationId: this.generateRandomString(16),\n token,\n };\n\n const result = await this.request<IyzicoPaymentResponse>(\n \"/payment/iyzi-pos/checkoutform/auth/ecom/detail\",\n body\n );\n\n return {\n paymentId: result.paymentId,\n status: result.status,\n paymentStatus: result.paymentStatus,\n price: result.price,\n paidPrice: result.paidPrice,\n currency: result.currency,\n installment: result.installment,\n basketId: result.basketId,\n binNumber: result.binNumber,\n lastFourDigits: result.lastFourDigits,\n cardAssociation: result.cardAssociation,\n cardFamily: result.cardFamily,\n cardType: result.cardType,\n fraudStatus: result.fraudStatus,\n raw: result,\n };\n }\n\n async getCheckout(_sessionId: string): Promise<CheckoutSession | null> {\n // Use retrieveCheckoutForm instead\n return null;\n }\n\n // ============================================================================\n // 3D Secure Payment\n // ============================================================================\n\n /**\n * Initialize 3D Secure payment\n */\n async initialize3DSPayment(options: {\n price: string;\n paidPrice: string;\n currency: \"TRY\" | \"USD\" | \"EUR\" | \"GBP\" | \"IRR\";\n installment: number;\n paymentCard: {\n cardHolderName: string;\n cardNumber: string;\n expireMonth: string;\n expireYear: string;\n cvc: string;\n registerCard?: 0 | 1;\n };\n buyer: IyzicoBuyer;\n billingAddress: IyzicoAddress;\n shippingAddress: IyzicoAddress;\n basketItems: IyzicoBasketItem[];\n callbackUrl: string;\n conversationId?: string;\n }): Promise<IyzicoThreeDSInitResult> {\n const body: Record<string, unknown> = {\n locale: \"tr\",\n conversationId: options.conversationId ?? this.generateRandomString(16),\n price: options.price,\n paidPrice: options.paidPrice,\n currency: options.currency,\n installment: options.installment,\n basketId: this.generateRandomString(16),\n paymentChannel: \"WEB\",\n paymentGroup: \"PRODUCT\",\n paymentCard: options.paymentCard,\n buyer: options.buyer,\n shippingAddress: options.shippingAddress,\n billingAddress: options.billingAddress,\n basketItems: options.basketItems,\n callbackUrl: options.callbackUrl,\n };\n\n const result = await this.request<IyzicoThreeDSResponse>(\n \"/payment/3dsecure/initialize\",\n body\n );\n\n return {\n threeDSHtmlContent: result.threeDSHtmlContent,\n status: result.status,\n };\n }\n\n /**\n * Complete 3D Secure payment after callback\n */\n async complete3DSPayment(paymentId: string, conversationId?: string): Promise<IyzicoPaymentResult> {\n const body = {\n locale: \"tr\",\n conversationId: conversationId ?? this.generateRandomString(16),\n paymentId,\n };\n\n const result = await this.request<IyzicoPaymentResponse>(\n \"/payment/3dsecure/auth\",\n body\n );\n\n return {\n paymentId: result.paymentId,\n status: result.status,\n paymentStatus: result.paymentStatus,\n price: result.price,\n paidPrice: result.paidPrice,\n currency: result.currency,\n installment: result.installment,\n basketId: result.basketId,\n binNumber: result.binNumber,\n lastFourDigits: result.lastFourDigits,\n cardAssociation: result.cardAssociation,\n cardFamily: result.cardFamily,\n cardType: result.cardType,\n fraudStatus: result.fraudStatus,\n raw: result,\n };\n }\n\n // ============================================================================\n // Refund\n // ============================================================================\n\n /**\n * Create a refund\n */\n async createRefund(options: {\n paymentTransactionId: string;\n price: string;\n currency: \"TRY\" | \"USD\" | \"EUR\" | \"GBP\" | \"IRR\";\n ip: string;\n conversationId?: string;\n }): Promise<IyzicoRefundResult> {\n const body = {\n locale: \"tr\",\n conversationId: options.conversationId ?? this.generateRandomString(16),\n paymentTransactionId: options.paymentTransactionId,\n price: options.price,\n currency: options.currency,\n ip: options.ip,\n };\n\n const result = await this.request<IyzicoRefundResponse>(\n \"/payment/refund\",\n body\n );\n\n return {\n paymentId: result.paymentId,\n paymentTransactionId: result.paymentTransactionId,\n price: result.price,\n status: result.status,\n };\n }\n\n /**\n * Cancel a payment (full refund before settlement)\n */\n async cancelPayment(options: {\n paymentId: string;\n ip: string;\n conversationId?: string;\n }): Promise<IyzicoCancelResult> {\n const body = {\n locale: \"tr\",\n conversationId: options.conversationId ?? this.generateRandomString(16),\n paymentId: options.paymentId,\n ip: options.ip,\n };\n\n const result = await this.request<IyzicoCancelResponse>(\n \"/payment/cancel\",\n body\n );\n\n return {\n paymentId: result.paymentId,\n price: result.price,\n currency: result.currency,\n status: result.status,\n };\n }\n\n // ============================================================================\n // Installment\n // ============================================================================\n\n /**\n * Get installment info for a BIN number\n */\n async getInstallmentInfo(\n binNumber: string,\n price: string\n ): Promise<IyzicoInstallmentResult> {\n const body = {\n locale: \"tr\",\n conversationId: this.generateRandomString(16),\n binNumber: binNumber.substring(0, 6),\n price,\n };\n\n const result = await this.request<IyzicoInstallmentResponse>(\n \"/payment/iyzi-pos/installment\",\n body\n );\n\n return {\n installmentDetails: result.installmentDetails ?? [],\n };\n }\n\n // ============================================================================\n // Subscriptions - iyzico has separate subscription API\n // ============================================================================\n\n async createSubscription(_options: CreateSubscriptionOptions): Promise<Subscription> {\n throw new PaymentError(\n \"Use iyzico subscription API methods directly\",\n PaymentErrorCodes.API_ERROR\n );\n }\n\n async getSubscription(_subscriptionId: string): Promise<Subscription | null> {\n return null;\n }\n\n async updateSubscription(\n _subscriptionId: string,\n _options: UpdateSubscriptionOptions\n ): Promise<Subscription> {\n throw new PaymentError(\n \"Use iyzico subscription API methods directly\",\n PaymentErrorCodes.API_ERROR\n );\n }\n\n async cancelSubscription(\n _subscriptionId: string,\n _cancelAtPeriodEnd?: boolean\n ): Promise<Subscription> {\n throw new PaymentError(\n \"Use iyzico subscription API methods directly\",\n PaymentErrorCodes.API_ERROR\n );\n }\n\n async listSubscriptions(_customerId: string): Promise<Subscription[]> {\n return [];\n }\n\n // ============================================================================\n // Portal - not supported\n // ============================================================================\n\n async createPortalSession(_options: CreatePortalOptions): Promise<PortalSession> {\n throw new PaymentError(\n \"iyzico does not support customer portal\",\n PaymentErrorCodes.API_ERROR\n );\n }\n\n // ============================================================================\n // Webhooks\n // ============================================================================\n\n async verifyWebhook(\n payload: string | Uint8Array,\n _signature: string\n ): Promise<WebhookEvent | null> {\n // iyzico uses IPN (Instant Payment Notification) system\n // The callback includes payment data that should be verified by retrieving the payment\n\n const payloadString = typeof payload === \"string\" ? payload : new TextDecoder().decode(payload);\n\n try {\n const data = JSON.parse(payloadString) as {\n token?: string;\n paymentId?: string;\n status?: string;\n iyziEventType?: string;\n };\n\n // Verify by retrieving the payment\n if (data.token) {\n const result = await this.retrieveCheckoutForm(data.token);\n\n return {\n id: result.paymentId ?? data.token,\n type: this.mapEventType(data.status ?? result.status),\n data: result,\n created: new Date(),\n provider: \"iyzico\",\n raw: data,\n };\n }\n\n return null;\n } catch {\n return null;\n }\n }\n\n private mapEventType(status: string): WebhookEventType {\n const mapping: Record<string, WebhookEventType> = {\n success: \"payment.succeeded\",\n failure: \"payment.failed\",\n INIT_THREEDS: \"payment.succeeded\",\n CALLBACK_THREEDS: \"payment.succeeded\",\n };\n\n return mapping[status] ?? \"payment.succeeded\";\n }\n}\n\n// ============================================================================\n// iyzico Response Types\n// ============================================================================\n\ninterface IyzicoResponse {\n status: \"success\" | \"failure\";\n errorCode?: string;\n errorMessage?: string;\n locale?: string;\n systemTime?: number;\n conversationId?: string;\n}\n\ninterface IyzicoCheckoutFormResponse extends IyzicoResponse {\n token: string;\n checkoutFormContent: string;\n tokenExpireTime: number;\n paymentPageUrl: string;\n}\n\ninterface IyzicoPaymentResponse extends IyzicoResponse {\n paymentId: string;\n paymentStatus: string;\n price: string;\n paidPrice: string;\n currency: string;\n installment: number;\n basketId: string;\n binNumber: string;\n lastFourDigits: string;\n cardAssociation: string;\n cardFamily: string;\n cardType: string;\n fraudStatus: number;\n itemTransactions?: Array<{\n itemId: string;\n paymentTransactionId: string;\n transactionStatus: number;\n price: string;\n paidPrice: string;\n }>;\n}\n\ninterface IyzicoThreeDSResponse extends IyzicoResponse {\n threeDSHtmlContent: string;\n}\n\ninterface IyzicoRefundResponse extends IyzicoResponse {\n paymentId: string;\n paymentTransactionId: string;\n price: string;\n}\n\ninterface IyzicoCancelResponse extends IyzicoResponse {\n paymentId: string;\n price: string;\n currency: string;\n}\n\ninterface IyzicoInstallmentResponse extends IyzicoResponse {\n installmentDetails?: Array<{\n binNumber: string;\n price: string;\n cardType: string;\n cardAssociation: string;\n cardFamilyName: string;\n force3ds: number;\n bankCode: number;\n bankName: string;\n forceCvc: number;\n installmentPrices: Array<{\n installmentNumber: number;\n totalPrice: string;\n installmentPrice: string;\n }>;\n }>;\n}\n\n// ============================================================================\n// Result Types\n// ============================================================================\n\nexport interface IyzicoCheckoutResult {\n token: string;\n checkoutFormContent: string;\n tokenExpireTime: number;\n paymentPageUrl: string;\n}\n\nexport interface IyzicoPaymentResult {\n paymentId: string;\n status: string;\n paymentStatus: string;\n price: string;\n paidPrice: string;\n currency: string;\n installment: number;\n basketId: string;\n binNumber: string;\n lastFourDigits: string;\n cardAssociation: string;\n cardFamily: string;\n cardType: string;\n fraudStatus: number;\n raw: unknown;\n}\n\nexport interface IyzicoThreeDSInitResult {\n threeDSHtmlContent: string;\n status: string;\n}\n\nexport interface IyzicoRefundResult {\n paymentId: string;\n paymentTransactionId: string;\n price: string;\n status: string;\n}\n\nexport interface IyzicoCancelResult {\n paymentId: string;\n price: string;\n currency: string;\n status: string;\n}\n\nexport interface IyzicoInstallmentResult {\n installmentDetails: Array<{\n binNumber: string;\n price: string;\n cardType: string;\n cardAssociation: string;\n cardFamilyName: string;\n force3ds: number;\n bankCode: number;\n bankName: string;\n forceCvc: number;\n installmentPrices: Array<{\n installmentNumber: number;\n totalPrice: string;\n installmentPrice: string;\n }>;\n }>;\n}\n\n/**\n * Create an iyzico provider\n */\nexport function createIyzicoProvider(config: IyzicoProviderConfig): IyzicoProvider {\n return new IyzicoProvider(config);\n}\n","/**\n * @parsrun/payments - Webhook Handlers\n * Utilities for handling payment webhooks\n */\n\nimport type {\n PaymentProvider,\n WebhookEvent,\n WebhookEventType,\n WebhookHandler,\n} from \"../types.js\";\n\n/**\n * Webhook event handler registry\n */\nexport class WebhookHandlerRegistry {\n private handlers = new Map<WebhookEventType | \"*\", WebhookHandler[]>();\n\n /**\n * Register a handler for a specific event type\n */\n on<T = unknown>(type: WebhookEventType | \"*\", handler: WebhookHandler<T>): this {\n const handlers = this.handlers.get(type) ?? [];\n handlers.push(handler as WebhookHandler);\n this.handlers.set(type, handlers);\n return this;\n }\n\n /**\n * Register handlers for checkout events\n */\n onCheckout(handler: WebhookHandler): this {\n this.on(\"checkout.session.completed\", handler);\n this.on(\"checkout.session.expired\", handler);\n return this;\n }\n\n /**\n * Register handlers for subscription events\n */\n onSubscription(handler: WebhookHandler): this {\n this.on(\"subscription.created\", handler);\n this.on(\"subscription.updated\", handler);\n this.on(\"subscription.deleted\", handler);\n this.on(\"subscription.trial_will_end\", handler);\n return this;\n }\n\n /**\n * Register handlers for payment events\n */\n onPayment(handler: WebhookHandler): this {\n this.on(\"payment.succeeded\", handler);\n this.on(\"payment.failed\", handler);\n return this;\n }\n\n /**\n * Register handlers for invoice events\n */\n onInvoice(handler: WebhookHandler): this {\n this.on(\"invoice.created\", handler);\n this.on(\"invoice.paid\", handler);\n this.on(\"invoice.payment_failed\", handler);\n this.on(\"invoice.upcoming\", handler);\n return this;\n }\n\n /**\n * Register handlers for customer events\n */\n onCustomer(handler: WebhookHandler): this {\n this.on(\"customer.created\", handler);\n this.on(\"customer.updated\", handler);\n this.on(\"customer.deleted\", handler);\n return this;\n }\n\n /**\n * Get handlers for an event type\n */\n getHandlers(type: WebhookEventType): WebhookHandler[] {\n const specificHandlers = this.handlers.get(type) ?? [];\n const globalHandlers = this.handlers.get(\"*\") ?? [];\n return [...specificHandlers, ...globalHandlers];\n }\n\n /**\n * Execute all handlers for an event\n */\n async handle(event: WebhookEvent): Promise<void> {\n const handlers = this.getHandlers(event.type);\n\n for (const handler of handlers) {\n await handler(event);\n }\n }\n}\n\n/**\n * Webhook processor for handling incoming webhooks\n */\nexport class WebhookProcessor {\n private provider: PaymentProvider;\n private registry: WebhookHandlerRegistry;\n\n constructor(provider: PaymentProvider, registry?: WebhookHandlerRegistry) {\n this.provider = provider;\n this.registry = registry ?? new WebhookHandlerRegistry();\n }\n\n /**\n * Get the handler registry\n */\n get handlers(): WebhookHandlerRegistry {\n return this.registry;\n }\n\n /**\n * Process a webhook request\n */\n async process(request: Request): Promise<WebhookProcessResult> {\n try {\n // Get payload and signature\n const payload = await request.text();\n const signature = this.getSignature(request);\n\n if (!signature) {\n return {\n success: false,\n error: \"Missing webhook signature\",\n };\n }\n\n // Verify webhook\n const event = await this.provider.verifyWebhook(payload, signature);\n\n if (!event) {\n return {\n success: false,\n error: \"Invalid webhook signature\",\n };\n }\n\n // Handle event\n await this.registry.handle(event);\n\n return {\n success: true,\n event,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n };\n }\n }\n\n /**\n * Process raw webhook payload\n */\n async processRaw(\n payload: string | Uint8Array,\n signature: string\n ): Promise<WebhookProcessResult> {\n try {\n // Verify webhook\n const event = await this.provider.verifyWebhook(payload, signature);\n\n if (!event) {\n return {\n success: false,\n error: \"Invalid webhook signature\",\n };\n }\n\n // Handle event\n await this.registry.handle(event);\n\n return {\n success: true,\n event,\n };\n } catch (err) {\n return {\n success: false,\n error: err instanceof Error ? err.message : \"Unknown error\",\n };\n }\n }\n\n private getSignature(request: Request): string | null {\n // Stripe uses stripe-signature header\n const stripeSignature = request.headers.get(\"stripe-signature\");\n if (stripeSignature) return stripeSignature;\n\n // Paddle uses paddle-signature header\n const paddleSignature = request.headers.get(\"paddle-signature\");\n if (paddleSignature) return paddleSignature;\n\n return null;\n }\n}\n\n/**\n * Webhook process result\n */\nexport interface WebhookProcessResult {\n success: boolean;\n event?: WebhookEvent | undefined;\n error?: string | undefined;\n}\n\n/**\n * Create a webhook processor\n */\nexport function createWebhookProcessor(\n provider: PaymentProvider,\n registry?: WebhookHandlerRegistry\n): WebhookProcessor {\n return new WebhookProcessor(provider, registry);\n}\n\n/**\n * Create a webhook handler registry\n */\nexport function createWebhookHandlerRegistry(): WebhookHandlerRegistry {\n return new WebhookHandlerRegistry();\n}\n\n/**\n * Create a Hono/Express-compatible webhook handler\n */\nexport function createWebhookHandler(\n provider: PaymentProvider,\n handlers: Partial<Record<WebhookEventType | \"*\", WebhookHandler>>\n): (request: Request) => Promise<Response> {\n const registry = new WebhookHandlerRegistry();\n\n for (const [type, handler] of Object.entries(handlers)) {\n if (handler) {\n registry.on(type as WebhookEventType, handler);\n }\n }\n\n const processor = new WebhookProcessor(provider, registry);\n\n return async (request: Request): Promise<Response> => {\n const result = await processor.process(request);\n\n if (result.success) {\n return new Response(JSON.stringify({ received: true }), {\n status: 200,\n headers: { \"Content-Type\": \"application/json\" },\n });\n }\n\n return new Response(JSON.stringify({ error: result.error }), {\n status: 400,\n headers: { \"Content-Type\": \"application/json\" },\n });\n };\n}\n","/**\n * @parsrun/payments - Billing Types\n * Types for multi-provider billing service\n */\n\nimport type {\n PaymentProvider,\n PaymentProviderType,\n Customer,\n Subscription,\n} from \"../types.js\";\n\n// ============================================================================\n// Region & Routing\n// ============================================================================\n\n/**\n * Supported regions for provider routing\n */\nexport type BillingRegion =\n | \"TR\" // Turkey\n | \"EU\" // European Union\n | \"US\" // United States\n | \"UK\" // United Kingdom\n | \"APAC\" // Asia Pacific\n | \"LATAM\" // Latin America\n | \"GLOBAL\" // Default/fallback\n | string; // Custom regions\n\n/**\n * Region detection result\n */\nexport interface RegionDetectionResult {\n /** Detected region code */\n region: BillingRegion;\n /** Country code (ISO 3166-1 alpha-2) */\n countryCode?: string;\n /** Detection method used */\n method: \"ip\" | \"customer\" | \"explicit\" | \"default\";\n /** Confidence level */\n confidence: \"high\" | \"medium\" | \"low\";\n}\n\n/**\n * Region detector function type\n */\nexport type RegionDetector = (\n context: RegionDetectionContext\n) => BillingRegion | Promise<BillingRegion>;\n\n/**\n * Context for region detection\n */\nexport interface RegionDetectionContext {\n /** Customer ID if available */\n customerId?: string | undefined;\n /** Customer email */\n email?: string | undefined;\n /** Explicit country code */\n countryCode?: string | undefined;\n /** IP address */\n ipAddress?: string | undefined;\n /** Request headers */\n headers?: Record<string, string> | undefined;\n /** Custom context data */\n custom?: Record<string, unknown> | undefined;\n}\n\n// ============================================================================\n// Provider Strategy\n// ============================================================================\n\n/**\n * Provider routing rule\n */\nexport interface ProviderRoutingRule {\n /** Regions this rule applies to */\n regions: BillingRegion[];\n /** Provider to use */\n provider: PaymentProvider;\n /** Priority (lower = higher priority) */\n priority?: number;\n /** Rule condition (optional) */\n condition?: (context: RegionDetectionContext) => boolean;\n}\n\n/**\n * Provider strategy configuration\n */\nexport interface ProviderStrategyConfig {\n /** Default provider (used when no region matches) */\n default: PaymentProvider;\n\n /**\n * Region-based provider mapping\n * @example { TR: iyzicoProvider, EU: stripeProvider }\n */\n regions?: Record<BillingRegion, PaymentProvider>;\n\n /**\n * Advanced routing rules (takes precedence over regions)\n */\n rules?: ProviderRoutingRule[];\n\n /**\n * Custom region detector\n * Default: uses countryCode from context or \"GLOBAL\"\n */\n regionDetector?: RegionDetector;\n}\n\n// ============================================================================\n// Fallback Configuration\n// ============================================================================\n\n/**\n * Fallback configuration\n */\nexport interface FallbackConfig {\n /**\n * Enable fallback to alternative providers\n * @default false\n *\n * WARNING: Enable with caution! Fallback may cause:\n * - Double charges if not handled properly\n * - Inconsistent customer records across providers\n * - Webhook handling complexity\n *\n * Recommended only for:\n * - One-time payments (not subscriptions)\n * - Idempotent operations\n * - When you have proper reconciliation in place\n */\n enabled: boolean;\n\n /**\n * Fallback providers in order of preference\n * If not specified, uses all configured providers except the failed one\n */\n providers?: PaymentProvider[];\n\n /**\n * Operations that allow fallback\n * @default [\"createCheckout\"] - Only checkout is safe by default\n */\n allowedOperations?: FallbackOperation[];\n\n /**\n * Maximum fallback attempts\n * @default 1\n */\n maxAttempts?: number;\n\n /**\n * Errors that should trigger fallback\n * @default [\"API_ERROR\", \"RATE_LIMITED\", \"PROVIDER_UNAVAILABLE\"]\n */\n retryableErrors?: string[];\n\n /**\n * Callback when fallback is triggered\n */\n onFallback?: (context: FallbackContext) => void | Promise<void>;\n\n /**\n * Callback when all providers fail\n */\n onAllFailed?: (context: FallbackContext) => void | Promise<void>;\n}\n\n/**\n * Operations that can trigger fallback\n */\nexport type FallbackOperation =\n | \"createCheckout\"\n | \"createCustomer\"\n | \"createSubscription\"\n | \"createPayment\";\n\n/**\n * Fallback context for callbacks\n */\nexport interface FallbackContext {\n /** Operation that failed */\n operation: FallbackOperation;\n /** Original provider that failed */\n originalProvider: PaymentProviderType;\n /** Fallback provider being tried */\n fallbackProvider?: PaymentProviderType;\n /** Error that triggered fallback */\n error: Error;\n /** Attempt number */\n attempt: number;\n /** Total attempts made */\n totalAttempts: number;\n /** Whether all providers failed */\n allFailed: boolean;\n}\n\n// ============================================================================\n// Billing Service Configuration\n// ============================================================================\n\n/**\n * Billing service configuration\n */\nexport interface BillingServiceConfig {\n /**\n * Provider strategy configuration\n */\n providers: ProviderStrategyConfig;\n\n /**\n * Fallback configuration\n * @default { enabled: false }\n */\n fallback?: FallbackConfig;\n\n /**\n * Tenant ID for multi-tenant setups\n */\n tenantId?: string;\n\n /**\n * Enable debug logging\n */\n debug?: boolean;\n\n /**\n * Custom logger\n */\n logger?: BillingLogger;\n\n /**\n * Webhook configuration\n */\n webhooks?: {\n /**\n * Normalize events from all providers to unified format\n * @default true\n */\n normalize?: boolean;\n\n /**\n * Secret keys for each provider\n */\n secrets?: Partial<Record<PaymentProviderType, string>>;\n };\n}\n\n/**\n * Logger interface for billing service\n */\nexport interface BillingLogger {\n debug(message: string, context?: Record<string, unknown>): void;\n info(message: string, context?: Record<string, unknown>): void;\n warn(message: string, context?: Record<string, unknown>): void;\n error(message: string, context?: Record<string, unknown>): void;\n}\n\n// ============================================================================\n// High-Level Billing API Types\n// ============================================================================\n\n/**\n * Subscribe options (high-level)\n */\nexport interface SubscribeOptions {\n /** Customer email */\n email: string;\n /** Customer name */\n name?: string;\n /** Plan/Price ID */\n planId: string;\n /** Success redirect URL */\n successUrl: string;\n /** Cancel redirect URL */\n cancelUrl: string;\n /** Trial days */\n trialDays?: number;\n /** Country code for region routing */\n countryCode?: string;\n /** Custom metadata */\n metadata?: Record<string, string>;\n /**\n * Existing customer ID (skip customer creation)\n */\n customerId?: string;\n /**\n * Force specific provider (bypass region routing)\n */\n forceProvider?: PaymentProviderType;\n}\n\n/**\n * Subscribe result\n */\nexport interface SubscribeResult {\n /** Checkout URL to redirect user */\n checkoutUrl: string;\n /** Checkout session ID */\n sessionId: string;\n /** Customer ID (created or existing) */\n customerId: string;\n /** Provider used */\n provider: PaymentProviderType;\n /** Region detected */\n region: BillingRegion;\n}\n\n/**\n * Cancel subscription options\n */\nexport interface CancelOptions {\n /** Subscription ID */\n subscriptionId: string;\n /** Cancel immediately or at period end */\n immediate?: boolean;\n /** Reason for cancellation */\n reason?: string;\n /** Provider (if known, for faster lookup) */\n provider?: PaymentProviderType;\n}\n\n/**\n * Cancel result\n */\nexport interface CancelResult {\n /** Subscription ID */\n subscriptionId: string;\n /** New status */\n status: string;\n /** When subscription will end */\n endsAt: Date;\n /** Provider used */\n provider: PaymentProviderType;\n}\n\n/**\n * Get subscription options\n */\nexport interface GetSubscriptionOptions {\n /** Customer ID */\n customerId?: string;\n /** Customer email (alternative to customerId) */\n email?: string;\n /** Specific subscription ID */\n subscriptionId?: string;\n /** Provider hint */\n provider?: PaymentProviderType;\n}\n\n/**\n * Subscription with provider info\n */\nexport interface BillingSubscription extends Subscription {\n /** Provider that manages this subscription */\n provider: PaymentProviderType;\n}\n\n/**\n * Customer with provider info\n */\nexport interface BillingCustomer extends Customer {\n /** Provider that manages this customer */\n provider: PaymentProviderType;\n /** Region */\n region?: BillingRegion;\n}\n\n// ============================================================================\n// Provider Selection Result\n// ============================================================================\n\n/**\n * Provider selection result\n */\nexport interface ProviderSelection {\n /** Selected provider */\n provider: PaymentProvider;\n /** Provider type */\n type: PaymentProviderType;\n /** Region used for selection */\n region: BillingRegion;\n /** Selection reason */\n reason: \"region\" | \"rule\" | \"default\" | \"forced\" | \"fallback\";\n}\n\n// ============================================================================\n// Billing Errors\n// ============================================================================\n\n/**\n * Billing error codes\n */\nexport const BillingErrorCodes = {\n NO_PROVIDER_CONFIGURED: \"NO_PROVIDER_CONFIGURED\",\n PROVIDER_UNAVAILABLE: \"PROVIDER_UNAVAILABLE\",\n ALL_PROVIDERS_FAILED: \"ALL_PROVIDERS_FAILED\",\n REGION_NOT_SUPPORTED: \"REGION_NOT_SUPPORTED\",\n SUBSCRIPTION_NOT_FOUND: \"SUBSCRIPTION_NOT_FOUND\",\n CUSTOMER_NOT_FOUND: \"CUSTOMER_NOT_FOUND\",\n FALLBACK_DISABLED: \"FALLBACK_DISABLED\",\n OPERATION_NOT_ALLOWED: \"OPERATION_NOT_ALLOWED\",\n} as const;\n\nexport type BillingErrorCode = keyof typeof BillingErrorCodes;\n\n/**\n * Billing error\n */\nexport class BillingError extends Error {\n constructor(\n message: string,\n public readonly code: BillingErrorCode,\n public readonly provider?: PaymentProviderType,\n public readonly cause?: Error\n ) {\n super(message);\n this.name = \"BillingError\";\n }\n}\n","/**\n * @parsrun/payments - Provider Strategy\n * Region-based provider routing and selection\n */\n\nimport type { PaymentProvider, PaymentProviderType } from \"../types.js\";\nimport type {\n BillingRegion,\n ProviderStrategyConfig,\n ProviderRoutingRule,\n RegionDetectionContext,\n RegionDetector,\n ProviderSelection,\n BillingLogger,\n} from \"./types.js\";\nimport { BillingError } from \"./types.js\";\n\n/**\n * Default region detector\n * Uses countryCode from context, maps to region\n */\nconst defaultRegionDetector: RegionDetector = (context) => {\n if (!context.countryCode) {\n return \"GLOBAL\";\n }\n\n const countryToRegion: Record<string, BillingRegion> = {\n // Turkey\n TR: \"TR\",\n // EU countries\n DE: \"EU\", FR: \"EU\", IT: \"EU\", ES: \"EU\", NL: \"EU\", BE: \"EU\",\n AT: \"EU\", PT: \"EU\", GR: \"EU\", PL: \"EU\", CZ: \"EU\", RO: \"EU\",\n HU: \"EU\", SE: \"EU\", DK: \"EU\", FI: \"EU\", IE: \"EU\", SK: \"EU\",\n BG: \"EU\", HR: \"EU\", LT: \"EU\", LV: \"EU\", SI: \"EU\", EE: \"EU\",\n CY: \"EU\", LU: \"EU\", MT: \"EU\",\n // UK\n GB: \"UK\", UK: \"UK\",\n // US\n US: \"US\",\n // APAC\n JP: \"APAC\", CN: \"APAC\", KR: \"APAC\", AU: \"APAC\", NZ: \"APAC\",\n SG: \"APAC\", HK: \"APAC\", TW: \"APAC\", IN: \"APAC\", ID: \"APAC\",\n MY: \"APAC\", TH: \"APAC\", PH: \"APAC\", VN: \"APAC\",\n // LATAM\n BR: \"LATAM\", MX: \"LATAM\", AR: \"LATAM\", CL: \"LATAM\", CO: \"LATAM\",\n PE: \"LATAM\", VE: \"LATAM\", EC: \"LATAM\", UY: \"LATAM\", PY: \"LATAM\",\n };\n\n return countryToRegion[context.countryCode.toUpperCase()] ?? \"GLOBAL\";\n};\n\n/**\n * Provider Strategy\n * Handles region-based provider routing and selection\n */\nexport class ProviderStrategy {\n private readonly defaultProvider: PaymentProvider;\n private readonly regionProviders: Map<BillingRegion, PaymentProvider>;\n private readonly rules: ProviderRoutingRule[];\n private readonly regionDetector: RegionDetector;\n private readonly logger: BillingLogger | undefined;\n\n constructor(config: ProviderStrategyConfig, logger?: BillingLogger) {\n this.defaultProvider = config.default;\n this.regionProviders = new Map();\n this.rules = config.rules ?? [];\n this.regionDetector = config.regionDetector ?? defaultRegionDetector;\n this.logger = logger ?? undefined;\n\n // Build region provider map\n if (config.regions) {\n for (const [region, provider] of Object.entries(config.regions)) {\n this.regionProviders.set(region as BillingRegion, provider);\n }\n }\n\n // Sort rules by priority\n this.rules.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));\n }\n\n /**\n * Select provider for given context\n */\n async selectProvider(\n context: RegionDetectionContext,\n forceProvider?: PaymentProviderType\n ): Promise<ProviderSelection> {\n // Forced provider\n if (forceProvider) {\n const provider = this.findProviderByType(forceProvider);\n if (provider) {\n this.logger?.debug(\"Provider forced\", { provider: forceProvider });\n return {\n provider,\n type: forceProvider,\n region: await this.detectRegion(context),\n reason: \"forced\",\n };\n }\n throw new BillingError(\n `Forced provider \"${forceProvider}\" not configured`,\n \"NO_PROVIDER_CONFIGURED\",\n forceProvider\n );\n }\n\n // Detect region\n const region = await this.detectRegion(context);\n this.logger?.debug(\"Region detected\", { region, context });\n\n // Check rules first (higher priority)\n for (const rule of this.rules) {\n if (rule.regions.includes(region)) {\n // Check additional condition if provided\n if (rule.condition && !rule.condition(context)) {\n continue;\n }\n\n this.logger?.debug(\"Rule matched\", {\n regions: rule.regions,\n provider: rule.provider.type,\n });\n\n return {\n provider: rule.provider,\n type: rule.provider.type,\n region,\n reason: \"rule\",\n };\n }\n }\n\n // Check region providers\n const regionProvider = this.regionProviders.get(region);\n if (regionProvider) {\n this.logger?.debug(\"Region provider selected\", {\n region,\n provider: regionProvider.type,\n });\n\n return {\n provider: regionProvider,\n type: regionProvider.type,\n region,\n reason: \"region\",\n };\n }\n\n // Fall back to default\n this.logger?.debug(\"Using default provider\", {\n region,\n provider: this.defaultProvider.type,\n });\n\n return {\n provider: this.defaultProvider,\n type: this.defaultProvider.type,\n region,\n reason: \"default\",\n };\n }\n\n /**\n * Detect region from context\n */\n async detectRegion(context: RegionDetectionContext): Promise<BillingRegion> {\n try {\n return await this.regionDetector(context);\n } catch (error) {\n this.logger?.warn(\"Region detection failed, using GLOBAL\", {\n error: error instanceof Error ? error.message : String(error),\n });\n return \"GLOBAL\";\n }\n }\n\n /**\n * Get all configured providers\n */\n getAllProviders(): PaymentProvider[] {\n const providers = new Set<PaymentProvider>();\n providers.add(this.defaultProvider);\n\n for (const provider of this.regionProviders.values()) {\n providers.add(provider);\n }\n\n for (const rule of this.rules) {\n providers.add(rule.provider);\n }\n\n return Array.from(providers);\n }\n\n /**\n * Get provider by type\n */\n getProviderByType(type: PaymentProviderType): PaymentProvider | undefined {\n return this.findProviderByType(type);\n }\n\n /**\n * Get default provider\n */\n getDefaultProvider(): PaymentProvider {\n return this.defaultProvider;\n }\n\n /**\n * Get provider for region\n */\n getProviderForRegion(region: BillingRegion): PaymentProvider {\n return this.regionProviders.get(region) ?? this.defaultProvider;\n }\n\n /**\n * Check if region is supported\n */\n isRegionSupported(region: BillingRegion): boolean {\n // GLOBAL is always supported via default provider\n if (region === \"GLOBAL\") return true;\n\n // Check if any rule matches\n for (const rule of this.rules) {\n if (rule.regions.includes(region)) return true;\n }\n\n // Check if region has explicit provider\n return this.regionProviders.has(region);\n }\n\n /**\n * Get supported regions\n */\n getSupportedRegions(): BillingRegion[] {\n const regions = new Set<BillingRegion>([\"GLOBAL\"]);\n\n for (const region of this.regionProviders.keys()) {\n regions.add(region);\n }\n\n for (const rule of this.rules) {\n for (const region of rule.regions) {\n regions.add(region);\n }\n }\n\n return Array.from(regions);\n }\n\n /**\n * Find provider by type across all configured providers\n */\n private findProviderByType(type: PaymentProviderType): PaymentProvider | undefined {\n if (this.defaultProvider.type === type) {\n return this.defaultProvider;\n }\n\n for (const provider of this.regionProviders.values()) {\n if (provider.type === type) {\n return provider;\n }\n }\n\n for (const rule of this.rules) {\n if (rule.provider.type === type) {\n return rule.provider;\n }\n }\n\n return undefined;\n }\n}\n\n/**\n * Create provider strategy\n */\nexport function createProviderStrategy(\n config: ProviderStrategyConfig,\n logger?: BillingLogger\n): ProviderStrategy {\n return new ProviderStrategy(config, logger);\n}\n","/**\n * @parsrun/payments - Fallback Executor\n * Handles provider fallback with safety controls\n */\n\nimport type { PaymentProvider, PaymentProviderType } from \"../types.js\";\nimport { PaymentErrorCodes } from \"../types.js\";\nimport type {\n FallbackConfig,\n FallbackOperation,\n FallbackContext,\n BillingLogger,\n} from \"./types.js\";\nimport { BillingError } from \"./types.js\";\n\n/**\n * Default retryable error codes\n */\nconst DEFAULT_RETRYABLE_ERRORS = [\n PaymentErrorCodes.API_ERROR,\n PaymentErrorCodes.RATE_LIMITED,\n \"PROVIDER_UNAVAILABLE\",\n \"ECONNREFUSED\",\n \"ETIMEDOUT\",\n \"ENOTFOUND\",\n \"NetworkError\",\n \"fetch failed\",\n];\n\n/**\n * Default allowed operations for fallback\n * Only checkout is safe by default - subscriptions can cause issues\n */\nconst DEFAULT_ALLOWED_OPERATIONS: FallbackOperation[] = [\"createCheckout\"];\n\n/**\n * Internal config type with required fields\n */\ninterface InternalFallbackConfig {\n enabled: boolean;\n maxAttempts: number;\n allowedOperations: FallbackOperation[];\n retryableErrors: string[];\n providers: PaymentProvider[] | undefined;\n onFallback: ((context: FallbackContext) => void | Promise<void>) | undefined;\n onAllFailed: ((context: FallbackContext) => void | Promise<void>) | undefined;\n}\n\n/**\n * Fallback Executor\n * Handles provider fallback with safety controls and logging\n */\nexport class FallbackExecutor {\n private readonly config: InternalFallbackConfig;\n private readonly logger: BillingLogger | undefined;\n\n constructor(config: FallbackConfig, logger?: BillingLogger) {\n this.config = {\n enabled: config.enabled,\n maxAttempts: config.maxAttempts ?? 1,\n allowedOperations: config.allowedOperations ?? DEFAULT_ALLOWED_OPERATIONS,\n retryableErrors: config.retryableErrors ?? DEFAULT_RETRYABLE_ERRORS,\n providers: config.providers,\n onFallback: config.onFallback,\n onAllFailed: config.onAllFailed,\n };\n this.logger = logger;\n }\n\n /**\n * Check if fallback is enabled\n */\n get isEnabled(): boolean {\n return this.config.enabled;\n }\n\n /**\n * Execute operation with fallback support\n *\n * @param operation - Operation name for safety checks\n * @param primaryProvider - Primary provider to try first\n * @param fallbackProviders - Fallback providers in order of preference\n * @param execute - Function that executes the operation on a provider\n */\n async execute<T>(\n operation: FallbackOperation,\n primaryProvider: PaymentProvider,\n fallbackProviders: PaymentProvider[],\n execute: (provider: PaymentProvider) => Promise<T>\n ): Promise<{ result: T; provider: PaymentProvider; usedFallback: boolean }> {\n // Check if fallback is enabled for this operation\n const canFallback = this.canFallback(operation);\n\n let lastError: Error | undefined;\n let attempt = 0;\n\n // Build provider list: primary + fallbacks\n const providers = [primaryProvider];\n if (canFallback) {\n for (const fb of fallbackProviders) {\n if (fb !== primaryProvider && providers.length <= this.config.maxAttempts) {\n providers.push(fb);\n }\n }\n }\n\n // Try each provider\n for (const provider of providers) {\n attempt++;\n const isUsingFallback = provider !== primaryProvider;\n\n try {\n this.logger?.debug(`Attempting ${operation}`, {\n provider: provider.type,\n attempt,\n isUsingFallback,\n });\n\n const result = await execute(provider);\n\n if (isUsingFallback) {\n this.logger?.info(`Fallback succeeded`, {\n operation,\n provider: provider.type,\n originalProvider: primaryProvider.type,\n });\n }\n\n return {\n result,\n provider,\n usedFallback: isUsingFallback,\n };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n this.logger?.warn(`Provider ${provider.type} failed`, {\n operation,\n error: lastError.message,\n attempt,\n maxAttempts: providers.length,\n });\n\n // Check if we should try fallback\n if (\n isUsingFallback ||\n !canFallback ||\n attempt >= providers.length ||\n !this.isRetryableError(lastError)\n ) {\n // If this is the last attempt or not retryable, we'll throw\n if (attempt >= providers.length) {\n // Notify all failed callback\n if (this.config.onAllFailed) {\n await this.notifyAllFailed(\n operation,\n primaryProvider.type,\n lastError,\n attempt\n );\n }\n break;\n }\n continue;\n }\n\n // Notify fallback callback before trying next provider\n if (this.config.onFallback && attempt < providers.length) {\n const nextProvider = providers[attempt];\n if (nextProvider) {\n await this.notifyFallback(\n operation,\n primaryProvider.type,\n nextProvider.type,\n lastError,\n attempt,\n providers.length\n );\n }\n }\n }\n }\n\n // All providers failed\n throw new BillingError(\n `All providers failed for ${operation}: ${lastError?.message}`,\n \"ALL_PROVIDERS_FAILED\",\n primaryProvider.type,\n lastError\n );\n }\n\n /**\n * Check if fallback is allowed for operation\n */\n canFallback(operation: FallbackOperation): boolean {\n if (!this.config.enabled) {\n return false;\n }\n\n return this.config.allowedOperations.includes(operation);\n }\n\n /**\n * Check if error is retryable\n */\n isRetryableError(error: Error): boolean {\n const errorCode = (error as { code?: string }).code;\n const errorMessage = error.message;\n\n for (const retryable of this.config.retryableErrors) {\n if (errorCode === retryable) return true;\n if (errorMessage.includes(retryable)) return true;\n }\n\n return false;\n }\n\n /**\n * Notify fallback callback\n */\n private async notifyFallback(\n operation: FallbackOperation,\n originalProvider: PaymentProviderType,\n fallbackProvider: PaymentProviderType,\n error: Error,\n attempt: number,\n totalAttempts: number\n ): Promise<void> {\n if (!this.config.onFallback) return;\n\n const context: FallbackContext = {\n operation,\n originalProvider,\n fallbackProvider,\n error,\n attempt,\n totalAttempts,\n allFailed: false,\n };\n\n try {\n await this.config.onFallback(context);\n } catch (callbackError) {\n this.logger?.error(\"Fallback callback failed\", {\n error: callbackError instanceof Error ? callbackError.message : String(callbackError),\n });\n }\n }\n\n /**\n * Notify all failed callback\n */\n private async notifyAllFailed(\n operation: FallbackOperation,\n originalProvider: PaymentProviderType,\n error: Error,\n totalAttempts: number\n ): Promise<void> {\n if (!this.config.onAllFailed) return;\n\n const context: FallbackContext = {\n operation,\n originalProvider,\n // fallbackProvider is omitted when all failed (undefined not allowed in type)\n error,\n attempt: totalAttempts,\n totalAttempts,\n allFailed: true,\n };\n\n try {\n await this.config.onAllFailed(context);\n } catch (callbackError) {\n this.logger?.error(\"All-failed callback failed\", {\n error: callbackError instanceof Error ? callbackError.message : String(callbackError),\n });\n }\n }\n}\n\n/**\n * Create a disabled fallback executor (default behavior)\n */\nexport function createDisabledFallback(): FallbackExecutor {\n return new FallbackExecutor({ enabled: false });\n}\n\n/**\n * Create fallback executor\n */\nexport function createFallbackExecutor(\n config: FallbackConfig,\n logger?: BillingLogger\n): FallbackExecutor {\n return new FallbackExecutor(config, logger);\n}\n","/**\n * @parsrun/payments - Billing Service\n * High-level billing API with multi-provider support\n */\n\nimport type {\n PaymentProvider,\n PaymentProviderType,\n WebhookEventType,\n WebhookHandler,\n} from \"../types.js\";\nimport {\n WebhookHandlerRegistry,\n WebhookProcessor,\n} from \"../webhooks/index.js\";\nimport type { WebhookProcessResult } from \"../webhooks/index.js\";\nimport { ProviderStrategy } from \"./provider-strategy.js\";\nimport { FallbackExecutor, createDisabledFallback } from \"./fallback-executor.js\";\nimport type {\n BillingServiceConfig,\n BillingRegion,\n RegionDetectionContext,\n SubscribeOptions,\n SubscribeResult,\n CancelOptions,\n CancelResult,\n GetSubscriptionOptions,\n BillingSubscription,\n BillingCustomer,\n ProviderSelection,\n BillingLogger,\n} from \"./types.js\";\nimport { BillingError } from \"./types.js\";\n\n/**\n * Console logger (default)\n */\nconst consoleLogger: BillingLogger = {\n debug: (msg, ctx) => console.debug(`[Billing] ${msg}`, ctx ?? \"\"),\n info: (msg, ctx) => console.info(`[Billing] ${msg}`, ctx ?? \"\"),\n warn: (msg, ctx) => console.warn(`[Billing] ${msg}`, ctx ?? \"\"),\n error: (msg, ctx) => console.error(`[Billing] ${msg}`, ctx ?? \"\"),\n};\n\n/**\n * Null logger (disabled)\n */\nconst nullLogger: BillingLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/**\n * Billing Service\n *\n * High-level billing API with:\n * - Multi-provider support (Stripe, Paddle, iyzico)\n * - Region-based provider routing\n * - Optional fallback mechanism\n * - Unified webhook handling\n *\n * @example Basic usage\n * ```typescript\n * const billing = createBillingService({\n * providers: {\n * default: stripeProvider,\n * regions: {\n * TR: iyzicoProvider,\n * EU: stripeProvider,\n * },\n * },\n * });\n *\n * // Subscribe a customer\n * const result = await billing.subscribe({\n * email: \"user@example.com\",\n * planId: \"price_xxx\",\n * successUrl: \"https://app.com/success\",\n * cancelUrl: \"https://app.com/cancel\",\n * countryCode: \"TR\", // Will use iyzico\n * });\n *\n * // Redirect to checkout\n * redirect(result.checkoutUrl);\n * ```\n *\n * @example With fallback (opt-in)\n * ```typescript\n * const billing = createBillingService({\n * providers: {\n * default: stripeProvider,\n * regions: { TR: iyzicoProvider },\n * },\n * fallback: {\n * enabled: true, // WARNING: Enable with caution\n * allowedOperations: [\"createCheckout\"],\n * maxAttempts: 1,\n * onFallback: (ctx) => {\n * logger.warn(\"Payment fallback triggered\", ctx);\n * },\n * },\n * });\n * ```\n */\nexport class BillingService {\n private readonly strategy: ProviderStrategy;\n private readonly fallback: FallbackExecutor;\n private readonly webhookRegistry: WebhookHandlerRegistry;\n private readonly webhookProcessors: Map<PaymentProviderType, WebhookProcessor>;\n private readonly logger: BillingLogger;\n private readonly tenantId: string | undefined;\n private readonly debug: boolean;\n\n constructor(config: BillingServiceConfig) {\n this.debug = config.debug ?? false;\n this.logger = config.logger ?? (this.debug ? consoleLogger : nullLogger);\n this.tenantId = config.tenantId;\n\n // Initialize provider strategy\n this.strategy = new ProviderStrategy(config.providers, this.logger);\n\n // Initialize fallback executor\n this.fallback = config.fallback\n ? new FallbackExecutor(config.fallback, this.logger)\n : createDisabledFallback();\n\n // Initialize webhook handling\n this.webhookRegistry = new WebhookHandlerRegistry();\n this.webhookProcessors = new Map();\n\n // Create webhook processor for each provider\n for (const provider of this.strategy.getAllProviders()) {\n const processor = new WebhookProcessor(provider, this.webhookRegistry);\n this.webhookProcessors.set(provider.type, processor);\n }\n\n this.logger.info(\"BillingService initialized\", {\n providers: this.strategy.getAllProviders().map((p) => p.type),\n regions: this.strategy.getSupportedRegions(),\n fallbackEnabled: this.fallback.isEnabled,\n });\n }\n\n // ============================================================================\n // High-Level API\n // ============================================================================\n\n /**\n * Subscribe a customer to a plan\n *\n * This is the recommended way to handle subscriptions:\n * 1. Creates or retrieves customer\n * 2. Selects provider based on region\n * 3. Creates checkout session\n * 4. Returns checkout URL for redirect\n *\n * @example\n * ```typescript\n * const { checkoutUrl } = await billing.subscribe({\n * email: \"user@example.com\",\n * planId: \"price_monthly\",\n * successUrl: \"https://app.com/success\",\n * cancelUrl: \"https://app.com/cancel\",\n * countryCode: \"TR\",\n * });\n * redirect(checkoutUrl);\n * ```\n */\n async subscribe(options: SubscribeOptions): Promise<SubscribeResult> {\n const context: RegionDetectionContext = {\n email: options.email,\n countryCode: options.countryCode,\n customerId: options.customerId,\n };\n\n // Select provider\n const selection = await this.strategy.selectProvider(\n context,\n options.forceProvider\n );\n\n this.logger.info(\"Starting subscription\", {\n email: options.email,\n planId: options.planId,\n provider: selection.type,\n region: selection.region,\n });\n\n // Get or create customer\n let customerId = options.customerId;\n if (!customerId) {\n const customer = await this.executeWithFallback(\n \"createCustomer\",\n selection,\n async (provider) => {\n return provider.createCustomer({\n email: options.email,\n name: options.name,\n metadata: {\n ...options.metadata,\n region: selection.region,\n ...(this.tenantId && { tenantId: this.tenantId }),\n },\n });\n }\n );\n customerId = customer.id;\n }\n\n // Create checkout session\n const checkout = await this.executeWithFallback(\n \"createCheckout\",\n selection,\n async (provider) => {\n return provider.createCheckout({\n customerId,\n customerEmail: options.email,\n lineItems: [{ priceId: options.planId, quantity: 1 }],\n successUrl: options.successUrl,\n cancelUrl: options.cancelUrl,\n mode: \"subscription\",\n trialDays: options.trialDays,\n metadata: {\n ...options.metadata,\n region: selection.region,\n ...(this.tenantId && { tenantId: this.tenantId }),\n },\n });\n }\n );\n\n return {\n checkoutUrl: checkout.url,\n sessionId: checkout.id,\n customerId: customerId!,\n provider: selection.type,\n region: selection.region,\n };\n }\n\n /**\n * Cancel a subscription\n *\n * @example\n * ```typescript\n * const result = await billing.cancel({\n * subscriptionId: \"sub_xxx\",\n * immediate: false, // Cancel at period end\n * });\n * ```\n */\n async cancel(options: CancelOptions): Promise<CancelResult> {\n // Find the provider that owns this subscription\n const provider = options.provider\n ? this.strategy.getProviderByType(options.provider)\n : await this.findSubscriptionProvider(options.subscriptionId);\n\n if (!provider) {\n throw new BillingError(\n `Cannot find provider for subscription: ${options.subscriptionId}`,\n \"SUBSCRIPTION_NOT_FOUND\"\n );\n }\n\n this.logger.info(\"Canceling subscription\", {\n subscriptionId: options.subscriptionId,\n provider: provider.type,\n immediate: options.immediate,\n });\n\n const subscription = await provider.cancelSubscription(\n options.subscriptionId,\n !options.immediate // cancelAtPeriodEnd = !immediate\n );\n\n return {\n subscriptionId: subscription.id,\n status: subscription.status,\n endsAt: subscription.cancelAtPeriodEnd\n ? subscription.currentPeriodEnd\n : new Date(),\n provider: provider.type,\n };\n }\n\n /**\n * Get subscription(s) for a customer\n *\n * @example\n * ```typescript\n * // Get by customer ID\n * const subs = await billing.getSubscriptions({ customerId: \"cus_xxx\" });\n *\n * // Get specific subscription\n * const sub = await billing.getSubscription({ subscriptionId: \"sub_xxx\" });\n * ```\n */\n async getSubscriptions(\n options: GetSubscriptionOptions\n ): Promise<BillingSubscription[]> {\n const results: BillingSubscription[] = [];\n\n // If specific subscription ID provided\n if (options.subscriptionId) {\n const sub = await this.getSubscription(options);\n if (sub) results.push(sub);\n return results;\n }\n\n // Search across providers\n const providers = options.provider\n ? [this.strategy.getProviderByType(options.provider)].filter(Boolean)\n : this.strategy.getAllProviders();\n\n for (const provider of providers) {\n if (!provider) continue;\n\n try {\n if (options.customerId) {\n const subs = await provider.listSubscriptions(options.customerId);\n for (const sub of subs) {\n results.push({ ...sub, provider: provider.type });\n }\n }\n } catch (error) {\n this.logger.warn(`Failed to get subscriptions from ${provider.type}`, {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return results;\n }\n\n /**\n * Get a single subscription\n */\n async getSubscription(\n options: GetSubscriptionOptions\n ): Promise<BillingSubscription | null> {\n if (!options.subscriptionId) {\n const subs = await this.getSubscriptions(options);\n return subs[0] ?? null;\n }\n\n // Search across providers for the subscription\n const providers = options.provider\n ? [this.strategy.getProviderByType(options.provider)].filter(Boolean)\n : this.strategy.getAllProviders();\n\n for (const provider of providers) {\n if (!provider) continue;\n\n try {\n const sub = await provider.getSubscription(options.subscriptionId);\n if (sub) {\n return { ...sub, provider: provider.type };\n }\n } catch {\n // Continue to next provider\n }\n }\n\n return null;\n }\n\n /**\n * Get customer by ID\n */\n async getCustomer(\n customerId: string,\n provider?: PaymentProviderType\n ): Promise<BillingCustomer | null> {\n const providers = provider\n ? [this.strategy.getProviderByType(provider)].filter(Boolean)\n : this.strategy.getAllProviders();\n\n for (const p of providers) {\n if (!p) continue;\n\n try {\n const customer = await p.getCustomer(customerId);\n if (customer) {\n return { ...customer, provider: p.type };\n }\n } catch {\n // Continue to next provider\n }\n }\n\n return null;\n }\n\n /**\n * Create a customer portal session\n */\n async createPortalSession(\n customerId: string,\n returnUrl: string,\n provider?: PaymentProviderType\n ): Promise<{ url: string; provider: PaymentProviderType }> {\n const p = provider\n ? this.strategy.getProviderByType(provider)\n : await this.findCustomerProvider(customerId);\n\n if (!p) {\n throw new BillingError(\n `Cannot find provider for customer: ${customerId}`,\n \"CUSTOMER_NOT_FOUND\"\n );\n }\n\n const session = await p.createPortalSession({ customerId, returnUrl });\n return { url: session.url, provider: p.type };\n }\n\n // ============================================================================\n // Provider Selection\n // ============================================================================\n\n /**\n * Select provider for a region/context\n */\n async selectProvider(\n context: RegionDetectionContext,\n forceProvider?: PaymentProviderType\n ): Promise<ProviderSelection> {\n return this.strategy.selectProvider(context, forceProvider);\n }\n\n /**\n * Get all configured providers\n */\n getProviders(): PaymentProvider[] {\n return this.strategy.getAllProviders();\n }\n\n /**\n * Get provider by type\n */\n getProvider(type: PaymentProviderType): PaymentProvider | undefined {\n return this.strategy.getProviderByType(type);\n }\n\n /**\n * Get supported regions\n */\n getSupportedRegions(): BillingRegion[] {\n return this.strategy.getSupportedRegions();\n }\n\n // ============================================================================\n // Webhooks\n // ============================================================================\n\n /**\n * Register webhook handler for all providers\n *\n * @example\n * ```typescript\n * billing.onWebhook(\"subscription.created\", async (event) => {\n * console.log(`New subscription from ${event.provider}:`, event.data);\n * });\n *\n * // Handle all events\n * billing.onWebhook(\"*\", async (event) => {\n * await saveToAuditLog(event);\n * });\n * ```\n */\n onWebhook(type: WebhookEventType | \"*\", handler: WebhookHandler): this {\n this.webhookRegistry.on(type, handler);\n return this;\n }\n\n /**\n * Handle webhook request\n *\n * @example\n * ```typescript\n * app.post(\"/webhooks/:provider\", async (c) => {\n * const provider = c.req.param(\"provider\") as PaymentProviderType;\n * const result = await billing.handleWebhook(c.req.raw, provider);\n * return c.json({ received: result.success });\n * });\n * ```\n */\n async handleWebhook(\n request: Request,\n provider: PaymentProviderType\n ): Promise<WebhookProcessResult> {\n const processor = this.webhookProcessors.get(provider);\n if (!processor) {\n this.logger.error(`No webhook processor for provider: ${provider}`);\n return {\n success: false,\n error: `Unknown provider: ${provider}`,\n };\n }\n\n return processor.process(request);\n }\n\n /**\n * Handle raw webhook payload\n */\n async handleWebhookRaw(\n payload: string | Uint8Array,\n signature: string,\n provider: PaymentProviderType\n ): Promise<WebhookProcessResult> {\n const processor = this.webhookProcessors.get(provider);\n if (!processor) {\n return {\n success: false,\n error: `Unknown provider: ${provider}`,\n };\n }\n\n return processor.processRaw(payload, signature);\n }\n\n // ============================================================================\n // Low-Level Provider Access\n // ============================================================================\n\n /**\n * Execute operation on specific provider\n *\n * Use this for advanced operations not covered by high-level API\n *\n * @example\n * ```typescript\n * const prices = await billing.withProvider(\"stripe\", async (provider) => {\n * return provider.listPrices?.(\"prod_xxx\") ?? [];\n * });\n * ```\n */\n async withProvider<T>(\n type: PaymentProviderType,\n operation: (provider: PaymentProvider) => Promise<T>\n ): Promise<T> {\n const provider = this.strategy.getProviderByType(type);\n if (!provider) {\n throw new BillingError(\n `Provider not configured: ${type}`,\n \"NO_PROVIDER_CONFIGURED\",\n type\n );\n }\n return operation(provider);\n }\n\n // ============================================================================\n // Private Helpers\n // ============================================================================\n\n /**\n * Execute operation with fallback support\n */\n private async executeWithFallback<T>(\n operation: \"createCustomer\" | \"createCheckout\" | \"createSubscription\" | \"createPayment\",\n selection: ProviderSelection,\n execute: (provider: PaymentProvider) => Promise<T>\n ): Promise<T> {\n // Get fallback providers (exclude primary)\n const fallbackProviders = this.strategy\n .getAllProviders()\n .filter((p) => p !== selection.provider);\n\n const result = await this.fallback.execute(\n operation,\n selection.provider,\n fallbackProviders,\n execute\n );\n\n if (result.usedFallback) {\n this.logger.warn(`Operation used fallback provider`, {\n operation,\n original: selection.type,\n fallback: result.provider.type,\n });\n }\n\n return result.result;\n }\n\n /**\n * Find which provider owns a subscription\n */\n private async findSubscriptionProvider(\n subscriptionId: string\n ): Promise<PaymentProvider | undefined> {\n for (const provider of this.strategy.getAllProviders()) {\n try {\n const sub = await provider.getSubscription(subscriptionId);\n if (sub) return provider;\n } catch {\n // Continue searching\n }\n }\n return undefined;\n }\n\n /**\n * Find which provider owns a customer\n */\n private async findCustomerProvider(\n customerId: string\n ): Promise<PaymentProvider | undefined> {\n for (const provider of this.strategy.getAllProviders()) {\n try {\n const customer = await provider.getCustomer(customerId);\n if (customer) return provider;\n } catch {\n // Continue searching\n }\n }\n return undefined;\n }\n}\n\n/**\n * Create billing service\n *\n * @example\n * ```typescript\n * import { createBillingService, createStripeProvider, createIyzicoProvider } from \"@parsrun/payments\";\n *\n * const stripeProvider = createStripeProvider({\n * secretKey: process.env.STRIPE_SECRET_KEY!,\n * webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,\n * });\n *\n * const iyzicoProvider = createIyzicoProvider({\n * apiKey: process.env.IYZICO_API_KEY!,\n * secretKey: process.env.IYZICO_SECRET_KEY!,\n * baseUrl: \"https://api.iyzipay.com\",\n * });\n *\n * const billing = createBillingService({\n * providers: {\n * default: stripeProvider,\n * regions: {\n * TR: iyzicoProvider,\n * EU: stripeProvider,\n * US: stripeProvider,\n * },\n * },\n * fallback: {\n * enabled: false, // Disabled by default - enable with caution!\n * },\n * debug: process.env.NODE_ENV === \"development\",\n * });\n *\n * export { billing };\n * ```\n */\nexport function createBillingService(config: BillingServiceConfig): BillingService {\n return new BillingService(config);\n}\n","/**\n * @parsrun/payments - Usage Types\n * Types for usage-based billing\n */\n\nimport type { PaymentProviderType } from \"../types.js\";\nimport type { BillingSubscription, BillingLogger as BillingLoggerType } from \"../billing/types.js\";\n\n// Re-export BillingLogger for convenience\nexport type BillingLogger = BillingLoggerType;\n\n// ============================================================================\n// Plan & Features\n// ============================================================================\n\n/**\n * Plan tier levels\n */\nexport type PlanTier = 0 | 1 | 2 | 3 | 4; // free, starter, pro, enterprise, custom\n\n/**\n * Billing interval\n */\nexport type BillingInterval = \"month\" | \"year\";\n\n/**\n * Limit period for features\n */\nexport type LimitPeriod = \"hour\" | \"day\" | \"month\" | null;\n\n/**\n * Reset period for quotas\n * - monthly: Reset on the 1st of each calendar month\n * - billing_cycle: Reset on subscription renewal date\n */\nexport type ResetPeriod = \"monthly\" | \"billing_cycle\";\n\n/**\n * Customer access status\n * - active: Full access, subscription is current\n * - past_due: Limited access, payment failed but grace period active\n * - suspended: No access, multiple payment failures\n * - canceled: No access, subscription canceled\n * - unpaid: No access, subscription unpaid\n */\nexport type AccessStatus = \"active\" | \"past_due\" | \"suspended\" | \"canceled\" | \"unpaid\";\n\n/**\n * Access status info for a customer\n */\nexport interface AccessStatusInfo {\n status: AccessStatus;\n /** When the status was last updated */\n updatedAt: Date;\n /** Reason for current status */\n reason?: string;\n /** When access will be suspended (for past_due) */\n suspensionDate?: Date;\n /** Number of failed payment attempts */\n failedPaymentAttempts?: number;\n /** Grace period end date */\n gracePeriodEnd?: Date;\n}\n\n/**\n * Plan definition\n */\nexport interface Plan {\n id: string;\n name: string;\n displayName: string;\n description: string | null;\n tier: PlanTier;\n basePrice: number; // cents\n currency: string;\n billingInterval: BillingInterval;\n features: PlanFeature[];\n isActive: boolean;\n metadata?: Record<string, unknown>;\n createdAt: Date;\n updatedAt: Date;\n}\n\n/**\n * Plan feature with limits\n */\nexport interface PlanFeature {\n id: string;\n planId: string;\n featureKey: string;\n limitValue: number | null; // null = unlimited\n limitPeriod: LimitPeriod;\n isEnabled: boolean;\n metadata?: Record<string, unknown>;\n}\n\n// ============================================================================\n// Usage Events\n// ============================================================================\n\n/**\n * Usage event record\n */\nexport interface UsageEvent {\n id: string;\n tenantId: string;\n customerId: string;\n subscriptionId?: string;\n featureKey: string;\n quantity: number;\n timestamp: Date;\n metadata?: Record<string, unknown>;\n idempotencyKey?: string;\n}\n\n/**\n * Options for tracking usage\n */\nexport interface TrackUsageOptions {\n tenantId: string;\n customerId: string;\n subscriptionId?: string;\n featureKey: string;\n quantity?: number;\n metadata?: Record<string, unknown>;\n idempotencyKey?: string;\n timestamp?: Date;\n}\n\n// ============================================================================\n// Usage Aggregates\n// ============================================================================\n\n/**\n * Period type for aggregation\n */\nexport type PeriodType = \"hour\" | \"day\" | \"month\";\n\n/**\n * Usage aggregate record\n */\nexport interface UsageAggregate {\n id: string;\n tenantId: string;\n customerId: string;\n subscriptionId?: string;\n featureKey: string;\n periodStart: Date;\n periodEnd: Date;\n periodType: PeriodType;\n totalQuantity: number;\n eventCount: number;\n lastUpdated: Date;\n}\n\n/**\n * Options for getting usage\n */\nexport interface GetUsageOptions {\n featureKey?: string;\n periodType?: PeriodType;\n startDate?: Date;\n endDate?: Date;\n subscriptionId?: string;\n}\n\n// ============================================================================\n// Quota\n// ============================================================================\n\n/**\n * Quota status for a feature\n */\nexport interface QuotaStatus {\n featureKey: string;\n limit: number | null; // null = unlimited\n used: number;\n remaining: number | null; // null = unlimited\n percentUsed: number | null;\n periodStart: Date;\n periodEnd: Date;\n isExceeded: boolean;\n isUnlimited: boolean;\n /** Overage amount (used - limit) when soft limits enabled */\n overage?: number;\n /** Whether overage is allowed for this feature */\n overageAllowed?: boolean;\n}\n\n/**\n * Quota check result\n */\nexport interface QuotaCheckResult {\n allowed: boolean;\n currentUsage: number;\n limit: number | null;\n remaining: number | null;\n wouldExceed: boolean;\n percentAfter: number | null;\n}\n\n// ============================================================================\n// Alerts\n// ============================================================================\n\n/**\n * Alert status\n */\nexport type AlertStatus = \"pending\" | \"triggered\" | \"acknowledged\" | \"resolved\";\n\n/**\n * Usage alert\n */\nexport interface UsageAlert {\n id: string;\n tenantId: string;\n customerId: string;\n subscriptionId?: string;\n featureKey: string;\n thresholdPercent: number;\n status: AlertStatus;\n currentUsage: number;\n limit: number;\n triggeredAt?: Date;\n acknowledgedAt?: Date;\n resolvedAt?: Date;\n metadata?: Record<string, unknown>;\n createdAt: Date;\n}\n\n// ============================================================================\n// Subscription Lifecycle\n// ============================================================================\n\n/**\n * Subscription lifecycle event types\n */\nexport type SubscriptionEventType =\n | \"subscription.created\"\n | \"subscription.activated\"\n | \"subscription.updated\"\n | \"subscription.plan_changed\"\n | \"subscription.canceled\"\n | \"subscription.expired\"\n | \"subscription.renewed\"\n | \"subscription.trial_started\"\n | \"subscription.trial_ended\"\n | \"subscription.payment_failed\"\n | \"subscription.payment_succeeded\"\n | \"subscription.period_reset\";\n\n/**\n * Subscription lifecycle event\n */\nexport interface SubscriptionEvent {\n type: SubscriptionEventType;\n subscription: BillingSubscription;\n previousPlan?: Plan;\n newPlan?: Plan;\n timestamp: Date;\n provider: PaymentProviderType;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Subscription event handler\n */\nexport type SubscriptionHandler = (event: SubscriptionEvent) => void | Promise<void>;\n\n// ============================================================================\n// Usage Webhook Events\n// ============================================================================\n\n/**\n * Usage-specific webhook event types\n */\nexport type UsageWebhookEventType =\n | \"usage.recorded\"\n | \"usage.threshold_reached\"\n | \"usage.limit_exceeded\"\n | \"usage.limit_reset\"\n | \"plan.upgraded\"\n | \"plan.downgraded\";\n\n// ============================================================================\n// Storage Interface\n// ============================================================================\n\n/**\n * Usage storage interface\n * Allows pluggable storage backends (database, in-memory, etc.)\n */\nexport interface UsageStorage {\n // Plans\n getPlan(planId: string): Promise<Plan | null>;\n getPlanByName(name: string): Promise<Plan | null>;\n listPlans(options?: { activeOnly?: boolean }): Promise<Plan[]>;\n\n // Plan Features\n getPlanFeatures(planId: string): Promise<PlanFeature[]>;\n getFeatureLimit(planId: string, featureKey: string): Promise<PlanFeature | null>;\n\n // Customer-Plan mapping\n getCustomerPlanId(customerId: string): Promise<string | null>;\n setCustomerPlanId(customerId: string, planId: string): Promise<void>;\n\n // Usage Events\n recordUsage(event: Omit<UsageEvent, \"id\">): Promise<UsageEvent>;\n recordUsageBatch(events: Omit<UsageEvent, \"id\">[]): Promise<UsageEvent[]>;\n getUsageEvents(customerId: string, options: GetUsageOptions): Promise<UsageEvent[]>;\n\n // Usage Aggregates\n getAggregate(customerId: string, featureKey: string, periodType: PeriodType, periodStart: Date): Promise<UsageAggregate | null>;\n upsertAggregate(aggregate: Omit<UsageAggregate, \"id\">): Promise<UsageAggregate>;\n getAggregates(customerId: string, options: GetUsageOptions): Promise<UsageAggregate[]>;\n\n // Current period usage (fast path)\n getCurrentPeriodUsage(customerId: string, featureKey: string, periodStart: Date): Promise<number>;\n\n // Alerts\n createAlert(alert: Omit<UsageAlert, \"id\" | \"createdAt\">): Promise<UsageAlert>;\n getActiveAlerts(customerId: string): Promise<UsageAlert[]>;\n updateAlertStatus(alertId: string, status: AlertStatus): Promise<void>;\n\n // Usage Reset\n /** Reset usage for a customer (all features or specific ones) */\n resetUsage(customerId: string, featureKeys?: string[], periodStart?: Date): Promise<void>;\n /** Reset all aggregates for a customer */\n resetAggregates(customerId: string, featureKeys?: string[]): Promise<void>;\n\n // Access Status\n /** Get customer access status */\n getAccessStatus(customerId: string): Promise<AccessStatusInfo | null>;\n /** Set customer access status */\n setAccessStatus(customerId: string, status: AccessStatusInfo): Promise<void>;\n\n // Billing Cycle (for billing_cycle reset period)\n /** Get customer's current billing cycle dates */\n getBillingCycle(customerId: string): Promise<{ start: Date; end: Date } | null>;\n /** Set customer's billing cycle dates */\n setBillingCycle(customerId: string, start: Date, end: Date): Promise<void>;\n}\n\n// ============================================================================\n// Service Configuration\n// ============================================================================\n\n/**\n * Usage service configuration\n */\nexport interface UsageServiceConfig {\n /** Storage backend */\n storage: UsageStorage;\n\n /** Logger */\n logger?: BillingLogger;\n\n /** Alert thresholds (default: [80, 100]) */\n alertThresholds?: number[];\n\n /** Aggregate usage immediately (default: false - async) */\n aggregateImmediately?: boolean;\n\n /**\n * Reset period for quotas\n * - monthly: Reset on the 1st of each calendar month (default)\n * - billing_cycle: Reset on subscription renewal date\n */\n resetPeriod?: ResetPeriod;\n\n /**\n * Auto-reset quotas on subscription renewal\n * Default: true\n */\n autoResetOnRenewal?: boolean;\n\n /**\n * Grace period in days before access is suspended after payment failure\n * Default: 3 days\n */\n paymentGraceDays?: number;\n\n /**\n * Number of failed payments before suspending access\n * Default: 3\n */\n maxFailedPayments?: number;\n\n /** Callback when threshold is reached */\n onThresholdReached?: (alert: UsageAlert) => void | Promise<void>;\n\n /** Callback when limit is exceeded */\n onLimitExceeded?: (quota: QuotaStatus, customerId: string) => void | Promise<void>;\n\n /** Callback when period resets */\n onPeriodReset?: (customerId: string, featureKey: string) => void | Promise<void>;\n\n /** Callback when access status changes */\n onAccessStatusChanged?: (customerId: string, status: AccessStatusInfo, previousStatus?: AccessStatus) => void | Promise<void>;\n}\n\n/**\n * Quota manager configuration\n */\nexport interface QuotaManagerConfig {\n /** Storage backend */\n storage: UsageStorage;\n\n /** Logger */\n logger?: BillingLogger;\n\n /** Soft limit behavior - warn but allow (default: false) */\n softLimits?: boolean;\n\n /** Grace period percentage over limit (default: 0) */\n gracePercent?: number;\n\n /**\n * Features that allow overage (soft limits)\n * If set, only these features will allow overage.\n * If not set and softLimits=true, all features allow overage.\n */\n overageAllowedFeatures?: string[];\n\n /**\n * Callback when overage is recorded\n * Called when usage exceeds limit for a soft-limit feature\n */\n onOverage?: (customerId: string, featureKey: string, overage: number, limit: number) => void | Promise<void>;\n}\n\n// ============================================================================\n// Errors\n// ============================================================================\n\n/**\n * Usage error codes\n */\nexport const UsageErrorCodes = {\n QUOTA_EXCEEDED: \"QUOTA_EXCEEDED\",\n PLAN_NOT_FOUND: \"PLAN_NOT_FOUND\",\n FEATURE_NOT_FOUND: \"FEATURE_NOT_FOUND\",\n CUSTOMER_NOT_FOUND: \"CUSTOMER_NOT_FOUND\",\n DUPLICATE_EVENT: \"DUPLICATE_EVENT\",\n STORAGE_ERROR: \"STORAGE_ERROR\",\n INVALID_PERIOD: \"INVALID_PERIOD\",\n} as const;\n\nexport type UsageErrorCode = keyof typeof UsageErrorCodes;\n\n/**\n * Usage error\n */\nexport class UsageError extends Error {\n constructor(\n message: string,\n public readonly code: UsageErrorCode,\n public readonly details?: Record<string, unknown>\n ) {\n super(message);\n this.name = \"UsageError\";\n }\n}\n\n/**\n * Quota exceeded error\n */\nexport class QuotaExceededError extends UsageError {\n constructor(\n public readonly featureKey: string,\n public readonly limit: number | null,\n public readonly currentUsage: number,\n public readonly requestedQuantity: number = 1\n ) {\n super(\n `Quota exceeded for feature \"${featureKey}\": ${currentUsage}/${limit ?? \"unlimited\"} used`,\n \"QUOTA_EXCEEDED\",\n { featureKey, limit, currentUsage, requestedQuantity }\n );\n this.name = \"QuotaExceededError\";\n }\n}\n","/**\n * @parsrun/payments - In-Memory Usage Storage\n * Default storage implementation for development and testing\n */\n\nimport type {\n UsageStorage,\n Plan,\n PlanFeature,\n UsageEvent,\n UsageAggregate,\n UsageAlert,\n AlertStatus,\n PeriodType,\n GetUsageOptions,\n AccessStatusInfo,\n} from \"./types.js\";\n\n/**\n * Generate unique ID\n */\nfunction generateId(): string {\n return `${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n/**\n * In-memory usage storage\n * For development, testing, and single-instance deployments\n */\nexport class MemoryUsageStorage implements UsageStorage {\n private plans = new Map<string, Plan>();\n private planFeatures = new Map<string, PlanFeature[]>();\n private customerPlans = new Map<string, string>();\n private usageEvents: UsageEvent[] = [];\n private usageAggregates = new Map<string, UsageAggregate>();\n private alerts = new Map<string, UsageAlert>();\n private idempotencyKeys = new Set<string>();\n private accessStatuses = new Map<string, AccessStatusInfo>();\n private billingCycles = new Map<string, { start: Date; end: Date }>();\n\n // ============================================================================\n // Plans\n // ============================================================================\n\n async getPlan(planId: string): Promise<Plan | null> {\n return this.plans.get(planId) ?? null;\n }\n\n async getPlanByName(name: string): Promise<Plan | null> {\n for (const plan of this.plans.values()) {\n if (plan.name === name) {\n return plan;\n }\n }\n return null;\n }\n\n async listPlans(options?: { activeOnly?: boolean }): Promise<Plan[]> {\n const plans = Array.from(this.plans.values());\n if (options?.activeOnly) {\n return plans.filter((p) => p.isActive);\n }\n return plans;\n }\n\n /**\n * Add a plan (for testing/setup)\n */\n addPlan(plan: Plan): void {\n this.plans.set(plan.id, plan);\n // Extract features\n if (plan.features.length > 0) {\n this.planFeatures.set(plan.id, plan.features);\n }\n }\n\n // ============================================================================\n // Plan Features\n // ============================================================================\n\n async getPlanFeatures(planId: string): Promise<PlanFeature[]> {\n return this.planFeatures.get(planId) ?? [];\n }\n\n async getFeatureLimit(planId: string, featureKey: string): Promise<PlanFeature | null> {\n const features = this.planFeatures.get(planId);\n if (!features) return null;\n return features.find((f) => f.featureKey === featureKey) ?? null;\n }\n\n /**\n * Add plan features (for testing/setup)\n */\n addPlanFeatures(planId: string, features: PlanFeature[]): void {\n this.planFeatures.set(planId, features);\n }\n\n // ============================================================================\n // Customer-Plan Mapping\n // ============================================================================\n\n async getCustomerPlanId(customerId: string): Promise<string | null> {\n return this.customerPlans.get(customerId) ?? null;\n }\n\n async setCustomerPlanId(customerId: string, planId: string): Promise<void> {\n this.customerPlans.set(customerId, planId);\n }\n\n // ============================================================================\n // Usage Events\n // ============================================================================\n\n async recordUsage(event: Omit<UsageEvent, \"id\">): Promise<UsageEvent> {\n // Check idempotency\n if (event.idempotencyKey) {\n if (this.idempotencyKeys.has(event.idempotencyKey)) {\n // Return existing event with same key\n const existing = this.usageEvents.find(\n (e) => e.idempotencyKey === event.idempotencyKey\n );\n if (existing) return existing;\n }\n this.idempotencyKeys.add(event.idempotencyKey);\n }\n\n const usageEvent: UsageEvent = {\n id: generateId(),\n ...event,\n timestamp: event.timestamp ?? new Date(),\n };\n\n this.usageEvents.push(usageEvent);\n return usageEvent;\n }\n\n async recordUsageBatch(events: Omit<UsageEvent, \"id\">[]): Promise<UsageEvent[]> {\n const results: UsageEvent[] = [];\n for (const event of events) {\n results.push(await this.recordUsage(event));\n }\n return results;\n }\n\n async getUsageEvents(customerId: string, options: GetUsageOptions): Promise<UsageEvent[]> {\n let events = this.usageEvents.filter((e) => e.customerId === customerId);\n\n if (options.featureKey) {\n events = events.filter((e) => e.featureKey === options.featureKey);\n }\n\n if (options.subscriptionId) {\n events = events.filter((e) => e.subscriptionId === options.subscriptionId);\n }\n\n if (options.startDate) {\n events = events.filter((e) => e.timestamp >= options.startDate!);\n }\n\n if (options.endDate) {\n events = events.filter((e) => e.timestamp <= options.endDate!);\n }\n\n return events;\n }\n\n // ============================================================================\n // Usage Aggregates\n // ============================================================================\n\n private getAggregateKey(\n customerId: string,\n featureKey: string,\n periodType: PeriodType,\n periodStart: Date\n ): string {\n return `${customerId}:${featureKey}:${periodType}:${periodStart.toISOString()}`;\n }\n\n async getAggregate(\n customerId: string,\n featureKey: string,\n periodType: PeriodType,\n periodStart: Date\n ): Promise<UsageAggregate | null> {\n const key = this.getAggregateKey(customerId, featureKey, periodType, periodStart);\n return this.usageAggregates.get(key) ?? null;\n }\n\n async upsertAggregate(aggregate: Omit<UsageAggregate, \"id\">): Promise<UsageAggregate> {\n const key = this.getAggregateKey(\n aggregate.customerId,\n aggregate.featureKey,\n aggregate.periodType,\n aggregate.periodStart\n );\n\n const existing = this.usageAggregates.get(key);\n const result: UsageAggregate = {\n id: existing?.id ?? generateId(),\n ...aggregate,\n lastUpdated: new Date(),\n };\n\n this.usageAggregates.set(key, result);\n return result;\n }\n\n async getAggregates(customerId: string, options: GetUsageOptions): Promise<UsageAggregate[]> {\n let aggregates = Array.from(this.usageAggregates.values()).filter(\n (a) => a.customerId === customerId\n );\n\n if (options.featureKey) {\n aggregates = aggregates.filter((a) => a.featureKey === options.featureKey);\n }\n\n if (options.periodType) {\n aggregates = aggregates.filter((a) => a.periodType === options.periodType);\n }\n\n if (options.subscriptionId) {\n aggregates = aggregates.filter((a) => a.subscriptionId === options.subscriptionId);\n }\n\n if (options.startDate) {\n aggregates = aggregates.filter((a) => a.periodStart >= options.startDate!);\n }\n\n if (options.endDate) {\n aggregates = aggregates.filter((a) => a.periodEnd <= options.endDate!);\n }\n\n return aggregates;\n }\n\n async getCurrentPeriodUsage(\n customerId: string,\n featureKey: string,\n periodStart: Date\n ): Promise<number> {\n // First check aggregate\n const aggregate = await this.getAggregate(customerId, featureKey, \"month\", periodStart);\n if (aggregate) {\n return aggregate.totalQuantity;\n }\n\n // Fall back to counting events\n const events = this.usageEvents.filter(\n (e) =>\n e.customerId === customerId &&\n e.featureKey === featureKey &&\n e.timestamp >= periodStart\n );\n\n return events.reduce((sum, e) => sum + e.quantity, 0);\n }\n\n // ============================================================================\n // Alerts\n // ============================================================================\n\n async createAlert(alert: Omit<UsageAlert, \"id\" | \"createdAt\">): Promise<UsageAlert> {\n const usageAlert: UsageAlert = {\n id: generateId(),\n ...alert,\n createdAt: new Date(),\n };\n\n this.alerts.set(usageAlert.id, usageAlert);\n return usageAlert;\n }\n\n async getActiveAlerts(customerId: string): Promise<UsageAlert[]> {\n return Array.from(this.alerts.values()).filter(\n (a) =>\n a.customerId === customerId &&\n (a.status === \"pending\" || a.status === \"triggered\")\n );\n }\n\n async updateAlertStatus(alertId: string, status: AlertStatus): Promise<void> {\n const alert = this.alerts.get(alertId);\n if (alert) {\n alert.status = status;\n if (status === \"triggered\") {\n alert.triggeredAt = new Date();\n } else if (status === \"acknowledged\") {\n alert.acknowledgedAt = new Date();\n } else if (status === \"resolved\") {\n alert.resolvedAt = new Date();\n }\n }\n }\n\n // ============================================================================\n // Usage Reset\n // ============================================================================\n\n async resetUsage(\n customerId: string,\n featureKeys?: string[],\n periodStart?: Date\n ): Promise<void> {\n // Remove events for this customer\n this.usageEvents = this.usageEvents.filter((e) => {\n if (e.customerId !== customerId) return true;\n if (featureKeys && !featureKeys.includes(e.featureKey)) return true;\n if (periodStart && e.timestamp < periodStart) return true;\n return false;\n });\n\n // Reset aggregates\n await this.resetAggregates(customerId, featureKeys);\n }\n\n async resetAggregates(customerId: string, featureKeys?: string[]): Promise<void> {\n const keysToDelete: string[] = [];\n\n for (const [key, aggregate] of this.usageAggregates) {\n if (aggregate.customerId !== customerId) continue;\n if (featureKeys && !featureKeys.includes(aggregate.featureKey)) continue;\n keysToDelete.push(key);\n }\n\n for (const key of keysToDelete) {\n this.usageAggregates.delete(key);\n }\n }\n\n // ============================================================================\n // Access Status\n // ============================================================================\n\n async getAccessStatus(customerId: string): Promise<AccessStatusInfo | null> {\n return this.accessStatuses.get(customerId) ?? null;\n }\n\n async setAccessStatus(customerId: string, status: AccessStatusInfo): Promise<void> {\n this.accessStatuses.set(customerId, status);\n }\n\n // ============================================================================\n // Billing Cycle\n // ============================================================================\n\n async getBillingCycle(customerId: string): Promise<{ start: Date; end: Date } | null> {\n return this.billingCycles.get(customerId) ?? null;\n }\n\n async setBillingCycle(customerId: string, start: Date, end: Date): Promise<void> {\n this.billingCycles.set(customerId, { start, end });\n }\n\n // ============================================================================\n // Utilities\n // ============================================================================\n\n /**\n * Clear all data (for testing)\n */\n clear(): void {\n this.plans.clear();\n this.planFeatures.clear();\n this.customerPlans.clear();\n this.usageEvents = [];\n this.usageAggregates.clear();\n this.alerts.clear();\n this.idempotencyKeys.clear();\n this.accessStatuses.clear();\n this.billingCycles.clear();\n }\n\n /**\n * Get stats (for debugging)\n */\n getStats(): {\n plans: number;\n customers: number;\n events: number;\n aggregates: number;\n alerts: number;\n accessStatuses: number;\n billingCycles: number;\n } {\n return {\n plans: this.plans.size,\n customers: this.customerPlans.size,\n events: this.usageEvents.length,\n aggregates: this.usageAggregates.size,\n alerts: this.alerts.size,\n accessStatuses: this.accessStatuses.size,\n billingCycles: this.billingCycles.size,\n };\n }\n}\n\n/**\n * Create in-memory usage storage\n */\nexport function createMemoryUsageStorage(): MemoryUsageStorage {\n return new MemoryUsageStorage();\n}\n","/**\n * @parsrun/payments - Drizzle Usage Storage\n * Database-backed storage implementation using Drizzle ORM\n *\n * @example\n * ```typescript\n * import { createDrizzleUsageStorage } from \"@parsrun/payments\";\n * import { drizzle } from \"drizzle-orm/postgres-js\";\n * import postgres from \"postgres\";\n *\n * const client = postgres(process.env.DATABASE_URL);\n * const db = drizzle(client);\n *\n * const storage = createDrizzleUsageStorage({ db });\n *\n * const usageService = createUsageService({ storage });\n * ```\n */\n\nimport { eq, and, gte, lte, sql, inArray } from \"drizzle-orm\";\nimport type { PostgresJsDatabase } from \"drizzle-orm/postgres-js\";\nimport type { NeonHttpDatabase } from \"drizzle-orm/neon-http\";\n\nimport type {\n UsageStorage,\n Plan,\n PlanFeature,\n UsageEvent,\n UsageAggregate,\n UsageAlert,\n AlertStatus,\n PeriodType,\n GetUsageOptions,\n AccessStatusInfo,\n LimitPeriod,\n BillingInterval,\n PlanTier,\n} from \"./types.js\";\n\nimport {\n plans,\n planFeatures,\n customerPlans,\n customerAccessStatus,\n customerBillingCycles,\n usageEvents,\n usageAggregates,\n usageAlerts,\n} from \"./schema.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Supported Drizzle database types\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type DrizzleDb = PostgresJsDatabase<any> | NeonHttpDatabase<any>;\n\n/**\n * Drizzle storage configuration\n */\nexport interface DrizzleUsageStorageConfig {\n /** Drizzle database instance */\n db: DrizzleDb;\n\n /** Table prefix (optional, for multi-tenant setups) */\n tablePrefix?: string;\n}\n\n/**\n * Generate unique ID\n */\nfunction generateId(): string {\n return `${Date.now().toString(36)}_${Math.random().toString(36).substring(2, 9)}`;\n}\n\n// ============================================================================\n// Drizzle Usage Storage\n// ============================================================================\n\n/**\n * Drizzle-backed usage storage\n * Persists all usage data to PostgreSQL/Neon database\n */\nexport class DrizzleUsageStorage implements UsageStorage {\n private readonly db: DrizzleDb;\n\n constructor(config: DrizzleUsageStorageConfig) {\n this.db = config.db;\n }\n\n // ============================================================================\n // Plans\n // ============================================================================\n\n async getPlan(planId: string): Promise<Plan | null> {\n const rows = await this.db\n .select()\n .from(plans)\n .where(eq(plans.id, planId))\n .limit(1);\n\n const row = rows[0];\n if (!row) return null;\n\n const features = await this.getPlanFeatures(planId);\n\n return this.mapRowToPlan(row, features);\n }\n\n async getPlanByName(name: string): Promise<Plan | null> {\n const rows = await this.db\n .select()\n .from(plans)\n .where(eq(plans.name, name))\n .limit(1);\n\n const row = rows[0];\n if (!row) return null;\n\n const features = await this.getPlanFeatures(row.id);\n\n return this.mapRowToPlan(row, features);\n }\n\n async listPlans(options?: { activeOnly?: boolean }): Promise<Plan[]> {\n let query = this.db.select().from(plans);\n\n if (options?.activeOnly) {\n query = query.where(eq(plans.isActive, true)) as typeof query;\n }\n\n const rows = await query;\n\n // Fetch features for all plans\n const result: Plan[] = [];\n for (const row of rows) {\n const features = await this.getPlanFeatures(row.id);\n result.push(this.mapRowToPlan(row, features));\n }\n\n return result;\n }\n\n private mapRowToPlan(\n row: typeof plans.$inferSelect,\n features: PlanFeature[]\n ): Plan {\n const plan: Plan = {\n id: row.id,\n name: row.name,\n displayName: row.displayName,\n description: row.description,\n tier: row.tier as PlanTier,\n basePrice: row.basePrice,\n currency: row.currency,\n billingInterval: row.billingInterval as BillingInterval,\n features,\n isActive: row.isActive,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n\n if (row.metadata !== null) {\n plan.metadata = row.metadata;\n }\n\n return plan;\n }\n\n // ============================================================================\n // Plan Features\n // ============================================================================\n\n async getPlanFeatures(planId: string): Promise<PlanFeature[]> {\n const rows = await this.db\n .select()\n .from(planFeatures)\n .where(eq(planFeatures.planId, planId));\n\n return rows.map((row) => this.mapRowToPlanFeature(row));\n }\n\n async getFeatureLimit(\n planId: string,\n featureKey: string\n ): Promise<PlanFeature | null> {\n const rows = await this.db\n .select()\n .from(planFeatures)\n .where(\n and(\n eq(planFeatures.planId, planId),\n eq(planFeatures.featureKey, featureKey)\n )\n )\n .limit(1);\n\n const row = rows[0];\n if (!row) return null;\n\n return this.mapRowToPlanFeature(row);\n }\n\n private mapRowToPlanFeature(\n row: typeof planFeatures.$inferSelect\n ): PlanFeature {\n const feature: PlanFeature = {\n id: row.id,\n planId: row.planId,\n featureKey: row.featureKey,\n limitValue: row.limitValue,\n limitPeriod: row.limitPeriod as LimitPeriod,\n isEnabled: row.isEnabled,\n };\n\n if (row.metadata !== null) {\n feature.metadata = row.metadata;\n }\n\n return feature;\n }\n\n // ============================================================================\n // Customer-Plan Mapping\n // ============================================================================\n\n async getCustomerPlanId(customerId: string): Promise<string | null> {\n const rows = await this.db\n .select({ planId: customerPlans.planId })\n .from(customerPlans)\n .where(eq(customerPlans.customerId, customerId))\n .limit(1);\n\n const row = rows[0];\n return row ? row.planId : null;\n }\n\n async setCustomerPlanId(customerId: string, planId: string): Promise<void> {\n await this.db\n .insert(customerPlans)\n .values({\n customerId,\n planId,\n assignedAt: new Date(),\n })\n .onConflictDoUpdate({\n target: customerPlans.customerId,\n set: {\n planId,\n assignedAt: new Date(),\n },\n });\n }\n\n // ============================================================================\n // Usage Events\n // ============================================================================\n\n async recordUsage(event: Omit<UsageEvent, \"id\">): Promise<UsageEvent> {\n const id = generateId();\n\n // Check idempotency\n if (event.idempotencyKey) {\n const existing = await this.db\n .select()\n .from(usageEvents)\n .where(eq(usageEvents.idempotencyKey, event.idempotencyKey))\n .limit(1);\n\n const existingRow = existing[0];\n if (existingRow) {\n return this.mapRowToUsageEvent(existingRow);\n }\n }\n\n const insertData: typeof usageEvents.$inferInsert = {\n id,\n tenantId: event.tenantId,\n customerId: event.customerId,\n featureKey: event.featureKey,\n quantity: event.quantity,\n timestamp: event.timestamp ?? new Date(),\n };\n\n if (event.subscriptionId !== undefined) {\n insertData.subscriptionId = event.subscriptionId;\n }\n if (event.metadata !== undefined) {\n insertData.metadata = event.metadata;\n }\n if (event.idempotencyKey !== undefined) {\n insertData.idempotencyKey = event.idempotencyKey;\n }\n\n await this.db.insert(usageEvents).values(insertData);\n\n return {\n id,\n ...event,\n timestamp: event.timestamp ?? new Date(),\n };\n }\n\n async recordUsageBatch(\n events: Omit<UsageEvent, \"id\">[]\n ): Promise<UsageEvent[]> {\n const results: UsageEvent[] = [];\n for (const event of events) {\n results.push(await this.recordUsage(event));\n }\n return results;\n }\n\n async getUsageEvents(\n customerId: string,\n options: GetUsageOptions\n ): Promise<UsageEvent[]> {\n const conditions = [eq(usageEvents.customerId, customerId)];\n\n if (options.featureKey) {\n conditions.push(eq(usageEvents.featureKey, options.featureKey));\n }\n if (options.subscriptionId) {\n conditions.push(eq(usageEvents.subscriptionId, options.subscriptionId));\n }\n if (options.startDate) {\n conditions.push(gte(usageEvents.timestamp, options.startDate));\n }\n if (options.endDate) {\n conditions.push(lte(usageEvents.timestamp, options.endDate));\n }\n\n const rows = await this.db\n .select()\n .from(usageEvents)\n .where(and(...conditions))\n .orderBy(usageEvents.timestamp);\n\n return rows.map((row) => this.mapRowToUsageEvent(row));\n }\n\n private mapRowToUsageEvent(\n row: typeof usageEvents.$inferSelect\n ): UsageEvent {\n const event: UsageEvent = {\n id: row.id,\n tenantId: row.tenantId,\n customerId: row.customerId,\n featureKey: row.featureKey,\n quantity: row.quantity,\n timestamp: row.timestamp,\n };\n\n if (row.subscriptionId !== null) {\n event.subscriptionId = row.subscriptionId;\n }\n if (row.metadata !== null) {\n event.metadata = row.metadata;\n }\n if (row.idempotencyKey !== null) {\n event.idempotencyKey = row.idempotencyKey;\n }\n\n return event;\n }\n\n // ============================================================================\n // Usage Aggregates\n // ============================================================================\n\n async getAggregate(\n customerId: string,\n featureKey: string,\n periodType: PeriodType,\n periodStart: Date\n ): Promise<UsageAggregate | null> {\n const rows = await this.db\n .select()\n .from(usageAggregates)\n .where(\n and(\n eq(usageAggregates.customerId, customerId),\n eq(usageAggregates.featureKey, featureKey),\n eq(usageAggregates.periodType, periodType),\n eq(usageAggregates.periodStart, periodStart)\n )\n )\n .limit(1);\n\n const row = rows[0];\n if (!row) return null;\n\n return this.mapRowToUsageAggregate(row);\n }\n\n async upsertAggregate(\n aggregate: Omit<UsageAggregate, \"id\">\n ): Promise<UsageAggregate> {\n const id = generateId();\n\n const insertData: typeof usageAggregates.$inferInsert = {\n id,\n tenantId: aggregate.tenantId,\n customerId: aggregate.customerId,\n featureKey: aggregate.featureKey,\n periodStart: aggregate.periodStart,\n periodEnd: aggregate.periodEnd,\n periodType: aggregate.periodType,\n totalQuantity: aggregate.totalQuantity,\n eventCount: aggregate.eventCount,\n lastUpdated: new Date(),\n };\n\n if (aggregate.subscriptionId !== undefined) {\n insertData.subscriptionId = aggregate.subscriptionId;\n }\n\n await this.db\n .insert(usageAggregates)\n .values(insertData)\n .onConflictDoUpdate({\n target: [\n usageAggregates.customerId,\n usageAggregates.featureKey,\n usageAggregates.periodType,\n usageAggregates.periodStart,\n ],\n set: {\n totalQuantity: aggregate.totalQuantity,\n eventCount: aggregate.eventCount,\n lastUpdated: new Date(),\n },\n });\n\n return {\n id,\n ...aggregate,\n lastUpdated: new Date(),\n };\n }\n\n async getAggregates(\n customerId: string,\n options: GetUsageOptions\n ): Promise<UsageAggregate[]> {\n const conditions = [eq(usageAggregates.customerId, customerId)];\n\n if (options.featureKey) {\n conditions.push(eq(usageAggregates.featureKey, options.featureKey));\n }\n if (options.periodType) {\n conditions.push(eq(usageAggregates.periodType, options.periodType));\n }\n if (options.subscriptionId) {\n conditions.push(\n eq(usageAggregates.subscriptionId, options.subscriptionId)\n );\n }\n if (options.startDate) {\n conditions.push(gte(usageAggregates.periodStart, options.startDate));\n }\n if (options.endDate) {\n conditions.push(lte(usageAggregates.periodEnd, options.endDate));\n }\n\n const rows = await this.db\n .select()\n .from(usageAggregates)\n .where(and(...conditions))\n .orderBy(usageAggregates.periodStart);\n\n return rows.map((row) => this.mapRowToUsageAggregate(row));\n }\n\n async getCurrentPeriodUsage(\n customerId: string,\n featureKey: string,\n periodStart: Date\n ): Promise<number> {\n // First check aggregate\n const aggregate = await this.getAggregate(\n customerId,\n featureKey,\n \"month\",\n periodStart\n );\n\n if (aggregate) {\n return aggregate.totalQuantity;\n }\n\n // Fall back to summing events\n const result = await this.db\n .select({\n total: sql<number>`COALESCE(SUM(${usageEvents.quantity}), 0)`,\n })\n .from(usageEvents)\n .where(\n and(\n eq(usageEvents.customerId, customerId),\n eq(usageEvents.featureKey, featureKey),\n gte(usageEvents.timestamp, periodStart)\n )\n );\n\n return Number(result[0]?.total ?? 0);\n }\n\n private mapRowToUsageAggregate(\n row: typeof usageAggregates.$inferSelect\n ): UsageAggregate {\n const aggregate: UsageAggregate = {\n id: row.id,\n tenantId: row.tenantId,\n customerId: row.customerId,\n featureKey: row.featureKey,\n periodStart: row.periodStart,\n periodEnd: row.periodEnd,\n periodType: row.periodType as PeriodType,\n totalQuantity: row.totalQuantity,\n eventCount: row.eventCount,\n lastUpdated: row.lastUpdated,\n };\n\n if (row.subscriptionId !== null) {\n aggregate.subscriptionId = row.subscriptionId;\n }\n\n return aggregate;\n }\n\n // ============================================================================\n // Alerts\n // ============================================================================\n\n async createAlert(\n alert: Omit<UsageAlert, \"id\" | \"createdAt\">\n ): Promise<UsageAlert> {\n const id = generateId();\n const createdAt = new Date();\n\n const insertData: typeof usageAlerts.$inferInsert = {\n id,\n tenantId: alert.tenantId,\n customerId: alert.customerId,\n featureKey: alert.featureKey,\n thresholdPercent: alert.thresholdPercent,\n status: alert.status,\n currentUsage: alert.currentUsage,\n limit: alert.limit,\n createdAt,\n };\n\n if (alert.subscriptionId !== undefined) {\n insertData.subscriptionId = alert.subscriptionId;\n }\n if (alert.triggeredAt !== undefined) {\n insertData.triggeredAt = alert.triggeredAt;\n }\n if (alert.acknowledgedAt !== undefined) {\n insertData.acknowledgedAt = alert.acknowledgedAt;\n }\n if (alert.resolvedAt !== undefined) {\n insertData.resolvedAt = alert.resolvedAt;\n }\n if (alert.metadata !== undefined) {\n insertData.metadata = alert.metadata;\n }\n\n await this.db.insert(usageAlerts).values(insertData);\n\n return {\n id,\n ...alert,\n createdAt,\n };\n }\n\n async getActiveAlerts(customerId: string): Promise<UsageAlert[]> {\n const rows = await this.db\n .select()\n .from(usageAlerts)\n .where(\n and(\n eq(usageAlerts.customerId, customerId),\n inArray(usageAlerts.status, [\"pending\", \"triggered\"])\n )\n );\n\n return rows.map((row) => this.mapRowToUsageAlert(row));\n }\n\n async updateAlertStatus(alertId: string, status: AlertStatus): Promise<void> {\n const updateData: Partial<typeof usageAlerts.$inferInsert> = { status };\n\n if (status === \"triggered\") {\n updateData.triggeredAt = new Date();\n } else if (status === \"acknowledged\") {\n updateData.acknowledgedAt = new Date();\n } else if (status === \"resolved\") {\n updateData.resolvedAt = new Date();\n }\n\n await this.db\n .update(usageAlerts)\n .set(updateData)\n .where(eq(usageAlerts.id, alertId));\n }\n\n private mapRowToUsageAlert(row: typeof usageAlerts.$inferSelect): UsageAlert {\n const alert: UsageAlert = {\n id: row.id,\n tenantId: row.tenantId,\n customerId: row.customerId,\n featureKey: row.featureKey,\n thresholdPercent: row.thresholdPercent,\n status: row.status as AlertStatus,\n currentUsage: row.currentUsage,\n limit: row.limit,\n createdAt: row.createdAt,\n };\n\n if (row.subscriptionId !== null) {\n alert.subscriptionId = row.subscriptionId;\n }\n if (row.triggeredAt !== null) {\n alert.triggeredAt = row.triggeredAt;\n }\n if (row.acknowledgedAt !== null) {\n alert.acknowledgedAt = row.acknowledgedAt;\n }\n if (row.resolvedAt !== null) {\n alert.resolvedAt = row.resolvedAt;\n }\n if (row.metadata !== null) {\n alert.metadata = row.metadata;\n }\n\n return alert;\n }\n\n // ============================================================================\n // Usage Reset\n // ============================================================================\n\n async resetUsage(\n customerId: string,\n featureKeys?: string[],\n periodStart?: Date\n ): Promise<void> {\n // Build conditions\n const eventConditions = [eq(usageEvents.customerId, customerId)];\n const aggregateConditions = [eq(usageAggregates.customerId, customerId)];\n\n if (featureKeys && featureKeys.length > 0) {\n eventConditions.push(inArray(usageEvents.featureKey, featureKeys));\n aggregateConditions.push(\n inArray(usageAggregates.featureKey, featureKeys)\n );\n }\n\n if (periodStart) {\n eventConditions.push(gte(usageEvents.timestamp, periodStart));\n aggregateConditions.push(gte(usageAggregates.periodStart, periodStart));\n }\n\n // Delete events\n await this.db.delete(usageEvents).where(and(...eventConditions));\n\n // Delete aggregates\n await this.db.delete(usageAggregates).where(and(...aggregateConditions));\n }\n\n async resetAggregates(\n customerId: string,\n featureKeys?: string[]\n ): Promise<void> {\n const conditions = [eq(usageAggregates.customerId, customerId)];\n\n if (featureKeys && featureKeys.length > 0) {\n conditions.push(inArray(usageAggregates.featureKey, featureKeys));\n }\n\n await this.db.delete(usageAggregates).where(and(...conditions));\n }\n\n // ============================================================================\n // Access Status\n // ============================================================================\n\n async getAccessStatus(customerId: string): Promise<AccessStatusInfo | null> {\n const rows = await this.db\n .select()\n .from(customerAccessStatus)\n .where(eq(customerAccessStatus.customerId, customerId))\n .limit(1);\n\n const row = rows[0];\n if (!row) return null;\n\n const status: AccessStatusInfo = {\n status: row.status as AccessStatusInfo[\"status\"],\n updatedAt: row.updatedAt,\n };\n\n if (row.reason !== null) {\n status.reason = row.reason;\n }\n if (row.suspensionDate !== null) {\n status.suspensionDate = row.suspensionDate;\n }\n if (row.failedPaymentAttempts !== null) {\n status.failedPaymentAttempts = row.failedPaymentAttempts;\n }\n if (row.gracePeriodEnd !== null) {\n status.gracePeriodEnd = row.gracePeriodEnd;\n }\n\n return status;\n }\n\n async setAccessStatus(\n customerId: string,\n status: AccessStatusInfo\n ): Promise<void> {\n const insertData: typeof customerAccessStatus.$inferInsert = {\n customerId,\n status: status.status,\n updatedAt: status.updatedAt,\n };\n\n if (status.reason !== undefined) {\n insertData.reason = status.reason;\n }\n if (status.suspensionDate !== undefined) {\n insertData.suspensionDate = status.suspensionDate;\n }\n if (status.failedPaymentAttempts !== undefined) {\n insertData.failedPaymentAttempts = status.failedPaymentAttempts;\n }\n if (status.gracePeriodEnd !== undefined) {\n insertData.gracePeriodEnd = status.gracePeriodEnd;\n }\n\n await this.db\n .insert(customerAccessStatus)\n .values(insertData)\n .onConflictDoUpdate({\n target: customerAccessStatus.customerId,\n set: {\n status: status.status,\n reason: status.reason ?? null,\n suspensionDate: status.suspensionDate ?? null,\n failedPaymentAttempts: status.failedPaymentAttempts ?? null,\n gracePeriodEnd: status.gracePeriodEnd ?? null,\n updatedAt: status.updatedAt,\n },\n });\n }\n\n // ============================================================================\n // Billing Cycle\n // ============================================================================\n\n async getBillingCycle(\n customerId: string\n ): Promise<{ start: Date; end: Date } | null> {\n const rows = await this.db\n .select()\n .from(customerBillingCycles)\n .where(eq(customerBillingCycles.customerId, customerId))\n .limit(1);\n\n const row = rows[0];\n if (!row) return null;\n\n return {\n start: row.periodStart,\n end: row.periodEnd,\n };\n }\n\n async setBillingCycle(\n customerId: string,\n start: Date,\n end: Date\n ): Promise<void> {\n await this.db\n .insert(customerBillingCycles)\n .values({\n customerId,\n periodStart: start,\n periodEnd: end,\n updatedAt: new Date(),\n })\n .onConflictDoUpdate({\n target: customerBillingCycles.customerId,\n set: {\n periodStart: start,\n periodEnd: end,\n updatedAt: new Date(),\n },\n });\n }\n\n // ============================================================================\n // Admin Methods (for setup)\n // ============================================================================\n\n /**\n * Create or update a plan\n */\n async upsertPlan(plan: Omit<Plan, \"createdAt\" | \"updatedAt\">): Promise<Plan> {\n const now = new Date();\n\n await this.db\n .insert(plans)\n .values({\n id: plan.id,\n name: plan.name,\n displayName: plan.displayName,\n description: plan.description,\n tier: plan.tier,\n basePrice: plan.basePrice,\n currency: plan.currency,\n billingInterval: plan.billingInterval,\n isActive: plan.isActive,\n metadata: plan.metadata,\n createdAt: now,\n updatedAt: now,\n })\n .onConflictDoUpdate({\n target: plans.id,\n set: {\n name: plan.name,\n displayName: plan.displayName,\n description: plan.description,\n tier: plan.tier,\n basePrice: plan.basePrice,\n currency: plan.currency,\n billingInterval: plan.billingInterval,\n isActive: plan.isActive,\n metadata: plan.metadata,\n updatedAt: now,\n },\n });\n\n // Delete existing features and insert new ones\n await this.db\n .delete(planFeatures)\n .where(eq(planFeatures.planId, plan.id));\n\n for (const feature of plan.features) {\n await this.db.insert(planFeatures).values({\n id: feature.id || generateId(),\n planId: plan.id,\n featureKey: feature.featureKey,\n limitValue: feature.limitValue,\n limitPeriod: feature.limitPeriod,\n isEnabled: feature.isEnabled,\n metadata: feature.metadata,\n });\n }\n\n return {\n ...plan,\n createdAt: now,\n updatedAt: now,\n };\n }\n\n /**\n * Delete a plan\n */\n async deletePlan(planId: string): Promise<void> {\n // Features are cascade deleted\n await this.db.delete(plans).where(eq(plans.id, planId));\n }\n}\n\n/**\n * Create Drizzle-backed usage storage\n */\nexport function createDrizzleUsageStorage(\n config: DrizzleUsageStorageConfig\n): DrizzleUsageStorage {\n return new DrizzleUsageStorage(config);\n}\n","/**\n * @parsrun/payments - Usage Database Schema\n * Drizzle ORM schema for usage-based billing tables\n *\n * These tables store:\n * - Plans and features with limits\n * - Customer plan assignments\n * - Usage events and aggregates\n * - Access status and billing cycles\n * - Usage alerts\n */\n\nimport {\n pgTable,\n text,\n integer,\n boolean,\n timestamp,\n jsonb,\n uniqueIndex,\n index,\n} from \"drizzle-orm/pg-core\";\n\n// ============================================================================\n// Plans & Features\n// ============================================================================\n\n/**\n * Plans table - defines billing plans with tiers\n */\nexport const plans = pgTable(\"usage_plans\", {\n id: text(\"id\").primaryKey(),\n name: text(\"name\").notNull().unique(),\n displayName: text(\"display_name\").notNull(),\n description: text(\"description\"),\n tier: integer(\"tier\").notNull().default(0), // 0=free, 1=starter, 2=pro, 3=enterprise, 4=custom\n basePrice: integer(\"base_price\").notNull().default(0), // cents\n currency: text(\"currency\").notNull().default(\"usd\"),\n billingInterval: text(\"billing_interval\").notNull().default(\"month\"), // month, year\n isActive: boolean(\"is_active\").notNull().default(true),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n});\n\n/**\n * Plan features table - defines feature limits for each plan\n */\nexport const planFeatures = pgTable(\n \"usage_plan_features\",\n {\n id: text(\"id\").primaryKey(),\n planId: text(\"plan_id\")\n .notNull()\n .references(() => plans.id, { onDelete: \"cascade\" }),\n featureKey: text(\"feature_key\").notNull(), // \"api_calls\", \"storage_gb\", \"team_members\"\n limitValue: integer(\"limit_value\"), // null = unlimited\n limitPeriod: text(\"limit_period\"), // \"hour\", \"day\", \"month\", null = total\n isEnabled: boolean(\"is_enabled\").notNull().default(true),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n },\n (table) => ({\n planFeatureIdx: uniqueIndex(\"usage_plan_features_plan_feature_idx\").on(\n table.planId,\n table.featureKey\n ),\n })\n);\n\n// ============================================================================\n// Customer Data\n// ============================================================================\n\n/**\n * Customer plans table - maps customers to their current plan\n */\nexport const customerPlans = pgTable(\"usage_customer_plans\", {\n customerId: text(\"customer_id\").primaryKey(),\n planId: text(\"plan_id\")\n .notNull()\n .references(() => plans.id),\n assignedAt: timestamp(\"assigned_at\").defaultNow().notNull(),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n});\n\n/**\n * Customer access status table - tracks access status for each customer\n */\nexport const customerAccessStatus = pgTable(\"usage_customer_access_status\", {\n customerId: text(\"customer_id\").primaryKey(),\n status: text(\"status\").notNull().default(\"active\"), // active, past_due, suspended, canceled, unpaid\n reason: text(\"reason\"),\n suspensionDate: timestamp(\"suspension_date\"),\n failedPaymentAttempts: integer(\"failed_payment_attempts\").default(0),\n gracePeriodEnd: timestamp(\"grace_period_end\"),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n});\n\n/**\n * Customer billing cycles table - tracks billing period for each customer\n */\nexport const customerBillingCycles = pgTable(\"usage_customer_billing_cycles\", {\n customerId: text(\"customer_id\").primaryKey(),\n periodStart: timestamp(\"period_start\").notNull(),\n periodEnd: timestamp(\"period_end\").notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n});\n\n// ============================================================================\n// Usage Events & Aggregates\n// ============================================================================\n\n/**\n * Usage events table - raw usage event log\n */\nexport const usageEvents = pgTable(\n \"usage_events\",\n {\n id: text(\"id\").primaryKey(),\n tenantId: text(\"tenant_id\").notNull(),\n customerId: text(\"customer_id\").notNull(),\n subscriptionId: text(\"subscription_id\"),\n featureKey: text(\"feature_key\").notNull(),\n quantity: integer(\"quantity\").notNull().default(1),\n timestamp: timestamp(\"timestamp\").defaultNow().notNull(),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n idempotencyKey: text(\"idempotency_key\"),\n },\n (table) => ({\n customerIdx: index(\"usage_events_customer_idx\").on(table.customerId),\n featureIdx: index(\"usage_events_feature_idx\").on(table.featureKey),\n timestampIdx: index(\"usage_events_timestamp_idx\").on(table.timestamp),\n idempotencyIdx: uniqueIndex(\"usage_events_idempotency_idx\").on(\n table.idempotencyKey\n ),\n // Composite index for common queries\n customerFeatureTimestampIdx: index(\n \"usage_events_customer_feature_timestamp_idx\"\n ).on(table.customerId, table.featureKey, table.timestamp),\n })\n);\n\n/**\n * Usage aggregates table - pre-computed usage summaries for performance\n */\nexport const usageAggregates = pgTable(\n \"usage_aggregates\",\n {\n id: text(\"id\").primaryKey(),\n tenantId: text(\"tenant_id\").notNull(),\n customerId: text(\"customer_id\").notNull(),\n subscriptionId: text(\"subscription_id\"),\n featureKey: text(\"feature_key\").notNull(),\n periodStart: timestamp(\"period_start\").notNull(),\n periodEnd: timestamp(\"period_end\").notNull(),\n periodType: text(\"period_type\").notNull(), // \"hour\", \"day\", \"month\"\n totalQuantity: integer(\"total_quantity\").notNull().default(0),\n eventCount: integer(\"event_count\").notNull().default(0),\n lastUpdated: timestamp(\"last_updated\").defaultNow().notNull(),\n },\n (table) => ({\n // Unique constraint for upsert\n lookupIdx: uniqueIndex(\"usage_aggregates_lookup_idx\").on(\n table.customerId,\n table.featureKey,\n table.periodType,\n table.periodStart\n ),\n // Index for customer queries\n customerIdx: index(\"usage_aggregates_customer_idx\").on(table.customerId),\n })\n);\n\n// ============================================================================\n// Alerts\n// ============================================================================\n\n/**\n * Usage alerts table - tracks quota threshold alerts\n */\nexport const usageAlerts = pgTable(\n \"usage_alerts\",\n {\n id: text(\"id\").primaryKey(),\n tenantId: text(\"tenant_id\").notNull(),\n customerId: text(\"customer_id\").notNull(),\n subscriptionId: text(\"subscription_id\"),\n featureKey: text(\"feature_key\").notNull(),\n thresholdPercent: integer(\"threshold_percent\").notNull(), // 80, 100, 120\n status: text(\"status\").notNull().default(\"pending\"), // pending, triggered, acknowledged, resolved\n currentUsage: integer(\"current_usage\").notNull(),\n limit: integer(\"limit\").notNull(),\n triggeredAt: timestamp(\"triggered_at\"),\n acknowledgedAt: timestamp(\"acknowledged_at\"),\n resolvedAt: timestamp(\"resolved_at\"),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (table) => ({\n customerIdx: index(\"usage_alerts_customer_idx\").on(table.customerId),\n statusIdx: index(\"usage_alerts_status_idx\").on(table.status),\n })\n);\n\n// ============================================================================\n// Type Exports\n// ============================================================================\n\nexport type Plan = typeof plans.$inferSelect;\nexport type NewPlan = typeof plans.$inferInsert;\n\nexport type PlanFeature = typeof planFeatures.$inferSelect;\nexport type NewPlanFeature = typeof planFeatures.$inferInsert;\n\nexport type CustomerPlan = typeof customerPlans.$inferSelect;\nexport type NewCustomerPlan = typeof customerPlans.$inferInsert;\n\nexport type CustomerAccessStatusRow = typeof customerAccessStatus.$inferSelect;\nexport type NewCustomerAccessStatus = typeof customerAccessStatus.$inferInsert;\n\nexport type CustomerBillingCycle = typeof customerBillingCycles.$inferSelect;\nexport type NewCustomerBillingCycle = typeof customerBillingCycles.$inferInsert;\n\nexport type UsageEventRow = typeof usageEvents.$inferSelect;\nexport type NewUsageEvent = typeof usageEvents.$inferInsert;\n\nexport type UsageAggregateRow = typeof usageAggregates.$inferSelect;\nexport type NewUsageAggregate = typeof usageAggregates.$inferInsert;\n\nexport type UsageAlertRow = typeof usageAlerts.$inferSelect;\nexport type NewUsageAlert = typeof usageAlerts.$inferInsert;\n","/**\n * @parsrun/payments - Quota Manager\n * Handles quota checking and enforcement\n */\n\nimport type {\n UsageStorage,\n QuotaStatus,\n QuotaCheckResult,\n QuotaManagerConfig,\n BillingLogger,\n} from \"./types.js\";\nimport { QuotaExceededError } from \"./types.js\";\n\n/**\n * Null logger\n */\nconst nullLogger: BillingLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/**\n * Get period boundaries based on limit period\n */\nfunction getPeriodBoundaries(limitPeriod: \"hour\" | \"day\" | \"month\" | null): {\n start: Date;\n end: Date;\n} {\n const now = new Date();\n\n switch (limitPeriod) {\n case \"hour\": {\n const start = new Date(now);\n start.setMinutes(0, 0, 0);\n const end = new Date(start);\n end.setHours(end.getHours() + 1);\n return { start, end };\n }\n\n case \"day\": {\n const start = new Date(now);\n start.setHours(0, 0, 0, 0);\n const end = new Date(start);\n end.setDate(end.getDate() + 1);\n return { start, end };\n }\n\n case \"month\":\n default: {\n const start = new Date(now.getFullYear(), now.getMonth(), 1);\n const end = new Date(now.getFullYear(), now.getMonth() + 1, 1);\n return { start, end };\n }\n }\n}\n\n/**\n * Quota Manager\n * Handles checking and enforcing usage quotas\n */\nexport class QuotaManager {\n private readonly storage: UsageStorage;\n private readonly logger: BillingLogger;\n private readonly softLimits: boolean;\n private readonly gracePercent: number;\n private readonly overageAllowedFeatures: string[] | null;\n private readonly onOverage?: (customerId: string, featureKey: string, overage: number, limit: number) => void | Promise<void>;\n\n constructor(config: QuotaManagerConfig) {\n this.storage = config.storage;\n this.logger = config.logger ?? nullLogger;\n this.softLimits = config.softLimits ?? false;\n this.gracePercent = config.gracePercent ?? 0;\n this.overageAllowedFeatures = config.overageAllowedFeatures ?? null;\n if (config.onOverage !== undefined) {\n this.onOverage = config.onOverage;\n }\n }\n\n /**\n * Check if overage is allowed for a feature\n */\n private isOverageAllowed(featureKey: string): boolean {\n if (!this.softLimits) return false;\n if (this.overageAllowedFeatures === null) return true; // All features allow overage\n return this.overageAllowedFeatures.includes(featureKey);\n }\n\n /**\n * Check if quota allows the requested quantity\n */\n async checkQuota(\n customerId: string,\n featureKey: string,\n requestedQuantity: number = 1\n ): Promise<QuotaCheckResult> {\n // Get customer's plan\n const planId = await this.storage.getCustomerPlanId(customerId);\n if (!planId) {\n // No plan = no limits\n return {\n allowed: true,\n currentUsage: 0,\n limit: null,\n remaining: null,\n wouldExceed: false,\n percentAfter: null,\n };\n }\n\n // Get feature limit\n const feature = await this.storage.getFeatureLimit(planId, featureKey);\n if (!feature) {\n // Feature not defined = unlimited\n return {\n allowed: true,\n currentUsage: 0,\n limit: null,\n remaining: null,\n wouldExceed: false,\n percentAfter: null,\n };\n }\n\n // Feature disabled\n if (!feature.isEnabled) {\n return {\n allowed: false,\n currentUsage: 0,\n limit: 0,\n remaining: 0,\n wouldExceed: true,\n percentAfter: 100,\n };\n }\n\n // Unlimited feature\n if (feature.limitValue === null) {\n return {\n allowed: true,\n currentUsage: 0,\n limit: null,\n remaining: null,\n wouldExceed: false,\n percentAfter: null,\n };\n }\n\n // Get current usage\n const { start } = getPeriodBoundaries(feature.limitPeriod);\n const currentUsage = await this.storage.getCurrentPeriodUsage(\n customerId,\n featureKey,\n start\n );\n\n // Calculate effective limit with grace\n const effectiveLimit = Math.ceil(feature.limitValue * (1 + this.gracePercent / 100));\n const usageAfter = currentUsage + requestedQuantity;\n const wouldExceed = usageAfter > effectiveLimit;\n const percentAfter = Math.round((usageAfter / feature.limitValue) * 100);\n\n // Check if overage is allowed for this specific feature\n const overageAllowed = this.isOverageAllowed(featureKey);\n const allowed = overageAllowed ? true : !wouldExceed;\n\n this.logger.debug(\"Quota check\", {\n customerId,\n featureKey,\n currentUsage,\n requestedQuantity,\n limit: feature.limitValue,\n effectiveLimit,\n allowed,\n wouldExceed,\n });\n\n return {\n allowed,\n currentUsage,\n limit: feature.limitValue,\n remaining: Math.max(0, feature.limitValue - currentUsage),\n wouldExceed,\n percentAfter,\n };\n }\n\n /**\n * Enforce quota - throws if exceeded\n */\n async enforceQuota(\n customerId: string,\n featureKey: string,\n requestedQuantity: number = 1\n ): Promise<void> {\n const result = await this.checkQuota(customerId, featureKey, requestedQuantity);\n\n if (!result.allowed) {\n this.logger.warn(\"Quota exceeded\", {\n customerId,\n featureKey,\n currentUsage: result.currentUsage,\n limit: result.limit,\n requestedQuantity,\n });\n\n throw new QuotaExceededError(\n featureKey,\n result.limit,\n result.currentUsage,\n requestedQuantity\n );\n }\n }\n\n /**\n * Get quota status for a feature\n */\n async getQuotaStatus(customerId: string, featureKey: string): Promise<QuotaStatus> {\n const planId = await this.storage.getCustomerPlanId(customerId);\n\n // No plan = unlimited\n if (!planId) {\n const now = new Date();\n return {\n featureKey,\n limit: null,\n used: 0,\n remaining: null,\n percentUsed: null,\n periodStart: new Date(now.getFullYear(), now.getMonth(), 1),\n periodEnd: new Date(now.getFullYear(), now.getMonth() + 1, 1),\n isExceeded: false,\n isUnlimited: true,\n };\n }\n\n const feature = await this.storage.getFeatureLimit(planId, featureKey);\n\n // Feature not defined = unlimited\n if (!feature) {\n const now = new Date();\n return {\n featureKey,\n limit: null,\n used: 0,\n remaining: null,\n percentUsed: null,\n periodStart: new Date(now.getFullYear(), now.getMonth(), 1),\n periodEnd: new Date(now.getFullYear(), now.getMonth() + 1, 1),\n isExceeded: false,\n isUnlimited: true,\n };\n }\n\n const { start, end } = getPeriodBoundaries(feature.limitPeriod);\n const used = await this.storage.getCurrentPeriodUsage(customerId, featureKey, start);\n\n const isUnlimited = feature.limitValue === null;\n const limit = feature.limitValue;\n const remaining = isUnlimited ? null : Math.max(0, limit! - used);\n const percentUsed = isUnlimited ? null : Math.round((used / limit!) * 100);\n const isExceeded = !isUnlimited && used >= limit!;\n const overageAllowed = this.isOverageAllowed(featureKey);\n const overage = isUnlimited ? undefined : (used > limit! ? used - limit! : undefined);\n\n // Trigger overage callback if exceeded and overage is allowed\n if (overage !== undefined && overage > 0 && overageAllowed && this.onOverage) {\n try {\n await this.onOverage(customerId, featureKey, overage, limit!);\n } catch (error) {\n this.logger.error(\"Overage callback failed\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n const result: QuotaStatus = {\n featureKey,\n limit,\n used,\n remaining,\n percentUsed,\n periodStart: start,\n periodEnd: end,\n isExceeded,\n isUnlimited,\n };\n\n // Add overage info only when relevant\n if (overage !== undefined) {\n result.overage = overage;\n }\n if (overageAllowed) {\n result.overageAllowed = true;\n }\n\n return result;\n }\n\n /**\n * Get all quota statuses for a customer\n */\n async getAllQuotas(customerId: string): Promise<QuotaStatus[]> {\n const planId = await this.storage.getCustomerPlanId(customerId);\n if (!planId) return [];\n\n const features = await this.storage.getPlanFeatures(planId);\n const quotas: QuotaStatus[] = [];\n\n for (const feature of features) {\n const status = await this.getQuotaStatus(customerId, feature.featureKey);\n quotas.push(status);\n }\n\n return quotas;\n }\n\n /**\n * Check if any quota is exceeded\n */\n async hasExceededQuotas(customerId: string): Promise<boolean> {\n const quotas = await this.getAllQuotas(customerId);\n return quotas.some((q) => q.isExceeded);\n }\n\n /**\n * Get exceeded quotas\n */\n async getExceededQuotas(customerId: string): Promise<QuotaStatus[]> {\n const quotas = await this.getAllQuotas(customerId);\n return quotas.filter((q) => q.isExceeded);\n }\n}\n\n/**\n * Create quota manager\n */\nexport function createQuotaManager(config: QuotaManagerConfig): QuotaManager {\n return new QuotaManager(config);\n}\n","/**\n * @parsrun/payments - Usage Tracker\n * Handles recording and tracking usage events\n */\n\nimport type {\n UsageStorage,\n UsageEvent,\n TrackUsageOptions,\n UsageAggregate,\n PeriodType,\n BillingLogger,\n UsageAlert,\n} from \"./types.js\";\n\n/**\n * Null logger\n */\nconst nullLogger: BillingLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/**\n * Get period boundaries for aggregation\n */\nfunction getPeriodStart(timestamp: Date, periodType: PeriodType): Date {\n const date = new Date(timestamp);\n\n switch (periodType) {\n case \"hour\":\n date.setMinutes(0, 0, 0);\n return date;\n\n case \"day\":\n date.setHours(0, 0, 0, 0);\n return date;\n\n case \"month\":\n return new Date(date.getFullYear(), date.getMonth(), 1);\n }\n}\n\n/**\n * Get period end from period start\n */\nfunction getPeriodEnd(periodStart: Date, periodType: PeriodType): Date {\n const date = new Date(periodStart);\n\n switch (periodType) {\n case \"hour\":\n date.setHours(date.getHours() + 1);\n return date;\n\n case \"day\":\n date.setDate(date.getDate() + 1);\n return date;\n\n case \"month\":\n return new Date(date.getFullYear(), date.getMonth() + 1, 1);\n }\n}\n\n/**\n * Usage tracker configuration\n */\nexport interface UsageTrackerConfig {\n storage: UsageStorage;\n logger?: BillingLogger;\n\n /** Update aggregates immediately on each event (default: true) */\n aggregateOnRecord?: boolean;\n\n /** Alert thresholds as percentages (default: [80, 100]) */\n alertThresholds?: number[];\n\n /** Callback when threshold is reached */\n onThresholdReached?: (alert: UsageAlert) => void | Promise<void>;\n}\n\n/**\n * Usage Tracker\n * Records usage events and maintains aggregates\n */\nexport class UsageTracker {\n private readonly storage: UsageStorage;\n private readonly logger: BillingLogger;\n private readonly aggregateOnRecord: boolean;\n private readonly alertThresholds: number[];\n private readonly onThresholdReached?: (alert: UsageAlert) => void | Promise<void>;\n\n constructor(config: UsageTrackerConfig) {\n this.storage = config.storage;\n this.logger = config.logger ?? nullLogger;\n this.aggregateOnRecord = config.aggregateOnRecord ?? true;\n this.alertThresholds = config.alertThresholds ?? [80, 100];\n if (config.onThresholdReached !== undefined) {\n this.onThresholdReached = config.onThresholdReached;\n }\n }\n\n /**\n * Track a usage event\n */\n async trackUsage(options: TrackUsageOptions): Promise<UsageEvent> {\n const timestamp = options.timestamp ?? new Date();\n const quantity = options.quantity ?? 1;\n\n this.logger.debug(\"Recording usage\", {\n customerId: options.customerId,\n featureKey: options.featureKey,\n quantity,\n });\n\n // Record the event - build object with only defined optional properties\n const eventData: Omit<UsageEvent, \"id\"> = {\n tenantId: options.tenantId,\n customerId: options.customerId,\n featureKey: options.featureKey,\n quantity,\n timestamp,\n };\n\n if (options.subscriptionId !== undefined) {\n eventData.subscriptionId = options.subscriptionId;\n }\n if (options.metadata !== undefined) {\n eventData.metadata = options.metadata;\n }\n if (options.idempotencyKey !== undefined) {\n eventData.idempotencyKey = options.idempotencyKey;\n }\n\n const event = await this.storage.recordUsage(eventData);\n\n // Update aggregates if enabled\n if (this.aggregateOnRecord) {\n await this.updateAggregates(event);\n }\n\n // Check thresholds and create alerts\n await this.checkThresholds(options.customerId, options.featureKey);\n\n return event;\n }\n\n /**\n * Track multiple usage events\n */\n async trackBatch(events: TrackUsageOptions[]): Promise<UsageEvent[]> {\n const results: UsageEvent[] = [];\n\n for (const event of events) {\n const result = await this.trackUsage(event);\n results.push(result);\n }\n\n return results;\n }\n\n /**\n * Update aggregates for an event\n */\n private async updateAggregates(event: UsageEvent): Promise<void> {\n const periodTypes: PeriodType[] = [\"hour\", \"day\", \"month\"];\n\n for (const periodType of periodTypes) {\n const periodStart = getPeriodStart(event.timestamp, periodType);\n const periodEnd = getPeriodEnd(periodStart, periodType);\n\n // Get existing aggregate\n const existing = await this.storage.getAggregate(\n event.customerId,\n event.featureKey,\n periodType,\n periodStart\n );\n\n // Upsert aggregate - build object with only defined optional properties\n const aggregateData: Omit<UsageAggregate, \"id\"> = {\n tenantId: event.tenantId,\n customerId: event.customerId,\n featureKey: event.featureKey,\n periodStart,\n periodEnd,\n periodType,\n totalQuantity: (existing?.totalQuantity ?? 0) + event.quantity,\n eventCount: (existing?.eventCount ?? 0) + 1,\n lastUpdated: new Date(),\n };\n\n if (event.subscriptionId !== undefined) {\n aggregateData.subscriptionId = event.subscriptionId;\n }\n\n await this.storage.upsertAggregate(aggregateData);\n }\n }\n\n /**\n * Check thresholds and create alerts if needed\n */\n private async checkThresholds(customerId: string, featureKey: string): Promise<void> {\n // Get customer's plan\n const planId = await this.storage.getCustomerPlanId(customerId);\n if (!planId) return;\n\n // Get feature limit\n const feature = await this.storage.getFeatureLimit(planId, featureKey);\n if (!feature || feature.limitValue === null) return;\n\n // Get current usage\n const periodStart = getPeriodStart(new Date(), \"month\");\n const currentUsage = await this.storage.getCurrentPeriodUsage(\n customerId,\n featureKey,\n periodStart\n );\n\n const percentUsed = Math.round((currentUsage / feature.limitValue) * 100);\n\n // Check active alerts to avoid duplicates\n const activeAlerts = await this.storage.getActiveAlerts(customerId);\n const alertedThresholds = new Set(\n activeAlerts\n .filter((a) => a.featureKey === featureKey)\n .map((a) => a.thresholdPercent)\n );\n\n // Check each threshold\n for (const threshold of this.alertThresholds) {\n if (percentUsed >= threshold && !alertedThresholds.has(threshold)) {\n const alert = await this.storage.createAlert({\n tenantId: \"\", // Will be filled from customer\n customerId,\n featureKey,\n thresholdPercent: threshold,\n status: \"triggered\",\n currentUsage,\n limit: feature.limitValue,\n triggeredAt: new Date(),\n });\n\n this.logger.info(\"Usage threshold reached\", {\n customerId,\n featureKey,\n threshold,\n percentUsed,\n currentUsage,\n limit: feature.limitValue,\n });\n\n // Notify callback\n if (this.onThresholdReached) {\n try {\n await this.onThresholdReached(alert);\n } catch (error) {\n this.logger.error(\"Threshold callback failed\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n }\n }\n\n /**\n * Get usage for a customer\n */\n async getUsage(\n customerId: string,\n featureKey: string,\n periodType: PeriodType = \"month\"\n ): Promise<number> {\n const periodStart = getPeriodStart(new Date(), periodType);\n return this.storage.getCurrentPeriodUsage(customerId, featureKey, periodStart);\n }\n\n /**\n * Get usage aggregates\n */\n async getAggregates(\n customerId: string,\n featureKey: string,\n periodType: PeriodType,\n startDate?: Date,\n endDate?: Date\n ): Promise<UsageAggregate[]> {\n const options: { featureKey: string; periodType: PeriodType; startDate?: Date; endDate?: Date } = {\n featureKey,\n periodType,\n };\n\n if (startDate !== undefined) {\n options.startDate = startDate;\n }\n if (endDate !== undefined) {\n options.endDate = endDate;\n }\n\n return this.storage.getAggregates(customerId, options);\n }\n\n /**\n * Force aggregate recalculation for a period\n */\n async recalculateAggregates(\n customerId: string,\n featureKey: string,\n periodType: PeriodType,\n periodStart: Date\n ): Promise<UsageAggregate> {\n const periodEnd = getPeriodEnd(periodStart, periodType);\n\n // Get all events in period\n const events = await this.storage.getUsageEvents(customerId, {\n featureKey,\n startDate: periodStart,\n endDate: periodEnd,\n });\n\n // Calculate totals\n const totalQuantity = events.reduce((sum, e) => sum + e.quantity, 0);\n const eventCount = events.length;\n\n // Get tenant ID from first event or empty\n const tenantId = events[0]?.tenantId ?? \"\";\n const subscriptionId = events[0]?.subscriptionId;\n\n // Upsert aggregate - build object with only defined optional properties\n const aggregateData: Omit<UsageAggregate, \"id\"> = {\n tenantId,\n customerId,\n featureKey,\n periodStart,\n periodEnd,\n periodType,\n totalQuantity,\n eventCount,\n lastUpdated: new Date(),\n };\n\n if (subscriptionId !== undefined) {\n aggregateData.subscriptionId = subscriptionId;\n }\n\n return this.storage.upsertAggregate(aggregateData);\n }\n}\n\n/**\n * Create usage tracker\n */\nexport function createUsageTracker(config: UsageTrackerConfig): UsageTracker {\n return new UsageTracker(config);\n}\n","/**\n * @parsrun/payments - Subscription Lifecycle Hooks\n * Event-driven subscription lifecycle management\n */\n\nimport type {\n SubscriptionEventType,\n SubscriptionEvent,\n SubscriptionHandler,\n BillingLogger,\n} from \"./types.js\";\n\n/**\n * Null logger\n */\nconst nullLogger: BillingLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/**\n * Subscription Lifecycle\n * Manages subscription event handlers\n */\nexport class SubscriptionLifecycle {\n private readonly handlers: Map<SubscriptionEventType | \"*\", SubscriptionHandler[]>;\n private readonly logger: BillingLogger;\n\n constructor(logger?: BillingLogger) {\n this.handlers = new Map();\n this.logger = logger ?? nullLogger;\n }\n\n /**\n * Register an event handler\n */\n on(event: SubscriptionEventType | \"*\", handler: SubscriptionHandler): this {\n const handlers = this.handlers.get(event) ?? [];\n handlers.push(handler);\n this.handlers.set(event, handlers);\n\n this.logger.debug(\"Lifecycle handler registered\", { event });\n return this;\n }\n\n /**\n * Remove an event handler\n */\n off(event: SubscriptionEventType | \"*\", handler: SubscriptionHandler): this {\n const handlers = this.handlers.get(event);\n if (handlers) {\n const index = handlers.indexOf(handler);\n if (index !== -1) {\n handlers.splice(index, 1);\n }\n }\n return this;\n }\n\n /**\n * Emit an event to all handlers\n */\n async emit(event: SubscriptionEvent): Promise<void> {\n this.logger.info(\"Lifecycle event\", {\n type: event.type,\n subscriptionId: event.subscription.id,\n provider: event.provider,\n });\n\n // Get specific handlers\n const specificHandlers = this.handlers.get(event.type) ?? [];\n\n // Get wildcard handlers\n const wildcardHandlers = this.handlers.get(\"*\") ?? [];\n\n // Combine all handlers\n const allHandlers = [...specificHandlers, ...wildcardHandlers];\n\n // Execute all handlers\n const results = await Promise.allSettled(\n allHandlers.map((handler) => handler(event))\n );\n\n // Log any failures\n for (const result of results) {\n if (result.status === \"rejected\") {\n this.logger.error(\"Lifecycle handler failed\", {\n type: event.type,\n error: result.reason instanceof Error ? result.reason.message : String(result.reason),\n });\n }\n }\n }\n\n /**\n * Check if there are handlers for an event\n */\n hasHandlers(event: SubscriptionEventType | \"*\"): boolean {\n const handlers = this.handlers.get(event);\n return handlers !== undefined && handlers.length > 0;\n }\n\n /**\n * Get handler count for an event\n */\n handlerCount(event: SubscriptionEventType | \"*\"): number {\n return this.handlers.get(event)?.length ?? 0;\n }\n\n /**\n * Clear all handlers\n */\n clear(): void {\n this.handlers.clear();\n }\n\n // ============================================================================\n // Convenience Methods\n // ============================================================================\n\n /**\n * Handle subscription created\n */\n onCreated(handler: SubscriptionHandler): this {\n return this.on(\"subscription.created\", handler);\n }\n\n /**\n * Handle subscription activated\n */\n onActivated(handler: SubscriptionHandler): this {\n return this.on(\"subscription.activated\", handler);\n }\n\n /**\n * Handle subscription updated\n */\n onUpdated(handler: SubscriptionHandler): this {\n return this.on(\"subscription.updated\", handler);\n }\n\n /**\n * Handle plan changed\n */\n onPlanChanged(handler: SubscriptionHandler): this {\n return this.on(\"subscription.plan_changed\", handler);\n }\n\n /**\n * Handle subscription canceled\n */\n onCanceled(handler: SubscriptionHandler): this {\n return this.on(\"subscription.canceled\", handler);\n }\n\n /**\n * Handle subscription expired\n */\n onExpired(handler: SubscriptionHandler): this {\n return this.on(\"subscription.expired\", handler);\n }\n\n /**\n * Handle subscription renewed\n */\n onRenewed(handler: SubscriptionHandler): this {\n return this.on(\"subscription.renewed\", handler);\n }\n\n /**\n * Handle trial started\n */\n onTrialStarted(handler: SubscriptionHandler): this {\n return this.on(\"subscription.trial_started\", handler);\n }\n\n /**\n * Handle trial ended\n */\n onTrialEnded(handler: SubscriptionHandler): this {\n return this.on(\"subscription.trial_ended\", handler);\n }\n\n /**\n * Handle payment failed\n */\n onPaymentFailed(handler: SubscriptionHandler): this {\n return this.on(\"subscription.payment_failed\", handler);\n }\n\n /**\n * Handle payment succeeded\n */\n onPaymentSucceeded(handler: SubscriptionHandler): this {\n return this.on(\"subscription.payment_succeeded\", handler);\n }\n\n /**\n * Handle period reset\n */\n onPeriodReset(handler: SubscriptionHandler): this {\n return this.on(\"subscription.period_reset\", handler);\n }\n\n /**\n * Handle all events\n */\n onAll(handler: SubscriptionHandler): this {\n return this.on(\"*\", handler);\n }\n}\n\n/**\n * Create subscription lifecycle manager\n */\nexport function createSubscriptionLifecycle(logger?: BillingLogger): SubscriptionLifecycle {\n return new SubscriptionLifecycle(logger);\n}\n","/**\n * @parsrun/payments - Usage Service\n * Main service for usage-based billing\n */\n\nimport type {\n UsageStorage,\n UsageServiceConfig,\n UsageEvent,\n TrackUsageOptions,\n UsageAggregate,\n QuotaStatus,\n QuotaCheckResult,\n Plan,\n PlanFeature,\n PeriodType,\n GetUsageOptions,\n SubscriptionEventType,\n SubscriptionHandler,\n BillingLogger,\n ResetPeriod,\n AccessStatus,\n AccessStatusInfo,\n} from \"./types.js\";\nimport { QuotaManager } from \"./quota-manager.js\";\nimport { UsageTracker } from \"./usage-tracker.js\";\nimport { SubscriptionLifecycle } from \"./lifecycle-hooks.js\";\n\n/**\n * Null logger\n */\nconst nullLogger: BillingLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/**\n * Usage Service\n *\n * High-level API for usage-based billing:\n * - Track usage events\n * - Check and enforce quotas\n * - Manage subscription lifecycle\n * - Generate usage reports\n *\n * @example\n * ```typescript\n * const usageService = createUsageService({\n * storage: createMemoryUsageStorage(),\n * alertThresholds: [80, 100],\n * onThresholdReached: async (alert) => {\n * await sendEmail(alert.customerId, \"usage-warning\");\n * },\n * });\n *\n * // Track usage\n * await usageService.trackUsage({\n * tenantId: \"tenant_123\",\n * customerId: \"cus_456\",\n * featureKey: \"api_calls\",\n * quantity: 1,\n * });\n *\n * // Check quota\n * const quota = await usageService.getQuotaStatus(\"cus_456\", \"api_calls\");\n * if (quota.isExceeded) {\n * throw new Error(\"Quota exceeded\");\n * }\n *\n * // Lifecycle hooks\n * usageService.onPlanChanged(async (event) => {\n * console.log(`Plan changed from ${event.previousPlan?.name} to ${event.newPlan?.name}`);\n * });\n * ```\n */\nexport class UsageService {\n private readonly storage: UsageStorage;\n private readonly logger: BillingLogger;\n private readonly quotaManager: QuotaManager;\n private readonly usageTracker: UsageTracker;\n private readonly lifecycle: SubscriptionLifecycle;\n private readonly limitExceededHandler?: (quota: QuotaStatus, customerId: string) => void | Promise<void>;\n private readonly resetPeriod: ResetPeriod;\n private readonly autoResetOnRenewal: boolean;\n private readonly paymentGraceDays: number;\n private readonly maxFailedPayments: number;\n private readonly accessStatusChangedHandler?: (customerId: string, status: AccessStatusInfo, previousStatus?: AccessStatus) => void | Promise<void>;\n private readonly periodResetHandler?: (customerId: string, featureKey: string) => void | Promise<void>;\n\n constructor(config: UsageServiceConfig) {\n this.storage = config.storage;\n this.logger = config.logger ?? nullLogger;\n this.resetPeriod = config.resetPeriod ?? \"monthly\";\n this.autoResetOnRenewal = config.autoResetOnRenewal ?? true;\n this.paymentGraceDays = config.paymentGraceDays ?? 3;\n this.maxFailedPayments = config.maxFailedPayments ?? 3;\n\n if (config.onAccessStatusChanged !== undefined) {\n this.accessStatusChangedHandler = config.onAccessStatusChanged;\n }\n if (config.onPeriodReset !== undefined) {\n this.periodResetHandler = config.onPeriodReset;\n }\n\n // Store handler with undefined check\n if (config.onLimitExceeded !== undefined) {\n this.limitExceededHandler = config.onLimitExceeded;\n }\n\n // Build quota manager config with only defined properties\n const quotaManagerConfig: { storage: UsageStorage; logger?: BillingLogger } = {\n storage: config.storage,\n };\n if (config.logger !== undefined) {\n quotaManagerConfig.logger = config.logger;\n }\n this.quotaManager = new QuotaManager(quotaManagerConfig);\n\n // Build usage tracker config with only defined properties\n const usageTrackerConfig: {\n storage: UsageStorage;\n logger?: BillingLogger;\n aggregateOnRecord?: boolean;\n alertThresholds?: number[];\n onThresholdReached?: (alert: import(\"./types.js\").UsageAlert) => void | Promise<void>;\n } = {\n storage: config.storage,\n aggregateOnRecord: config.aggregateImmediately ?? true,\n alertThresholds: config.alertThresholds ?? [80, 100],\n };\n if (config.logger !== undefined) {\n usageTrackerConfig.logger = config.logger;\n }\n if (config.onThresholdReached !== undefined) {\n usageTrackerConfig.onThresholdReached = config.onThresholdReached;\n }\n this.usageTracker = new UsageTracker(usageTrackerConfig);\n\n // Initialize lifecycle\n this.lifecycle = config.logger !== undefined\n ? new SubscriptionLifecycle(config.logger)\n : new SubscriptionLifecycle();\n\n this.logger.info(\"UsageService initialized\");\n }\n\n // ============================================================================\n // Usage Tracking\n // ============================================================================\n\n /**\n * Track a usage event\n */\n async trackUsage(options: TrackUsageOptions): Promise<UsageEvent> {\n return this.usageTracker.trackUsage(options);\n }\n\n /**\n * Track multiple usage events\n */\n async trackBatch(events: TrackUsageOptions[]): Promise<UsageEvent[]> {\n return this.usageTracker.trackBatch(events);\n }\n\n /**\n * Get current usage for a feature\n */\n async getUsage(\n customerId: string,\n featureKey: string,\n periodType: PeriodType = \"month\"\n ): Promise<number> {\n return this.usageTracker.getUsage(customerId, featureKey, periodType);\n }\n\n /**\n * Get usage aggregates\n */\n async getAggregates(\n customerId: string,\n options: GetUsageOptions = {}\n ): Promise<UsageAggregate[]> {\n return this.storage.getAggregates(customerId, options);\n }\n\n // ============================================================================\n // Quota Management\n // ============================================================================\n\n /**\n * Check if quota allows the requested quantity\n */\n async checkQuota(\n customerId: string,\n featureKey: string,\n quantity: number = 1\n ): Promise<QuotaCheckResult> {\n return this.quotaManager.checkQuota(customerId, featureKey, quantity);\n }\n\n /**\n * Enforce quota - throws if exceeded\n */\n async enforceQuota(\n customerId: string,\n featureKey: string,\n quantity: number = 1\n ): Promise<void> {\n return this.quotaManager.enforceQuota(customerId, featureKey, quantity);\n }\n\n /**\n * Get quota status for a feature\n */\n async getQuotaStatus(customerId: string, featureKey: string): Promise<QuotaStatus> {\n const status = await this.quotaManager.getQuotaStatus(customerId, featureKey);\n\n // Trigger limit exceeded callback if needed\n if (status.isExceeded && this.limitExceededHandler) {\n try {\n await this.limitExceededHandler(status, customerId);\n } catch (error) {\n this.logger.error(\"Limit exceeded callback failed\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n\n return status;\n }\n\n /**\n * Get all quota statuses for a customer\n */\n async getAllQuotas(customerId: string): Promise<QuotaStatus[]> {\n return this.quotaManager.getAllQuotas(customerId);\n }\n\n /**\n * Check if any quota is exceeded\n */\n async hasExceededQuotas(customerId: string): Promise<boolean> {\n return this.quotaManager.hasExceededQuotas(customerId);\n }\n\n // ============================================================================\n // Plan Management\n // ============================================================================\n\n /**\n * Get customer's current plan\n */\n async getCustomerPlan(customerId: string): Promise<Plan | null> {\n const planId = await this.storage.getCustomerPlanId(customerId);\n if (!planId) return null;\n return this.storage.getPlan(planId);\n }\n\n /**\n * Set customer's plan\n */\n async setCustomerPlan(customerId: string, planId: string): Promise<void> {\n this.logger.info(\"Setting customer plan\", { customerId, planId });\n await this.storage.setCustomerPlanId(customerId, planId);\n }\n\n /**\n * Get plan by ID\n */\n async getPlan(planId: string): Promise<Plan | null> {\n return this.storage.getPlan(planId);\n }\n\n /**\n * Get plan by name\n */\n async getPlanByName(name: string): Promise<Plan | null> {\n return this.storage.getPlanByName(name);\n }\n\n /**\n * List all plans\n */\n async listPlans(options?: { activeOnly?: boolean }): Promise<Plan[]> {\n return this.storage.listPlans(options);\n }\n\n /**\n * Get plan features\n */\n async getPlanFeatures(planId: string): Promise<PlanFeature[]> {\n return this.storage.getPlanFeatures(planId);\n }\n\n // ============================================================================\n // Subscription Lifecycle\n // ============================================================================\n\n /**\n * Register a subscription event handler\n */\n on(event: SubscriptionEventType | \"*\", handler: SubscriptionHandler): this {\n this.lifecycle.on(event, handler);\n return this;\n }\n\n /**\n * Remove a subscription event handler\n */\n off(event: SubscriptionEventType | \"*\", handler: SubscriptionHandler): this {\n this.lifecycle.off(event, handler);\n return this;\n }\n\n /**\n * Handle subscription created\n */\n onSubscriptionCreated(handler: SubscriptionHandler): this {\n this.lifecycle.onCreated(handler);\n return this;\n }\n\n /**\n * Handle subscription updated\n */\n onSubscriptionUpdated(handler: SubscriptionHandler): this {\n this.lifecycle.onUpdated(handler);\n return this;\n }\n\n /**\n * Handle subscription canceled\n */\n onSubscriptionCanceled(handler: SubscriptionHandler): this {\n this.lifecycle.onCanceled(handler);\n return this;\n }\n\n /**\n * Handle plan changed\n */\n onPlanChanged(handler: SubscriptionHandler): this {\n this.lifecycle.onPlanChanged(handler);\n return this;\n }\n\n /**\n * Handle subscription renewed\n */\n onRenewed(handler: SubscriptionHandler): this {\n this.lifecycle.onRenewed(handler);\n return this;\n }\n\n /**\n * Handle payment failed\n */\n onPaymentFailed(handler: SubscriptionHandler): this {\n this.lifecycle.onPaymentFailed(handler);\n return this;\n }\n\n /**\n * Handle period reset\n */\n onPeriodReset(handler: SubscriptionHandler): this {\n this.lifecycle.onPeriodReset(handler);\n return this;\n }\n\n /**\n * Get the lifecycle manager for advanced usage\n */\n get lifecycleManager(): SubscriptionLifecycle {\n return this.lifecycle;\n }\n\n // ============================================================================\n // Alerts\n // ============================================================================\n\n /**\n * Get active alerts for a customer\n */\n async getActiveAlerts(customerId: string) {\n return this.storage.getActiveAlerts(customerId);\n }\n\n /**\n * Acknowledge an alert\n */\n async acknowledgeAlert(alertId: string): Promise<void> {\n await this.storage.updateAlertStatus(alertId, \"acknowledged\");\n }\n\n /**\n * Resolve an alert\n */\n async resolveAlert(alertId: string): Promise<void> {\n await this.storage.updateAlertStatus(alertId, \"resolved\");\n }\n\n // ============================================================================\n // Usage Reset\n // ============================================================================\n\n /**\n * Reset usage for a customer\n * Typically called on subscription renewal\n */\n async resetUsage(\n customerId: string,\n featureKeys?: string[]\n ): Promise<void> {\n this.logger.info(\"Resetting usage\", { customerId, featureKeys });\n\n // Get the period start based on reset period setting\n const periodStart = await this.getResetPeriodStart(customerId);\n\n await this.storage.resetUsage(customerId, featureKeys, periodStart);\n\n // Trigger callbacks\n if (this.periodResetHandler) {\n const features = featureKeys ?? await this.getCustomerFeatureKeys(customerId);\n for (const featureKey of features) {\n try {\n await this.periodResetHandler(customerId, featureKey);\n } catch (error) {\n this.logger.error(\"Period reset callback failed\", {\n customerId,\n featureKey,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n\n // Emit lifecycle event\n const plan = await this.getCustomerPlan(customerId);\n if (plan) {\n await this.lifecycle.emit({\n type: \"subscription.period_reset\",\n subscription: {\n id: \"\",\n customerId,\n status: \"active\",\n priceId: \"\",\n currentPeriodStart: periodStart,\n currentPeriodEnd: new Date(),\n cancelAtPeriodEnd: false,\n provider: \"stripe\", // Default, will be overridden by BillingIntegration\n },\n newPlan: plan,\n timestamp: new Date(),\n provider: \"stripe\",\n });\n }\n\n this.logger.info(\"Usage reset complete\", { customerId });\n }\n\n /**\n * Get the period start date based on reset period setting\n */\n private async getResetPeriodStart(customerId: string): Promise<Date> {\n if (this.resetPeriod === \"billing_cycle\") {\n // Use the customer's billing cycle\n const billingCycle = await this.storage.getBillingCycle(customerId);\n if (billingCycle) {\n return billingCycle.start;\n }\n }\n\n // Default to calendar month\n const now = new Date();\n return new Date(now.getFullYear(), now.getMonth(), 1);\n }\n\n /**\n * Get feature keys for a customer's plan\n */\n private async getCustomerFeatureKeys(customerId: string): Promise<string[]> {\n const planId = await this.storage.getCustomerPlanId(customerId);\n if (!planId) return [];\n\n const features = await this.storage.getPlanFeatures(planId);\n return features.map(f => f.featureKey);\n }\n\n /**\n * Check if auto-reset on renewal is enabled\n */\n get autoResetEnabled(): boolean {\n return this.autoResetOnRenewal;\n }\n\n /**\n * Get current reset period setting\n */\n get currentResetPeriod(): ResetPeriod {\n return this.resetPeriod;\n }\n\n // ============================================================================\n // Access Status\n // ============================================================================\n\n /**\n * Get customer access status\n */\n async getAccessStatus(customerId: string): Promise<AccessStatusInfo> {\n const status = await this.storage.getAccessStatus(customerId);\n if (status) {\n return status;\n }\n\n // Default to active\n return {\n status: \"active\",\n updatedAt: new Date(),\n };\n }\n\n /**\n * Set customer access status\n */\n async setAccessStatus(\n customerId: string,\n status: AccessStatus,\n options?: {\n reason?: string;\n suspensionDate?: Date;\n failedPaymentAttempts?: number;\n gracePeriodEnd?: Date;\n }\n ): Promise<void> {\n const previousStatusInfo = await this.storage.getAccessStatus(customerId);\n const previousStatus = previousStatusInfo?.status;\n\n const newStatus: AccessStatusInfo = {\n status,\n updatedAt: new Date(),\n };\n\n if (options?.reason !== undefined) {\n newStatus.reason = options.reason;\n }\n if (options?.suspensionDate !== undefined) {\n newStatus.suspensionDate = options.suspensionDate;\n }\n if (options?.failedPaymentAttempts !== undefined) {\n newStatus.failedPaymentAttempts = options.failedPaymentAttempts;\n }\n if (options?.gracePeriodEnd !== undefined) {\n newStatus.gracePeriodEnd = options.gracePeriodEnd;\n }\n\n await this.storage.setAccessStatus(customerId, newStatus);\n\n this.logger.info(\"Access status changed\", {\n customerId,\n previousStatus,\n newStatus: status,\n reason: options?.reason,\n });\n\n // Trigger callback\n if (this.accessStatusChangedHandler) {\n try {\n await this.accessStatusChangedHandler(customerId, newStatus, previousStatus);\n } catch (error) {\n this.logger.error(\"Access status change callback failed\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n\n /**\n * Handle payment failure - update access status\n */\n async handlePaymentFailure(customerId: string): Promise<void> {\n const currentStatus = await this.getAccessStatus(customerId);\n const failedAttempts = (currentStatus.failedPaymentAttempts ?? 0) + 1;\n\n if (failedAttempts >= this.maxFailedPayments) {\n // Suspend access\n await this.setAccessStatus(customerId, \"suspended\", {\n reason: `Payment failed ${failedAttempts} times`,\n failedPaymentAttempts: failedAttempts,\n });\n } else {\n // Set to past_due with grace period\n const gracePeriodEnd = new Date();\n gracePeriodEnd.setDate(gracePeriodEnd.getDate() + this.paymentGraceDays);\n\n await this.setAccessStatus(customerId, \"past_due\", {\n reason: `Payment failed (attempt ${failedAttempts}/${this.maxFailedPayments})`,\n failedPaymentAttempts: failedAttempts,\n gracePeriodEnd,\n suspensionDate: gracePeriodEnd,\n });\n }\n }\n\n /**\n * Handle successful payment - restore access status\n */\n async handlePaymentSuccess(customerId: string): Promise<void> {\n const currentStatus = await this.getAccessStatus(customerId);\n\n if (currentStatus.status !== \"active\") {\n await this.setAccessStatus(customerId, \"active\", {\n reason: \"Payment successful\",\n failedPaymentAttempts: 0,\n });\n }\n }\n\n /**\n * Check if customer has access (not suspended/canceled)\n */\n async hasAccess(customerId: string): Promise<boolean> {\n const status = await this.getAccessStatus(customerId);\n return status.status === \"active\" || status.status === \"past_due\";\n }\n\n /**\n * Check if customer is in grace period\n */\n async isInGracePeriod(customerId: string): Promise<boolean> {\n const status = await this.getAccessStatus(customerId);\n if (status.status !== \"past_due\") return false;\n if (!status.gracePeriodEnd) return false;\n return new Date() < status.gracePeriodEnd;\n }\n\n // ============================================================================\n // Billing Cycle\n // ============================================================================\n\n /**\n * Set customer billing cycle\n */\n async setBillingCycle(customerId: string, start: Date, end: Date): Promise<void> {\n await this.storage.setBillingCycle(customerId, start, end);\n this.logger.debug(\"Billing cycle set\", { customerId, start, end });\n }\n\n /**\n * Get customer billing cycle\n */\n async getBillingCycle(customerId: string): Promise<{ start: Date; end: Date } | null> {\n return this.storage.getBillingCycle(customerId);\n }\n\n // ============================================================================\n // Internal\n // ============================================================================\n\n /**\n * Get the underlying storage\n */\n get storageBackend(): UsageStorage {\n return this.storage;\n }\n\n /**\n * Get the quota manager\n */\n get quotas(): QuotaManager {\n return this.quotaManager;\n }\n\n /**\n * Get the usage tracker\n */\n get tracker(): UsageTracker {\n return this.usageTracker;\n }\n}\n\n/**\n * Create usage service\n */\nexport function createUsageService(config: UsageServiceConfig): UsageService {\n return new UsageService(config);\n}\n","/**\n * @parsrun/payments - Billing Integration\n * Connects BillingService webhooks to UsageService lifecycle\n */\n\nimport type { WebhookEvent, PaymentProviderType } from \"../types.js\";\nimport type { BillingService } from \"../billing/billing-service.js\";\nimport type { UsageService } from \"./usage-service.js\";\nimport type { SubscriptionEvent, Plan, BillingLogger } from \"./types.js\";\n\n/**\n * Null logger\n */\nconst nullLogger: BillingLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n/**\n * Billing integration configuration\n */\nexport interface BillingIntegrationConfig {\n /** Billing service instance */\n billing: BillingService;\n\n /** Usage service instance */\n usage: UsageService;\n\n /** Logger */\n logger?: BillingLogger;\n\n /** Auto-initialize customer plan on subscription creation */\n autoInitializePlan?: boolean;\n\n /**\n * Auto-reset quotas on subscription renewal\n * Default: true (uses UsageService.autoResetOnRenewal setting)\n */\n autoResetOnRenewal?: boolean;\n\n /**\n * Auto-update access status based on payment events\n * Default: true\n */\n autoManageAccessStatus?: boolean;\n\n /** Plan ID resolver - maps payment provider price IDs to internal plan IDs */\n resolvePlanId?: (priceId: string, provider: PaymentProviderType) => string | Promise<string>;\n\n /** Custom event handlers */\n onSubscriptionCreated?: (event: SubscriptionEvent) => void | Promise<void>;\n onSubscriptionCanceled?: (event: SubscriptionEvent) => void | Promise<void>;\n onSubscriptionRenewed?: (event: SubscriptionEvent) => void | Promise<void>;\n onPlanChanged?: (event: SubscriptionEvent) => void | Promise<void>;\n onPaymentFailed?: (event: SubscriptionEvent) => void | Promise<void>;\n}\n\n/**\n * Billing Integration\n *\n * Connects BillingService webhooks to UsageService lifecycle events.\n * This enables automatic:\n * - Customer plan initialization on subscription creation\n * - Plan updates when subscription changes\n * - Usage reset on subscription renewal\n * - Lifecycle event emission\n *\n * @example\n * ```typescript\n * import { createBillingService, createUsageService, integrateBillingWithUsage } from \"@parsrun/payments\";\n *\n * const billing = createBillingService({\n * providers: { default: stripeProvider },\n * });\n *\n * const usage = createUsageService({\n * storage: createMemoryUsageStorage(),\n * });\n *\n * // Connect them\n * const integration = integrateBillingWithUsage({\n * billing,\n * usage,\n * autoInitializePlan: true,\n * resolvePlanId: (priceId) => {\n * // Map Stripe price IDs to your internal plan IDs\n * const mapping: Record<string, string> = {\n * \"price_starter\": \"starter\",\n * \"price_pro\": \"pro\",\n * \"price_enterprise\": \"enterprise\",\n * };\n * return mapping[priceId] ?? \"free\";\n * },\n * });\n *\n * // Now subscription webhooks automatically update usage quotas\n * ```\n */\nexport class BillingIntegration {\n private readonly billing: BillingService;\n private readonly usage: UsageService;\n private readonly logger: BillingLogger;\n private readonly autoInitializePlan: boolean;\n private readonly autoResetOnRenewal: boolean;\n private readonly autoManageAccessStatus: boolean;\n private readonly resolvePlanId: (priceId: string, provider: PaymentProviderType) => string | Promise<string>;\n private readonly config: BillingIntegrationConfig;\n\n constructor(config: BillingIntegrationConfig) {\n this.billing = config.billing;\n this.usage = config.usage;\n this.logger = config.logger ?? nullLogger;\n this.autoInitializePlan = config.autoInitializePlan ?? true;\n this.autoResetOnRenewal = config.autoResetOnRenewal ?? true;\n this.autoManageAccessStatus = config.autoManageAccessStatus ?? true;\n this.resolvePlanId = config.resolvePlanId ?? ((priceId) => priceId);\n this.config = config;\n\n // Register webhook handlers\n this.setupWebhookHandlers();\n }\n\n /**\n * Setup webhook handlers on billing service\n */\n private setupWebhookHandlers(): void {\n // Subscription created\n this.billing.onWebhook(\"subscription.created\", async (event) => {\n await this.handleSubscriptionCreated(event);\n });\n\n // Subscription updated (plan change)\n this.billing.onWebhook(\"subscription.updated\", async (event) => {\n await this.handleSubscriptionUpdated(event);\n });\n\n // Subscription deleted (canceled)\n this.billing.onWebhook(\"subscription.deleted\", async (event) => {\n await this.handleSubscriptionCanceled(event);\n });\n\n // Invoice paid (renewal)\n this.billing.onWebhook(\"invoice.paid\", async (event) => {\n await this.handleInvoicePaid(event);\n });\n\n // Payment failed\n this.billing.onWebhook(\"invoice.payment_failed\", async (event) => {\n await this.handlePaymentFailed(event);\n });\n\n this.logger.info(\"Billing integration initialized\");\n }\n\n /**\n * Handle subscription created webhook\n */\n private async handleSubscriptionCreated(event: WebhookEvent): Promise<void> {\n const subscription = event.data as {\n id: string;\n customerId: string;\n status: string;\n priceId?: string;\n currentPeriodStart?: Date;\n currentPeriodEnd?: Date;\n };\n\n this.logger.info(\"Subscription created\", {\n subscriptionId: subscription.id,\n customerId: subscription.customerId,\n provider: event.provider,\n });\n\n // Initialize customer plan if enabled\n if (this.autoInitializePlan && subscription.priceId) {\n const planId = await this.resolvePlanId(subscription.priceId, event.provider);\n await this.usage.setCustomerPlan(subscription.customerId, planId);\n\n this.logger.debug(\"Customer plan initialized\", {\n customerId: subscription.customerId,\n planId,\n });\n }\n\n // Set billing cycle for billing_cycle reset period\n if (subscription.currentPeriodStart && subscription.currentPeriodEnd) {\n await this.usage.setBillingCycle(\n subscription.customerId,\n subscription.currentPeriodStart,\n subscription.currentPeriodEnd\n );\n }\n\n // Initialize access status\n if (this.autoManageAccessStatus) {\n await this.usage.setAccessStatus(subscription.customerId, \"active\", {\n reason: \"Subscription created\",\n });\n }\n\n // Get plan for event\n const plan = subscription.priceId\n ? await this.usage.getPlan(await this.resolvePlanId(subscription.priceId, event.provider))\n : null;\n\n // Emit lifecycle event - build with only defined optional properties\n const lifecycleEvent: SubscriptionEvent = {\n type: \"subscription.created\",\n subscription: {\n id: subscription.id,\n customerId: subscription.customerId,\n status: subscription.status as \"active\" | \"canceled\" | \"past_due\" | \"trialing\" | \"paused\" | \"incomplete\",\n priceId: subscription.priceId ?? \"\",\n currentPeriodStart: subscription.currentPeriodStart ?? new Date(),\n currentPeriodEnd: subscription.currentPeriodEnd ?? new Date(),\n cancelAtPeriodEnd: false,\n provider: event.provider,\n },\n timestamp: new Date(),\n provider: event.provider,\n };\n\n if (plan !== null) {\n lifecycleEvent.newPlan = plan;\n }\n\n await this.usage.lifecycleManager.emit(lifecycleEvent);\n\n // Custom handler\n if (this.config.onSubscriptionCreated) {\n await this.config.onSubscriptionCreated(lifecycleEvent);\n }\n }\n\n /**\n * Handle subscription updated webhook\n */\n private async handleSubscriptionUpdated(event: WebhookEvent): Promise<void> {\n const subscription = event.data as {\n id: string;\n customerId: string;\n status: string;\n priceId?: string;\n previousPriceId?: string;\n currentPeriodStart?: Date;\n currentPeriodEnd?: Date;\n };\n\n this.logger.info(\"Subscription updated\", {\n subscriptionId: subscription.id,\n customerId: subscription.customerId,\n provider: event.provider,\n });\n\n // Check if plan changed\n const priceChanged = subscription.priceId !== subscription.previousPriceId;\n\n let previousPlan: Plan | null = null;\n let newPlan: Plan | null = null;\n\n if (priceChanged && subscription.priceId) {\n // Get previous plan\n if (subscription.previousPriceId) {\n const previousPlanId = await this.resolvePlanId(subscription.previousPriceId, event.provider);\n previousPlan = await this.usage.getPlan(previousPlanId);\n }\n\n // Update customer plan\n const newPlanId = await this.resolvePlanId(subscription.priceId, event.provider);\n await this.usage.setCustomerPlan(subscription.customerId, newPlanId);\n newPlan = await this.usage.getPlan(newPlanId);\n\n this.logger.info(\"Customer plan changed\", {\n customerId: subscription.customerId,\n previousPlanId: previousPlan?.id,\n newPlanId,\n });\n }\n\n // Emit lifecycle event - build with only defined optional properties\n const eventType = priceChanged ? \"subscription.plan_changed\" : \"subscription.updated\";\n const lifecycleEvent: SubscriptionEvent = {\n type: eventType,\n subscription: {\n id: subscription.id,\n customerId: subscription.customerId,\n status: subscription.status as \"active\" | \"canceled\" | \"past_due\" | \"trialing\" | \"paused\" | \"incomplete\",\n priceId: subscription.priceId ?? \"\",\n currentPeriodStart: subscription.currentPeriodStart ?? new Date(),\n currentPeriodEnd: subscription.currentPeriodEnd ?? new Date(),\n cancelAtPeriodEnd: false,\n provider: event.provider,\n },\n timestamp: new Date(),\n provider: event.provider,\n };\n\n if (previousPlan !== null) {\n lifecycleEvent.previousPlan = previousPlan;\n }\n if (newPlan !== null) {\n lifecycleEvent.newPlan = newPlan;\n }\n\n await this.usage.lifecycleManager.emit(lifecycleEvent);\n\n // Custom handler for plan change\n if (priceChanged && this.config.onPlanChanged) {\n await this.config.onPlanChanged(lifecycleEvent);\n }\n }\n\n /**\n * Handle subscription canceled webhook\n */\n private async handleSubscriptionCanceled(event: WebhookEvent): Promise<void> {\n const subscription = event.data as {\n id: string;\n customerId: string;\n status: string;\n priceId?: string;\n currentPeriodEnd?: Date;\n };\n\n this.logger.info(\"Subscription canceled\", {\n subscriptionId: subscription.id,\n customerId: subscription.customerId,\n provider: event.provider,\n });\n\n // Update access status to canceled\n if (this.autoManageAccessStatus) {\n await this.usage.setAccessStatus(subscription.customerId, \"canceled\", {\n reason: \"Subscription canceled\",\n });\n }\n\n // Get current plan before removing\n const currentPlan = await this.usage.getCustomerPlan(subscription.customerId);\n\n // Emit lifecycle event - build with only defined optional properties\n const lifecycleEvent: SubscriptionEvent = {\n type: \"subscription.canceled\",\n subscription: {\n id: subscription.id,\n customerId: subscription.customerId,\n status: \"canceled\",\n priceId: subscription.priceId ?? \"\",\n currentPeriodStart: new Date(),\n currentPeriodEnd: subscription.currentPeriodEnd ?? new Date(),\n cancelAtPeriodEnd: true,\n provider: event.provider,\n },\n timestamp: new Date(),\n provider: event.provider,\n };\n\n if (currentPlan !== null) {\n lifecycleEvent.previousPlan = currentPlan;\n }\n\n await this.usage.lifecycleManager.emit(lifecycleEvent);\n\n // Custom handler\n if (this.config.onSubscriptionCanceled) {\n await this.config.onSubscriptionCanceled(lifecycleEvent);\n }\n }\n\n /**\n * Handle invoice paid webhook (renewal)\n */\n private async handleInvoicePaid(event: WebhookEvent): Promise<void> {\n const invoice = event.data as {\n id: string;\n customerId: string;\n subscriptionId?: string;\n billingReason?: string;\n periodStart?: Date;\n periodEnd?: Date;\n };\n\n // Only handle subscription renewals, not initial payments\n if (invoice.billingReason !== \"subscription_cycle\") {\n return;\n }\n\n this.logger.info(\"Subscription renewed\", {\n invoiceId: invoice.id,\n customerId: invoice.customerId,\n subscriptionId: invoice.subscriptionId,\n provider: event.provider,\n });\n\n // Update billing cycle\n if (invoice.periodStart && invoice.periodEnd) {\n await this.usage.setBillingCycle(\n invoice.customerId,\n invoice.periodStart,\n invoice.periodEnd\n );\n }\n\n // Auto-reset quotas on renewal if enabled\n if (this.autoResetOnRenewal && this.usage.autoResetEnabled) {\n this.logger.info(\"Auto-resetting quotas on renewal\", {\n customerId: invoice.customerId,\n });\n await this.usage.resetUsage(invoice.customerId);\n }\n\n // Restore access status if payment succeeded\n if (this.autoManageAccessStatus) {\n await this.usage.handlePaymentSuccess(invoice.customerId);\n }\n\n // Get current plan\n const currentPlan = await this.usage.getCustomerPlan(invoice.customerId);\n\n // Emit lifecycle event - build with only defined optional properties\n const periodStart = invoice.periodStart ?? new Date();\n const periodEnd = invoice.periodEnd ?? new Date();\n\n const lifecycleEvent: SubscriptionEvent = {\n type: \"subscription.renewed\",\n subscription: {\n id: invoice.subscriptionId ?? invoice.id,\n customerId: invoice.customerId,\n status: \"active\",\n priceId: \"\",\n currentPeriodStart: periodStart,\n currentPeriodEnd: periodEnd,\n cancelAtPeriodEnd: false,\n provider: event.provider,\n },\n timestamp: new Date(),\n provider: event.provider,\n };\n\n if (currentPlan !== null) {\n lifecycleEvent.newPlan = currentPlan;\n }\n\n await this.usage.lifecycleManager.emit(lifecycleEvent);\n\n // Custom handler\n if (this.config.onSubscriptionRenewed) {\n await this.config.onSubscriptionRenewed(lifecycleEvent);\n }\n }\n\n /**\n * Handle payment failed webhook\n */\n private async handlePaymentFailed(event: WebhookEvent): Promise<void> {\n const invoice = event.data as {\n id: string;\n customerId: string;\n subscriptionId?: string;\n };\n\n this.logger.warn(\"Payment failed\", {\n invoiceId: invoice.id,\n customerId: invoice.customerId,\n subscriptionId: invoice.subscriptionId,\n provider: event.provider,\n });\n\n // Update access status based on payment failure\n if (this.autoManageAccessStatus) {\n await this.usage.handlePaymentFailure(invoice.customerId);\n }\n\n // Get current plan\n const currentPlan = await this.usage.getCustomerPlan(invoice.customerId);\n\n // Emit lifecycle event - build with only defined optional properties\n const lifecycleEvent: SubscriptionEvent = {\n type: \"subscription.payment_failed\",\n subscription: {\n id: invoice.subscriptionId ?? invoice.id,\n customerId: invoice.customerId,\n status: \"past_due\",\n priceId: \"\",\n currentPeriodStart: new Date(),\n currentPeriodEnd: new Date(),\n cancelAtPeriodEnd: false,\n provider: event.provider,\n },\n timestamp: new Date(),\n provider: event.provider,\n };\n\n if (currentPlan !== null) {\n lifecycleEvent.newPlan = currentPlan;\n }\n\n await this.usage.lifecycleManager.emit(lifecycleEvent);\n\n // Custom handler\n if (this.config.onPaymentFailed) {\n await this.config.onPaymentFailed(lifecycleEvent);\n }\n }\n\n /**\n * Manually sync customer plan from billing provider\n */\n async syncCustomerPlan(customerId: string, provider?: PaymentProviderType): Promise<Plan | null> {\n // Get subscriptions from billing - build options with only defined properties\n const subscriptionOptions: { customerId: string; provider?: PaymentProviderType } = {\n customerId,\n };\n if (provider !== undefined) {\n subscriptionOptions.provider = provider;\n }\n const subscriptions = await this.billing.getSubscriptions(subscriptionOptions);\n\n // Find active subscription\n const activeSubscription = subscriptions.find(\n (sub) => sub.status === \"active\" || sub.status === \"trialing\"\n );\n\n if (!activeSubscription) {\n this.logger.debug(\"No active subscription found\", { customerId });\n return null;\n }\n\n // Resolve and set plan\n const planId = await this.resolvePlanId(\n activeSubscription.priceId,\n activeSubscription.provider\n );\n await this.usage.setCustomerPlan(customerId, planId);\n\n const plan = await this.usage.getPlan(planId);\n\n this.logger.info(\"Customer plan synced\", {\n customerId,\n planId,\n subscriptionId: activeSubscription.id,\n });\n\n return plan;\n }\n}\n\n/**\n * Create billing integration\n *\n * Connects BillingService webhooks to UsageService lifecycle events.\n *\n * @example\n * ```typescript\n * const integration = integrateBillingWithUsage({\n * billing,\n * usage,\n * autoInitializePlan: true,\n * resolvePlanId: (priceId) => priceMapping[priceId] ?? \"free\",\n * });\n * ```\n */\nexport function integrateBillingWithUsage(config: BillingIntegrationConfig): BillingIntegration {\n return new BillingIntegration(config);\n}\n\n/**\n * Alias for integrateBillingWithUsage\n */\nexport const createBillingIntegration = integrateBillingWithUsage;\n","/**\n * @parsrun/payments - Usage Meter\n * Buffers usage events and syncs to payment provider\n *\n * This solves the problem of:\n * - Not hitting provider API limits with per-request calls\n * - Reducing latency by batching usage reports\n * - Ensuring reliable usage reporting with retry logic\n */\n\nimport type { PaymentProviderType } from \"../types.js\";\nimport type { BillingLogger } from \"./types.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Usage record to report to provider\n */\nexport interface UsageRecord {\n /** Subscription item ID (Stripe) or subscription ID (Paddle) */\n subscriptionItemId: string;\n /** Usage quantity */\n quantity: number;\n /** Timestamp of usage (defaults to now) */\n timestamp?: Date;\n /** Action: increment (add to existing) or set (replace) */\n action?: \"increment\" | \"set\";\n /** Idempotency key to prevent duplicates */\n idempotencyKey?: string;\n}\n\n/**\n * Buffered usage record with metadata\n */\ninterface BufferedRecord {\n record: UsageRecord;\n customerId: string;\n featureKey: string;\n addedAt: Date;\n attempts: number;\n}\n\n/**\n * Usage reporter interface - implemented by providers\n */\nexport interface UsageReporter {\n /**\n * Report usage to the payment provider\n */\n reportUsage(record: UsageRecord): Promise<void>;\n\n /**\n * Report multiple usage records (batch)\n */\n reportUsageBatch?(records: UsageRecord[]): Promise<void>;\n\n /**\n * Get subscription item ID for a subscription and price\n */\n getSubscriptionItemId?(subscriptionId: string, priceId: string): Promise<string | null>;\n}\n\n/**\n * Sync strategy configuration\n */\nexport type SyncStrategy =\n | { type: \"interval\"; intervalMs: number }\n | { type: \"threshold\"; maxRecords: number; maxAgeMs: number }\n | { type: \"manual\" };\n\n/**\n * Usage meter configuration\n */\nexport interface UsageMeterConfig {\n /** Usage reporter (provider with reportUsage method) */\n reporter: UsageReporter;\n\n /** Provider type for logging */\n providerType: PaymentProviderType;\n\n /** Sync strategy */\n strategy: SyncStrategy;\n\n /** Logger */\n logger?: BillingLogger;\n\n /** Max retry attempts for failed syncs */\n maxRetries?: number;\n\n /** Retry delay in ms */\n retryDelayMs?: number;\n\n /** Callback on successful sync */\n onSyncSuccess?: (count: number) => void;\n\n /** Callback on sync failure */\n onSyncError?: (error: Error, records: BufferedRecord[]) => void;\n\n /** Callback when buffer is getting full (>80%) */\n onBufferWarning?: (size: number, maxSize: number) => void;\n\n /** Maximum buffer size before forcing sync */\n maxBufferSize?: number;\n}\n\n/**\n * Null logger\n */\nconst nullLogger: BillingLogger = {\n debug: () => {},\n info: () => {},\n warn: () => {},\n error: () => {},\n};\n\n// ============================================================================\n// Usage Meter\n// ============================================================================\n\n/**\n * Usage Meter\n *\n * Buffers usage events and syncs to payment provider periodically.\n * Supports multiple sync strategies:\n * - interval: Sync every N milliseconds\n * - threshold: Sync when buffer reaches N records or records are older than N ms\n * - manual: Only sync when explicitly called\n *\n * @example\n * ```typescript\n * import { createUsageMeter } from \"@parsrun/payments\";\n *\n * const meter = createUsageMeter({\n * reporter: stripeProvider, // Provider must implement UsageReporter\n * providerType: \"stripe\",\n * strategy: { type: \"interval\", intervalMs: 60000 }, // Sync every minute\n * });\n *\n * // Record usage (buffered, not sent immediately)\n * meter.record({\n * customerId: \"cus_123\",\n * featureKey: \"api_calls\",\n * subscriptionItemId: \"si_xxx\",\n * quantity: 1,\n * });\n *\n * // Force immediate sync\n * await meter.flush();\n *\n * // Cleanup when done\n * meter.stop();\n * ```\n */\nexport class UsageMeter {\n private readonly reporter: UsageReporter;\n private readonly providerType: PaymentProviderType;\n private readonly logger: BillingLogger;\n private readonly strategy: SyncStrategy;\n private readonly maxRetries: number;\n private readonly retryDelayMs: number;\n private readonly maxBufferSize: number;\n private readonly config: UsageMeterConfig;\n\n private buffer: BufferedRecord[] = [];\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private isSyncing = false;\n private isRunning = false;\n\n constructor(config: UsageMeterConfig) {\n this.reporter = config.reporter;\n this.providerType = config.providerType;\n this.logger = config.logger ?? nullLogger;\n this.strategy = config.strategy;\n this.maxRetries = config.maxRetries ?? 3;\n this.retryDelayMs = config.retryDelayMs ?? 1000;\n this.maxBufferSize = config.maxBufferSize ?? 10000;\n this.config = config;\n\n this.start();\n }\n\n /**\n * Start the meter (auto-sync based on strategy)\n */\n start(): void {\n if (this.isRunning) return;\n this.isRunning = true;\n\n if (this.strategy.type === \"interval\") {\n this.intervalId = setInterval(() => {\n this.flush().catch((err) => {\n this.logger.error(\"Auto-sync failed\", { error: err.message });\n });\n }, this.strategy.intervalMs);\n\n this.logger.info(\"Usage meter started\", {\n strategy: \"interval\",\n intervalMs: this.strategy.intervalMs,\n provider: this.providerType,\n });\n } else if (this.strategy.type === \"threshold\") {\n // Threshold strategy uses checkThreshold on each record\n this.logger.info(\"Usage meter started\", {\n strategy: \"threshold\",\n maxRecords: this.strategy.maxRecords,\n maxAgeMs: this.strategy.maxAgeMs,\n provider: this.providerType,\n });\n } else {\n this.logger.info(\"Usage meter started\", {\n strategy: \"manual\",\n provider: this.providerType,\n });\n }\n }\n\n /**\n * Stop the meter\n */\n stop(): void {\n this.isRunning = false;\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n this.logger.info(\"Usage meter stopped\");\n }\n\n /**\n * Record usage (buffered)\n */\n record(options: {\n customerId: string;\n featureKey: string;\n subscriptionItemId: string;\n quantity: number;\n timestamp?: Date;\n action?: \"increment\" | \"set\";\n idempotencyKey?: string;\n }): void {\n // Build record with only defined optional properties\n const usageRecord: UsageRecord = {\n subscriptionItemId: options.subscriptionItemId,\n quantity: options.quantity,\n action: options.action ?? \"increment\",\n };\n\n if (options.timestamp !== undefined) {\n usageRecord.timestamp = options.timestamp;\n }\n if (options.idempotencyKey !== undefined) {\n usageRecord.idempotencyKey = options.idempotencyKey;\n }\n\n const record: BufferedRecord = {\n record: usageRecord,\n customerId: options.customerId,\n featureKey: options.featureKey,\n addedAt: new Date(),\n attempts: 0,\n };\n\n this.buffer.push(record);\n\n this.logger.debug(\"Usage recorded\", {\n customerId: options.customerId,\n featureKey: options.featureKey,\n quantity: options.quantity,\n bufferSize: this.buffer.length,\n });\n\n // Check buffer size warning\n if (this.buffer.length > this.maxBufferSize * 0.8) {\n this.config.onBufferWarning?.(this.buffer.length, this.maxBufferSize);\n }\n\n // Force sync if buffer is full\n if (this.buffer.length >= this.maxBufferSize) {\n this.logger.warn(\"Buffer full, forcing sync\", { size: this.buffer.length });\n this.flush().catch((err) => {\n this.logger.error(\"Forced sync failed\", { error: err.message });\n });\n return;\n }\n\n // Check threshold strategy\n if (this.strategy.type === \"threshold\") {\n this.checkThreshold();\n }\n }\n\n /**\n * Check threshold and trigger sync if needed\n */\n private checkThreshold(): void {\n if (this.strategy.type !== \"threshold\") return;\n if (this.isSyncing) return;\n\n const { maxRecords, maxAgeMs } = this.strategy;\n\n // Check record count\n if (this.buffer.length >= maxRecords) {\n this.logger.debug(\"Threshold reached (count)\", { count: this.buffer.length });\n this.flush().catch((err) => {\n this.logger.error(\"Threshold sync failed\", { error: err.message });\n });\n return;\n }\n\n // Check age of oldest record\n const oldestRecord = this.buffer[0];\n if (oldestRecord) {\n const age = Date.now() - oldestRecord.addedAt.getTime();\n if (age >= maxAgeMs) {\n this.logger.debug(\"Threshold reached (age)\", { ageMs: age });\n this.flush().catch((err) => {\n this.logger.error(\"Threshold sync failed\", {\n error: err instanceof Error ? err.message : String(err),\n });\n });\n }\n }\n }\n\n /**\n * Flush buffer to provider\n */\n async flush(): Promise<number> {\n if (this.isSyncing) {\n this.logger.debug(\"Sync already in progress, skipping\");\n return 0;\n }\n\n if (this.buffer.length === 0) {\n return 0;\n }\n\n this.isSyncing = true;\n\n try {\n // Take current buffer and clear it\n const toSync = [...this.buffer];\n this.buffer = [];\n\n this.logger.info(\"Syncing usage to provider\", {\n count: toSync.length,\n provider: this.providerType,\n });\n\n // Aggregate by subscription item ID\n const aggregated = this.aggregateRecords(toSync);\n\n // Sync to provider\n const failed: BufferedRecord[] = [];\n\n for (const [subscriptionItemId, records] of aggregated) {\n try {\n const totalQuantity = records.reduce((sum, r) => sum + r.record.quantity, 0);\n\n // Build sync record with only defined optional properties\n const syncRecord: UsageRecord = {\n subscriptionItemId,\n quantity: totalQuantity,\n action: \"increment\",\n };\n\n // Use first record's timestamp for the batch if available\n const firstTimestamp = records[0]?.record.timestamp;\n if (firstTimestamp !== undefined) {\n syncRecord.timestamp = firstTimestamp;\n }\n\n await this.syncWithRetry(syncRecord);\n\n this.logger.debug(\"Usage synced\", {\n subscriptionItemId,\n quantity: totalQuantity,\n recordCount: records.length,\n });\n } catch (error) {\n this.logger.error(\"Failed to sync usage\", {\n subscriptionItemId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n // Mark records as failed and add back to buffer if retries left\n for (const record of records) {\n record.attempts++;\n if (record.attempts < this.maxRetries) {\n failed.push(record);\n } else {\n this.logger.error(\"Record exceeded max retries, dropping\", {\n customerId: record.customerId,\n featureKey: record.featureKey,\n attempts: record.attempts,\n });\n }\n }\n }\n }\n\n // Add failed records back to buffer\n if (failed.length > 0) {\n this.buffer.unshift(...failed);\n this.config.onSyncError?.(new Error(\"Some records failed to sync\"), failed);\n }\n\n const syncedCount = toSync.length - failed.length;\n\n if (syncedCount > 0) {\n this.config.onSyncSuccess?.(syncedCount);\n }\n\n return syncedCount;\n } finally {\n this.isSyncing = false;\n }\n }\n\n /**\n * Aggregate records by subscription item ID\n */\n private aggregateRecords(records: BufferedRecord[]): Map<string, BufferedRecord[]> {\n const map = new Map<string, BufferedRecord[]>();\n\n for (const record of records) {\n const key = record.record.subscriptionItemId;\n const existing = map.get(key) ?? [];\n existing.push(record);\n map.set(key, existing);\n }\n\n return map;\n }\n\n /**\n * Sync single record with retry\n */\n private async syncWithRetry(record: UsageRecord): Promise<void> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < this.maxRetries; attempt++) {\n try {\n await this.reporter.reportUsage(record);\n return;\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n this.logger.warn(\"Sync attempt failed, retrying\", {\n attempt: attempt + 1,\n maxRetries: this.maxRetries,\n error: lastError.message,\n });\n\n if (attempt < this.maxRetries - 1) {\n await this.delay(this.retryDelayMs * (attempt + 1)); // Exponential backoff\n }\n }\n }\n\n throw lastError ?? new Error(\"Sync failed after retries\");\n }\n\n /**\n * Delay helper\n */\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n /**\n * Get buffer size\n */\n get bufferSize(): number {\n return this.buffer.length;\n }\n\n /**\n * Get sync status\n */\n get syncing(): boolean {\n return this.isSyncing;\n }\n\n /**\n * Get running status\n */\n get running(): boolean {\n return this.isRunning;\n }\n\n /**\n * Get buffer contents (for debugging)\n */\n getBuffer(): ReadonlyArray<BufferedRecord> {\n return this.buffer;\n }\n}\n\n/**\n * Create usage meter\n */\nexport function createUsageMeter(config: UsageMeterConfig): UsageMeter {\n return new UsageMeter(config);\n}\n\n// ============================================================================\n// Subscription Item Resolver\n// ============================================================================\n\n/**\n * Subscription item mapping\n * Maps (customerId, featureKey) to subscriptionItemId\n */\nexport interface SubscriptionItemMapping {\n customerId: string;\n featureKey: string;\n subscriptionId: string;\n subscriptionItemId: string;\n priceId: string;\n createdAt: Date;\n}\n\n/**\n * Subscription item resolver configuration\n */\nexport interface SubscriptionItemResolverConfig {\n /** Reporter to fetch subscription items */\n reporter: UsageReporter;\n\n /** Cache TTL in ms (default: 1 hour) */\n cacheTtlMs?: number;\n\n /** Logger */\n logger?: BillingLogger;\n}\n\n/**\n * Subscription Item Resolver\n *\n * Resolves and caches subscription item IDs.\n * Stripe requires subscription_item_id for metered billing,\n * this resolver handles the lookup and caching.\n */\nexport class SubscriptionItemResolver {\n private readonly reporter: UsageReporter;\n private readonly cacheTtlMs: number;\n private readonly logger: BillingLogger;\n private cache = new Map<string, { itemId: string; expiresAt: Date }>();\n\n constructor(config: SubscriptionItemResolverConfig) {\n this.reporter = config.reporter;\n this.cacheTtlMs = config.cacheTtlMs ?? 60 * 60 * 1000; // 1 hour default\n this.logger = config.logger ?? nullLogger;\n }\n\n /**\n * Get subscription item ID\n */\n async resolve(subscriptionId: string, priceId: string): Promise<string | null> {\n const cacheKey = `${subscriptionId}:${priceId}`;\n\n // Check cache\n const cached = this.cache.get(cacheKey);\n if (cached && cached.expiresAt > new Date()) {\n return cached.itemId;\n }\n\n // Fetch from provider\n if (!this.reporter.getSubscriptionItemId) {\n this.logger.warn(\"Reporter does not support getSubscriptionItemId\");\n return null;\n }\n\n const itemId = await this.reporter.getSubscriptionItemId(subscriptionId, priceId);\n\n if (itemId) {\n // Cache the result\n this.cache.set(cacheKey, {\n itemId,\n expiresAt: new Date(Date.now() + this.cacheTtlMs),\n });\n }\n\n return itemId;\n }\n\n /**\n * Set cache entry manually (useful when creating subscriptions)\n */\n setCache(subscriptionId: string, priceId: string, itemId: string): void {\n const cacheKey = `${subscriptionId}:${priceId}`;\n this.cache.set(cacheKey, {\n itemId,\n expiresAt: new Date(Date.now() + this.cacheTtlMs),\n });\n }\n\n /**\n * Clear cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Get cache size\n */\n get cacheSize(): number {\n return this.cache.size;\n }\n}\n\n/**\n * Create subscription item resolver\n */\nexport function createSubscriptionItemResolver(\n config: SubscriptionItemResolverConfig\n): SubscriptionItemResolver {\n return new SubscriptionItemResolver(config);\n}\n","/**\n * @parsrun/payments - Dunning Sequence\n * Default sequences and step builders for dunning automation\n */\n\nimport type {\n DunningSequence,\n DunningStep,\n DunningAction,\n NotificationChannel,\n DunningContext,\n} from \"./types.js\";\n\n// ============================================================================\n// Step Builder\n// ============================================================================\n\n/**\n * Fluent builder for dunning steps\n */\nexport class DunningStepBuilder {\n private step: Partial<DunningStep> = {\n actions: [],\n notificationChannels: [],\n };\n\n constructor(id: string, name: string) {\n this.step.id = id;\n this.step.name = name;\n }\n\n /**\n * Set days after initial failure\n */\n afterDays(days: number): this {\n this.step.daysAfterFailure = days;\n return this;\n }\n\n /**\n * Set hours offset within the day\n */\n atHour(hour: number): this {\n this.step.hoursOffset = hour;\n return this;\n }\n\n /**\n * Add actions to take\n */\n withActions(...actions: DunningAction[]): this {\n this.step.actions = actions;\n return this;\n }\n\n /**\n * Add notification channels\n */\n notify(...channels: NotificationChannel[]): this {\n this.step.notificationChannels = channels;\n return this;\n }\n\n /**\n * Set notification template\n */\n withTemplate(templateId: string): this {\n this.step.notificationTemplateId = templateId;\n return this;\n }\n\n /**\n * Enable payment retry in this step\n */\n retryPayment(retry = true): this {\n this.step.retryPayment = retry;\n if (retry && !this.step.actions?.includes(\"retry_payment\")) {\n this.step.actions = [...(this.step.actions || []), \"retry_payment\"];\n }\n return this;\n }\n\n /**\n * Set access level for this step\n */\n setAccessLevel(level: \"full\" | \"limited\" | \"read_only\" | \"none\"): this {\n this.step.accessLevel = level;\n if (!this.step.actions?.includes(\"limit_features\")) {\n this.step.actions = [...(this.step.actions || []), \"limit_features\"];\n }\n return this;\n }\n\n /**\n * Mark this as the final step\n */\n final(isFinal = true): this {\n this.step.isFinal = isFinal;\n return this;\n }\n\n /**\n * Add custom action handler\n */\n withCustomAction(handler: (context: DunningContext) => Promise<void>): this {\n this.step.customAction = handler;\n if (!this.step.actions?.includes(\"custom\")) {\n this.step.actions = [...(this.step.actions || []), \"custom\"];\n }\n return this;\n }\n\n /**\n * Add condition for this step\n */\n when(condition: (context: DunningContext) => boolean | Promise<boolean>): this {\n this.step.condition = condition;\n return this;\n }\n\n /**\n * Add metadata\n */\n withMetadata(metadata: Record<string, unknown>): this {\n this.step.metadata = metadata;\n return this;\n }\n\n /**\n * Build the step\n */\n build(): DunningStep {\n if (!this.step.id || !this.step.name || this.step.daysAfterFailure === undefined) {\n throw new Error(\"DunningStep requires id, name, and daysAfterFailure\");\n }\n\n const result: DunningStep = {\n id: this.step.id,\n name: this.step.name,\n daysAfterFailure: this.step.daysAfterFailure,\n actions: this.step.actions || [],\n };\n\n // Only add optional properties if they have values\n if (this.step.hoursOffset !== undefined) result.hoursOffset = this.step.hoursOffset;\n if (this.step.notificationChannels !== undefined)\n result.notificationChannels = this.step.notificationChannels;\n if (this.step.notificationTemplateId !== undefined)\n result.notificationTemplateId = this.step.notificationTemplateId;\n if (this.step.retryPayment !== undefined) result.retryPayment = this.step.retryPayment;\n if (this.step.accessLevel !== undefined) result.accessLevel = this.step.accessLevel;\n if (this.step.isFinal !== undefined) result.isFinal = this.step.isFinal;\n if (this.step.customAction !== undefined) result.customAction = this.step.customAction;\n if (this.step.condition !== undefined) result.condition = this.step.condition;\n if (this.step.metadata !== undefined) result.metadata = this.step.metadata;\n\n return result;\n }\n}\n\n/**\n * Create a new dunning step builder\n */\nexport function step(id: string, name: string): DunningStepBuilder {\n return new DunningStepBuilder(id, name);\n}\n\n// ============================================================================\n// Sequence Builder\n// ============================================================================\n\n/**\n * Fluent builder for dunning sequences\n */\nexport class DunningSequenceBuilder {\n private sequence: Partial<DunningSequence> = {\n steps: [],\n isActive: true,\n };\n\n constructor(id: string, name: string) {\n this.sequence.id = id;\n this.sequence.name = name;\n }\n\n /**\n * Set description\n */\n describe(description: string): this {\n this.sequence.description = description;\n return this;\n }\n\n /**\n * Add steps\n */\n withSteps(...steps: DunningStep[]): this {\n this.sequence.steps = steps;\n return this;\n }\n\n /**\n * Set maximum duration before auto-cancel\n */\n maxDays(days: number): this {\n this.sequence.maxDurationDays = days;\n return this;\n }\n\n /**\n * Set active status\n */\n active(isActive = true): this {\n this.sequence.isActive = isActive;\n return this;\n }\n\n /**\n * Add metadata\n */\n withMetadata(metadata: Record<string, unknown>): this {\n this.sequence.metadata = metadata;\n return this;\n }\n\n /**\n * Build the sequence\n */\n build(): DunningSequence {\n if (!this.sequence.id || !this.sequence.name || !this.sequence.maxDurationDays) {\n throw new Error(\"DunningSequence requires id, name, and maxDurationDays\");\n }\n\n // Sort steps by daysAfterFailure\n const sortedSteps = [...(this.sequence.steps || [])].sort(\n (a, b) => a.daysAfterFailure - b.daysAfterFailure\n );\n\n const result: DunningSequence = {\n id: this.sequence.id,\n name: this.sequence.name,\n steps: sortedSteps,\n maxDurationDays: this.sequence.maxDurationDays,\n isActive: this.sequence.isActive ?? true,\n };\n\n // Only add optional properties if they have values\n if (this.sequence.description !== undefined) result.description = this.sequence.description;\n if (this.sequence.metadata !== undefined) result.metadata = this.sequence.metadata;\n\n return result;\n }\n}\n\n/**\n * Create a new dunning sequence builder\n */\nexport function sequence(id: string, name: string): DunningSequenceBuilder {\n return new DunningSequenceBuilder(id, name);\n}\n\n// ============================================================================\n// Default Sequences\n// ============================================================================\n\n/**\n * Standard SaaS dunning sequence (28 days)\n *\n * Day 0: Immediate retry + email notification\n * Day 1: Retry + email reminder\n * Day 3: Retry + email warning\n * Day 7: Retry + email + in-app notification, limit features\n * Day 14: Retry + email, suspend account\n * Day 21: Final warning email\n * Day 28: Cancel subscription\n */\nexport const standardSaasSequence: DunningSequence = sequence(\"standard-saas\", \"Standard SaaS Dunning\")\n .describe(\"Standard 28-day dunning sequence for SaaS applications\")\n .maxDays(28)\n .withSteps(\n step(\"immediate-retry\", \"Immediate Retry\")\n .afterDays(0)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-payment-failed\")\n .retryPayment()\n .build(),\n\n step(\"day-1-reminder\", \"Day 1 Reminder\")\n .afterDays(1)\n .atHour(10) // 10 AM\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-reminder\")\n .retryPayment()\n .build(),\n\n step(\"day-3-warning\", \"Day 3 Warning\")\n .afterDays(3)\n .atHour(10)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-warning\")\n .retryPayment()\n .build(),\n\n step(\"day-7-limit\", \"Day 7 Feature Limit\")\n .afterDays(7)\n .atHour(10)\n .withActions(\"retry_payment\", \"notify\", \"limit_features\")\n .notify(\"email\", \"in_app\")\n .withTemplate(\"dunning-feature-limit\")\n .retryPayment()\n .setAccessLevel(\"limited\")\n .build(),\n\n step(\"day-14-suspend\", \"Day 14 Suspension\")\n .afterDays(14)\n .atHour(10)\n .withActions(\"retry_payment\", \"notify\", \"suspend\")\n .notify(\"email\", \"in_app\")\n .withTemplate(\"dunning-suspension\")\n .retryPayment()\n .setAccessLevel(\"read_only\")\n .build(),\n\n step(\"day-21-final-warning\", \"Day 21 Final Warning\")\n .afterDays(21)\n .atHour(10)\n .withActions(\"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-final-warning\")\n .build(),\n\n step(\"day-28-cancel\", \"Day 28 Cancellation\")\n .afterDays(28)\n .atHour(10)\n .withActions(\"notify\", \"cancel\")\n .notify(\"email\")\n .withTemplate(\"dunning-canceled\")\n .final()\n .setAccessLevel(\"none\")\n .build()\n )\n .build();\n\n/**\n * Aggressive dunning sequence (14 days)\n * For lower-tier plans or high-risk customers\n */\nexport const aggressiveSequence: DunningSequence = sequence(\"aggressive\", \"Aggressive Dunning\")\n .describe(\"Aggressive 14-day dunning sequence\")\n .maxDays(14)\n .withSteps(\n step(\"immediate\", \"Immediate Retry\")\n .afterDays(0)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-payment-failed\")\n .retryPayment()\n .build(),\n\n step(\"day-1\", \"Day 1\")\n .afterDays(1)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\", \"sms\")\n .withTemplate(\"dunning-urgent\")\n .retryPayment()\n .build(),\n\n step(\"day-3-limit\", \"Day 3 Limit\")\n .afterDays(3)\n .withActions(\"retry_payment\", \"notify\", \"limit_features\")\n .notify(\"email\", \"in_app\")\n .withTemplate(\"dunning-feature-limit\")\n .retryPayment()\n .setAccessLevel(\"limited\")\n .build(),\n\n step(\"day-7-suspend\", \"Day 7 Suspend\")\n .afterDays(7)\n .withActions(\"retry_payment\", \"notify\", \"suspend\")\n .notify(\"email\", \"sms\", \"in_app\")\n .withTemplate(\"dunning-suspension\")\n .retryPayment()\n .setAccessLevel(\"read_only\")\n .build(),\n\n step(\"day-14-cancel\", \"Day 14 Cancel\")\n .afterDays(14)\n .withActions(\"notify\", \"cancel\")\n .notify(\"email\")\n .withTemplate(\"dunning-canceled\")\n .final()\n .setAccessLevel(\"none\")\n .build()\n )\n .build();\n\n/**\n * Lenient dunning sequence (45 days)\n * For enterprise or high-value customers\n */\nexport const lenientSequence: DunningSequence = sequence(\"lenient\", \"Lenient Dunning\")\n .describe(\"Lenient 45-day dunning sequence for enterprise customers\")\n .maxDays(45)\n .withSteps(\n step(\"immediate\", \"Immediate Retry\")\n .afterDays(0)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-payment-failed-enterprise\")\n .retryPayment()\n .build(),\n\n step(\"day-3\", \"Day 3 Reminder\")\n .afterDays(3)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-reminder-enterprise\")\n .retryPayment()\n .build(),\n\n step(\"day-7\", \"Day 7 Reminder\")\n .afterDays(7)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-reminder-enterprise\")\n .retryPayment()\n .build(),\n\n step(\"day-14\", \"Day 14 Warning\")\n .afterDays(14)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\", \"in_app\")\n .withTemplate(\"dunning-warning-enterprise\")\n .retryPayment()\n .build(),\n\n step(\"day-21-limit\", \"Day 21 Feature Limit\")\n .afterDays(21)\n .withActions(\"retry_payment\", \"notify\", \"limit_features\")\n .notify(\"email\", \"in_app\")\n .withTemplate(\"dunning-feature-limit-enterprise\")\n .retryPayment()\n .setAccessLevel(\"limited\")\n .build(),\n\n step(\"day-30-suspend\", \"Day 30 Suspension\")\n .afterDays(30)\n .withActions(\"retry_payment\", \"notify\", \"suspend\")\n .notify(\"email\", \"in_app\")\n .withTemplate(\"dunning-suspension-enterprise\")\n .retryPayment()\n .setAccessLevel(\"read_only\")\n .build(),\n\n step(\"day-40-final\", \"Day 40 Final Warning\")\n .afterDays(40)\n .withActions(\"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-final-warning-enterprise\")\n .build(),\n\n step(\"day-45-cancel\", \"Day 45 Cancel\")\n .afterDays(45)\n .withActions(\"notify\", \"cancel\")\n .notify(\"email\")\n .withTemplate(\"dunning-canceled-enterprise\")\n .final()\n .setAccessLevel(\"none\")\n .build()\n )\n .build();\n\n/**\n * Minimal dunning sequence (7 days)\n * For free-to-paid conversions or trials\n */\nexport const minimalSequence: DunningSequence = sequence(\"minimal\", \"Minimal Dunning\")\n .describe(\"Minimal 7-day dunning sequence\")\n .maxDays(7)\n .withSteps(\n step(\"immediate\", \"Immediate Retry\")\n .afterDays(0)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-payment-failed\")\n .retryPayment()\n .build(),\n\n step(\"day-3\", \"Day 3\")\n .afterDays(3)\n .withActions(\"retry_payment\", \"notify\")\n .notify(\"email\")\n .withTemplate(\"dunning-reminder\")\n .retryPayment()\n .build(),\n\n step(\"day-7-cancel\", \"Day 7 Cancel\")\n .afterDays(7)\n .withActions(\"notify\", \"cancel\")\n .notify(\"email\")\n .withTemplate(\"dunning-canceled\")\n .final()\n .setAccessLevel(\"none\")\n .build()\n )\n .build();\n\n// ============================================================================\n// Sequence Registry\n// ============================================================================\n\n/**\n * Default sequences by tier\n */\nexport const defaultSequences: Record<string, DunningSequence> = {\n standard: standardSaasSequence,\n aggressive: aggressiveSequence,\n lenient: lenientSequence,\n minimal: minimalSequence,\n};\n\n/**\n * Get sequence by tier level\n *\n * @param tier - Plan tier (0=free, 1=starter, 2=pro, 3=enterprise)\n * @returns Appropriate dunning sequence\n */\nexport function getSequenceByTier(tier: number): DunningSequence {\n if (tier >= 3) return lenientSequence; // Enterprise\n if (tier >= 2) return standardSaasSequence; // Pro\n if (tier >= 1) return aggressiveSequence; // Starter\n return minimalSequence; // Free/Trial\n}\n","/**\n * @parsrun/payments - Payment Retry Strategy\n * Smart retry logic based on payment failure codes\n */\n\nimport type {\n PaymentFailure,\n PaymentFailureCategory,\n RetryStrategy,\n RetryResult,\n DunningContext,\n DunningLogger,\n} from \"./types.js\";\n\n// ============================================================================\n// Error Code Mapping\n// ============================================================================\n\n/**\n * Map provider error codes to failure categories\n */\nexport interface ErrorCodeMapping {\n provider: string;\n codes: Record<string, PaymentFailureCategory>;\n}\n\n/**\n * Stripe error code mappings\n */\nexport const stripeErrorCodes: ErrorCodeMapping = {\n provider: \"stripe\",\n codes: {\n // Card declined\n card_declined: \"card_declined\",\n generic_decline: \"card_declined\",\n do_not_honor: \"card_declined\",\n transaction_not_allowed: \"card_declined\",\n\n // Insufficient funds\n insufficient_funds: \"insufficient_funds\",\n\n // Card expired/invalid\n expired_card: \"card_expired\",\n invalid_expiry_month: \"card_expired\",\n invalid_expiry_year: \"card_expired\",\n invalid_number: \"invalid_card\",\n invalid_cvc: \"invalid_card\",\n incorrect_number: \"invalid_card\",\n incorrect_cvc: \"invalid_card\",\n\n // Processing errors (retry immediately)\n processing_error: \"processing_error\",\n try_again_later: \"processing_error\",\n bank_not_supported: \"processing_error\",\n\n // Authentication required\n authentication_required: \"authentication_required\",\n card_not_supported: \"authentication_required\",\n\n // Fraud\n fraudulent: \"fraud_suspected\",\n merchant_blacklist: \"fraud_suspected\",\n stolen_card: \"fraud_suspected\",\n lost_card: \"fraud_suspected\",\n\n // Rate limits\n rate_limit: \"velocity_exceeded\",\n },\n};\n\n/**\n * Paddle error code mappings\n */\nexport const paddleErrorCodes: ErrorCodeMapping = {\n provider: \"paddle\",\n codes: {\n declined: \"card_declined\",\n insufficient_funds: \"insufficient_funds\",\n card_expired: \"card_expired\",\n invalid_card: \"invalid_card\",\n processing_error: \"processing_error\",\n authentication_required: \"authentication_required\",\n fraud: \"fraud_suspected\",\n },\n};\n\n/**\n * iyzico error code mappings\n */\nexport const iyzicoErrorCodes: ErrorCodeMapping = {\n provider: \"iyzico\",\n codes: {\n // Turkish bank error codes\n \"10051\": \"insufficient_funds\", // Yetersiz bakiye\n \"10054\": \"card_expired\", // Süresi dolmuş kart\n \"10057\": \"card_declined\", // İşlem onaylanmadı\n \"10005\": \"invalid_card\", // Geçersiz kart\n \"10012\": \"invalid_card\", // Geçersiz işlem\n \"10041\": \"fraud_suspected\", // Kayıp kart\n \"10043\": \"fraud_suspected\", // Çalıntı kart\n \"10058\": \"card_declined\", // Terminal işlem yapma yetkisi yok\n \"10034\": \"fraud_suspected\", // Dolandırıcılık şüphesi\n },\n};\n\n/**\n * All provider mappings\n */\nexport const allErrorCodeMappings: ErrorCodeMapping[] = [\n stripeErrorCodes,\n paddleErrorCodes,\n iyzicoErrorCodes,\n];\n\n// ============================================================================\n// Default Retry Strategies\n// ============================================================================\n\n/**\n * Default retry strategies by failure category\n */\nexport const defaultRetryStrategies: RetryStrategy[] = [\n {\n category: \"card_declined\",\n shouldRetry: true,\n initialDelayHours: 24, // Wait a day\n maxRetries: 4,\n backoffMultiplier: 2,\n maxDelayHours: 168, // 1 week max\n optimalRetryHours: [10, 14, 18], // Business hours\n optimalRetryDays: [1, 2, 3, 4, 5], // Weekdays\n },\n {\n category: \"insufficient_funds\",\n shouldRetry: true,\n initialDelayHours: 72, // Wait until likely payday\n maxRetries: 4,\n backoffMultiplier: 1.5,\n maxDelayHours: 168,\n // Optimal times: end of month, mid-month (paydays)\n optimalRetryDays: [0, 1, 15, 16, 28, 29, 30, 31].map((d) => d % 7), // Around paydays\n },\n {\n category: \"card_expired\",\n shouldRetry: false, // Don't retry - needs card update\n initialDelayHours: 0,\n maxRetries: 0,\n backoffMultiplier: 1,\n maxDelayHours: 0,\n },\n {\n category: \"invalid_card\",\n shouldRetry: false, // Don't retry - needs card update\n initialDelayHours: 0,\n maxRetries: 0,\n backoffMultiplier: 1,\n maxDelayHours: 0,\n },\n {\n category: \"processing_error\",\n shouldRetry: true,\n initialDelayHours: 1, // Retry soon\n maxRetries: 5,\n backoffMultiplier: 2,\n maxDelayHours: 24,\n },\n {\n category: \"authentication_required\",\n shouldRetry: false, // Needs customer action (3DS)\n initialDelayHours: 0,\n maxRetries: 0,\n backoffMultiplier: 1,\n maxDelayHours: 0,\n },\n {\n category: \"fraud_suspected\",\n shouldRetry: false, // Never retry fraud\n initialDelayHours: 0,\n maxRetries: 0,\n backoffMultiplier: 1,\n maxDelayHours: 0,\n },\n {\n category: \"velocity_exceeded\",\n shouldRetry: true,\n initialDelayHours: 6, // Wait for rate limit reset\n maxRetries: 3,\n backoffMultiplier: 2,\n maxDelayHours: 48,\n },\n {\n category: \"unknown\",\n shouldRetry: true, // Cautious retry\n initialDelayHours: 24,\n maxRetries: 2,\n backoffMultiplier: 2,\n maxDelayHours: 72,\n },\n];\n\n// ============================================================================\n// Retry Calculator\n// ============================================================================\n\n/**\n * Payment retry calculator\n * Determines optimal retry timing based on failure category\n */\nexport class PaymentRetryCalculator {\n private strategies: Map<PaymentFailureCategory, RetryStrategy>;\n private errorMappings: Map<string, Map<string, PaymentFailureCategory>>;\n private logger?: DunningLogger;\n\n constructor(\n strategies: RetryStrategy[] = defaultRetryStrategies,\n errorMappings: ErrorCodeMapping[] = allErrorCodeMappings,\n logger?: DunningLogger\n ) {\n this.strategies = new Map(strategies.map((s) => [s.category, s]));\n this.errorMappings = new Map();\n if (logger) {\n this.logger = logger;\n }\n\n // Build error code lookup\n for (const mapping of errorMappings) {\n this.errorMappings.set(mapping.provider, new Map(Object.entries(mapping.codes)));\n }\n }\n\n /**\n * Map error code to failure category\n */\n categorizeError(provider: string, errorCode: string): PaymentFailureCategory {\n const providerMapping = this.errorMappings.get(provider.toLowerCase());\n if (providerMapping) {\n const category = providerMapping.get(errorCode.toLowerCase());\n if (category) return category;\n }\n return \"unknown\";\n }\n\n /**\n * Get retry strategy for failure category\n */\n getStrategy(category: PaymentFailureCategory): RetryStrategy {\n return (\n this.strategies.get(category) ?? {\n category: \"unknown\",\n shouldRetry: true,\n initialDelayHours: 24,\n maxRetries: 2,\n backoffMultiplier: 2,\n maxDelayHours: 72,\n }\n );\n }\n\n /**\n * Check if a failure should be retried\n */\n shouldRetry(failure: PaymentFailure): boolean {\n const strategy = this.getStrategy(failure.category);\n\n // Check if strategy allows retry\n if (!strategy.shouldRetry) {\n this.logger?.debug(\"Retry not allowed for category\", {\n category: failure.category,\n failureId: failure.id,\n });\n return false;\n }\n\n // Check retry count\n if (failure.retryCount >= strategy.maxRetries) {\n this.logger?.debug(\"Max retries reached\", {\n category: failure.category,\n retryCount: failure.retryCount,\n maxRetries: strategy.maxRetries,\n });\n return false;\n }\n\n return true;\n }\n\n /**\n * Calculate next retry time\n */\n calculateNextRetry(failure: PaymentFailure): Date | null {\n if (!this.shouldRetry(failure)) {\n return null;\n }\n\n const strategy = this.getStrategy(failure.category);\n\n // Calculate delay with exponential backoff\n const baseDelay = strategy.initialDelayHours;\n const multiplier = Math.pow(strategy.backoffMultiplier, failure.retryCount);\n let delayHours = Math.min(baseDelay * multiplier, strategy.maxDelayHours);\n\n // Calculate base retry time\n let retryTime = new Date(failure.failedAt.getTime() + delayHours * 60 * 60 * 1000);\n\n // Optimize for best retry time\n retryTime = this.optimizeRetryTime(retryTime, strategy);\n\n this.logger?.debug(\"Calculated next retry time\", {\n failureId: failure.id,\n category: failure.category,\n retryCount: failure.retryCount,\n delayHours,\n nextRetry: retryTime.toISOString(),\n });\n\n return retryTime;\n }\n\n /**\n * Optimize retry time based on strategy\n */\n private optimizeRetryTime(baseTime: Date, strategy: RetryStrategy): Date {\n const optimalHours = strategy.optimalRetryHours;\n const optimalDays = strategy.optimalRetryDays;\n\n if (!optimalHours?.length && !optimalDays?.length) {\n return baseTime;\n }\n\n let optimizedTime = new Date(baseTime);\n\n // Adjust to optimal hour if specified\n if (optimalHours?.length) {\n const currentHour = optimizedTime.getHours();\n const nearestOptimalHour = this.findNearestValue(currentHour, optimalHours);\n\n if (nearestOptimalHour !== currentHour) {\n optimizedTime.setHours(nearestOptimalHour, 0, 0, 0);\n\n // If we moved to an earlier hour, add a day\n if (nearestOptimalHour < currentHour) {\n optimizedTime.setDate(optimizedTime.getDate() + 1);\n }\n }\n }\n\n // Adjust to optimal day if specified\n if (optimalDays?.length) {\n const currentDay = optimizedTime.getDay();\n const nearestOptimalDay = this.findNearestValue(currentDay, optimalDays);\n\n if (nearestOptimalDay !== currentDay) {\n const daysToAdd = (nearestOptimalDay - currentDay + 7) % 7;\n optimizedTime.setDate(optimizedTime.getDate() + (daysToAdd || 7));\n }\n }\n\n // Don't move earlier than base time\n if (optimizedTime < baseTime) {\n return baseTime;\n }\n\n return optimizedTime;\n }\n\n /**\n * Find nearest value in array\n */\n private findNearestValue(current: number, values: number[]): number {\n const firstValue = values[0];\n if (firstValue === undefined) {\n return current;\n }\n\n let nearest = firstValue;\n let minDiff = Math.abs(current - nearest);\n\n for (const value of values) {\n const diff = Math.abs(current - value);\n if (diff < minDiff) {\n minDiff = diff;\n nearest = value;\n }\n }\n\n return nearest;\n }\n\n /**\n * Check if failure is recoverable (can be retried eventually)\n */\n isRecoverable(category: PaymentFailureCategory): boolean {\n const strategy = this.getStrategy(category);\n return strategy.shouldRetry;\n }\n\n /**\n * Get recommendation message for failure category\n */\n getRecommendation(category: PaymentFailureCategory): string {\n switch (category) {\n case \"card_declined\":\n return \"The payment was declined. We'll retry automatically.\";\n case \"insufficient_funds\":\n return \"There were insufficient funds. We'll retry around payday.\";\n case \"card_expired\":\n return \"Your card has expired. Please update your payment method.\";\n case \"invalid_card\":\n return \"The card information is invalid. Please update your payment method.\";\n case \"processing_error\":\n return \"A temporary processing error occurred. We'll retry shortly.\";\n case \"authentication_required\":\n return \"Additional authentication is required. Please complete the payment manually.\";\n case \"fraud_suspected\":\n return \"The payment was flagged. Please contact your bank or use a different card.\";\n case \"velocity_exceeded\":\n return \"Too many payment attempts. We'll retry later.\";\n default:\n return \"An error occurred. We'll retry the payment.\";\n }\n }\n}\n\n// ============================================================================\n// Payment Retrier\n// ============================================================================\n\n/**\n * Payment retry handler configuration\n */\nexport interface PaymentRetrierConfig {\n /** Retry calculator */\n calculator?: PaymentRetryCalculator;\n\n /** Function to actually retry the payment */\n retryPayment: (context: DunningContext) => Promise<RetryResult>;\n\n /** Logger */\n logger?: DunningLogger;\n\n /** Maximum retries per dunning session */\n maxSessionRetries?: number;\n}\n\n/**\n * Payment retrier\n * Handles intelligent payment retry logic\n */\nexport class PaymentRetrier {\n private calculator: PaymentRetryCalculator;\n private retryPayment: (context: DunningContext) => Promise<RetryResult>;\n private logger?: DunningLogger;\n private maxSessionRetries: number;\n\n constructor(config: PaymentRetrierConfig) {\n this.calculator =\n config.calculator ?? new PaymentRetryCalculator(undefined, undefined, config.logger);\n this.retryPayment = config.retryPayment;\n if (config.logger) {\n this.logger = config.logger;\n }\n this.maxSessionRetries = config.maxSessionRetries ?? 10;\n }\n\n /**\n * Attempt to retry a payment\n */\n async retry(context: DunningContext): Promise<RetryResult> {\n const failure = context.latestFailure;\n\n // Check if we should retry\n if (!this.calculator.shouldRetry(failure)) {\n this.logger?.info(\"Payment retry skipped - not recoverable\", {\n failureId: failure.id,\n category: failure.category,\n reason: this.calculator.getRecommendation(failure.category),\n });\n\n return {\n success: false,\n failure,\n attemptedAt: new Date(),\n };\n }\n\n // Check session retry limit\n if (context.state.totalRetryAttempts >= this.maxSessionRetries) {\n this.logger?.warn(\"Payment retry skipped - session limit reached\", {\n customerId: context.customer.id,\n totalAttempts: context.state.totalRetryAttempts,\n maxAttempts: this.maxSessionRetries,\n });\n\n return {\n success: false,\n failure,\n attemptedAt: new Date(),\n };\n }\n\n // Attempt retry\n this.logger?.info(\"Attempting payment retry\", {\n failureId: failure.id,\n customerId: context.customer.id,\n amount: failure.amount,\n retryCount: failure.retryCount,\n });\n\n try {\n const result = await this.retryPayment(context);\n\n if (result.success) {\n this.logger?.info(\"Payment retry successful\", {\n failureId: failure.id,\n transactionId: result.transactionId,\n });\n } else {\n this.logger?.info(\"Payment retry failed\", {\n failureId: failure.id,\n newFailure: result.failure,\n });\n }\n\n return result;\n } catch (error) {\n this.logger?.error(\"Payment retry error\", {\n failureId: failure.id,\n error: error instanceof Error ? error.message : String(error),\n });\n\n return {\n success: false,\n failure,\n attemptedAt: new Date(),\n };\n }\n }\n\n /**\n * Get next retry time for a failure\n */\n getNextRetryTime(failure: PaymentFailure): Date | null {\n return this.calculator.calculateNextRetry(failure);\n }\n\n /**\n * Check if failure is recoverable\n */\n isRecoverable(failure: PaymentFailure): boolean {\n return this.calculator.isRecoverable(failure.category);\n }\n\n /**\n * Categorize an error code\n */\n categorizeError(provider: string, errorCode: string): PaymentFailureCategory {\n return this.calculator.categorizeError(provider, errorCode);\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create a payment retry calculator\n */\nexport function createPaymentRetryCalculator(\n strategies?: RetryStrategy[],\n errorMappings?: ErrorCodeMapping[],\n logger?: DunningLogger\n): PaymentRetryCalculator {\n return new PaymentRetryCalculator(strategies, errorMappings, logger);\n}\n\n/**\n * Create a payment retrier\n */\nexport function createPaymentRetrier(config: PaymentRetrierConfig): PaymentRetrier {\n return new PaymentRetrier(config);\n}\n","/**\n * @parsrun/payments - Dunning Manager\n * Main orchestrator for dunning state management and step execution\n */\n\nimport type {\n DunningManagerConfig,\n DunningSequence,\n DunningStep,\n DunningState,\n DunningStatus,\n DunningContext,\n DunningEvent,\n DunningEventHandler,\n PaymentFailure,\n ExecutedStep,\n DunningNotification,\n NotificationResult,\n DunningStorage,\n DunningLogger,\n} from \"./types.js\";\nimport { standardSaasSequence } from \"./dunning-sequence.js\";\n\n// ============================================================================\n// Dunning Manager\n// ============================================================================\n\n/**\n * Dunning Manager\n * Orchestrates the dunning process including state management and step execution\n */\nexport class DunningManager {\n private config: DunningManagerConfig;\n private storage: DunningStorage;\n private eventHandlers: DunningEventHandler[] = [];\n private logger?: DunningLogger;\n\n constructor(config: DunningManagerConfig, storage: DunningStorage) {\n this.config = config;\n this.storage = storage;\n if (config.logger) {\n this.logger = config.logger;\n }\n\n // Register event handler from config\n if (config.onEvent) {\n this.eventHandlers.push(config.onEvent);\n }\n }\n\n // ============================================================================\n // Dunning Lifecycle\n // ============================================================================\n\n /**\n * Start dunning process for a payment failure\n */\n async startDunning(failure: PaymentFailure): Promise<DunningState> {\n // Check if dunning already exists\n const existingState = await this.storage.getDunningState(failure.customerId);\n if (existingState && existingState.status === \"active\") {\n this.logger?.info(\"Dunning already active, adding failure\", {\n customerId: failure.customerId,\n dunningId: existingState.id,\n });\n\n // Add new failure to existing state\n existingState.failures.push(failure);\n await this.storage.updateDunningState(existingState.id, {\n failures: existingState.failures,\n });\n\n return existingState;\n }\n\n // Get appropriate sequence\n const sequence = await this.getSequenceForCustomer(failure.customerId);\n const firstStep = sequence.steps[0];\n\n if (!firstStep) {\n throw new Error(`Dunning sequence ${sequence.id} has no steps`);\n }\n\n // Create new dunning state\n const state: DunningState = {\n id: this.generateId(),\n customerId: failure.customerId,\n subscriptionId: failure.subscriptionId,\n sequenceId: sequence.id,\n currentStepIndex: 0,\n currentStepId: firstStep.id,\n status: \"active\",\n initialFailure: failure,\n failures: [failure],\n executedSteps: [],\n startedAt: new Date(),\n nextStepAt: this.calculateStepTime(firstStep, failure.failedAt),\n totalRetryAttempts: 0,\n };\n\n // Save state\n await this.storage.saveDunningState(state);\n\n // Record failure\n await this.storage.recordPaymentFailure(failure);\n\n // Emit event\n await this.emitEvent({\n type: \"dunning.started\",\n customerId: state.customerId,\n subscriptionId: state.subscriptionId,\n dunningStateId: state.id,\n timestamp: new Date(),\n data: {\n sequenceId: sequence.id,\n initialFailure: failure,\n },\n });\n\n this.logger?.info(\"Dunning started\", {\n customerId: state.customerId,\n dunningId: state.id,\n sequenceId: sequence.id,\n });\n\n return state;\n }\n\n /**\n * Execute the next step in dunning sequence\n */\n async executeStep(stateId: string): Promise<ExecutedStep | null> {\n const state = await this.getDunningStateById(stateId);\n if (!state || state.status !== \"active\") {\n this.logger?.warn(\"Cannot execute step - invalid state\", {\n stateId,\n status: state?.status,\n });\n return null;\n }\n\n const sequence = this.getSequence(state.sequenceId);\n const step = sequence.steps[state.currentStepIndex];\n\n if (!step) {\n this.logger?.warn(\"No step found at index\", {\n stateId,\n stepIndex: state.currentStepIndex,\n });\n return null;\n }\n\n // Build context\n const context = await this.buildContext(state, step);\n\n // Check step condition\n if (step.condition) {\n const shouldExecute = await step.condition(context);\n if (!shouldExecute) {\n this.logger?.info(\"Step condition not met, skipping\", {\n stateId,\n stepId: step.id,\n });\n return this.advanceToNextStep(state);\n }\n }\n\n // Execute step\n const executedStep = await this.performStepActions(context, step);\n\n // Update state\n state.executedSteps.push(executedStep);\n state.lastStepAt = executedStep.executedAt;\n state.totalRetryAttempts += executedStep.paymentRetried ? 1 : 0;\n\n // Check if payment recovered\n if (executedStep.paymentSucceeded) {\n await this.recoverDunning(state, \"payment_recovered\");\n return executedStep;\n }\n\n // Check if final step\n if (step.isFinal) {\n await this.exhaustDunning(state);\n return executedStep;\n }\n\n // Advance to next step\n await this.advanceToNextStep(state);\n\n return executedStep;\n }\n\n /**\n * Recover from dunning (payment successful)\n */\n async recoverDunning(\n stateOrId: DunningState | string,\n reason: \"payment_recovered\" = \"payment_recovered\"\n ): Promise<void> {\n const state =\n typeof stateOrId === \"string\" ? await this.getDunningStateById(stateOrId) : stateOrId;\n\n if (!state) return;\n\n state.status = \"recovered\";\n state.endedAt = new Date();\n state.endReason = reason;\n\n await this.storage.updateDunningState(state.id, {\n status: state.status,\n endedAt: state.endedAt,\n endReason: state.endReason,\n });\n\n // Restore full access\n if (this.config.onAccessUpdate) {\n await this.config.onAccessUpdate(state.customerId, \"full\");\n }\n\n await this.emitEvent({\n type: \"dunning.payment_recovered\",\n customerId: state.customerId,\n subscriptionId: state.subscriptionId,\n dunningStateId: state.id,\n timestamp: new Date(),\n data: { reason },\n });\n\n this.logger?.info(\"Dunning recovered\", {\n dunningId: state.id,\n customerId: state.customerId,\n });\n }\n\n /**\n * Pause dunning process\n */\n async pauseDunning(stateId: string): Promise<void> {\n await this.storage.updateDunningState(stateId, {\n status: \"paused\",\n });\n\n const state = await this.getDunningStateById(stateId);\n if (state) {\n await this.emitEvent({\n type: \"dunning.paused\",\n customerId: state.customerId,\n subscriptionId: state.subscriptionId,\n dunningStateId: state.id,\n timestamp: new Date(),\n data: {},\n });\n }\n }\n\n /**\n * Resume paused dunning\n */\n async resumeDunning(stateId: string): Promise<void> {\n const state = await this.getDunningStateById(stateId);\n if (!state || state.status !== \"paused\") return;\n\n const sequence = this.getSequence(state.sequenceId);\n const step = sequence.steps[state.currentStepIndex];\n\n const updates: Partial<DunningState> = { status: \"active\" };\n if (step) {\n updates.nextStepAt = this.calculateStepTime(step, new Date());\n }\n await this.storage.updateDunningState(stateId, updates);\n\n await this.emitEvent({\n type: \"dunning.resumed\",\n customerId: state.customerId,\n subscriptionId: state.subscriptionId,\n dunningStateId: state.id,\n timestamp: new Date(),\n data: {},\n });\n }\n\n /**\n * Cancel dunning manually\n */\n async cancelDunning(stateId: string, reason?: string): Promise<void> {\n const state = await this.getDunningStateById(stateId);\n if (!state) return;\n\n state.status = \"canceled\";\n state.endedAt = new Date();\n state.endReason = \"manually_canceled\";\n\n await this.storage.updateDunningState(stateId, {\n status: state.status,\n endedAt: state.endedAt,\n endReason: state.endReason,\n metadata: { ...state.metadata, cancelReason: reason },\n });\n\n await this.emitEvent({\n type: \"dunning.canceled\",\n customerId: state.customerId,\n subscriptionId: state.subscriptionId,\n dunningStateId: state.id,\n timestamp: new Date(),\n data: { reason },\n });\n }\n\n // ============================================================================\n // State Queries\n // ============================================================================\n\n /**\n * Get dunning state by customer ID\n */\n async getDunningState(customerId: string): Promise<DunningState | null> {\n return this.storage.getDunningState(customerId);\n }\n\n /**\n * Get dunning state by ID\n */\n async getDunningStateById(stateId: string): Promise<DunningState | null> {\n // Storage should support this - for now iterate active states\n const states = await this.storage.getActiveDunningStates();\n return states.find((s) => s.id === stateId) ?? null;\n }\n\n /**\n * Get all active dunning states\n */\n async getActiveDunningStates(): Promise<DunningState[]> {\n return this.storage.getActiveDunningStates();\n }\n\n /**\n * Get dunning states by status\n */\n async getDunningStatesByStatus(status: DunningStatus): Promise<DunningState[]> {\n return this.storage.getDunningStatesByStatus(status);\n }\n\n /**\n * Get scheduled steps due for execution\n */\n async getScheduledSteps(\n before: Date\n ): Promise<Array<{ stateId: string; stepId: string; scheduledAt: Date }>> {\n return this.storage.getScheduledSteps(before);\n }\n\n // ============================================================================\n // Events\n // ============================================================================\n\n /**\n * Register event handler\n */\n onEvent(handler: DunningEventHandler): this {\n this.eventHandlers.push(handler);\n return this;\n }\n\n /**\n * Emit dunning event\n */\n private async emitEvent(event: DunningEvent): Promise<void> {\n for (const handler of this.eventHandlers) {\n try {\n await handler(event);\n } catch (error) {\n this.logger?.error(\"Event handler error\", {\n eventType: event.type,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n }\n\n // ============================================================================\n // Internal Methods\n // ============================================================================\n\n /**\n * Perform step actions\n */\n private async performStepActions(\n context: DunningContext,\n step: DunningStep\n ): Promise<ExecutedStep> {\n const executed: ExecutedStep = {\n stepId: step.id,\n stepName: step.name,\n executedAt: new Date(),\n actionsTaken: [],\n paymentRetried: false,\n notificationsSent: [],\n };\n\n for (const action of step.actions) {\n try {\n switch (action) {\n case \"notify\":\n const notifyResults = await this.sendNotifications(context, step);\n executed.notificationsSent = notifyResults\n .filter((r) => r.success)\n .map((r) => r.channel);\n executed.actionsTaken.push(\"notify\");\n break;\n\n case \"retry_payment\":\n if (this.config.onRetryPayment) {\n const retryResult = await this.config.onRetryPayment(context);\n executed.paymentRetried = true;\n executed.paymentSucceeded = retryResult.success;\n executed.actionsTaken.push(\"retry_payment\");\n\n await this.emitEvent({\n type: \"dunning.payment_retried\",\n customerId: context.customer.id,\n subscriptionId: context.subscription.id,\n dunningStateId: context.state.id,\n timestamp: new Date(),\n data: {\n success: retryResult.success,\n transactionId: retryResult.transactionId,\n },\n });\n\n // If retry succeeded, stop processing other actions\n if (retryResult.success) {\n return executed;\n }\n }\n break;\n\n case \"limit_features\":\n if (this.config.onAccessUpdate && step.accessLevel) {\n await this.config.onAccessUpdate(context.customer.id, step.accessLevel);\n executed.actionsTaken.push(\"limit_features\");\n\n await this.emitEvent({\n type: \"dunning.access_limited\",\n customerId: context.customer.id,\n subscriptionId: context.subscription.id,\n dunningStateId: context.state.id,\n timestamp: new Date(),\n data: { accessLevel: step.accessLevel },\n });\n }\n break;\n\n case \"suspend\":\n if (this.config.onAccessUpdate) {\n await this.config.onAccessUpdate(context.customer.id, \"read_only\");\n executed.actionsTaken.push(\"suspend\");\n\n await this.emitEvent({\n type: \"dunning.suspended\",\n customerId: context.customer.id,\n subscriptionId: context.subscription.id,\n dunningStateId: context.state.id,\n timestamp: new Date(),\n data: {},\n });\n }\n break;\n\n case \"cancel\":\n if (this.config.onCancelSubscription) {\n await this.config.onCancelSubscription(\n context.subscription.id,\n \"dunning_exhausted\"\n );\n executed.actionsTaken.push(\"cancel\");\n }\n break;\n\n case \"custom\":\n if (step.customAction) {\n await step.customAction(context);\n executed.actionsTaken.push(\"custom\");\n }\n break;\n }\n } catch (error) {\n this.logger?.error(\"Step action failed\", {\n stepId: step.id,\n action,\n error: error instanceof Error ? error.message : String(error),\n });\n executed.error = error instanceof Error ? error.message : String(error);\n }\n }\n\n // Emit step executed event\n await this.emitEvent({\n type: \"dunning.step_executed\",\n customerId: context.customer.id,\n subscriptionId: context.subscription.id,\n dunningStateId: context.state.id,\n timestamp: new Date(),\n data: {\n stepId: step.id,\n stepName: step.name,\n actionsTaken: executed.actionsTaken,\n },\n });\n\n return executed;\n }\n\n /**\n * Send notifications for a step\n */\n private async sendNotifications(\n context: DunningContext,\n step: DunningStep\n ): Promise<NotificationResult[]> {\n if (!step.notificationChannels?.length || !this.config.onNotification) {\n return [];\n }\n\n const results: NotificationResult[] = [];\n\n for (const channel of step.notificationChannels) {\n // Build recipient with only defined properties\n const recipient: DunningNotification[\"recipient\"] = {\n customerId: context.customer.id,\n };\n if (context.customer.email) {\n recipient.email = context.customer.email;\n }\n\n // Build variables with only defined properties\n const variables: DunningNotification[\"variables\"] = {\n amount: context.amountOwed,\n currency: context.currency,\n daysSinceFailure: context.daysSinceFailure,\n };\n if (context.customer.name) {\n variables.customerName = context.customer.name;\n }\n if (this.config.urls?.updatePayment) {\n variables.updatePaymentUrl = this.config.urls.updatePayment;\n }\n if (this.config.urls?.viewInvoice) {\n variables.invoiceUrl = this.config.urls.viewInvoice;\n }\n if (this.config.urls?.support) {\n variables.supportUrl = this.config.urls.support;\n }\n\n const notification: DunningNotification = {\n channel,\n templateId: step.notificationTemplateId ?? `dunning-${step.id}`,\n recipient,\n variables,\n context,\n };\n\n try {\n const result = await this.config.onNotification(notification);\n results.push(result);\n\n if (result.success) {\n await this.emitEvent({\n type: \"dunning.notification_sent\",\n customerId: context.customer.id,\n subscriptionId: context.subscription.id,\n dunningStateId: context.state.id,\n timestamp: new Date(),\n data: {\n channel,\n templateId: notification.templateId,\n },\n });\n }\n } catch (error) {\n results.push({\n success: false,\n channel,\n error: error instanceof Error ? error.message : String(error),\n sentAt: new Date(),\n });\n }\n }\n\n return results;\n }\n\n /**\n * Advance to next step\n */\n private async advanceToNextStep(state: DunningState): Promise<ExecutedStep | null> {\n const sequence = this.getSequence(state.sequenceId);\n const nextIndex = state.currentStepIndex + 1;\n\n if (nextIndex >= sequence.steps.length) {\n await this.exhaustDunning(state);\n return null;\n }\n\n const nextStep = sequence.steps[nextIndex];\n if (!nextStep) {\n await this.exhaustDunning(state);\n return null;\n }\n\n const nextStepTime = this.calculateStepTime(nextStep, state.startedAt);\n\n await this.storage.updateDunningState(state.id, {\n currentStepIndex: nextIndex,\n currentStepId: nextStep.id,\n nextStepAt: nextStepTime,\n });\n\n // Schedule step\n await this.storage.scheduleStep(state.id, nextStep.id, nextStepTime);\n\n return null;\n }\n\n /**\n * Mark dunning as exhausted (all steps completed without recovery)\n */\n private async exhaustDunning(state: DunningState): Promise<void> {\n state.status = \"exhausted\";\n state.endedAt = new Date();\n state.endReason = \"max_retries\";\n\n await this.storage.updateDunningState(state.id, {\n status: state.status,\n endedAt: state.endedAt,\n endReason: state.endReason,\n });\n\n await this.emitEvent({\n type: \"dunning.exhausted\",\n customerId: state.customerId,\n subscriptionId: state.subscriptionId,\n dunningStateId: state.id,\n timestamp: new Date(),\n data: {\n totalRetries: state.totalRetryAttempts,\n stepsExecuted: state.executedSteps.length,\n },\n });\n\n this.logger?.info(\"Dunning exhausted\", {\n dunningId: state.id,\n customerId: state.customerId,\n });\n }\n\n /**\n * Build dunning context for step execution\n */\n private async buildContext(state: DunningState, step: DunningStep): Promise<DunningContext> {\n const latestFailure = state.failures[state.failures.length - 1] ?? state.initialFailure;\n\n // Build customer object with only defined properties\n const customer: DunningContext[\"customer\"] = {\n id: state.customerId,\n };\n const customerEmail = state.metadata?.[\"customerEmail\"];\n if (typeof customerEmail === \"string\") {\n customer.email = customerEmail;\n }\n const customerName = state.metadata?.[\"customerName\"];\n if (typeof customerName === \"string\") {\n customer.name = customerName;\n }\n const customerMetadata = state.metadata?.[\"customer\"];\n if (customerMetadata && typeof customerMetadata === \"object\") {\n customer.metadata = customerMetadata as Record<string, unknown>;\n }\n\n // Build subscription object with only defined properties\n const subscription: DunningContext[\"subscription\"] = {\n id: state.subscriptionId,\n status: \"past_due\",\n };\n const planId = state.metadata?.[\"planId\"];\n if (typeof planId === \"string\") {\n subscription.planId = planId;\n }\n\n return {\n state,\n step,\n latestFailure,\n customer,\n subscription,\n daysSinceFailure: Math.floor(\n (Date.now() - state.initialFailure.failedAt.getTime()) / (1000 * 60 * 60 * 24)\n ),\n amountOwed: state.failures.reduce((sum, f) => sum + f.amount, 0),\n currency: latestFailure.currency,\n };\n }\n\n /**\n * Calculate when a step should execute\n */\n private calculateStepTime(step: DunningStep, baseTime: Date): Date {\n const time = new Date(baseTime);\n time.setDate(time.getDate() + step.daysAfterFailure);\n\n if (step.hoursOffset !== undefined) {\n time.setHours(step.hoursOffset, 0, 0, 0);\n }\n\n return time;\n }\n\n /**\n * Get sequence for a customer (by tier if configured)\n */\n private async getSequenceForCustomer(_customerId: string): Promise<DunningSequence> {\n // TODO: Could lookup customer tier and return appropriate sequence\n // For now, return default sequence\n return this.config.defaultSequence;\n }\n\n /**\n * Get sequence by ID\n */\n private getSequence(sequenceId: string): DunningSequence {\n if (sequenceId === this.config.defaultSequence.id) {\n return this.config.defaultSequence;\n }\n\n // Check tier sequences\n if (this.config.sequencesByPlanTier) {\n for (const seq of Object.values(this.config.sequencesByPlanTier)) {\n if (seq.id === sequenceId) return seq;\n }\n }\n\n return this.config.defaultSequence;\n }\n\n /**\n * Generate unique ID\n */\n private generateId(): string {\n return `dun_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create a dunning manager\n */\nexport function createDunningManager(\n config: DunningManagerConfig,\n storage: DunningStorage\n): DunningManager {\n return new DunningManager(config, storage);\n}\n\n/**\n * Create default dunning config\n */\nexport function createDefaultDunningConfig(\n overrides?: Partial<DunningManagerConfig>\n): DunningManagerConfig {\n return {\n defaultSequence: standardSaasSequence,\n ...overrides,\n };\n}\n","/**\n * @parsrun/payments - Dunning Scheduler\n * Automated scheduling and execution of dunning steps\n */\n\nimport type { DunningLogger } from \"./types.js\";\nimport { DunningManager } from \"./dunning-manager.js\";\n\n// ============================================================================\n// Scheduler Configuration\n// ============================================================================\n\n/**\n * Dunning scheduler configuration\n */\nexport interface DunningSchedulerConfig {\n /** Dunning manager instance */\n manager: DunningManager;\n\n /** Poll interval in milliseconds (default: 60000 = 1 minute) */\n pollInterval?: number;\n\n /** Batch size for processing (default: 50) */\n batchSize?: number;\n\n /** Maximum concurrent executions (default: 5) */\n maxConcurrent?: number;\n\n /** Timezone for scheduling (default: UTC) */\n timezone?: string;\n\n /** Logger */\n logger?: DunningLogger;\n\n /** Error handler */\n onError?: (error: Error, stateId: string) => void | Promise<void>;\n\n /** Before step execution hook */\n beforeStep?: (stateId: string, stepId: string) => void | Promise<void>;\n\n /** After step execution hook */\n afterStep?: (stateId: string, stepId: string, success: boolean) => void | Promise<void>;\n}\n\n// ============================================================================\n// Dunning Scheduler\n// ============================================================================\n\n/**\n * Dunning Scheduler\n * Handles automated execution of scheduled dunning steps\n */\nexport class DunningScheduler {\n private manager: DunningManager;\n private pollInterval: number;\n private batchSize: number;\n private maxConcurrent: number;\n private logger?: DunningLogger;\n private onError?: (error: Error, stateId: string) => void | Promise<void>;\n private beforeStep?: (stateId: string, stepId: string) => void | Promise<void>;\n private afterStep?: (stateId: string, stepId: string, success: boolean) => void | Promise<void>;\n\n private isRunning = false;\n private pollTimer?: ReturnType<typeof setTimeout>;\n private processingStates: Set<string> = new Set();\n\n /** Timezone for scheduling (reserved for future use) */\n readonly timezone: string;\n\n constructor(config: DunningSchedulerConfig) {\n this.manager = config.manager;\n this.pollInterval = config.pollInterval ?? 60000; // 1 minute\n this.batchSize = config.batchSize ?? 50;\n this.maxConcurrent = config.maxConcurrent ?? 5;\n this.timezone = config.timezone ?? \"UTC\";\n if (config.logger) {\n this.logger = config.logger;\n }\n if (config.onError) {\n this.onError = config.onError;\n }\n if (config.beforeStep) {\n this.beforeStep = config.beforeStep;\n }\n if (config.afterStep) {\n this.afterStep = config.afterStep;\n }\n }\n\n // ============================================================================\n // Lifecycle\n // ============================================================================\n\n /**\n * Start the scheduler\n */\n start(): void {\n if (this.isRunning) {\n this.logger?.warn(\"Scheduler already running\");\n return;\n }\n\n this.isRunning = true;\n this.logger?.info(\"Dunning scheduler started\", {\n pollInterval: this.pollInterval,\n batchSize: this.batchSize,\n maxConcurrent: this.maxConcurrent,\n });\n\n // Start polling\n this.poll();\n }\n\n /**\n * Stop the scheduler\n */\n stop(): void {\n this.isRunning = false;\n\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n delete this.pollTimer;\n }\n\n this.logger?.info(\"Dunning scheduler stopped\");\n }\n\n /**\n * Check if scheduler is running\n */\n get running(): boolean {\n return this.isRunning;\n }\n\n /**\n * Get current processing count\n */\n get processingCount(): number {\n return this.processingStates.size;\n }\n\n // ============================================================================\n // Processing\n // ============================================================================\n\n /**\n * Poll for scheduled steps\n */\n private async poll(): Promise<void> {\n if (!this.isRunning) return;\n\n try {\n await this.processScheduledSteps();\n } catch (error) {\n this.logger?.error(\"Poll error\", {\n error: error instanceof Error ? error.message : String(error),\n });\n }\n\n // Schedule next poll\n if (this.isRunning) {\n this.pollTimer = setTimeout(() => this.poll(), this.pollInterval);\n }\n }\n\n /**\n * Process all scheduled steps that are due\n */\n async processScheduledSteps(): Promise<number> {\n const now = new Date();\n const scheduled = await this.manager.getScheduledSteps(now);\n\n if (scheduled.length === 0) {\n return 0;\n }\n\n this.logger?.debug(\"Found scheduled steps\", {\n count: scheduled.length,\n before: now.toISOString(),\n });\n\n // Filter out already processing\n const toProcess = scheduled\n .filter((s) => !this.processingStates.has(s.stateId))\n .slice(0, this.batchSize);\n\n if (toProcess.length === 0) {\n return 0;\n }\n\n // Process in batches respecting maxConcurrent\n let processed = 0;\n const batches = this.chunk(toProcess, this.maxConcurrent);\n\n for (const batch of batches) {\n const results = await Promise.allSettled(\n batch.map((item) => this.executeScheduledStep(item.stateId, item.stepId))\n );\n\n processed += results.filter((r) => r.status === \"fulfilled\").length;\n }\n\n return processed;\n }\n\n /**\n * Execute a single scheduled step\n */\n private async executeScheduledStep(stateId: string, stepId: string): Promise<void> {\n // Mark as processing\n this.processingStates.add(stateId);\n\n try {\n // Before hook\n if (this.beforeStep) {\n await this.beforeStep(stateId, stepId);\n }\n\n this.logger?.debug(\"Executing scheduled step\", { stateId, stepId });\n\n // Execute step\n const result = await this.manager.executeStep(stateId);\n const success = result !== null;\n\n this.logger?.info(\"Scheduled step executed\", {\n stateId,\n stepId,\n success,\n actionsTaken: result?.actionsTaken,\n });\n\n // After hook\n if (this.afterStep) {\n await this.afterStep(stateId, stepId, success);\n }\n } catch (error) {\n this.logger?.error(\"Step execution failed\", {\n stateId,\n stepId,\n error: error instanceof Error ? error.message : String(error),\n });\n\n if (this.onError) {\n await this.onError(error instanceof Error ? error : new Error(String(error)), stateId);\n }\n } finally {\n // Remove from processing\n this.processingStates.delete(stateId);\n }\n }\n\n /**\n * Manually trigger processing (for testing or cron jobs)\n */\n async trigger(): Promise<number> {\n return this.processScheduledSteps();\n }\n\n /**\n * Process a specific dunning state immediately\n */\n async processNow(stateId: string): Promise<boolean> {\n const state = await this.manager.getDunningState(stateId);\n if (!state) {\n this.logger?.warn(\"State not found for immediate processing\", { stateId });\n return false;\n }\n\n try {\n await this.executeScheduledStep(state.id, state.currentStepId);\n return true;\n } catch (error) {\n this.logger?.error(\"Immediate processing failed\", {\n stateId,\n error: error instanceof Error ? error.message : String(error),\n });\n return false;\n }\n }\n\n // ============================================================================\n // Utilities\n // ============================================================================\n\n /**\n * Split array into chunks\n */\n private chunk<T>(array: T[], size: number): T[][] {\n const chunks: T[][] = [];\n for (let i = 0; i < array.length; i += size) {\n chunks.push(array.slice(i, i + size));\n }\n return chunks;\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create a dunning scheduler\n */\nexport function createDunningScheduler(config: DunningSchedulerConfig): DunningScheduler {\n return new DunningScheduler(config);\n}\n\n// ============================================================================\n// Cron Integration\n// ============================================================================\n\n/**\n * Create a cron-compatible handler for dunning processing\n *\n * @example\n * ```typescript\n * // In a cron job or serverless function\n * export async function handler() {\n * const processor = createDunningCronHandler(manager);\n * const result = await processor();\n * console.log(`Processed ${result.processed} dunning steps`);\n * }\n * ```\n */\nexport function createDunningCronHandler(\n manager: DunningManager,\n options?: {\n batchSize?: number;\n maxConcurrent?: number;\n logger?: DunningLogger;\n }\n): () => Promise<{ processed: number; errors: number }> {\n return async () => {\n const config: DunningSchedulerConfig = {\n manager,\n batchSize: options?.batchSize ?? 100,\n maxConcurrent: options?.maxConcurrent ?? 10,\n };\n if (options?.logger) {\n config.logger = options.logger;\n }\n\n const scheduler = new DunningScheduler(config);\n\n let errors = 0;\n const originalOnError = scheduler[\"onError\"];\n scheduler[\"onError\"] = async (error, stateId) => {\n errors++;\n if (originalOnError) await originalOnError(error, stateId);\n };\n\n const processed = await scheduler.trigger();\n\n return { processed, errors };\n };\n}\n\n// ============================================================================\n// Edge/Serverless Handler\n// ============================================================================\n\n/**\n * Create a handler for edge/serverless environments\n * Processes dunning in a single invocation\n *\n * @example\n * ```typescript\n * // In a Cloudflare Worker or similar\n * export default {\n * async scheduled(event, env, ctx) {\n * const handler = createDunningEdgeHandler(manager, { maxDurationMs: 25000 });\n * const result = await handler();\n * console.log(result);\n * }\n * }\n * ```\n */\nexport function createDunningEdgeHandler(\n manager: DunningManager,\n options?: {\n maxDurationMs?: number;\n batchSize?: number;\n logger?: DunningLogger;\n }\n): () => Promise<{\n processed: number;\n errors: number;\n duration: number;\n timedOut: boolean;\n}> {\n const maxDuration = options?.maxDurationMs ?? 30000; // 30 seconds default\n const batchSize = options?.batchSize ?? 25;\n\n return async () => {\n const startTime = Date.now();\n let processed = 0;\n let errors = 0;\n let timedOut = false;\n\n const now = new Date();\n const scheduled = await manager.getScheduledSteps(now);\n\n for (let i = 0; i < scheduled.length; i += batchSize) {\n // Check timeout\n if (Date.now() - startTime > maxDuration) {\n timedOut = true;\n options?.logger?.warn(\"Edge handler timed out\", {\n processed,\n remaining: scheduled.length - i,\n });\n break;\n }\n\n const batch = scheduled.slice(i, i + batchSize);\n\n const results = await Promise.allSettled(\n batch.map(async (item) => {\n try {\n await manager.executeStep(item.stateId);\n return true;\n } catch (error) {\n options?.logger?.error(\"Step execution error\", {\n stateId: item.stateId,\n error: error instanceof Error ? error.message : String(error),\n });\n throw error;\n }\n })\n );\n\n for (const result of results) {\n if (result.status === \"fulfilled\") {\n processed++;\n } else {\n errors++;\n }\n }\n }\n\n const duration = Date.now() - startTime;\n\n return { processed, errors, duration, timedOut };\n };\n}\n","/**\n * @parsrun/payments - Dunning Memory Storage\n * In-memory storage implementation for development and testing\n */\n\nimport type {\n DunningStorage,\n DunningState,\n DunningStatus,\n PaymentFailure,\n} from \"./types.js\";\n\n// ============================================================================\n// Memory Storage Implementation\n// ============================================================================\n\n/**\n * In-memory dunning storage implementation\n * Use only for development/testing - data is lost on restart\n */\nexport class MemoryDunningStorage implements DunningStorage {\n private states: Map<string, DunningState> = new Map();\n private failures: Map<string, PaymentFailure[]> = new Map();\n private scheduledSteps: Array<{\n stateId: string;\n stepId: string;\n scheduledAt: Date;\n }> = [];\n\n // ============================================================================\n // Dunning State Methods\n // ============================================================================\n\n async getDunningState(customerId: string): Promise<DunningState | null> {\n for (const state of this.states.values()) {\n if (state.customerId === customerId) {\n return state;\n }\n }\n return null;\n }\n\n async getActiveDunningStates(): Promise<DunningState[]> {\n return Array.from(this.states.values()).filter((s) => s.status === \"active\");\n }\n\n async getDunningStatesByStatus(status: DunningStatus): Promise<DunningState[]> {\n return Array.from(this.states.values()).filter((s) => s.status === status);\n }\n\n async saveDunningState(state: DunningState): Promise<void> {\n this.states.set(state.id, { ...state });\n }\n\n async updateDunningState(id: string, updates: Partial<DunningState>): Promise<void> {\n const state = this.states.get(id);\n if (state) {\n this.states.set(id, { ...state, ...updates });\n }\n }\n\n // ============================================================================\n // Payment Failure Methods\n // ============================================================================\n\n async recordPaymentFailure(failure: PaymentFailure): Promise<void> {\n const customerFailures = this.failures.get(failure.customerId) ?? [];\n customerFailures.push({ ...failure });\n this.failures.set(failure.customerId, customerFailures);\n }\n\n async getPaymentFailures(customerId: string, limit = 50): Promise<PaymentFailure[]> {\n const customerFailures = this.failures.get(customerId) ?? [];\n return customerFailures\n .sort((a, b) => b.failedAt.getTime() - a.failedAt.getTime())\n .slice(0, limit);\n }\n\n // ============================================================================\n // Scheduled Steps Methods\n // ============================================================================\n\n async getScheduledSteps(\n before: Date\n ): Promise<Array<{ stateId: string; stepId: string; scheduledAt: Date }>> {\n return this.scheduledSteps.filter((s) => s.scheduledAt <= before);\n }\n\n async scheduleStep(stateId: string, stepId: string, scheduledAt: Date): Promise<void> {\n // Remove existing schedule for this step\n await this.removeScheduledStep(stateId, stepId);\n\n this.scheduledSteps.push({ stateId, stepId, scheduledAt });\n }\n\n async removeScheduledStep(stateId: string, stepId: string): Promise<void> {\n this.scheduledSteps = this.scheduledSteps.filter(\n (s) => !(s.stateId === stateId && s.stepId === stepId)\n );\n }\n\n // ============================================================================\n // Utility Methods\n // ============================================================================\n\n /**\n * Clear all data (for testing)\n */\n clear(): void {\n this.states.clear();\n this.failures.clear();\n this.scheduledSteps = [];\n }\n\n /**\n * Get state by ID\n */\n getStateById(id: string): DunningState | undefined {\n return this.states.get(id);\n }\n\n /**\n * Get all states (for debugging)\n */\n getAllStates(): DunningState[] {\n return Array.from(this.states.values());\n }\n\n /**\n * Get all scheduled steps (for debugging)\n */\n getAllScheduledSteps(): Array<{ stateId: string; stepId: string; scheduledAt: Date }> {\n return [...this.scheduledSteps];\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create an in-memory dunning storage instance\n */\nexport function createMemoryDunningStorage(): MemoryDunningStorage {\n return new MemoryDunningStorage();\n}\n","/**\n * @parsrun/payments - Dunning Drizzle Storage\n * Persistent storage implementation using Drizzle ORM\n */\n\nimport { eq, and, lt, desc } from \"drizzle-orm\";\nimport type {\n DunningStorage,\n DunningState,\n DunningStatus,\n PaymentFailure,\n PaymentFailureCategory,\n ExecutedStep,\n DunningAction,\n NotificationChannel,\n} from \"./types.js\";\nimport {\n dunningStates,\n paymentFailures,\n scheduledSteps,\n executedSteps as executedStepsTable,\n type DunningStateRow,\n type PaymentFailureRow,\n} from \"./schema.js\";\n\n// ============================================================================\n// Types\n// ============================================================================\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype QueryBuilder = Promise<unknown[]> & {\n where: (condition: unknown) => QueryBuilder;\n orderBy: (...order: unknown[]) => QueryBuilder;\n limit: (n: number) => QueryBuilder;\n};\n\n/**\n * Drizzle database type (compatible with various drivers)\n */\nexport type DrizzleDb = {\n select: () => {\n from: (table: unknown) => QueryBuilder;\n };\n insert: (table: unknown) => {\n values: (values: unknown) => {\n onConflictDoUpdate: (config: unknown) => Promise<unknown>;\n returning: () => Promise<unknown[]>;\n } & Promise<unknown>;\n };\n update: (table: unknown) => {\n set: (values: unknown) => {\n where: (condition: unknown) => Promise<unknown>;\n };\n };\n delete: (table: unknown) => {\n where: (condition: unknown) => Promise<unknown>;\n };\n};\n\n/**\n * Configuration for Drizzle dunning storage\n */\nexport interface DrizzleDunningStorageConfig {\n /** Drizzle database instance */\n db: DrizzleDb;\n}\n\n// ============================================================================\n// Storage Implementation\n// ============================================================================\n\n/**\n * Drizzle-based dunning storage implementation\n */\nexport class DrizzleDunningStorage implements DunningStorage {\n private db: DrizzleDb;\n\n constructor(config: DrizzleDunningStorageConfig) {\n this.db = config.db;\n }\n\n // ============================================================================\n // Dunning State Methods\n // ============================================================================\n\n async getDunningState(customerId: string): Promise<DunningState | null> {\n const rows = (await this.db\n .select()\n .from(dunningStates)\n .where(eq(dunningStates.customerId, customerId))) as DunningStateRow[];\n\n const row = rows[0];\n if (!row) return null;\n\n return this.mapRowToState(row);\n }\n\n async getActiveDunningStates(): Promise<DunningState[]> {\n const rows = (await this.db\n .select()\n .from(dunningStates)\n .where(eq(dunningStates.status, \"active\"))) as DunningStateRow[];\n\n return Promise.all(rows.map((row) => this.mapRowToState(row)));\n }\n\n async getDunningStatesByStatus(status: DunningStatus): Promise<DunningState[]> {\n const rows = (await this.db\n .select()\n .from(dunningStates)\n .where(eq(dunningStates.status, status))) as DunningStateRow[];\n\n return Promise.all(rows.map((row) => this.mapRowToState(row)));\n }\n\n async saveDunningState(state: DunningState): Promise<void> {\n await this.db.insert(dunningStates).values({\n id: state.id,\n customerId: state.customerId,\n subscriptionId: state.subscriptionId,\n sequenceId: state.sequenceId,\n currentStepIndex: state.currentStepIndex,\n currentStepId: state.currentStepId,\n status: state.status,\n initialFailureId: state.initialFailure.id,\n failureIds: state.failures.map((f) => f.id),\n startedAt: state.startedAt,\n lastStepAt: state.lastStepAt,\n nextStepAt: state.nextStepAt,\n endedAt: state.endedAt,\n endReason: state.endReason,\n totalRetryAttempts: state.totalRetryAttempts,\n metadata: state.metadata,\n });\n\n // Save executed steps\n for (const step of state.executedSteps) {\n await this.saveExecutedStep(state.id, step);\n }\n }\n\n async updateDunningState(id: string, updates: Partial<DunningState>): Promise<void> {\n const setValues: Record<string, unknown> = {};\n\n if (updates[\"currentStepIndex\"] !== undefined)\n setValues[\"currentStepIndex\"] = updates[\"currentStepIndex\"];\n if (updates[\"currentStepId\"] !== undefined)\n setValues[\"currentStepId\"] = updates[\"currentStepId\"];\n if (updates[\"status\"] !== undefined) setValues[\"status\"] = updates[\"status\"];\n if (updates[\"lastStepAt\"] !== undefined) setValues[\"lastStepAt\"] = updates[\"lastStepAt\"];\n if (updates[\"nextStepAt\"] !== undefined) setValues[\"nextStepAt\"] = updates[\"nextStepAt\"];\n if (updates[\"endedAt\"] !== undefined) setValues[\"endedAt\"] = updates[\"endedAt\"];\n if (updates[\"endReason\"] !== undefined) setValues[\"endReason\"] = updates[\"endReason\"];\n if (updates[\"totalRetryAttempts\"] !== undefined)\n setValues[\"totalRetryAttempts\"] = updates[\"totalRetryAttempts\"];\n if (updates[\"metadata\"] !== undefined) setValues[\"metadata\"] = updates[\"metadata\"];\n if (updates[\"failures\"] !== undefined)\n setValues[\"failureIds\"] = updates[\"failures\"].map((f) => f.id);\n\n if (Object.keys(setValues).length > 0) {\n await this.db.update(dunningStates).set(setValues).where(eq(dunningStates.id, id));\n }\n }\n\n // ============================================================================\n // Payment Failure Methods\n // ============================================================================\n\n async recordPaymentFailure(failure: PaymentFailure): Promise<void> {\n await this.db.insert(paymentFailures).values({\n id: failure.id,\n customerId: failure.customerId,\n subscriptionId: failure.subscriptionId,\n invoiceId: failure.invoiceId,\n amount: failure.amount,\n currency: failure.currency,\n category: failure.category,\n errorCode: failure.errorCode,\n errorMessage: failure.errorMessage,\n provider: failure.provider,\n failedAt: failure.failedAt,\n retryCount: failure.retryCount,\n nextRetryAt: failure.nextRetryAt,\n isRecoverable: failure.isRecoverable,\n metadata: failure.metadata,\n });\n }\n\n async getPaymentFailures(customerId: string, limit = 50): Promise<PaymentFailure[]> {\n const rows = (await this.db\n .select()\n .from(paymentFailures)\n .where(eq(paymentFailures.customerId, customerId))\n .orderBy(desc(paymentFailures.failedAt))\n .limit(limit)) as PaymentFailureRow[];\n\n return rows.map((row) => this.mapRowToFailure(row));\n }\n\n // ============================================================================\n // Scheduled Steps Methods\n // ============================================================================\n\n async getScheduledSteps(\n before: Date\n ): Promise<Array<{ stateId: string; stepId: string; scheduledAt: Date }>> {\n const rows = (await this.db\n .select()\n .from(scheduledSteps)\n .where(lt(scheduledSteps.scheduledAt, before))) as Array<{\n dunningStateId: string;\n stepId: string;\n scheduledAt: Date;\n }>;\n\n return rows.map((row) => ({\n stateId: row.dunningStateId,\n stepId: row.stepId,\n scheduledAt: row.scheduledAt,\n }));\n }\n\n async scheduleStep(stateId: string, stepId: string, scheduledAt: Date): Promise<void> {\n const id = `sched_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\n\n await this.db.insert(scheduledSteps).values({\n id,\n dunningStateId: stateId,\n stepId,\n scheduledAt,\n });\n }\n\n async removeScheduledStep(stateId: string, stepId: string): Promise<void> {\n await this.db\n .delete(scheduledSteps)\n .where(\n and(eq(scheduledSteps.dunningStateId, stateId), eq(scheduledSteps.stepId, stepId))\n );\n }\n\n // ============================================================================\n // Helper Methods\n // ============================================================================\n\n private async saveExecutedStep(stateId: string, step: ExecutedStep): Promise<void> {\n const id = `exec_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\n\n await this.db.insert(executedStepsTable).values({\n id,\n dunningStateId: stateId,\n stepId: step.stepId,\n stepName: step.stepName,\n executedAt: step.executedAt,\n actionsTaken: step.actionsTaken,\n paymentRetried: step.paymentRetried,\n paymentSucceeded: step.paymentSucceeded,\n notificationsSent: step.notificationsSent,\n error: step.error,\n });\n }\n\n private async mapRowToState(row: DunningStateRow): Promise<DunningState> {\n // Get initial failure\n const failureRows = (await this.db\n .select()\n .from(paymentFailures)\n .where(eq(paymentFailures.id, row.initialFailureId))) as PaymentFailureRow[];\n\n const initialFailureRow = failureRows[0];\n if (!initialFailureRow) {\n throw new Error(`Initial failure not found: ${row.initialFailureId}`);\n }\n\n const initialFailure = this.mapRowToFailure(initialFailureRow);\n\n // Get all failures\n const failures: PaymentFailure[] = [initialFailure];\n const failureIds = (row.failureIds as string[]) || [];\n for (const failureId of failureIds) {\n if (failureId !== row.initialFailureId) {\n const additionalRows = (await this.db\n .select()\n .from(paymentFailures)\n .where(eq(paymentFailures.id, failureId))) as PaymentFailureRow[];\n\n const additionalRow = additionalRows[0];\n if (additionalRow) {\n failures.push(this.mapRowToFailure(additionalRow));\n }\n }\n }\n\n // Get executed steps\n const execStepRows = (await this.db\n .select()\n .from(executedStepsTable)\n .where(eq(executedStepsTable.dunningStateId, row.id))\n .orderBy(executedStepsTable.executedAt)) as Array<{\n stepId: string;\n stepName: string;\n executedAt: Date;\n actionsTaken: string[] | null;\n paymentRetried: boolean;\n paymentSucceeded: boolean | null;\n notificationsSent: string[] | null;\n error: string | null;\n }>;\n\n const executedStepsList: ExecutedStep[] = execStepRows.map((es) => {\n const step: ExecutedStep = {\n stepId: es.stepId,\n stepName: es.stepName,\n executedAt: es.executedAt,\n actionsTaken: (es.actionsTaken || []) as DunningAction[],\n paymentRetried: es.paymentRetried,\n notificationsSent: (es.notificationsSent || []) as NotificationChannel[],\n };\n if (es.paymentSucceeded !== null) step.paymentSucceeded = es.paymentSucceeded;\n if (es.error !== null) step.error = es.error;\n return step;\n });\n\n const result: DunningState = {\n id: row.id,\n customerId: row.customerId,\n subscriptionId: row.subscriptionId,\n sequenceId: row.sequenceId,\n currentStepIndex: row.currentStepIndex,\n currentStepId: row.currentStepId,\n status: row.status as DunningStatus,\n initialFailure,\n failures,\n executedSteps: executedStepsList,\n startedAt: row.startedAt,\n totalRetryAttempts: row.totalRetryAttempts,\n };\n if (row.lastStepAt) result.lastStepAt = row.lastStepAt;\n if (row.nextStepAt) result.nextStepAt = row.nextStepAt;\n if (row.endedAt) result.endedAt = row.endedAt;\n const endReason = row.endReason;\n if (\n endReason === \"payment_recovered\" ||\n endReason === \"max_retries\" ||\n endReason === \"manually_canceled\" ||\n endReason === \"subscription_canceled\"\n ) {\n result.endReason = endReason;\n }\n if (row.metadata) result.metadata = row.metadata as Record<string, unknown>;\n\n return result;\n }\n\n private mapRowToFailure(row: PaymentFailureRow): PaymentFailure {\n const result: PaymentFailure = {\n id: row.id,\n customerId: row.customerId,\n subscriptionId: row.subscriptionId,\n amount: row.amount,\n currency: row.currency,\n category: row.category as PaymentFailureCategory,\n errorCode: row.errorCode,\n errorMessage: row.errorMessage,\n provider: row.provider as PaymentFailure[\"provider\"],\n failedAt: row.failedAt,\n retryCount: row.retryCount,\n isRecoverable: row.isRecoverable,\n };\n if (row.invoiceId) result.invoiceId = row.invoiceId;\n if (row.nextRetryAt) result.nextRetryAt = row.nextRetryAt;\n if (row.metadata) result.metadata = row.metadata as Record<string, unknown>;\n\n return result;\n }\n}\n\n// ============================================================================\n// Factory\n// ============================================================================\n\n/**\n * Create a Drizzle dunning storage instance\n */\nexport function createDrizzleDunningStorage(\n config: DrizzleDunningStorageConfig\n): DrizzleDunningStorage {\n return new DrizzleDunningStorage(config);\n}\n","/**\n * @parsrun/payments - Dunning Database Schema\n * Drizzle ORM schema for dunning automation tables\n *\n * These tables store:\n * - Dunning sequences and steps\n * - Dunning states for active processes\n * - Payment failures\n * - Executed steps history\n * - Scheduled steps for automation\n */\n\nimport {\n pgTable,\n text,\n integer,\n boolean,\n timestamp,\n jsonb,\n uniqueIndex,\n index,\n} from \"drizzle-orm/pg-core\";\n\n// ============================================================================\n// Dunning Sequences\n// ============================================================================\n\n/**\n * Dunning sequences table - defines dunning workflows\n */\nexport const dunningSequences = pgTable(\"dunning_sequences\", {\n id: text(\"id\").primaryKey(),\n name: text(\"name\").notNull().unique(),\n description: text(\"description\"),\n maxDurationDays: integer(\"max_duration_days\").notNull().default(28),\n isActive: boolean(\"is_active\").notNull().default(true),\n isDefault: boolean(\"is_default\").notNull().default(false),\n planTier: integer(\"plan_tier\"), // null = default for all, otherwise specific tier\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n});\n\n/**\n * Dunning steps table - defines steps within sequences\n */\nexport const dunningSteps = pgTable(\n \"dunning_steps\",\n {\n id: text(\"id\").primaryKey(),\n sequenceId: text(\"sequence_id\")\n .notNull()\n .references(() => dunningSequences.id, { onDelete: \"cascade\" }),\n name: text(\"name\").notNull(),\n stepOrder: integer(\"step_order\").notNull(), // Order within sequence\n daysAfterFailure: integer(\"days_after_failure\").notNull().default(0),\n hoursOffset: integer(\"hours_offset\"), // Hour of day to execute (0-23)\n actions: jsonb(\"actions\").$type<string[]>().notNull().default([]), // Array of action types\n notificationChannels: jsonb(\"notification_channels\").$type<string[]>(), // email, sms, in_app, webhook, push\n notificationTemplateId: text(\"notification_template_id\"),\n accessLevel: text(\"access_level\"), // full, limited, read_only, none\n isFinal: boolean(\"is_final\").notNull().default(false),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n },\n (table) => ({\n sequenceOrderIdx: uniqueIndex(\"dunning_steps_sequence_order_idx\").on(\n table.sequenceId,\n table.stepOrder\n ),\n sequenceIdx: index(\"dunning_steps_sequence_idx\").on(table.sequenceId),\n })\n);\n\n// ============================================================================\n// Payment Failures\n// ============================================================================\n\n/**\n * Payment failures table - records all payment failures\n */\nexport const paymentFailures = pgTable(\n \"dunning_payment_failures\",\n {\n id: text(\"id\").primaryKey(),\n customerId: text(\"customer_id\").notNull(),\n subscriptionId: text(\"subscription_id\").notNull(),\n invoiceId: text(\"invoice_id\"),\n amount: integer(\"amount\").notNull(), // cents\n currency: text(\"currency\").notNull().default(\"usd\"),\n category: text(\"category\").notNull(), // card_declined, insufficient_funds, etc.\n errorCode: text(\"error_code\").notNull(),\n errorMessage: text(\"error_message\").notNull(),\n provider: text(\"provider\").notNull(), // stripe, paddle, iyzico\n failedAt: timestamp(\"failed_at\").notNull(),\n retryCount: integer(\"retry_count\").notNull().default(0),\n nextRetryAt: timestamp(\"next_retry_at\"),\n isRecoverable: boolean(\"is_recoverable\").notNull().default(true),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n },\n (table) => ({\n customerIdx: index(\"dunning_payment_failures_customer_idx\").on(table.customerId),\n subscriptionIdx: index(\"dunning_payment_failures_subscription_idx\").on(\n table.subscriptionId\n ),\n failedAtIdx: index(\"dunning_payment_failures_failed_at_idx\").on(table.failedAt),\n categoryIdx: index(\"dunning_payment_failures_category_idx\").on(table.category),\n })\n);\n\n// ============================================================================\n// Dunning States\n// ============================================================================\n\n/**\n * Dunning states table - tracks active dunning processes\n */\nexport const dunningStates = pgTable(\n \"dunning_states\",\n {\n id: text(\"id\").primaryKey(),\n customerId: text(\"customer_id\").notNull(),\n subscriptionId: text(\"subscription_id\").notNull(),\n sequenceId: text(\"sequence_id\")\n .notNull()\n .references(() => dunningSequences.id),\n currentStepIndex: integer(\"current_step_index\").notNull().default(0),\n currentStepId: text(\"current_step_id\").notNull(),\n status: text(\"status\").notNull().default(\"active\"), // active, recovered, exhausted, canceled, paused\n initialFailureId: text(\"initial_failure_id\")\n .notNull()\n .references(() => paymentFailures.id),\n failureIds: jsonb(\"failure_ids\").$type<string[]>().notNull().default([]), // All failure IDs\n startedAt: timestamp(\"started_at\").notNull(),\n lastStepAt: timestamp(\"last_step_at\"),\n nextStepAt: timestamp(\"next_step_at\"),\n endedAt: timestamp(\"ended_at\"),\n endReason: text(\"end_reason\"), // payment_recovered, max_retries, manually_canceled, subscription_canceled\n totalRetryAttempts: integer(\"total_retry_attempts\").notNull().default(0),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n },\n (table) => ({\n customerIdx: uniqueIndex(\"dunning_states_customer_idx\").on(table.customerId),\n statusIdx: index(\"dunning_states_status_idx\").on(table.status),\n nextStepIdx: index(\"dunning_states_next_step_idx\").on(table.nextStepAt),\n subscriptionIdx: index(\"dunning_states_subscription_idx\").on(table.subscriptionId),\n })\n);\n\n// ============================================================================\n// Executed Steps\n// ============================================================================\n\n/**\n * Executed steps table - history of executed dunning steps\n */\nexport const executedSteps = pgTable(\n \"dunning_executed_steps\",\n {\n id: text(\"id\").primaryKey(),\n dunningStateId: text(\"dunning_state_id\")\n .notNull()\n .references(() => dunningStates.id, { onDelete: \"cascade\" }),\n stepId: text(\"step_id\").notNull(),\n stepName: text(\"step_name\").notNull(),\n executedAt: timestamp(\"executed_at\").notNull(),\n actionsTaken: jsonb(\"actions_taken\").$type<string[]>().notNull().default([]),\n paymentRetried: boolean(\"payment_retried\").notNull().default(false),\n paymentSucceeded: boolean(\"payment_succeeded\"),\n notificationsSent: jsonb(\"notifications_sent\").$type<string[]>().notNull().default([]),\n error: text(\"error\"),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n },\n (table) => ({\n stateIdx: index(\"dunning_executed_steps_state_idx\").on(table.dunningStateId),\n executedAtIdx: index(\"dunning_executed_steps_executed_at_idx\").on(table.executedAt),\n })\n);\n\n// ============================================================================\n// Scheduled Steps\n// ============================================================================\n\n/**\n * Scheduled steps table - steps pending execution\n */\nexport const scheduledSteps = pgTable(\n \"dunning_scheduled_steps\",\n {\n id: text(\"id\").primaryKey(),\n dunningStateId: text(\"dunning_state_id\")\n .notNull()\n .references(() => dunningStates.id, { onDelete: \"cascade\" }),\n stepId: text(\"step_id\").notNull(),\n scheduledAt: timestamp(\"scheduled_at\").notNull(),\n createdAt: timestamp(\"created_at\").defaultNow().notNull(),\n },\n (table) => ({\n stateStepIdx: uniqueIndex(\"dunning_scheduled_steps_state_step_idx\").on(\n table.dunningStateId,\n table.stepId\n ),\n scheduledAtIdx: index(\"dunning_scheduled_steps_scheduled_at_idx\").on(\n table.scheduledAt\n ),\n })\n);\n\n// ============================================================================\n// Dunning Events Log\n// ============================================================================\n\n/**\n * Dunning events table - audit log for all dunning events\n */\nexport const dunningEvents = pgTable(\n \"dunning_events\",\n {\n id: text(\"id\").primaryKey(),\n type: text(\"type\").notNull(), // dunning.started, dunning.step_executed, etc.\n customerId: text(\"customer_id\").notNull(),\n subscriptionId: text(\"subscription_id\").notNull(),\n dunningStateId: text(\"dunning_state_id\")\n .notNull()\n .references(() => dunningStates.id, { onDelete: \"cascade\" }),\n timestamp: timestamp(\"timestamp\").notNull(),\n data: jsonb(\"data\").$type<Record<string, unknown>>().notNull().default({}),\n },\n (table) => ({\n typeIdx: index(\"dunning_events_type_idx\").on(table.type),\n customerIdx: index(\"dunning_events_customer_idx\").on(table.customerId),\n timestampIdx: index(\"dunning_events_timestamp_idx\").on(table.timestamp),\n stateIdx: index(\"dunning_events_state_idx\").on(table.dunningStateId),\n })\n);\n\n// ============================================================================\n// Retry Strategies (Optional - for custom strategies)\n// ============================================================================\n\n/**\n * Custom retry strategies table - overrides for default strategies\n */\nexport const retryStrategies = pgTable(\n \"dunning_retry_strategies\",\n {\n id: text(\"id\").primaryKey(),\n category: text(\"category\").notNull().unique(), // failure category\n shouldRetry: boolean(\"should_retry\").notNull().default(true),\n initialDelayHours: integer(\"initial_delay_hours\").notNull().default(24),\n maxRetries: integer(\"max_retries\").notNull().default(4),\n backoffMultiplier: integer(\"backoff_multiplier\").notNull().default(2), // stored as x100 for decimals\n maxDelayHours: integer(\"max_delay_hours\").notNull().default(168),\n optimalRetryHours: jsonb(\"optimal_retry_hours\").$type<number[]>(),\n optimalRetryDays: jsonb(\"optimal_retry_days\").$type<number[]>(),\n metadata: jsonb(\"metadata\").$type<Record<string, unknown>>(),\n updatedAt: timestamp(\"updated_at\").defaultNow().notNull(),\n },\n (table) => ({\n categoryIdx: uniqueIndex(\"dunning_retry_strategies_category_idx\").on(table.category),\n })\n);\n\n// ============================================================================\n// Type Exports\n// ============================================================================\n\nexport type DunningSequenceRow = typeof dunningSequences.$inferSelect;\nexport type NewDunningSequence = typeof dunningSequences.$inferInsert;\n\nexport type DunningStepRow = typeof dunningSteps.$inferSelect;\nexport type NewDunningStep = typeof dunningSteps.$inferInsert;\n\nexport type PaymentFailureRow = typeof paymentFailures.$inferSelect;\nexport type NewPaymentFailure = typeof paymentFailures.$inferInsert;\n\nexport type DunningStateRow = typeof dunningStates.$inferSelect;\nexport type NewDunningState = typeof dunningStates.$inferInsert;\n\nexport type ExecutedStepRow = typeof executedSteps.$inferSelect;\nexport type NewExecutedStep = typeof executedSteps.$inferInsert;\n\nexport type ScheduledStepRow = typeof scheduledSteps.$inferSelect;\nexport type NewScheduledStep = typeof scheduledSteps.$inferInsert;\n\nexport type DunningEventRow = typeof dunningEvents.$inferSelect;\nexport type NewDunningEvent = typeof dunningEvents.$inferInsert;\n\nexport type RetryStrategyRow = typeof retryStrategies.$inferSelect;\nexport type NewRetryStrategy = typeof retryStrategies.$inferInsert;\n\n// ============================================================================\n// Schema Export\n// ============================================================================\n\n/**\n * All dunning schema tables\n */\nexport const dunningSchema = {\n dunningSequences,\n dunningSteps,\n paymentFailures,\n dunningStates,\n executedSteps,\n scheduledSteps,\n dunningEvents,\n retryStrategies,\n};\n","/**\n * @parsrun/payments\n * Edge-compatible payment processing for Pars\n *\n * Supports multiple providers:\n * - Stripe\n * - Paddle\n *\n * @example\n * ```typescript\n * import { createPaymentService, createStripeProvider } from '@parsrun/payments';\n *\n * const payments = createPaymentService({\n * provider: createStripeProvider({\n * secretKey: process.env.STRIPE_SECRET_KEY,\n * webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,\n * }),\n * });\n *\n * // Create checkout session\n * const checkout = await payments.createCheckout({\n * lineItems: [{ priceId: 'price_xxx', quantity: 1 }],\n * successUrl: 'https://example.com/success',\n * cancelUrl: 'https://example.com/cancel',\n * mode: 'subscription',\n * });\n *\n * // Handle webhooks\n * app.post('/webhooks/stripe', async (c) => {\n * const result = await payments.handleWebhook(c.req.raw);\n * return c.json({ received: result.success });\n * });\n * ```\n */\n\n// Re-export types\nexport * from \"./types.js\";\n\n// Re-export providers\nexport { StripeProvider, createStripeProvider } from \"./providers/stripe.js\";\nexport { PaddleProvider, createPaddleProvider } from \"./providers/paddle.js\";\nexport { IyzicoProvider, createIyzicoProvider } from \"./providers/iyzico.js\";\nexport type {\n IyzicoProviderConfig,\n IyzicoBasketItem,\n IyzicoBuyer,\n IyzicoAddress,\n IyzicoCheckoutOptions,\n IyzicoCheckoutResult,\n IyzicoPaymentResult,\n IyzicoThreeDSInitResult,\n IyzicoRefundResult,\n IyzicoCancelResult,\n IyzicoInstallmentResult,\n} from \"./providers/iyzico.js\";\n\n// Re-export webhooks\nexport {\n WebhookHandlerRegistry,\n WebhookProcessor,\n createWebhookProcessor,\n createWebhookHandlerRegistry,\n createWebhookHandler,\n} from \"./webhooks/index.js\";\nexport type { WebhookProcessResult } from \"./webhooks/index.js\";\n\nimport type {\n CheckoutSession,\n CreateCheckoutOptions,\n CreateCustomerOptions,\n CreatePortalOptions,\n CreateSubscriptionOptions,\n Customer,\n PaymentProvider,\n PaymentServiceConfig,\n PortalSession,\n Price,\n Product,\n Subscription,\n UpdateSubscriptionOptions,\n WebhookEvent,\n WebhookEventType,\n WebhookHandler,\n} from \"./types.js\";\nimport {\n WebhookHandlerRegistry,\n WebhookProcessor,\n} from \"./webhooks/index.js\";\nimport type { WebhookProcessResult } from \"./webhooks/index.js\";\n\n/**\n * Payment Service\n * High-level payment service with provider abstraction\n */\nexport class PaymentService {\n private provider: PaymentProvider;\n private webhookProcessor: WebhookProcessor;\n private debug: boolean;\n\n constructor(config: PaymentServiceConfig) {\n this.provider = config.provider;\n this.debug = config.debug ?? false;\n this.webhookProcessor = new WebhookProcessor(\n this.provider,\n new WebhookHandlerRegistry()\n );\n }\n\n /**\n * Get provider type\n */\n get providerType(): string {\n return this.provider.type;\n }\n\n /**\n * Get webhook handler registry\n */\n get webhooks(): WebhookHandlerRegistry {\n return this.webhookProcessor.handlers;\n }\n\n // ============================================================================\n // Customer\n // ============================================================================\n\n /**\n * Create a customer\n */\n async createCustomer(options: CreateCustomerOptions): Promise<Customer> {\n if (this.debug) {\n console.log(\"[Payments] Creating customer:\", options.email);\n }\n\n return this.provider.createCustomer(options);\n }\n\n /**\n * Get a customer by ID\n */\n async getCustomer(customerId: string): Promise<Customer | null> {\n return this.provider.getCustomer(customerId);\n }\n\n /**\n * Update a customer\n */\n async updateCustomer(\n customerId: string,\n options: Partial<CreateCustomerOptions>\n ): Promise<Customer> {\n return this.provider.updateCustomer(customerId, options);\n }\n\n /**\n * Delete a customer\n */\n async deleteCustomer(customerId: string): Promise<void> {\n return this.provider.deleteCustomer(customerId);\n }\n\n // ============================================================================\n // Checkout\n // ============================================================================\n\n /**\n * Create a checkout session\n */\n async createCheckout(options: CreateCheckoutOptions): Promise<CheckoutSession> {\n if (this.debug) {\n console.log(\"[Payments] Creating checkout:\", {\n mode: options.mode,\n items: options.lineItems.length,\n });\n }\n\n return this.provider.createCheckout(options);\n }\n\n /**\n * Get a checkout session\n */\n async getCheckout(sessionId: string): Promise<CheckoutSession | null> {\n return this.provider.getCheckout(sessionId);\n }\n\n // ============================================================================\n // Subscriptions\n // ============================================================================\n\n /**\n * Create a subscription\n */\n async createSubscription(options: CreateSubscriptionOptions): Promise<Subscription> {\n if (this.debug) {\n console.log(\"[Payments] Creating subscription:\", {\n customerId: options.customerId,\n priceId: options.priceId,\n });\n }\n\n return this.provider.createSubscription(options);\n }\n\n /**\n * Get a subscription\n */\n async getSubscription(subscriptionId: string): Promise<Subscription | null> {\n return this.provider.getSubscription(subscriptionId);\n }\n\n /**\n * Update a subscription\n */\n async updateSubscription(\n subscriptionId: string,\n options: UpdateSubscriptionOptions\n ): Promise<Subscription> {\n return this.provider.updateSubscription(subscriptionId, options);\n }\n\n /**\n * Cancel a subscription\n */\n async cancelSubscription(\n subscriptionId: string,\n cancelAtPeriodEnd = true\n ): Promise<Subscription> {\n if (this.debug) {\n console.log(\"[Payments] Canceling subscription:\", {\n subscriptionId,\n cancelAtPeriodEnd,\n });\n }\n\n return this.provider.cancelSubscription(subscriptionId, cancelAtPeriodEnd);\n }\n\n /**\n * List subscriptions for a customer\n */\n async listSubscriptions(customerId: string): Promise<Subscription[]> {\n return this.provider.listSubscriptions(customerId);\n }\n\n // ============================================================================\n // Portal\n // ============================================================================\n\n /**\n * Create a customer portal session\n */\n async createPortalSession(options: CreatePortalOptions): Promise<PortalSession> {\n return this.provider.createPortalSession(options);\n }\n\n // ============================================================================\n // Products & Prices\n // ============================================================================\n\n /**\n * Get a product\n */\n async getProduct(productId: string): Promise<Product | null> {\n if (this.provider.getProduct) {\n return this.provider.getProduct(productId);\n }\n return null;\n }\n\n /**\n * Get a price\n */\n async getPrice(priceId: string): Promise<Price | null> {\n if (this.provider.getPrice) {\n return this.provider.getPrice(priceId);\n }\n return null;\n }\n\n /**\n * List prices\n */\n async listPrices(productId?: string): Promise<Price[]> {\n if (this.provider.listPrices) {\n return this.provider.listPrices(productId);\n }\n return [];\n }\n\n // ============================================================================\n // Webhooks\n // ============================================================================\n\n /**\n * Register a webhook handler\n */\n onWebhook(type: WebhookEventType | \"*\", handler: WebhookHandler): this {\n this.webhookProcessor.handlers.on(type, handler);\n return this;\n }\n\n /**\n * Handle a webhook request\n */\n async handleWebhook(request: Request): Promise<WebhookProcessResult> {\n return this.webhookProcessor.process(request);\n }\n\n /**\n * Handle raw webhook payload\n */\n async handleWebhookRaw(\n payload: string | Uint8Array,\n signature: string\n ): Promise<WebhookProcessResult> {\n return this.webhookProcessor.processRaw(payload, signature);\n }\n\n /**\n * Verify a webhook (without handling)\n */\n async verifyWebhook(\n payload: string | Uint8Array,\n signature: string\n ): Promise<WebhookEvent | null> {\n return this.provider.verifyWebhook(payload, signature);\n }\n}\n\n/**\n * Create a payment service\n *\n * @example\n * ```typescript\n * // With Stripe\n * const payments = createPaymentService({\n * provider: createStripeProvider({\n * secretKey: process.env.STRIPE_SECRET_KEY,\n * webhookSecret: process.env.STRIPE_WEBHOOK_SECRET,\n * }),\n * });\n *\n * // With Paddle\n * const payments = createPaymentService({\n * provider: createPaddleProvider({\n * apiKey: process.env.PADDLE_API_KEY,\n * environment: 'sandbox',\n * webhookSecret: process.env.PADDLE_WEBHOOK_SECRET,\n * }),\n * });\n * ```\n */\nexport function createPaymentService(config: PaymentServiceConfig): PaymentService {\n return new PaymentService(config);\n}\n\n// Re-export billing module - values\nexport {\n BillingService,\n createBillingService,\n ProviderStrategy,\n createProviderStrategy,\n FallbackExecutor,\n createFallbackExecutor,\n createDisabledFallback,\n BillingError,\n BillingErrorCodes,\n} from \"./billing/index.js\";\n\n// Re-export billing module - types\nexport type {\n BillingRegion,\n RegionDetectionResult,\n RegionDetector,\n RegionDetectionContext,\n ProviderRoutingRule,\n ProviderStrategyConfig,\n FallbackConfig,\n FallbackOperation,\n FallbackContext,\n BillingServiceConfig,\n BillingLogger,\n SubscribeOptions,\n SubscribeResult,\n CancelOptions,\n CancelResult,\n GetSubscriptionOptions,\n BillingSubscription,\n BillingCustomer,\n ProviderSelection,\n BillingErrorCode,\n} from \"./billing/index.js\";\n\n// Re-export usage module - values\nexport {\n UsageService,\n createUsageService,\n UsageTracker,\n createUsageTracker,\n QuotaManager,\n createQuotaManager,\n SubscriptionLifecycle,\n createSubscriptionLifecycle,\n // Storage - In-Memory (dev/testing)\n MemoryUsageStorage,\n createMemoryUsageStorage,\n // Storage - Drizzle (production)\n DrizzleUsageStorage,\n createDrizzleUsageStorage,\n // Database Schema\n usageSchema,\n // Errors\n UsageError,\n QuotaExceededError,\n UsageErrorCodes,\n // Billing Integration\n BillingIntegration,\n integrateBillingWithUsage,\n createBillingIntegration,\n // Usage Meter (Provider Sync)\n UsageMeter,\n createUsageMeter,\n SubscriptionItemResolver,\n createSubscriptionItemResolver,\n} from \"./usage/index.js\";\n\n// Re-export usage module - types\nexport type {\n UsageStorage,\n UsageServiceConfig,\n QuotaManagerConfig,\n UsageTrackerConfig,\n Plan,\n PlanFeature,\n PlanTier,\n LimitPeriod,\n UsageEvent,\n TrackUsageOptions,\n UsageAggregate,\n PeriodType,\n GetUsageOptions,\n QuotaStatus,\n QuotaCheckResult,\n UsageAlert,\n AlertStatus,\n SubscriptionEventType,\n SubscriptionEvent,\n SubscriptionHandler,\n UsageWebhookEventType,\n UsageErrorCode,\n BillingIntegrationConfig,\n // Usage Meter types\n UsageRecord,\n UsageReporter,\n SyncStrategy,\n UsageMeterConfig,\n SubscriptionItemMapping,\n SubscriptionItemResolverConfig,\n // Reset & Access Status types\n ResetPeriod,\n AccessStatus,\n AccessStatusInfo,\n // Drizzle Storage types\n DrizzleDb,\n DrizzleUsageStorageConfig,\n} from \"./usage/index.js\";\n\n// Re-export dunning module - values\nexport {\n // Manager\n DunningManager,\n createDunningManager,\n createDefaultDunningConfig,\n // Scheduler\n DunningScheduler,\n createDunningScheduler,\n createDunningCronHandler,\n createDunningEdgeHandler,\n // Sequences\n DunningStepBuilder,\n DunningSequenceBuilder,\n step as dunningStep,\n sequence as dunningSequence,\n standardSaasSequence,\n aggressiveSequence,\n lenientSequence,\n minimalSequence,\n defaultSequences,\n getSequenceByTier,\n // Payment Retry\n PaymentRetryCalculator,\n PaymentRetrier,\n createPaymentRetryCalculator,\n createPaymentRetrier,\n defaultRetryStrategies,\n stripeErrorCodes,\n paddleErrorCodes,\n iyzicoErrorCodes,\n allErrorCodeMappings,\n // Storage - Memory (dev/testing)\n MemoryDunningStorage,\n createMemoryDunningStorage,\n // Storage - Drizzle (production)\n DrizzleDunningStorage,\n createDrizzleDunningStorage,\n // Database Schema\n dunningSchema,\n} from \"./dunning/index.js\";\n\n// Re-export dunning module - types\nexport type {\n // Core types\n PaymentFailureCategory,\n PaymentFailure,\n DunningAction,\n NotificationChannel,\n DunningStep,\n DunningSequence,\n DunningStatus,\n DunningState,\n ExecutedStep,\n DunningContext,\n RetryStrategy,\n RetryResult,\n DunningNotification,\n NotificationResult,\n DunningEventType,\n DunningEvent,\n DunningEventHandler,\n DunningManagerConfig,\n DunningLogger,\n DunningStorage,\n // Scheduler types\n DunningSchedulerConfig,\n // Retry types\n ErrorCodeMapping,\n PaymentRetrierConfig,\n // Drizzle types\n DrizzleDunningStorageConfig,\n // Schema row types\n DunningSequenceRow,\n NewDunningSequence,\n DunningStepRow,\n NewDunningStep,\n PaymentFailureRow,\n NewPaymentFailure,\n DunningStateRow,\n NewDunningState,\n ExecutedStepRow,\n NewExecutedStep,\n ScheduledStepRow,\n NewScheduledStep,\n DunningEventRow,\n NewDunningEvent,\n RetryStrategyRow,\n NewRetryStrategy,\n} from \"./dunning/index.js\";\n\n// Import for default export\nimport { BillingService, createBillingService } from \"./billing/index.js\";\nimport { UsageService, createUsageService } from \"./usage/index.js\";\nimport { DunningManager, createDunningManager } from \"./dunning/index.js\";\n\n// Default export\nexport default {\n PaymentService,\n createPaymentService,\n BillingService,\n createBillingService,\n UsageService,\n createUsageService,\n DunningManager,\n createDunningManager,\n};\n"],"mappings":"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","names":["index","price","timestamp","subscription","price","timestamp","price","type","type","subscription","type","plans","generateId","nullLogger","nullLogger","timestamp","nullLogger","index","nullLogger","nullLogger","subscription","nullLogger","sequence","step","subscription","eq","and","pgTable","text","integer","boolean","timestamp","jsonb","uniqueIndex","index","eq","step","and","type"]}
|