@stacksjs/payments 0.75.19 → 0.75.21
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/index.d.ts +1 -0
- package/dist/billable/index.js +1 -1
- package/dist/billable/portal.d.ts +41 -0
- package/dist/billable/portal.js +1 -0
- package/dist/billable/setup-products.d.ts +2 -2
- package/dist/billable/setup-products.js +1 -1
- package/dist/payment.d.ts +7 -0
- package/dist/payment.js +1 -1
- package/package.json +8 -7
package/dist/billable/index.d.ts
CHANGED
package/dist/billable/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./billing-enabled";export*from"./charge";export*from"./checkout";export*from"./customer";export*from"./intent";export*from"./invoice";export*from"./payment-method";export*from"./price";export*from"./product";export*from"./setup-products";export*from"./subscription";export*from"./transaction";export*from"./webhook";
|
|
1
|
+
export*from"./billing-enabled";export*from"./charge";export*from"./checkout";export*from"./customer";export*from"./intent";export*from"./invoice";export*from"./payment-method";export*from"./price";export*from"./portal";export*from"./product";export*from"./setup-products";export*from"./subscription";export*from"./transaction";export*from"./webhook";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { SaasPortal } from '@stacksjs/types';
|
|
2
|
+
import type Stripe from 'stripe';
|
|
3
|
+
/**
|
|
4
|
+
* The Stripe customer portal: a Stripe-hosted page where a customer cancels or
|
|
5
|
+
* changes a subscription, updates the card on file and downloads invoices.
|
|
6
|
+
*
|
|
7
|
+
* `buddy stripe:setup` keeps one portal configuration in the account to match
|
|
8
|
+
* `config/saas.ts` (`portal`), tagged with this app's name so it is found again
|
|
9
|
+
* among any others the account holds - one Stripe account commonly serves
|
|
10
|
+
* several apps. A session then uses it, or the account's default when the app
|
|
11
|
+
* declares no portal.
|
|
12
|
+
*/
|
|
13
|
+
/** The metadata that marks a portal configuration as this app's. */
|
|
14
|
+
export declare function managedPortalTag(appName?: string): Record<string, string>;
|
|
15
|
+
/** What `config/saas.ts` asks the portal to allow, as Stripe configuration params. */
|
|
16
|
+
export declare function portalConfigurationParams(portal: SaasPortal, appName?: string): Stripe.BillingPortal.ConfigurationCreateParams;
|
|
17
|
+
/**
|
|
18
|
+
* Whether a live configuration already allows exactly what the params ask for,
|
|
19
|
+
* so a re-run of `stripe:setup` writes nothing.
|
|
20
|
+
*/
|
|
21
|
+
export declare function portalConfigurationMatches(live: Stripe.BillingPortal.Configuration, params: Stripe.BillingPortal.ConfigurationCreateParams): boolean;
|
|
22
|
+
/** This app's portal configuration, if `stripe:setup` has made one. */
|
|
23
|
+
export declare function findManagedPortalConfiguration(appName?: string, client?: Pick<Stripe, 'billingPortal'>): Promise<Stripe.BillingPortal.Configuration | undefined>;
|
|
24
|
+
/**
|
|
25
|
+
* @defaultValue
|
|
26
|
+
* ```ts
|
|
27
|
+
* {
|
|
28
|
+
* createSession: (customerId: string, options?: BillingPortalOptions) => Promise<Stripe.BillingPortal.Session>
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare const manageBillingPortal: {
|
|
33
|
+
/**
|
|
34
|
+
* A one-time link into the portal for `customerId`. Send the customer to
|
|
35
|
+
* `session.url`; it expires after a few minutes, so create one per visit.
|
|
36
|
+
*/
|
|
37
|
+
createSession: (customerId: string, options?: BillingPortalOptions) => Promise<Stripe.BillingPortal.Session>
|
|
38
|
+
};
|
|
39
|
+
export declare interface BillingPortalOptions {
|
|
40
|
+
returnUrl?: string
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{app}from"@stacksjs/config";import{stripe}from"../drivers/stripe";export function managedPortalTag(appName=app?.name||"stacks"){return{managed_by:"stacks",stacks_app:appName}}export function portalConfigurationParams(portal,appName){const emailUpdate=portal.emailUpdate!==!1,cancel=portal.cancel??"at_period_end",businessProfile={};if(portal.headline)businessProfile.headline=portal.headline;if(portal.privacyPolicyUrl)businessProfile.privacy_policy_url=portal.privacyPolicyUrl;if(portal.termsOfServiceUrl)businessProfile.terms_of_service_url=portal.termsOfServiceUrl;return{features:{customer_update:emailUpdate?{enabled:!0,allowed_updates:["email"]}:{enabled:!1},invoice_history:{enabled:portal.invoiceHistory!==!1},payment_method_update:{enabled:portal.paymentMethodUpdate!==!1},subscription_cancel:cancel===!1?{enabled:!1}:{enabled:!0,mode:cancel}},...Object.keys(businessProfile).length?{business_profile:businessProfile}:{},...portal.returnUrl?{default_return_url:portal.returnUrl}:{},metadata:managedPortalTag(appName)}}export function portalConfigurationMatches(live,params){const want=params.features,have=live.features,cancelWanted=want.subscription_cancel;return have.invoice_history.enabled===want.invoice_history?.enabled&&have.payment_method_update.enabled===want.payment_method_update?.enabled&&have.customer_update.enabled===want.customer_update?.enabled&&have.subscription_cancel.enabled===cancelWanted?.enabled&&(!cancelWanted?.enabled||have.subscription_cancel.mode===cancelWanted.mode)&&(live.default_return_url??void 0)===(params.default_return_url||void 0)&&(live.business_profile.headline??void 0)===(params.business_profile?.headline||void 0)}export async function findManagedPortalConfiguration(appName,client=stripe){const tag=managedPortalTag(appName);for await(const configuration of client.billingPortal.configurations.list({active:!0,limit:100}))if(configuration.metadata?.managed_by===tag.managed_by&&configuration.metadata?.stacks_app===tag.stacks_app)return configuration;return}export const manageBillingPortal={async createSession(customerId,options={}){const configuration=await findManagedPortalConfiguration();return stripe.billingPortal.sessions.create({customer:customerId,...options.returnUrl?{return_url:options.returnUrl}:{},...configuration?{configuration:configuration.id}:{}})}};
|
|
@@ -22,8 +22,8 @@ export declare interface SetupProductsOptions {
|
|
|
22
22
|
}
|
|
23
23
|
/** One line of the plan of record, in the order it would be applied. */
|
|
24
24
|
export declare interface SetupProductAction {
|
|
25
|
-
kind: 'product' | 'price'
|
|
26
|
-
verb: 'create' | 'reuse' | 'replace'
|
|
25
|
+
kind: 'product' | 'price' | 'coupon' | 'promotion-code' | 'portal'
|
|
26
|
+
verb: 'create' | 'reuse' | 'replace' | 'update' | 'conflict'
|
|
27
27
|
target: string
|
|
28
28
|
detail?: string
|
|
29
29
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{saas}from"@stacksjs/config";import{err,ok}from"@stacksjs/error-handling";import{log}from"@stacksjs/logging";import{stripe}from"@stacksjs/payments";async function findProductByName(name){for await(const product of stripe.products.list({active:!0,limit:100}))if(product.name===name)return product;return}async function findPriceByLookupKey(lookupKey){return(await stripe.prices.list({lookup_keys:[lookupKey],active:!0,limit:1})).data[0]}function priceMatches(price,params){return price.unit_amount===params.unit_amount&&price.currency===params.currency&&price.product===params.product&&(price.recurring?.interval??void 0)===params.recurring?.interval}export async function createStripeProduct(options={}){const dryRun=options.dryRun??!1,actions=[],plans=saas.plans;try{if(plans
|
|
1
|
+
import{saas}from"@stacksjs/config";import{err,ok}from"@stacksjs/error-handling";import{log}from"@stacksjs/logging";import{stripe}from"@stacksjs/payments";import{findManagedPortalConfiguration,portalConfigurationMatches,portalConfigurationParams}from"./portal";async function findProductByName(name){for await(const product of stripe.products.list({active:!0,limit:100}))if(product.name===name)return product;return}async function findPriceByLookupKey(lookupKey){return(await stripe.prices.list({lookup_keys:[lookupKey],active:!0,limit:1})).data[0]}function priceMatches(price,params){return price.unit_amount===params.unit_amount&&price.currency===params.currency&&price.product===params.product&&(price.recurring?.interval??void 0)===params.recurring?.interval}export async function createStripeProduct(options={}){const dryRun=options.dryRun??!1,actions=[],plans=saas.plans??[],productIds=new Map;try{if(!plans.length&&!saas.coupons?.length&&!saas.portal)return ok({dryRun,actions});for(const plan of plans){const existingProduct=await findProductByName(plan.productName);let productId=existingProduct?.id;if(existingProduct)actions.push({kind:"product",verb:"reuse",target:plan.productName,detail:existingProduct.id});else{actions.push({kind:"product",verb:"create",target:plan.productName});if(!dryRun)productId=(await stripe.products.create({name:plan.productName,description:plan.description,metadata:plan.metadata})).id}if(productId)productIds.set(plan.productName,productId);for(const pricing of plan.pricing){if(!productId){actions.push({kind:"price",verb:"create",target:pricing.key});continue}const priceParams={unit_amount:pricing.price,currency:pricing.currency,product:productId,lookup_key:pricing.key};if(pricing.interval)priceParams.recurring={interval:pricing.interval};const existingPrice=await findPriceByLookupKey(pricing.key);if(existingPrice&&priceMatches(existingPrice,priceParams)){actions.push({kind:"price",verb:"reuse",target:pricing.key,detail:existingPrice.id});continue}if(existingPrice){actions.push({kind:"price",verb:"replace",target:pricing.key,detail:`${existingPrice.id} -> new price (${pricing.price} ${pricing.currency})`});priceParams.transfer_lookup_key=!0}else actions.push({kind:"price",verb:"create",target:pricing.key});if(!dryRun)await stripe.prices.create(priceParams)}}for(const coupon of saas.coupons??[])await reconcileCoupon(coupon,productIds,dryRun,actions);if(saas.portal)await reconcilePortal(dryRun,actions);return ok({dryRun,actions})}catch(error){const e=error instanceof Error?error:Error(String(error));log.error(e);return err(e)}}async function findCoupon(id){try{const coupon=await stripe.coupons.retrieve(id);return coupon.deleted?void 0:coupon}catch(error){if(error.statusCode===404||error.code==="resource_missing")return;throw error}}function promotionCouponId(promotion){const coupon=promotion.promotion?.coupon;return typeof coupon==="string"?coupon:coupon?.id}function couponMatches(live,want){return(live.percent_off??void 0)===want.percentOff&&(live.amount_off??void 0)===want.amountOff&&live.duration===want.duration&&(live.duration_in_months??void 0)===(want.duration==="repeating"?want.durationInMonths:void 0)}async function reconcileCoupon(coupon,productIds,dryRun,actions){const id=coupon.id??coupon.code;if(!id){actions.push({kind:"coupon",verb:"conflict",target:"(unnamed)",detail:"a coupon needs an id or a code"});return}const live=await findCoupon(id);if(live&&!couponMatches(live,coupon)){actions.push({kind:"coupon",verb:"conflict",target:id,detail:"exists with a different discount; coupons cannot change, so give this one a new id"});return}if(live)actions.push({kind:"coupon",verb:"reuse",target:id});else{const products=(coupon.appliesTo??[]).map((name)=>productIds.get(name)),unresolved=(coupon.appliesTo??[]).filter((_name,index)=>!products[index]);if(unresolved.length&&!dryRun){actions.push({kind:"coupon",verb:"conflict",target:id,detail:`appliesTo names no plan: ${unresolved.join(", ")}`});return}actions.push({kind:"coupon",verb:"create",target:id});if(!dryRun)await stripe.coupons.create({id,...coupon.name?{name:coupon.name}:{},...coupon.percentOff!==void 0?{percent_off:coupon.percentOff}:{},...coupon.amountOff!==void 0?{amount_off:coupon.amountOff,currency:coupon.currency??"usd"}:{},duration:coupon.duration,...coupon.duration==="repeating"&&coupon.durationInMonths?{duration_in_months:coupon.durationInMonths}:{},...coupon.maxRedemptions?{max_redemptions:coupon.maxRedemptions}:{},...products.length?{applies_to:{products}}:{}})}for(const code of coupon.codes??(coupon.code?[coupon.code]:[])){const existing=(await stripe.promotionCodes.list({code,active:!0,limit:1})).data[0];if(existing&&promotionCouponId(existing)===id){actions.push({kind:"promotion-code",verb:"reuse",target:code,detail:existing.id});continue}if(existing){actions.push({kind:"promotion-code",verb:"conflict",target:code,detail:`already belongs to coupon ${promotionCouponId(existing)}`});continue}actions.push({kind:"promotion-code",verb:"create",target:code,detail:`for ${id}`});if(!dryRun)await stripe.promotionCodes.create({promotion:{type:"coupon",coupon:id},code})}}async function reconcilePortal(dryRun,actions){const params=portalConfigurationParams(saas.portal),live=await findManagedPortalConfiguration(void 0,stripe);if(live&&portalConfigurationMatches(live,params)){actions.push({kind:"portal",verb:"reuse",target:"customer portal",detail:live.id});return}if(live){actions.push({kind:"portal",verb:"update",target:"customer portal",detail:live.id});if(!dryRun)await stripe.billingPortal.configurations.update(live.id,params);return}actions.push({kind:"portal",verb:"create",target:"customer portal"});if(!dryRun)await stripe.billingPortal.configurations.create(params)}export function formatSetupReport(report){if(!report.actions.length)return["No plans, coupons or portal are declared in config/saas.ts, so there is nothing to provision."];const verbs={reuse:"already exists",replace:"moves lookup key to a new price",update:"updates",conflict:"CONFLICT, left alone",create:"creates"};return report.actions.map((action)=>{const verb=verbs[action.verb];return` ${action.kind} "${action.target}" ${verb}${action.detail?` (${action.detail})`:""}`})}
|
package/dist/payment.d.ts
CHANGED
|
@@ -134,6 +134,12 @@ export declare function toCents(dollars: number): number;
|
|
|
134
134
|
* Convert cents to dollars
|
|
135
135
|
*/
|
|
136
136
|
export declare function toDollars(cents: number): number;
|
|
137
|
+
/**
|
|
138
|
+
* A link into the Stripe customer portal, where the customer manages their
|
|
139
|
+
* subscription, card and invoices. Takes a Stripe customer id, or a user with
|
|
140
|
+
* one. The link is single-use and short-lived: create it when they click.
|
|
141
|
+
*/
|
|
142
|
+
export declare function billingPortal(customer: string | UserModel, options?: { returnUrl?: string }): Promise<Stripe.BillingPortal.Session>;
|
|
137
143
|
// =============================================================================
|
|
138
144
|
// Payment Facade Object
|
|
139
145
|
// =============================================================================
|
|
@@ -160,6 +166,7 @@ export declare const Payment: {
|
|
|
160
166
|
createProduct: typeof createProduct;
|
|
161
167
|
getPrice: typeof getPrice;
|
|
162
168
|
listProducts: typeof listProducts;
|
|
169
|
+
billingPortal: typeof billingPortal;
|
|
163
170
|
createCoupon: typeof createCoupon;
|
|
164
171
|
createPromoCode: typeof createPromoCode;
|
|
165
172
|
validatePromoCode: typeof validatePromoCode;
|
package/dist/payment.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{stripe}from"./drivers/stripe";import{manageCharge}from"./billable/charge";import{manageCheckout}from"./billable/checkout";import{manageCustomer}from"./billable/customer";import{manageInvoice}from"./billable/invoice";import{managePaymentMethod}from"./billable/payment-method";import{managePrice}from"./billable/price";import{manageCoupon,managePriceExtended,manageProduct}from"./billable/product";import{manageSubscription}from"./billable/subscription";import{manageSetupIntent}from"./billable/intent";import{manageWebhook,onCharge,onCheckout,onInvoice,onPaymentIntent,onSubscription,processWebhook}from"./billable/webhook";import{connect}from"./connect";export async function charge(user,amount,paymentMethod,options={}){return manageCharge.charge(user,amount,paymentMethod,options)}export async function createPayment(user,amount,options={}){return manageCharge.createPayment(user,amount,options)}export async function refund(paymentIntentId,amount,options={}){return manageCharge.refund(paymentIntentId,{amount,...options})}export async function checkout(user,lineItems,options={}){return manageCheckout.create(user,{line_items:lineItems,mode:"payment",...options})}export async function subscriptionCheckout(user,priceId,options={}){return manageCheckout.create(user,{line_items:[{price:priceId,quantity:1}],mode:"subscription",...options})}export async function subscribe(user,lookupKey,options={}){return manageSubscription.create(user,"default",lookupKey,options)}export async function cancelSubscription(subscriptionId,immediately=!1){return manageSubscription.cancel(subscriptionId,{prorate:!immediately,invoice_now:immediately})}export async function hasActiveSubscription(user,type="default"){return manageSubscription.isValid(user,type)}export async function changeSubscription(user,newLookupKey,type="default"){return manageSubscription.update(user,type,newLookupKey,{})}export async function getOrCreateCustomer(user,options={}){return manageCustomer.createOrGetStripeUser(user,options)}export async function updateCustomer(user,options){return manageCustomer.updateStripeCustomer(user,options)}export async function deleteCustomer(user){return manageCustomer.deleteStripeUser(user)}export async function addPaymentMethod(user,paymentMethodId){return managePaymentMethod.addPaymentMethod(user,paymentMethodId)}export async function setDefaultPaymentMethod(user,paymentMethodId){return managePaymentMethod.setUserDefaultPayment(user,paymentMethodId)}export async function removePaymentMethod(user,paymentMethodId){return managePaymentMethod.deletePaymentMethod(user,paymentMethodId)}export async function createSetupIntent(user,options={}){return manageSetupIntent.create(user,options)}export async function getInvoices(user){return manageInvoice.list(user)}export async function createInvoice(customerId,options={}){return stripe.invoices.create({customer:customerId,...options})}export async function payInvoice(invoiceId){return stripe.invoices.pay(invoiceId)}export async function createProduct(name,price,options={}){const{currency="usd",interval,description,metadata}=options,priceParams={unit_amount:price,currency};if(interval)priceParams.recurring={interval};return manageProduct.createWithPrice({name,description,metadata},priceParams)}export async function getPrice(lookupKey){return managePrice.retrieveByLookupKey(lookupKey)}export async function listProducts(options={}){return manageProduct.list(options)}export async function createCoupon(options){const params={duration:options.duration||"once"};if(options.percentOff)params.percent_off=options.percentOff;else if(options.amountOff){params.amount_off=options.amountOff;params.currency=options.currency||"usd"}if(options.name)params.name=options.name;if(options.durationInMonths)params.duration_in_months=options.durationInMonths;if(options.maxRedemptions)params.max_redemptions=options.maxRedemptions;return manageCoupon.create(params)}export async function createPromoCode(couponId,code,options={}){return manageCoupon.createPromotionCode({promotion:{type:"coupon",coupon:couponId},code,...options})}export async function validatePromoCode(code){return manageCoupon.retrievePromotionCode(code)}export function formatAmount(amount,currency){const cfg=globalThis.config||{},ccy=(currency||cfg.payment?.currency||cfg.billing?.currency||process.env.STRIPE_CURRENCY||"usd").toLowerCase(),locale=cfg.app?.locale||"en-US";return new Intl.NumberFormat(locale,{style:"currency",currency:ccy.toUpperCase()}).format(amount/100)}export function toCents(dollars){return Math.round(dollars*100)}export function toDollars(cents){return cents/100}export const Payment={charge,createPayment,refund,checkout,subscriptionCheckout,subscribe,cancelSubscription,hasActiveSubscription,changeSubscription,getOrCreateCustomer,updateCustomer,deleteCustomer,addPaymentMethod,setDefaultPaymentMethod,removePaymentMethod,createSetupIntent,getInvoices,createInvoice,payInvoice,createProduct,getPrice,listProducts,createCoupon,createPromoCode,validatePromoCode,formatAmount,toCents,toDollars,webhook:manageWebhook,onPaymentIntent,onSubscription,onInvoice,onCheckout,onCharge,processWebhook,connect,stripe,customer:manageCustomer,subscription:manageSubscription,invoice:manageInvoice,paymentMethod:managePaymentMethod,product:manageProduct,price:managePriceExtended,coupon:manageCoupon};export default Payment;
|
|
1
|
+
import{stripe}from"./drivers/stripe";import{manageCharge}from"./billable/charge";import{manageCheckout}from"./billable/checkout";import{manageCustomer}from"./billable/customer";import{manageInvoice}from"./billable/invoice";import{managePaymentMethod}from"./billable/payment-method";import{managePrice}from"./billable/price";import{manageBillingPortal}from"./billable/portal";import{manageCoupon,managePriceExtended,manageProduct}from"./billable/product";import{manageSubscription}from"./billable/subscription";import{manageSetupIntent}from"./billable/intent";import{manageWebhook,onCharge,onCheckout,onInvoice,onPaymentIntent,onSubscription,processWebhook}from"./billable/webhook";import{connect}from"./connect";export async function charge(user,amount,paymentMethod,options={}){return manageCharge.charge(user,amount,paymentMethod,options)}export async function createPayment(user,amount,options={}){return manageCharge.createPayment(user,amount,options)}export async function refund(paymentIntentId,amount,options={}){return manageCharge.refund(paymentIntentId,{amount,...options})}export async function checkout(user,lineItems,options={}){return manageCheckout.create(user,{line_items:lineItems,mode:"payment",...options})}export async function subscriptionCheckout(user,priceId,options={}){return manageCheckout.create(user,{line_items:[{price:priceId,quantity:1}],mode:"subscription",...options})}export async function subscribe(user,lookupKey,options={}){return manageSubscription.create(user,"default",lookupKey,options)}export async function cancelSubscription(subscriptionId,immediately=!1){return manageSubscription.cancel(subscriptionId,{prorate:!immediately,invoice_now:immediately})}export async function hasActiveSubscription(user,type="default"){return manageSubscription.isValid(user,type)}export async function changeSubscription(user,newLookupKey,type="default"){return manageSubscription.update(user,type,newLookupKey,{})}export async function getOrCreateCustomer(user,options={}){return manageCustomer.createOrGetStripeUser(user,options)}export async function updateCustomer(user,options){return manageCustomer.updateStripeCustomer(user,options)}export async function deleteCustomer(user){return manageCustomer.deleteStripeUser(user)}export async function addPaymentMethod(user,paymentMethodId){return managePaymentMethod.addPaymentMethod(user,paymentMethodId)}export async function setDefaultPaymentMethod(user,paymentMethodId){return managePaymentMethod.setUserDefaultPayment(user,paymentMethodId)}export async function removePaymentMethod(user,paymentMethodId){return managePaymentMethod.deletePaymentMethod(user,paymentMethodId)}export async function createSetupIntent(user,options={}){return manageSetupIntent.create(user,options)}export async function getInvoices(user){return manageInvoice.list(user)}export async function createInvoice(customerId,options={}){return stripe.invoices.create({customer:customerId,...options})}export async function payInvoice(invoiceId){return stripe.invoices.pay(invoiceId)}export async function createProduct(name,price,options={}){const{currency="usd",interval,description,metadata}=options,priceParams={unit_amount:price,currency};if(interval)priceParams.recurring={interval};return manageProduct.createWithPrice({name,description,metadata},priceParams)}export async function getPrice(lookupKey){return managePrice.retrieveByLookupKey(lookupKey)}export async function listProducts(options={}){return manageProduct.list(options)}export async function createCoupon(options){const params={duration:options.duration||"once"};if(options.percentOff)params.percent_off=options.percentOff;else if(options.amountOff){params.amount_off=options.amountOff;params.currency=options.currency||"usd"}if(options.name)params.name=options.name;if(options.durationInMonths)params.duration_in_months=options.durationInMonths;if(options.maxRedemptions)params.max_redemptions=options.maxRedemptions;return manageCoupon.create(params)}export async function createPromoCode(couponId,code,options={}){return manageCoupon.createPromotionCode({promotion:{type:"coupon",coupon:couponId},code,...options})}export async function validatePromoCode(code){return manageCoupon.retrievePromotionCode(code)}export function formatAmount(amount,currency){const cfg=globalThis.config||{},ccy=(currency||cfg.payment?.currency||cfg.billing?.currency||process.env.STRIPE_CURRENCY||"usd").toLowerCase(),locale=cfg.app?.locale||"en-US";return new Intl.NumberFormat(locale,{style:"currency",currency:ccy.toUpperCase()}).format(amount/100)}export function toCents(dollars){return Math.round(dollars*100)}export function toDollars(cents){return cents/100}export async function billingPortal(customer,options={}){const customerId=typeof customer==="string"?customer:customer.stripe_id;if(!customerId)throw Error("billingPortal needs a Stripe customer: this user has no stripe_id yet.");return manageBillingPortal.createSession(customerId,options)}export const Payment={charge,createPayment,refund,checkout,subscriptionCheckout,subscribe,cancelSubscription,hasActiveSubscription,changeSubscription,getOrCreateCustomer,updateCustomer,deleteCustomer,addPaymentMethod,setDefaultPaymentMethod,removePaymentMethod,createSetupIntent,getInvoices,createInvoice,payInvoice,createProduct,getPrice,listProducts,billingPortal,createCoupon,createPromoCode,validatePromoCode,formatAmount,toCents,toDollars,webhook:manageWebhook,onPaymentIntent,onSubscription,onInvoice,onCheckout,onCharge,processWebhook,connect,stripe,customer:manageCustomer,subscription:manageSubscription,invoice:manageInvoice,paymentMethod:managePaymentMethod,product:manageProduct,price:managePriceExtended,coupon:manageCoupon};export default Payment;
|
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.21",
|
|
6
6
|
"description": "The Stacks payments package. Currently supporting Stripe.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -60,11 +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.
|
|
63
|
+
"@stacksjs/config": "0.75.21",
|
|
64
|
+
"@stacksjs/database": "0.75.21",
|
|
65
|
+
"@stacksjs/error-handling": "0.75.21",
|
|
66
|
+
"@stacksjs/logging": "0.75.21",
|
|
67
|
+
"@stacksjs/orm": "0.75.21",
|
|
68
|
+
"@stacksjs/types": "0.75.21"
|
|
68
69
|
},
|
|
69
70
|
"peerDependencies": {
|
|
70
71
|
"@stripe/stripe-js": "^9.10.0",
|
|
@@ -79,7 +80,7 @@
|
|
|
79
80
|
}
|
|
80
81
|
},
|
|
81
82
|
"devDependencies": {
|
|
82
|
-
"@stacksjs/utils": "0.75.
|
|
83
|
+
"@stacksjs/utils": "0.75.21",
|
|
83
84
|
"@stripe/stripe-js": "^9.10.0",
|
|
84
85
|
"better-dx": "^0.2.24",
|
|
85
86
|
"stripe": "22.3.2"
|