@stacksjs/payments 0.75.268 → 0.75.269
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/billable/checkout.d.ts +8 -0
- package/dist/billable/checkout.js +1 -1
- package/dist/connect/account.d.ts +15 -0
- package/dist/connect/account.js +1 -1
- package/dist/connect/direct.d.ts +111 -0
- package/dist/connect/direct.js +1 -0
- package/dist/connect/index.d.ts +11 -0
- package/dist/connect/index.js +1 -1
- package/dist/connect/refund.d.ts +1 -0
- package/dist/connect/refund.js +1 -1
- package/package.json +8 -8
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { UserModel } from '@stacksjs/orm';
|
|
2
2
|
import type Stripe from 'stripe';
|
|
3
|
+
/**
|
|
4
|
+
* Validate that a redirect target URL is on the configured app origin.
|
|
5
|
+
* Without this, an attacker who could influence params (e.g. via a
|
|
6
|
+
* forged form) could route the post-payment redirect to a phishing
|
|
7
|
+
* site impersonating the brand. We compare origins (scheme+host+port)
|
|
8
|
+
* so subdomains and paths are still flexible within the trust boundary.
|
|
9
|
+
*/
|
|
10
|
+
export declare function assertSameOriginUrl(url: string | undefined, label: string): void;
|
|
3
11
|
export declare const manageCheckout: Checkout;
|
|
4
12
|
export declare interface Checkout {
|
|
5
13
|
create: (user: UserModel, params: Stripe.Checkout.SessionCreateParams) => Promise<Stripe.Response<Stripe.Checkout.Session>>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{config}from"@stacksjs/config";import{stripe}from"../drivers/stripe";import{freshIdempotencyKey}from"../idempotency";function assertSameOriginUrl(url,label){if(!url)return;let parsed;try{parsed=new URL(url)}catch{throw Error(`[payments/checkout] ${label} is not a valid URL: ${url}`)}const appUrl=config?.app?.url;if(!appUrl)return;let appOrigin;try{appOrigin=new URL(appUrl.startsWith("http")?appUrl:`https://${appUrl}`).origin}catch{return}if(parsed.origin!==appOrigin)throw Error(`[payments/checkout] ${label} origin (${parsed.origin}) does not match app origin (${appOrigin})`)}export const manageCheckout=(()=>{async function create(user,params){const customerId=params.customer||user.stripe_id;if(!customerId)throw Error("User has no Stripe customer");assertSameOriginUrl(params.success_url,"success_url");assertSameOriginUrl(params.cancel_url,"cancel_url");const mergedParams={...{customer:customerId,mode:"payment",success_url:params.success_url,cancel_url:params.cancel_url},...params};return await stripe.checkout.sessions.create(mergedParams,{idempotencyKey:freshIdempotencyKey("checkout.session.create",user.id)})}return{create}})();
|
|
1
|
+
import{config}from"@stacksjs/config";import{stripe}from"../drivers/stripe";import{freshIdempotencyKey}from"../idempotency";export function assertSameOriginUrl(url,label){if(!url)return;let parsed;try{parsed=new URL(url)}catch{throw Error(`[payments/checkout] ${label} is not a valid URL: ${url}`)}const appUrl=config?.app?.url;if(!appUrl)return;let appOrigin;try{appOrigin=new URL(appUrl.startsWith("http")?appUrl:`https://${appUrl}`).origin}catch{return}if(parsed.origin!==appOrigin)throw Error(`[payments/checkout] ${label} origin (${parsed.origin}) does not match app origin (${appOrigin})`)}export const manageCheckout=(()=>{async function create(user,params){const customerId=params.customer||user.stripe_id;if(!customerId)throw Error("User has no Stripe customer");assertSameOriginUrl(params.success_url,"success_url");assertSameOriginUrl(params.cancel_url,"cancel_url");const mergedParams={...{customer:customerId,mode:"payment",success_url:params.success_url,cancel_url:params.cancel_url},...params};return await stripe.checkout.sessions.create(mergedParams,{idempotencyKey:freshIdempotencyKey("checkout.session.create",user.id)})}return{create}})();
|
|
@@ -7,6 +7,8 @@ import type Stripe from 'stripe';
|
|
|
7
7
|
* parameters give another.
|
|
8
8
|
*/
|
|
9
9
|
export declare function connectedAccountIdempotencyKey(scope: 'connect.account.create' | 'connect.account.create_test', userId: number | string, params: Stripe.AccountCreateParams, reference?: string): string;
|
|
10
|
+
/** The defaults' controller unless the caller chose a `type` or a `controller` of its own. */
|
|
11
|
+
export declare function connectedAccountDefaults(params: Partial<Stripe.AccountCreateParams>): Partial<Stripe.AccountCreateParams>;
|
|
10
12
|
/**
|
|
11
13
|
* Connected-account ids are `acct_...`. Checking the shape here turns a
|
|
12
14
|
* confusing Stripe 404 (which reads as "no such account" even when the caller
|
|
@@ -14,6 +16,19 @@ export declare function connectedAccountIdempotencyKey(scope: 'connect.account.c
|
|
|
14
16
|
* names the argument.
|
|
15
17
|
*/
|
|
16
18
|
export declare function requireAccountId(accountId: string, caller: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* How a new connected account is controlled when the caller does not say:
|
|
21
|
+
* Stripe's Managed Risk. Stripe manages the account's credit and fraud risk
|
|
22
|
+
* and carries unrecoverable negative balances, the merchant gets the full
|
|
23
|
+
* Stripe Dashboard and pays Stripe's fees on its own charges, and Stripe
|
|
24
|
+
* collects what onboarding needs. It is what Stripe recommends for SaaS
|
|
25
|
+
* platforms and the only setup a platform that has not taken on loss
|
|
26
|
+
* liability may create: Stripe refuses the legacy `type: 'express'` and
|
|
27
|
+
* `type: 'custom'` there ("your platform as the losses collector"). Sell on
|
|
28
|
+
* such an account with direct charges (`connect/direct.ts`). A platform that
|
|
29
|
+
* did accept loss liability passes `type` or its own `controller`.
|
|
30
|
+
*/
|
|
31
|
+
export declare const MANAGED_RISK_CONTROLLER: Stripe.AccountCreateParams.Controller;
|
|
17
32
|
export declare const manageConnectedAccount: ManageConnectedAccount;
|
|
18
33
|
/**
|
|
19
34
|
* A connected account's readiness, reduced to the questions a marketplace
|
package/dist/connect/account.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{stripe}from"../drivers/stripe";import{idempotencyFingerprint,stacksIdempotencyKey}from"../idempotency";export function connectedAccountIdempotencyKey(scope,userId,params,reference){return stacksIdempotencyKey(scope,userId,reference,idempotencyFingerprint(params))}export const manageConnectedAccount=(()=>{async function createConnectedAccount(user,params={},options={}){const merged={...{
|
|
1
|
+
import{stripe}from"../drivers/stripe";import{idempotencyFingerprint,stacksIdempotencyKey}from"../idempotency";export function connectedAccountIdempotencyKey(scope,userId,params,reference){return stacksIdempotencyKey(scope,userId,reference,idempotencyFingerprint(params))}export const MANAGED_RISK_CONTROLLER={stripe_dashboard:{type:"full"},fees:{payer:"account"},losses:{payments:"stripe"},requirement_collection:"stripe"};export function connectedAccountDefaults(params){return params.type||params.controller?{}:{controller:MANAGED_RISK_CONTROLLER}}export const manageConnectedAccount=(()=>{async function createConnectedAccount(user,params={},options={}){const merged={...{...connectedAccountDefaults(params),email:user.email??void 0,metadata:{stacks_user_id:String(user.id)}},...params};return await stripe.accounts.create(merged,{idempotencyKey:connectedAccountIdempotencyKey("connect.account.create",user.id,merged,options.reference)})}async function createTestConnectedAccount(user,params={},options={}){const merged={...{...connectedAccountDefaults(params),email:user.email??void 0,business_type:"individual",capabilities:{card_payments:{requested:!0},transfers:{requested:!0}},business_profile:{url:"https://example.com",mcc:"5812"},metadata:{stacks_user_id:String(user.id),stacks_test_account:"true"}},...params};return await stripe.accounts.create(merged,{idempotencyKey:connectedAccountIdempotencyKey("connect.account.create_test",user.id,merged,options.reference)})}async function accountOnboardingLink(accountId,options){requireAccountId(accountId,"accountOnboardingLink");if(!options?.refreshUrl||!options?.returnUrl)throw Error("[payments/connect] accountOnboardingLink requires refreshUrl and returnUrl");return await stripe.accountLinks.create({account:accountId,refresh_url:options.refreshUrl,return_url:options.returnUrl,type:options.type??"account_onboarding",...options.collect?{collection_options:{fields:options.collect}}:{}})}async function retrieveConnectedAccount(accountId){requireAccountId(accountId,"retrieveConnectedAccount");return await stripe.accounts.retrieve(accountId)}async function accountStatus(accountId){const account=await retrieveConnectedAccount(accountId),requirements=account.requirements;return{chargesEnabled:account.charges_enabled===!0,payoutsEnabled:account.payouts_enabled===!0,detailsSubmitted:account.details_submitted===!0,currentlyDue:requirements?.currently_due??[],pastDue:requirements?.past_due??[],disabledReason:requirements?.disabled_reason??null,raw:account}}return{createConnectedAccount,createTestConnectedAccount,accountOnboardingLink,accountStatus,retrieveConnectedAccount}})();export function requireAccountId(accountId,caller){if(!accountId||typeof accountId!=="string")throw Error(`[payments/connect] ${caller} requires a connected account id`);if(!accountId.startsWith("acct_"))throw Error(`[payments/connect] ${caller} expects a connected account id (acct_...), got "${accountId}"`)}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { DestinationOptions } from './destination';
|
|
2
|
+
import type { InlineRecurringPrice } from './subscription';
|
|
3
|
+
import type { UserModel } from '@stacksjs/orm';
|
|
4
|
+
import type Stripe from 'stripe';
|
|
5
|
+
/**
|
|
6
|
+
* Request options that make a Stripe call as the connected account (the
|
|
7
|
+
* `Stripe-Account` header), merged with any others (an idempotency key).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* await stripe.checkout.sessions.retrieve(sessionId, asAccount(gym.stripe_account_id))
|
|
11
|
+
*/
|
|
12
|
+
export declare function asAccount(accountId: string, extra?: Stripe.RequestOptions): Stripe.RequestOptions;
|
|
13
|
+
/** The fields of a PaymentIntent for `amount` minor units charged directly, to spread into its params. */
|
|
14
|
+
export declare function directPaymentIntentParams(amount: number, options?: DirectFeeOptions): DirectPaymentFields;
|
|
15
|
+
/**
|
|
16
|
+
* `payment_intent_data` for a Checkout Session in `mode: 'payment'`, created
|
|
17
|
+
* on the connected account, whose line items total `amount` minor units.
|
|
18
|
+
* `extra` carries the PaymentIntent's other fields (metadata, a description);
|
|
19
|
+
* any destination fields in it are dropped, since a direct charge has none.
|
|
20
|
+
*/
|
|
21
|
+
export declare function directCheckoutPaymentData(amount: number, options?: DirectFeeOptions, extra?: Stripe.Checkout.SessionCreateParams.PaymentIntentData): Stripe.Checkout.SessionCreateParams.PaymentIntentData;
|
|
22
|
+
/**
|
|
23
|
+
* `subscription_data` for a Checkout Session in `mode: 'subscription'`,
|
|
24
|
+
* created on the connected account: every invoice pays the platform
|
|
25
|
+
* `feePercent`. `extra` carries the subscription's other fields.
|
|
26
|
+
*/
|
|
27
|
+
export declare function directCheckoutSubscriptionData(options?: Pick<DirectFeeOptions, 'feePercent' | 'feeCents'>, extra?: Stripe.Checkout.SessionCreateParams.SubscriptionData): Stripe.Checkout.SessionCreateParams.SubscriptionData;
|
|
28
|
+
/** The fields of a subscription created directly on the account (`stripe.subscriptions.create`). */
|
|
29
|
+
export declare function directSubscriptionParams(options?: Pick<DirectFeeOptions, 'feePercent' | 'feeCents'>): DirectSubscriptionFields;
|
|
30
|
+
/**
|
|
31
|
+
* The idempotency key for creating `user`'s customer on `accountId`: the same
|
|
32
|
+
* for every attempt with the same details, so two requests racing to create
|
|
33
|
+
* one make one, while a changed name or email is a new request rather than a
|
|
34
|
+
* reused key Stripe would refuse.
|
|
35
|
+
*/
|
|
36
|
+
export declare function connectedCustomerIdempotencyKey(accountId: string, userId: number | string, params?: Stripe.CustomerCreateParams): string;
|
|
37
|
+
/**
|
|
38
|
+
* The user's customer on a connected account, created on first use. A
|
|
39
|
+
* customer belongs to one account, so the platform's own customer (the user's
|
|
40
|
+
* `stripe_id`) cannot pay a direct charge; each merchant the user buys from
|
|
41
|
+
* holds its own. Found again by the user's id in the customer's metadata,
|
|
42
|
+
* looked up by email first (immediately consistent) and by metadata search
|
|
43
|
+
* when the email has changed, and created with a deterministic idempotency
|
|
44
|
+
* key, so nothing on the app's side has to remember it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function connectedCustomer(user: Pick<UserModel, 'id' | 'email' | 'name'> & { email?: string | null, name?: string | null }, accountId: string, client?: CustomerClient): Promise<Stripe.Customer>;
|
|
47
|
+
/**
|
|
48
|
+
* A Checkout Session on the connected account, as `manageCheckout.create`
|
|
49
|
+
* makes one on the platform: the user's customer there unless `params` names
|
|
50
|
+
* one, return URLs held to the app's origin, and a fresh idempotency key so a
|
|
51
|
+
* retried request does not open a second session.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* await directCheckout(user, gym.stripe_account_id, {
|
|
55
|
+
* mode: 'payment', line_items,
|
|
56
|
+
* payment_intent_data: directCheckoutPaymentData(checkoutLineItemsTotal(line_items), { feeCents }),
|
|
57
|
+
* success_url, cancel_url,
|
|
58
|
+
* })
|
|
59
|
+
*/
|
|
60
|
+
export declare function directCheckout(user: UserModel, accountId: string, params: Stripe.Checkout.SessionCreateParams, client?: Pick<Stripe, 'customers' | 'checkout'>): Promise<Stripe.Response<Stripe.Checkout.Session>>;
|
|
61
|
+
/** Subscriptions billed on the merchant's account, the platform paid its fee from each invoice. */
|
|
62
|
+
export declare const manageDirectSubscription: ManageDirectSubscription;
|
|
63
|
+
export declare interface DirectSubscriptionCheckoutOptions {
|
|
64
|
+
account: string
|
|
65
|
+
price: string | InlineRecurringPrice
|
|
66
|
+
quantity?: number
|
|
67
|
+
trialDays?: number
|
|
68
|
+
platformFeePercent?: number
|
|
69
|
+
metadata?: Record<string, string>
|
|
70
|
+
clientReferenceId?: string
|
|
71
|
+
customer?: string
|
|
72
|
+
successUrl: string
|
|
73
|
+
cancelUrl: string
|
|
74
|
+
sessionParams?: Partial<Stripe.Checkout.SessionCreateParams>
|
|
75
|
+
}
|
|
76
|
+
export declare interface ManageDirectSubscription {
|
|
77
|
+
subscriptionData: (options?: Pick<DirectSubscriptionCheckoutOptions, 'trialDays' | 'platformFeePercent' | 'metadata'>) => Stripe.Checkout.SessionCreateParams.SubscriptionData
|
|
78
|
+
checkout: (user: UserModel, options: DirectSubscriptionCheckoutOptions, client?: Pick<Stripe, 'customers' | 'checkout'>) => Promise<Stripe.Response<Stripe.Checkout.Session>>
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Direct charges: the sale is made on the merchant's own connected account,
|
|
82
|
+
* and the platform takes its cut as an application fee.
|
|
83
|
+
*
|
|
84
|
+
* This is the funds flow Stripe's Managed Risk is for (Stripe manages the
|
|
85
|
+
* merchant's credit and fraud risk and carries unrecoverable negative
|
|
86
|
+
* balances), and the one Stripe now requires of a platform that has not taken
|
|
87
|
+
* on loss liability itself: destination charges and separate transfers need
|
|
88
|
+
* the platform to be the losses collector.
|
|
89
|
+
*
|
|
90
|
+
* Everything that belongs to the sale lives on the connected account: the
|
|
91
|
+
* customer, the Checkout Session, the PaymentIntent, the subscription and its
|
|
92
|
+
* invoices, saved payment methods and mandates, and the refund. A call acts as
|
|
93
|
+
* the account with Stripe's `Stripe-Account` header, `asAccount(id)` as the
|
|
94
|
+
* request options. Stripe's processing fees are the merchant's; the platform
|
|
95
|
+
* receives the application fee whole.
|
|
96
|
+
*
|
|
97
|
+
* | Where the money is taken | Fields | Request options |
|
|
98
|
+
* |-----------------------------------|--------------------------------------------|---------------------|
|
|
99
|
+
* | Checkout, `mode: 'payment'` | `payment_intent_data.application_fee_amount` | `asAccount(id)` |
|
|
100
|
+
* | Checkout, `mode: 'subscription'` | `subscription_data.application_fee_percent` | `asAccount(id)` |
|
|
101
|
+
* | `stripe.subscriptions.create` | `application_fee_percent` | `asAccount(id)` |
|
|
102
|
+
* | `stripe.paymentIntents.create` | `application_fee_amount` | `asAccount(id)` |
|
|
103
|
+
*/
|
|
104
|
+
/** The platform's cut of a direct charge: a percent or an amount, as for destination charges. */
|
|
105
|
+
export type DirectFeeOptions = Pick<DestinationOptions, 'feePercent' | 'feeCents' | 'rounding'>;
|
|
106
|
+
/** The Connect fields of a one-off direct charge. */
|
|
107
|
+
export type DirectPaymentFields = Pick<Stripe.PaymentIntentCreateParams, 'application_fee_amount'>;
|
|
108
|
+
/** The Connect fields of a subscription created directly on the account. */
|
|
109
|
+
export type DirectSubscriptionFields = Pick<Stripe.SubscriptionCreateParams, 'application_fee_percent'>;
|
|
110
|
+
/** The Stripe customer calls a connected customer needs. */
|
|
111
|
+
declare type CustomerClient = Pick<Stripe, 'customers'>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{stripe}from"../drivers/stripe";import{assertSameOriginUrl}from"../billable/checkout";import{freshIdempotencyKey,idempotencyFingerprint,stacksIdempotencyKey}from"../idempotency";import{requireAccountId}from"./account";import{destinationFeeCents,destinationFeePercent}from"./destination";import{manageDestinationSubscription}from"./subscription";export function asAccount(accountId,extra={}){requireAccountId(accountId,"asAccount");return{...extra,stripeAccount:accountId}}export function directPaymentIntentParams(amount,options={}){const fee=destinationFeeCents(amount,options);return fee>0?{application_fee_amount:fee}:{}}export function directCheckoutPaymentData(amount,options={},extra={}){const rest={...extra};delete rest.application_fee_amount;delete rest.transfer_data;delete rest.on_behalf_of;delete rest.transfer_group;return{...rest,...directPaymentIntentParams(amount,options)}}export function directCheckoutSubscriptionData(options={},extra={}){const percent=destinationFeePercent(options),rest={...extra};delete rest.application_fee_percent;delete rest.transfer_data;delete rest.on_behalf_of;return{...rest,...percent!=null?{application_fee_percent:percent}:{}}}export function directSubscriptionParams(options={}){const percent=destinationFeePercent(options);return percent!=null?{application_fee_percent:percent}:{}}export function connectedCustomerIdempotencyKey(accountId,userId,params={}){return stacksIdempotencyKey("connect.customer.create",userId,accountId,idempotencyFingerprint(params))}export async function connectedCustomer(user,accountId,client=stripe){requireAccountId(accountId,"connectedCustomer");const userId=String(user.id),options=asAccount(accountId),own=(customer)=>!(("deleted"in customer)&&customer.deleted)&&customer.metadata?.stacks_user_id===userId;if(user.email){const found=(await client.customers.list({email:user.email,limit:100},options)).data.find(own);if(found)return found}try{const found=(await client.customers.search({query:`metadata['stacks_user_id']:'${userId.replace(/'/g,"")}'`,limit:1},options)).data.find(own);if(found)return found}catch{}const params={...user.email?{email:user.email}:{},...user.name?{name:user.name}:{},metadata:{stacks_user_id:userId}};return await client.customers.create(params,asAccount(accountId,{idempotencyKey:connectedCustomerIdempotencyKey(accountId,userId,params)}))}export async function directCheckout(user,accountId,params,client=stripe){requireAccountId(accountId,"directCheckout");assertSameOriginUrl(params.success_url,"success_url");assertSameOriginUrl(params.cancel_url,"cancel_url");const customer=params.customer??(params.customer_email?void 0:(await connectedCustomer(user,accountId,client)).id);return await client.checkout.sessions.create({mode:"payment",...params,...customer?{customer}:{}},asAccount(accountId,{idempotencyKey:freshIdempotencyKey("connect.checkout.create",user.id,accountId)}))}export const manageDirectSubscription=(()=>{function subscriptionData(options={}){if(options.trialDays!=null&&(!Number.isInteger(options.trialDays)||options.trialDays<1||options.trialDays>730))throw Error(`[payments/connect] trialDays must be a whole number from 1 to 730, got ${options.trialDays}`);const fee=manageDestinationSubscription.feePercentFor({platformFeePercent:options.platformFeePercent});return{...fee!=null?{application_fee_percent:fee}:{},...options.trialDays?{trial_period_days:options.trialDays}:{},...options.metadata?{metadata:options.metadata}:{}}}async function checkout(user,options,client=stripe){requireAccountId(options.account,"manageDirectSubscription.checkout");const customer=options.customer??(await connectedCustomer(user,options.account,client)).id;return await directCheckout(user,options.account,{mode:"subscription",customer,line_items:[manageDestinationSubscription.lineItem(options.price,options.quantity)],subscription_data:subscriptionData(options),success_url:options.successUrl,cancel_url:options.cancelUrl,...options.clientReferenceId?{client_reference_id:options.clientReferenceId}:{},...options.metadata?{metadata:options.metadata}:{},...options.sessionParams},client)}return{subscriptionData,checkout}})();
|
package/dist/connect/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { asAccount, connectedCustomer, directCheckout, directCheckoutPaymentData, directCheckoutSubscriptionData, directPaymentIntentParams, directSubscriptionParams, manageDirectSubscription } from './direct';
|
|
1
2
|
import { checkoutLineItemsTotal, destinationCheckoutPaymentData, destinationCheckoutSubscriptionData, destinationFeeCents, destinationFeePercent, destinationPaymentIntentParams, destinationSubscriptionParams, splitFee } from './destination';
|
|
2
3
|
import { connectRefund, connectRefundParams, isDestinationCharge } from './refund';
|
|
3
4
|
import { manageConnectedAccount } from './account';
|
|
@@ -25,6 +26,14 @@ export declare const connect: {
|
|
|
25
26
|
subscriptionParams: typeof destinationSubscriptionParams;
|
|
26
27
|
lineItemsTotal: typeof checkoutLineItemsTotal;
|
|
27
28
|
splitFee: typeof splitFee;
|
|
29
|
+
asAccount: typeof asAccount;
|
|
30
|
+
customer: typeof connectedCustomer;
|
|
31
|
+
directCheckout: typeof directCheckout;
|
|
32
|
+
directPaymentIntentParams: typeof directPaymentIntentParams;
|
|
33
|
+
directCheckoutPaymentData: typeof directCheckoutPaymentData;
|
|
34
|
+
directCheckoutSubscriptionData: typeof directCheckoutSubscriptionData;
|
|
35
|
+
directSubscriptionParams: typeof directSubscriptionParams;
|
|
36
|
+
directSubscriptionCheckout: typeof manageDirectSubscription.checkout;
|
|
28
37
|
refund: typeof connectRefund;
|
|
29
38
|
refundParams: typeof connectRefundParams;
|
|
30
39
|
isDestinationCharge: typeof isDestinationCharge;
|
|
@@ -46,6 +55,7 @@ export declare const connect: {
|
|
|
46
55
|
account: typeof manageConnectedAccount;
|
|
47
56
|
charge: typeof manageDestinationCharge;
|
|
48
57
|
subscription: typeof manageDestinationSubscription;
|
|
58
|
+
directSubscription: typeof manageDirectSubscription;
|
|
49
59
|
transfer: typeof manageTransfer;
|
|
50
60
|
payout: typeof managePayout
|
|
51
61
|
};
|
|
@@ -63,6 +73,7 @@ export declare const connect: {
|
|
|
63
73
|
export * from './account';
|
|
64
74
|
export * from './charge';
|
|
65
75
|
export * from './destination';
|
|
76
|
+
export * from './direct';
|
|
66
77
|
export * from './payout';
|
|
67
78
|
export * from './refund';
|
|
68
79
|
export * from './subscription';
|
package/dist/connect/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./account";export*from"./charge";export*from"./destination";export*from"./payout";export*from"./refund";export*from"./subscription";export*from"./transfer";export*from"./webhook";import{manageConnectedAccount}from"./account";import{manageDestinationCharge}from"./charge";import{checkoutLineItemsTotal,destinationCheckoutPaymentData,destinationCheckoutSubscriptionData,destinationFeeCents,destinationFeePercent,destinationPaymentIntentParams,destinationSubscriptionParams,splitFee}from"./destination";import{managePayout}from"./payout";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,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,transfer:manageTransfer,payout:managePayout};
|
|
1
|
+
export*from"./account";export*from"./charge";export*from"./destination";export*from"./direct";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{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,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};
|
package/dist/connect/refund.d.ts
CHANGED
package/dist/connect/refund.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{stripe}from"../drivers/stripe";import{freshIdempotencyKey}from"../idempotency";function expandedCharge(source){return source.latest_charge&&typeof source.latest_charge==="object"?source.latest_charge:null}export function isDestinationCharge(source){if(!source)return!1;const charge=expandedCharge(source);return Boolean(source.transfer_data?.destination||source.transfer||charge?.transfer_data?.destination||charge?.transfer)}export function tookApplicationFee(source){if(!source)return!1;const charge=expandedCharge(source);return Boolean((source.application_fee_amount??0)>0||source.application_fee||(charge?.application_fee_amount??0)>0||charge?.application_fee)}export function connectRefundParams(source,options={}){if(!source?.id||typeof source.id!=="string")throw Error("[payments/connect] connectRefundParams needs the PaymentIntent or Charge to refund");if(options.amount!=null&&(!Number.isSafeInteger(options.amount)||options.amount<=0))throw Error(`[payments/connect] a refund amount is a positive whole number of minor units, got ${options.amount}`);const isIntent=source.object==="payment_intent"||source.id.startsWith("pi_"),destination=isDestinationCharge(source),reverse=destination&&(options.reverseTransfer??!0),refundFee=destination&&tookApplicationFee(source)&&(options.refundApplicationFee??!0);return{...isIntent?{payment_intent:source.id}:{charge:source.id},...options.amount!=null?{amount:options.amount}:{},...options.reason?{reason:options.reason}:{},...options.metadata?{metadata:options.metadata}:{},...reverse?{reverse_transfer:!0}:{},...refundFee?{refund_application_fee:!0}:{}}}export async function connectRefund(paymentId,options={}){if(!paymentId||typeof paymentId!=="string")throw Error("[payments/connect] connectRefund needs a PaymentIntent or Charge id");const{idempotencyKey,client=stripe,...refundOptions}=options,source=paymentId.startsWith("pi_")?await client.paymentIntents.retrieve(paymentId,{expand:["latest_charge"]}):await client.charges.retrieve(paymentId);return await client.refunds.create(connectRefundParams(source,refundOptions),{idempotencyKey:idempotencyKey??freshIdempotencyKey("connect.refund",paymentId,refundOptions.amount??"full")})}
|
|
1
|
+
import{stripe}from"../drivers/stripe";import{freshIdempotencyKey}from"../idempotency";function expandedCharge(source){return source.latest_charge&&typeof source.latest_charge==="object"?source.latest_charge:null}export function isDestinationCharge(source){if(!source)return!1;const charge=expandedCharge(source);return Boolean(source.transfer_data?.destination||source.transfer||charge?.transfer_data?.destination||charge?.transfer)}export function tookApplicationFee(source){if(!source)return!1;const charge=expandedCharge(source);return Boolean((source.application_fee_amount??0)>0||source.application_fee||(charge?.application_fee_amount??0)>0||charge?.application_fee)}export function connectRefundParams(source,options={}){if(!source?.id||typeof source.id!=="string")throw Error("[payments/connect] connectRefundParams needs the PaymentIntent or Charge to refund");if(options.amount!=null&&(!Number.isSafeInteger(options.amount)||options.amount<=0))throw Error(`[payments/connect] a refund amount is a positive whole number of minor units, got ${options.amount}`);const isIntent=source.object==="payment_intent"||source.id.startsWith("pi_"),destination=isDestinationCharge(source),reverse=destination&&(options.reverseTransfer??!0),refundFee=(destination||Boolean(options.account))&&tookApplicationFee(source)&&(options.refundApplicationFee??!0);return{...isIntent?{payment_intent:source.id}:{charge:source.id},...options.amount!=null?{amount:options.amount}:{},...options.reason?{reason:options.reason}:{},...options.metadata?{metadata:options.metadata}:{},...reverse?{reverse_transfer:!0}:{},...refundFee?{refund_application_fee:!0}:{}}}export async function connectRefund(paymentId,options={}){if(!paymentId||typeof paymentId!=="string")throw Error("[payments/connect] connectRefund needs a PaymentIntent or Charge id");const{idempotencyKey,client=stripe,...refundOptions}=options,onAccount=refundOptions.account?{stripeAccount:refundOptions.account}:{},source=paymentId.startsWith("pi_")?await client.paymentIntents.retrieve(paymentId,{expand:["latest_charge"]},onAccount):await client.charges.retrieve(paymentId,{},onAccount);return await client.refunds.create(connectRefundParams(source,refundOptions),{...onAccount,idempotencyKey:idempotencyKey??freshIdempotencyKey("connect.refund",paymentId,refundOptions.amount??"full")})}
|
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.269",
|
|
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.269",
|
|
64
|
+
"@stacksjs/database": "0.75.269",
|
|
65
|
+
"@stacksjs/error-handling": "0.75.269",
|
|
66
|
+
"@stacksjs/logging": "0.75.269",
|
|
67
|
+
"@stacksjs/orm": "0.75.269",
|
|
68
|
+
"@stacksjs/types": "0.75.269"
|
|
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.269",
|
|
84
84
|
"@stripe/stripe-js": "^10.0.0",
|
|
85
85
|
"better-dx": "^0.2.24",
|
|
86
86
|
"stripe": "23.0.0"
|