@stacksjs/payments 0.75.360 → 0.75.361
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/dist/connect/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { asAccount, connectedCustomer, directCheckout, directCheckoutPaymentData, directCheckoutSubscriptionData, directPaymentIntentParams, directSubscriptionParams, manageDirectSubscription } from './direct';
|
|
2
2
|
import { checkoutLineItemsTotal, destinationCheckoutPaymentData, destinationCheckoutSubscriptionData, destinationFeeCents, destinationFeePercent, destinationPaymentIntentParams, destinationSubscriptionParams, splitFee } from './destination';
|
|
3
3
|
import { collectDirectInvoice } from './invoice-collection';
|
|
4
|
+
import { completeDirectInvoicePurchase, directInvoicePurchaseMetadata } from './invoice-purchase';
|
|
4
5
|
import { connectRefund, connectRefundParams, isDestinationCharge } from './refund';
|
|
5
6
|
import { creditDirectInvoiceRefund } from './invoice-credit';
|
|
6
7
|
import { directChargeFinancials } from './financials';
|
|
7
8
|
import { directInvoiceTaxFinancials } from './invoice-tax';
|
|
9
|
+
import { ensureDirectInvoicePrice } from './invoice-price';
|
|
8
10
|
import { manageConnectedAccount } from './account';
|
|
9
11
|
import { manageConnectWebhook } from './webhook';
|
|
10
12
|
import { manageDestinationCharge } from './charge';
|
|
@@ -37,6 +39,9 @@ export declare const connect: {
|
|
|
37
39
|
directChargeFinancials: typeof directChargeFinancials;
|
|
38
40
|
prepareDirectInvoiceFee: typeof prepareDirectInvoiceFee;
|
|
39
41
|
collectDirectInvoice: typeof collectDirectInvoice;
|
|
42
|
+
ensureDirectInvoicePrice: typeof ensureDirectInvoicePrice;
|
|
43
|
+
directInvoicePurchaseMetadata: typeof directInvoicePurchaseMetadata;
|
|
44
|
+
completeDirectInvoicePurchase: typeof completeDirectInvoicePurchase;
|
|
40
45
|
creditDirectInvoiceRefund: typeof creditDirectInvoiceRefund;
|
|
41
46
|
directInvoiceTaxFinancials: typeof directInvoiceTaxFinancials;
|
|
42
47
|
directPaymentIntentParams: typeof directPaymentIntentParams;
|
|
@@ -87,6 +92,8 @@ export * from './direct';
|
|
|
87
92
|
export * from './financials';
|
|
88
93
|
export * from './invoice-fee';
|
|
89
94
|
export * from './invoice-collection';
|
|
95
|
+
export * from './invoice-price';
|
|
96
|
+
export * from './invoice-purchase';
|
|
90
97
|
export * from './invoice-credit';
|
|
91
98
|
export * from './tax';
|
|
92
99
|
export * from './invoice-tax';
|
package/dist/connect/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./account";export*from"./charge";export*from"./destination";export*from"./direct";export*from"./financials";export*from"./invoice-fee";export*from"./invoice-collection";export*from"./invoice-credit";export*from"./tax";export*from"./invoice-tax";export*from"./payout";export*from"./refund";export*from"./subscription";export*from"./transfer";export*from"./webhook";import{manageConnectedAccount}from"./account";import{manageDestinationCharge}from"./charge";import{asAccount,connectedCustomer,directCheckout,directCheckoutPaymentData,directCheckoutSubscriptionData,directPaymentIntentParams,directSubscriptionParams,manageDirectSubscription}from"./direct";import{checkoutLineItemsTotal,destinationCheckoutPaymentData,destinationCheckoutSubscriptionData,destinationFeeCents,destinationFeePercent,destinationPaymentIntentParams,destinationSubscriptionParams,splitFee}from"./destination";import{managePayout}from"./payout";import{directChargeFinancials}from"./financials";import{prepareDirectInvoiceFee}from"./invoice-fee";import{collectDirectInvoice}from"./invoice-collection";import{creditDirectInvoiceRefund}from"./invoice-credit";import{directInvoiceTaxFinancials}from"./invoice-tax";import{connectRefund,connectRefundParams,isDestinationCharge}from"./refund";import{manageDestinationSubscription}from"./subscription";import{manageTransfer}from"./transfer";import{manageConnectWebhook}from"./webhook";export const connect={createAccount:manageConnectedAccount.createConnectedAccount,createTestAccount:manageConnectedAccount.createTestConnectedAccount,onboardingLink:manageConnectedAccount.accountOnboardingLink,accountStatus:manageConnectedAccount.accountStatus,retrieveAccount:manageConnectedAccount.retrieveConnectedAccount,destinationCharge:manageDestinationCharge.destinationCharge,applicationFeeFor:manageDestinationCharge.applicationFeeFor,feeCents:destinationFeeCents,feePercent:destinationFeePercent,paymentIntentParams:destinationPaymentIntentParams,checkoutPaymentData:destinationCheckoutPaymentData,checkoutSubscriptionData:destinationCheckoutSubscriptionData,subscriptionParams:destinationSubscriptionParams,lineItemsTotal:checkoutLineItemsTotal,splitFee,asAccount,customer:connectedCustomer,directCheckout,directChargeFinancials,prepareDirectInvoiceFee,collectDirectInvoice,creditDirectInvoiceRefund,directInvoiceTaxFinancials,directPaymentIntentParams,directCheckoutPaymentData,directCheckoutSubscriptionData,directSubscriptionParams,directSubscriptionCheckout:manageDirectSubscription.checkout,refund:connectRefund,refundParams:connectRefundParams,isDestinationCharge,subscriptionCheckout:manageDestinationSubscription.checkout,subscriptionFeePercent:manageDestinationSubscription.feePercentFor,subscriptionDestination:manageDestinationSubscription.destinationOf,createTransfer:manageTransfer.createTransfer,reverseTransfer:manageTransfer.reverseTransfer,listTransfers:manageTransfer.listTransfers,retrieveTransfer:manageTransfer.retrieveTransfer,listPayouts:managePayout.listPayouts,retrievePayout:managePayout.retrievePayout,accountBalance:managePayout.accountBalance,onAccount:manageConnectWebhook.onAccount,onPayout:manageConnectWebhook.onPayout,getAccount:manageConnectWebhook.getAccount,getPayout:manageConnectWebhook.getPayout,getConnectedAccountId:manageConnectWebhook.getConnectedAccountId,account:manageConnectedAccount,charge:manageDestinationCharge,subscription:manageDestinationSubscription,directSubscription:manageDirectSubscription,transfer:manageTransfer,payout:managePayout};
|
|
1
|
+
export*from"./account";export*from"./charge";export*from"./destination";export*from"./direct";export*from"./financials";export*from"./invoice-fee";export*from"./invoice-collection";export*from"./invoice-price";export*from"./invoice-purchase";export*from"./invoice-credit";export*from"./tax";export*from"./invoice-tax";export*from"./payout";export*from"./refund";export*from"./subscription";export*from"./transfer";export*from"./webhook";import{manageConnectedAccount}from"./account";import{manageDestinationCharge}from"./charge";import{asAccount,connectedCustomer,directCheckout,directCheckoutPaymentData,directCheckoutSubscriptionData,directPaymentIntentParams,directSubscriptionParams,manageDirectSubscription}from"./direct";import{checkoutLineItemsTotal,destinationCheckoutPaymentData,destinationCheckoutSubscriptionData,destinationFeeCents,destinationFeePercent,destinationPaymentIntentParams,destinationSubscriptionParams,splitFee}from"./destination";import{managePayout}from"./payout";import{directChargeFinancials}from"./financials";import{prepareDirectInvoiceFee}from"./invoice-fee";import{collectDirectInvoice}from"./invoice-collection";import{ensureDirectInvoicePrice}from"./invoice-price";import{completeDirectInvoicePurchase,directInvoicePurchaseMetadata}from"./invoice-purchase";import{creditDirectInvoiceRefund}from"./invoice-credit";import{directInvoiceTaxFinancials}from"./invoice-tax";import{connectRefund,connectRefundParams,isDestinationCharge}from"./refund";import{manageDestinationSubscription}from"./subscription";import{manageTransfer}from"./transfer";import{manageConnectWebhook}from"./webhook";export const connect={createAccount:manageConnectedAccount.createConnectedAccount,createTestAccount:manageConnectedAccount.createTestConnectedAccount,onboardingLink:manageConnectedAccount.accountOnboardingLink,accountStatus:manageConnectedAccount.accountStatus,retrieveAccount:manageConnectedAccount.retrieveConnectedAccount,destinationCharge:manageDestinationCharge.destinationCharge,applicationFeeFor:manageDestinationCharge.applicationFeeFor,feeCents:destinationFeeCents,feePercent:destinationFeePercent,paymentIntentParams:destinationPaymentIntentParams,checkoutPaymentData:destinationCheckoutPaymentData,checkoutSubscriptionData:destinationCheckoutSubscriptionData,subscriptionParams:destinationSubscriptionParams,lineItemsTotal:checkoutLineItemsTotal,splitFee,asAccount,customer:connectedCustomer,directCheckout,directChargeFinancials,prepareDirectInvoiceFee,collectDirectInvoice,ensureDirectInvoicePrice,directInvoicePurchaseMetadata,completeDirectInvoicePurchase,creditDirectInvoiceRefund,directInvoiceTaxFinancials,directPaymentIntentParams,directCheckoutPaymentData,directCheckoutSubscriptionData,directSubscriptionParams,directSubscriptionCheckout:manageDirectSubscription.checkout,refund:connectRefund,refundParams:connectRefundParams,isDestinationCharge,subscriptionCheckout:manageDestinationSubscription.checkout,subscriptionFeePercent:manageDestinationSubscription.feePercentFor,subscriptionDestination:manageDestinationSubscription.destinationOf,createTransfer:manageTransfer.createTransfer,reverseTransfer:manageTransfer.reverseTransfer,listTransfers:manageTransfer.listTransfers,retrieveTransfer:manageTransfer.retrieveTransfer,listPayouts:managePayout.listPayouts,retrievePayout:managePayout.retrievePayout,accountBalance:managePayout.accountBalance,onAccount:manageConnectWebhook.onAccount,onPayout:manageConnectWebhook.onPayout,getAccount:manageConnectWebhook.getAccount,getPayout:manageConnectWebhook.getPayout,getConnectedAccountId:manageConnectWebhook.getConnectedAccountId,account:manageConnectedAccount,charge:manageDestinationCharge,subscription:manageDestinationSubscription,directSubscription:manageDirectSubscription,transfer:manageTransfer,payout:managePayout};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type Stripe from 'stripe';
|
|
2
|
+
/** Find or create an inclusive catalog price on the original merchant. Stripe's
|
|
3
|
+
* unique lookup key survives the idempotency window and lost create responses.
|
|
4
|
+
* Different commercial terms receive a different immutable price. Existing
|
|
5
|
+
* prices are verified, never silently edited/reactivated or transferred from
|
|
6
|
+
* another lookup key. The merchant supplies its actual tax classification.
|
|
7
|
+
*/
|
|
8
|
+
export declare function ensureDirectInvoicePrice(account: string, options: DirectInvoicePriceOptions, client?: Pick<Stripe, 'prices'>): Promise<Stripe.Price>;
|
|
9
|
+
export declare interface DirectInvoicePriceOptions {
|
|
10
|
+
reference: string
|
|
11
|
+
name: string
|
|
12
|
+
amount: number
|
|
13
|
+
currency: string
|
|
14
|
+
taxCode: string
|
|
15
|
+
interval?: 'day' | 'week' | 'month' | 'year'
|
|
16
|
+
intervalCount?: number
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{stripe}from"../drivers/stripe";import{idempotencyFingerprint,stacksIdempotencyKey}from"../idempotency";import{asAccount}from"./direct";export async function ensureDirectInvoicePrice(account,options,client=stripe){const request=asAccount(account);if(typeof options.reference!=="string"||!/^[a-z0-9:._-]{1,160}$/i.test(options.reference)||typeof options.name!=="string"||!options.name.trim()||options.name.length>250||!Number.isSafeInteger(options.amount)||options.amount<=0||!/^[a-z]{3}$/i.test(options.currency)||!/^txcd_\d{8}$/.test(options.taxCode)||options.interval!==void 0&&!["day","week","month","year"].includes(options.interval)||options.intervalCount!==void 0&&(!options.interval||!Number.isSafeInteger(options.intervalCount)||options.intervalCount<1))throw Error("[payments/connect] Expected stable offer identity, name, positive minor-unit price, currency and merchant tax code");const terms={reference:options.reference,name:options.name.trim(),amount:options.amount,currency:options.currency.toLowerCase(),taxCode:options.taxCode,interval:options.interval??null,intervalCount:options.interval?options.intervalCount??1:null},fingerprint=idempotencyFingerprint(terms),lookup=`stacks.invoice-price.${fingerprint}`,listed=await client.prices.list({lookup_keys:[lookup],limit:100},request);if(listed.has_more||listed.data.length>1)throw Error("[payments/connect] Merchant invoice price lookup is ambiguous");const price=listed.data[0]??await client.prices.create({currency:terms.currency,unit_amount:terms.amount,tax_behavior:"inclusive",lookup_key:lookup,metadata:{stacks_invoice_price:fingerprint,stacks_offer_reference:terms.reference},product_data:{name:terms.name,tax_code:terms.taxCode,metadata:{stacks_invoice_price:fingerprint,stacks_offer_reference:terms.reference}},...options.interval?{recurring:{interval:options.interval,interval_count:options.intervalCount??1}}:{}},{...request,idempotencyKey:stacksIdempotencyKey("connect.invoice.price",account,fingerprint)});if(!/^price_[a-z0-9_]+$/i.test(price.id))throw Error("[payments/connect] Provider returned no catalog price identity");const current=await client.prices.retrieve(price.id,{expand:["product"]},request),{product,recurring}=current;if(current.id!==price.id||!current.active||current.lookup_key!==lookup||current.metadata?.stacks_invoice_price!==fingerprint||current.currency!==terms.currency||current.unit_amount!==terms.amount||current.tax_behavior!=="inclusive"||current.type!==(terms.interval?"recurring":"one_time")||(terms.interval?!recurring||recurring.interval!==terms.interval||recurring.interval_count!==terms.intervalCount||recurring.usage_type!=="licensed":recurring!=null)||typeof product==="string"||product.deleted||!product.active||product.name!==terms.name||(typeof product.tax_code==="string"?product.tax_code:product.tax_code?.id)!==terms.taxCode)throw Error("[payments/connect] Existing merchant price differs from the frozen inclusive offer or is inactive");return current}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DirectInvoiceCollection } from './invoice-collection';
|
|
2
|
+
import type { DirectInvoicePriceOptions } from './invoice-price';
|
|
3
|
+
import type Stripe from 'stripe';
|
|
4
|
+
/** Copy onto Setup Checkout's setup_intent_data.metadata. Completion verifies
|
|
5
|
+
* this binding before creating any purchase. The app owns explicit consent and
|
|
6
|
+
* durable locking of the reference; metadata is not a substitute for either. */
|
|
7
|
+
export declare function directInvoicePurchaseMetadata(account: string, options: DirectInvoicePurchaseOptions): Record<string, string>;
|
|
8
|
+
/** Complete only a successful setup bound to the original frozen quote. The
|
|
9
|
+
* caller serializes the durable purchase reference. Provider lists recover the
|
|
10
|
+
* original invoice/schedule beyond idempotency retention; no search-index lag
|
|
11
|
+
* or process-local cache decides whether to create another purchase. */
|
|
12
|
+
export declare function completeDirectInvoicePurchase(setupIntentId: string, account: string, options: DirectInvoicePurchaseOptions, client?: PurchaseClient): Promise<DirectInvoiceCollection & { subscription?: Stripe.Subscription }>;
|
|
13
|
+
export declare interface DirectInvoicePurchaseOptions extends Pick<DirectInvoicePriceOptions, 'amount' | 'currency' | 'taxCode' | 'interval' | 'intervalCount'> {
|
|
14
|
+
reference: string
|
|
15
|
+
customer: string
|
|
16
|
+
price: string
|
|
17
|
+
expiresAt: number
|
|
18
|
+
platformFeePercent: number
|
|
19
|
+
trialDays?: number
|
|
20
|
+
metadata?: Record<string, string>
|
|
21
|
+
}
|
|
22
|
+
declare type PurchaseClient = Pick<Stripe, 'setupIntents' | 'prices' | 'paymentMethods' | 'invoices' | 'invoiceItems' | 'subscriptionSchedules' | 'subscriptions' | 'invoicePayments' | 'paymentIntents'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{stripe}from"../drivers/stripe";import{idempotencyFingerprint,stacksIdempotencyKey}from"../idempotency";import{asAccount}from"./direct";import{collectDirectInvoice}from"./invoice-collection";import{allPages}from"./pagination";import{manageDestinationSubscription}from"./subscription";export function directInvoicePurchaseMetadata(account,options){asAccount(account);if(typeof options.reference!=="string"||!/^[a-z0-9:._-]{1,160}$/i.test(options.reference)||!/^cus_[a-z0-9_]+$/i.test(options.customer)||!/^price_[a-z0-9_]+$/i.test(options.price)||!Number.isSafeInteger(options.expiresAt)||options.expiresAt<=0||!Number.isSafeInteger(options.amount)||options.amount<=0||!/^[a-z]{3}$/i.test(options.currency)||!/^txcd_\d{8}$/.test(options.taxCode)||options.interval!==void 0&&!["day","week","month","year"].includes(options.interval)||options.intervalCount!==void 0&&(!options.interval||!Number.isSafeInteger(options.intervalCount)||options.intervalCount<1)||options.trialDays!==void 0&&(!Number.isSafeInteger(options.trialDays)||options.trialDays<0||options.trialDays>730||!options.interval&&options.trialDays>0))throw Error("[payments/connect] Expected original customer, price and frozen invoice purchase terms");if(options.platformFeePercent==null)throw Error("[payments/connect] An explicit invoice fee percentage is required");manageDestinationSubscription.feePercentFor({platformFeePercent:options.platformFeePercent});const metadata=options.metadata??{};if(typeof metadata!=="object"||Array.isArray(metadata)||Object.keys(metadata).length>47||Object.entries(metadata).some(([key,value])=>!key||key.length>40||/[\[\]]/.test(key)||key.startsWith("stacks_purchase_")||typeof value!=="string"||value.length>500))throw Error("[payments/connect] Invalid purchase metadata or reserved binding fields");const terms={account,reference:options.reference,customer:options.customer,price:options.price,amount:options.amount,currency:options.currency.toLowerCase(),taxCode:options.taxCode,expiresAt:options.expiresAt,interval:options.interval??null,intervalCount:options.interval?options.intervalCount??1:null,trialDays:options.trialDays??0,platformFeePercent:options.platformFeePercent,metadata};return{...metadata,stacks_purchase_reference:options.reference,stacks_purchase_quote:idempotencyFingerprint(terms)}}function id(value){return typeof value==="string"?value:value?.id}export async function completeDirectInvoicePurchase(setupIntentId,account,options,client=stripe){const quote=directInvoicePurchaseMetadata(account,options),request=asAccount(account);if(!/^seti_[a-z0-9_]+$/i.test(setupIntentId))throw Error("[payments/connect] Expected original successful payment setup");const setup=await client.setupIntents.retrieve(setupIntentId,{},request),matches=(metadata,expected)=>Object.entries(expected).every(([key,value])=>metadata?.[key]===value);if(setup.id!==setupIntentId||setup.status!=="succeeded"||setup.usage!=="off_session"||!Number.isSafeInteger(setup.created)||setup.created<=0||id(setup.customer)!==options.customer||!/^pm_[a-z0-9_]+$/i.test(id(setup.payment_method)||"")||!matches(setup.metadata,quote))throw Error("[payments/connect] Payment setup does not match the original customer and frozen quote");const paymentMethod=id(setup.payment_method),metadata={...quote,stacks_purchase_setup:setupIntentId},key=(operation)=>stacksIdempotencyKey(`connect.invoice.purchase.${operation}`,account,options.reference,quote.stacks_purchase_quote),canCreate=()=>{if(Date.now()/1000>=Math.min(options.expiresAt,setup.created+86400))throw Error("[payments/connect] Expired purchase can only recover its original provider invoice or schedule")},existing=(rows)=>{const own=rows.filter((row)=>row.metadata?.stacks_purchase_reference===options.reference);if(own.length>1||own.some((row)=>!matches(row.metadata,metadata)))throw Error("[payments/connect] Purchase reference has ambiguous or different provider bindings");return own[0]},verifyPrice=async()=>{const price=await client.prices.retrieve(options.price,{expand:["product"]},request),product=price.product;if(price.id!==options.price||!price.active||price.currency!==options.currency.toLowerCase()||price.unit_amount!==options.amount||price.tax_behavior!=="inclusive"||price.type!==(options.interval?"recurring":"one_time")||(options.interval?price.recurring?.interval!==options.interval||price.recurring?.interval_count!==(options.intervalCount??1)||price.recurring?.usage_type!=="licensed":price.recurring!=null)||typeof product==="string"||product.deleted||!product.active||id(product.tax_code)!==options.taxCode)throw Error("[payments/connect] Catalog price does not match the approved inclusive purchase");const method=await client.paymentMethods.retrieve(paymentMethod,{},request);if(method.id!==paymentMethod||id(method.customer)!==options.customer)throw Error("[payments/connect] Purchase payment method belongs to another customer")};let invoice,subscription,reloadSubscription;if(options.interval){let schedule=existing(await allPages((after)=>client.subscriptionSchedules.list({customer:options.customer,limit:100,...after?{starting_after:after}:{}},request)));if(!schedule){canCreate();await verifyPrice();const phase={items:[{price:options.price,quantity:1}],automatic_tax:{enabled:!0},metadata};schedule=await client.subscriptionSchedules.create({customer:options.customer,start_date:"now",end_behavior:"release",default_settings:{default_payment_method:paymentMethod},phases:options.trialDays?[{...phase,trial:!0,duration:{interval:"day",interval_count:options.trialDays}},phase]:[phase],metadata},{...request,idempotencyKey:key("schedule")})}const subscriptionId=id(schedule.subscription)??id(schedule.released_subscription);if(!/^sub_sched_[a-z0-9_]+$/i.test(schedule.id)||id(schedule.customer)!==options.customer||!matches(schedule.metadata,metadata)||!/^sub_[a-z0-9_]+$/i.test(subscriptionId||""))throw Error("[payments/connect] Purchase schedule has no original customer and subscription");const readSubscription=async()=>{const value=await client.subscriptions.retrieve(subscriptionId,{},request);if(value.id!==subscriptionId||id(value.customer)!==options.customer||!matches(value.metadata,metadata)||value.items.has_more||value.items.data.length!==1||id(value.items.data[0].price)!==options.price||value.items.data[0].quantity!==1)throw Error("[payments/connect] Subscription does not match the original frozen purchase");return value};reloadSubscription=readSubscription;subscription=await readSubscription();const initial=(await allPages((after)=>client.invoices.list({customer:options.customer,subscription:subscriptionId,limit:100,...after?{starting_after:after}:{}},request))).filter((value)=>value.billing_reason==="subscription_create"&&id(value.parent?.subscription_details?.subscription)===subscriptionId);if(initial.length!==1)throw Error("[payments/connect] Purchase has no unique original subscription invoice");invoice=await client.invoices.retrieve(initial[0].id,{},request);if(invoice.id!==initial[0].id||id(invoice.customer)!==options.customer||id(invoice.parent?.subscription_details?.subscription)!==subscriptionId||!matches(invoice.parent?.subscription_details?.metadata,metadata))throw Error("[payments/connect] First invoice does not match the original subscription quote");if(invoice.status!=="paid"&&["canceled","incomplete_expired","unpaid"].includes(subscription.status))throw Error("[payments/connect] Subscription no longer permits its initial collection");if(invoice.status==="draft"&&invoice.auto_advance!==!1){invoice=await client.invoices.update(invoice.id,{auto_advance:!1},{...request,idempotencyKey:key("hold")});if(invoice.id!==initial[0].id||id(invoice.customer)!==options.customer||id(invoice.parent?.subscription_details?.subscription)!==subscriptionId||!matches(invoice.parent?.subscription_details?.metadata,metadata))throw Error("[payments/connect] Held invoice no longer matches the original subscription")}if(schedule.status==="active"){if(id(subscription.schedule)!==schedule.id)throw Error("[payments/connect] Subscription belongs to another schedule");const trialEnd=subscription.trial_end,released=await client.subscriptionSchedules.release(schedule.id,{},{...request,idempotencyKey:key("release")});if(released.id!==schedule.id||released.status!=="released"||id(released.released_subscription)!==subscriptionId)throw Error("[payments/connect] Schedule release did not preserve its original subscription");subscription=await readSubscription();if(subscription.schedule!=null||subscription.trial_end!==trialEnd)throw Error("[payments/connect] Released purchase changed its schedule or native trial");if(invoice.status!=="paid"&&["canceled","incomplete_expired","unpaid"].includes(subscription.status))throw Error("[payments/connect] Subscription no longer permits its initial collection")}else if(!["released","completed","canceled"].includes(schedule.status))throw Error("[payments/connect] Purchase schedule has not started")}else{const previous=existing(await allPages((after)=>client.invoices.list({customer:options.customer,limit:100,...after?{starting_after:after}:{}},request)));if(previous)invoice=await client.invoices.retrieve(previous.id,{},request);else{canCreate();await verifyPrice();invoice=await client.invoices.create({customer:options.customer,currency:options.currency.toLowerCase(),auto_advance:!1,automatic_tax:{enabled:!0},default_payment_method:paymentMethod,pending_invoice_items_behavior:"exclude",metadata},{...request,idempotencyKey:key("create")})}if(!/^in_[a-z0-9_]+$/i.test(invoice.id)||previous&&invoice.id!==previous.id||id(invoice.customer)!==options.customer||!matches(invoice.metadata,metadata))throw Error("[payments/connect] Purchase invoice belongs to another customer or quote");let lines=await allPages((after)=>client.invoices.listLineItems(invoice.id,{limit:100,...after?{starting_after:after}:{}},request));if(lines.length===0&&invoice.status==="draft"){if(previous)await verifyPrice();await client.invoiceItems.create({customer:options.customer,invoice:invoice.id,pricing:{price:options.price},quantity:1},{...request,idempotencyKey:key("line")});lines=await allPages((after)=>client.invoices.listLineItems(invoice.id,{limit:100,...after?{starting_after:after}:{}},request))}if(lines.length!==1||lines[0].quantity!==1||id(lines[0].pricing?.price_details?.price)!==options.price)throw Error("[payments/connect] Purchase invoice contains different catalog lines")}if(!invoice.automatic_tax.enabled)throw Error("[payments/connect] Purchase invoice no longer uses its original automatic tax policy");return{...await collectDirectInvoice(invoice.id,account,{customer:options.customer,...subscription?{subscription:subscription.id}:{},currency:options.currency,platformFeePercent:options.platformFeePercent,approvedTotal:options.trialDays?0:options.amount,paymentMethod},client),...reloadSubscription?{subscription:await reloadSubscription()}:{}}}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/payments",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.75.
|
|
5
|
+
"version": "0.75.361",
|
|
6
6
|
"description": "The Stacks payments package. Currently supporting Stripe.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -60,12 +60,12 @@
|
|
|
60
60
|
"prepublishOnly": "bun run build"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
|
-
"@stacksjs/config": "0.75.
|
|
64
|
-
"@stacksjs/database": "0.75.
|
|
65
|
-
"@stacksjs/error-handling": "0.75.
|
|
66
|
-
"@stacksjs/logging": "0.75.
|
|
67
|
-
"@stacksjs/orm": "0.75.
|
|
68
|
-
"@stacksjs/types": "0.75.
|
|
63
|
+
"@stacksjs/config": "0.75.361",
|
|
64
|
+
"@stacksjs/database": "0.75.361",
|
|
65
|
+
"@stacksjs/error-handling": "0.75.361",
|
|
66
|
+
"@stacksjs/logging": "0.75.361",
|
|
67
|
+
"@stacksjs/orm": "0.75.361",
|
|
68
|
+
"@stacksjs/types": "0.75.361"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"@stripe/stripe-js": "^10.0.0",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
}
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
|
-
"@stacksjs/utils": "0.75.
|
|
83
|
+
"@stacksjs/utils": "0.75.361",
|
|
84
84
|
"@stripe/stripe-js": "^10.0.0",
|
|
85
85
|
"better-dx": "^0.2.24",
|
|
86
86
|
"stripe": "23.0.0"
|