@stacksjs/payments 0.72.56 → 0.72.60

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.
@@ -10,20 +10,38 @@ export declare function registerWebhookHandlers(handlerMap: Record<WebhookEventT
10
10
  /**
11
11
  * Construct and verify a webhook event from the raw request.
12
12
  *
13
+ * Async on every runtime, deliberately. Bun resolves the Stripe SDK's crypto
14
+ * provider to WebCrypto's `SubtleCrypto`, which is async-only, so the SDK's
15
+ * synchronous `constructEvent` throws "SubtleCryptoProvider cannot be used in a
16
+ * synchronous context" there. This package used to wrap that sync call under
17
+ * this name and offer the working one as `constructEventAsync`, which made the
18
+ * shorter and more obvious export the one that could never work on the
19
+ * framework's own default runtime.
20
+ *
21
+ * It failed where it hurt most. Verification lives inside the caller's
22
+ * try/catch, so the throw surfaced as a 401 on every genuine Stripe delivery:
23
+ * Stripe retried, every retry 401'd, and local subscription state silently
24
+ * stopped tracking reality. Tests that call the handler directly rather than
25
+ * POSTing a signed body never touch verification at all, so nothing caught it
26
+ * (stacksjs/stacks#2355).
27
+ *
28
+ * There is one name now, and it works on Node and Bun alike. A caller that
29
+ * genuinely needs the synchronous path on Node can still reach
30
+ * `stripe.webhooks.constructEvent` through the exported client.
31
+ *
13
32
  * `tolerance` (in seconds) controls how much clock skew between Stripe and
14
33
  * this server is acceptable before signatures are rejected. Stripe's SDK
15
34
  * default is 300s; tightening this is recommended in production but the
16
35
  * previous code dropped the value entirely, so a configured tolerance was
17
36
  * silently ignored.
18
37
  */
19
- export declare function constructEvent(payload: string | Buffer, signature: string, secret: string, tolerance?: number): Stripe.Event;
38
+ export declare function constructEvent(payload: string | Buffer, signature: string, secret: string, tolerance?: number): Promise<Stripe.Event>;
20
39
  /**
21
- * Async variant of {@link constructEvent}. Some runtimes (notably Bun) resolve
22
- * the Stripe SDK's crypto provider to WebCrypto's `SubtleCrypto`, which is
23
- * async-only — the synchronous `constructEvent` then throws
24
- * "SubtleCryptoProvider cannot be used in a synchronous context". Verifying via
25
- * `constructEventAsync` works across Node and Bun, so webhook processing uses
26
- * this path.
40
+ * Alias of {@link constructEvent}, kept so callers that adopted this name while
41
+ * `constructEvent` could not work on Bun keep compiling unchanged.
42
+ *
43
+ * @deprecated Use {@link constructEvent}. It is async on every runtime as of
44
+ * stacksjs/stacks#2355, so the two are the same function and one name is enough.
27
45
  */
28
46
  export declare function constructEventAsync(payload: string | Buffer, signature: string, secret: string, tolerance?: number): Promise<Stripe.Event>;
29
47
  /**
@@ -1 +1 @@
1
- import{stripe}from"../drivers/stripe";const handlers=new Map;export function onWebhookEvent(eventType,handler){const existing=handlers.get(eventType)||[];existing.push(handler);handlers.set(eventType,existing)}export function registerWebhookHandlers(handlerMap){for(const[eventType,handler]of Object.entries(handlerMap))onWebhookEvent(eventType,handler)}export function constructEvent(payload,signature,secret,tolerance){if(tolerance!=null&&Number.isFinite(tolerance)&&tolerance>0)return stripe.webhooks.constructEvent(payload,signature,secret,tolerance);return stripe.webhooks.constructEvent(payload,signature,secret)}export async function constructEventAsync(payload,signature,secret,tolerance){if(tolerance!=null&&Number.isFinite(tolerance)&&tolerance>0)return await stripe.webhooks.constructEventAsync(payload,signature,secret,tolerance);return await stripe.webhooks.constructEventAsync(payload,signature,secret)}export async function handleWebhookEvent(event){const eventHandlers=handlers.get(event.type)||[];if(eventHandlers.length===0)return{handled:!1,eventType:event.type};const errors=[];for(const handler of eventHandlers)try{await handler(event)}catch(error){errors.push(error instanceof Error?error.message:String(error))}return{handled:!0,eventType:event.type,...errors.length>0?{errors}:{}}}export async function processWebhook(payload,signature,config){try{const event=await constructEventAsync(payload,signature,config.secret,config.tolerance),result=await handleWebhookEvent(event);if(result.errors&&result.errors.length>0)return{success:!1,eventType:result.eventType,error:result.errors.join("; ")};return{success:!0,eventType:result.eventType}}catch(error){return{success:!1,error:error instanceof Error?error.message:"Unknown error"}}}export function onPaymentIntent(handlers){if(handlers.succeeded)onWebhookEvent("payment_intent.succeeded",handlers.succeeded);if(handlers.failed)onWebhookEvent("payment_intent.payment_failed",handlers.failed);if(handlers.created)onWebhookEvent("payment_intent.created",handlers.created);if(handlers.canceled)onWebhookEvent("payment_intent.canceled",handlers.canceled)}export function onSubscription(handlers){if(handlers.created)onWebhookEvent("customer.subscription.created",handlers.created);if(handlers.updated)onWebhookEvent("customer.subscription.updated",handlers.updated);if(handlers.deleted)onWebhookEvent("customer.subscription.deleted",handlers.deleted);if(handlers.trialWillEnd)onWebhookEvent("customer.subscription.trial_will_end",handlers.trialWillEnd)}export function onInvoice(handlers){if(handlers.paid)onWebhookEvent("invoice.paid",handlers.paid);if(handlers.paymentFailed)onWebhookEvent("invoice.payment_failed",handlers.paymentFailed);if(handlers.created)onWebhookEvent("invoice.created",handlers.created);if(handlers.finalized)onWebhookEvent("invoice.finalized",handlers.finalized)}export function onCheckout(handlers){if(handlers.completed)onWebhookEvent("checkout.session.completed",handlers.completed);if(handlers.expired)onWebhookEvent("checkout.session.expired",handlers.expired)}export function onCharge(handlers){if(handlers.succeeded)onWebhookEvent("charge.succeeded",handlers.succeeded);if(handlers.failed)onWebhookEvent("charge.failed",handlers.failed);if(handlers.refunded)onWebhookEvent("charge.refunded",handlers.refunded);if(handlers.disputed)onWebhookEvent("charge.dispute.created",handlers.disputed)}export function getPaymentIntent(event){if(event.type.startsWith("payment_intent."))return event.data.object;return null}export function getSubscription(event){if(event.type.startsWith("customer.subscription."))return event.data.object;return null}export function getInvoice(event){if(event.type.startsWith("invoice."))return event.data.object;return null}export function getCheckoutSession(event){if(event.type.startsWith("checkout.session."))return event.data.object;return null}export function getCharge(event){if(event.type.startsWith("charge."))return event.data.object;return null}export function getCustomer(event){if(event.type.startsWith("customer.")&&!event.type.includes("subscription"))return event.data.object;return null}export const manageWebhook={onWebhookEvent,registerWebhookHandlers,constructEvent,constructEventAsync,handleWebhookEvent,processWebhook,onPaymentIntent,onSubscription,onInvoice,onCheckout,onCharge,getPaymentIntent,getSubscription,getInvoice,getCheckoutSession,getCharge,getCustomer};
1
+ import{stripe}from"../drivers/stripe";const handlers=new Map;export function onWebhookEvent(eventType,handler){const existing=handlers.get(eventType)||[];existing.push(handler);handlers.set(eventType,existing)}export function registerWebhookHandlers(handlerMap){for(const[eventType,handler]of Object.entries(handlerMap))onWebhookEvent(eventType,handler)}export async function constructEvent(payload,signature,secret,tolerance){if(tolerance!=null&&Number.isFinite(tolerance)&&tolerance>0)return await stripe.webhooks.constructEventAsync(payload,signature,secret,tolerance);return await stripe.webhooks.constructEventAsync(payload,signature,secret)}export async function constructEventAsync(payload,signature,secret,tolerance){return await constructEvent(payload,signature,secret,tolerance)}export async function handleWebhookEvent(event){const eventHandlers=handlers.get(event.type)||[];if(eventHandlers.length===0)return{handled:!1,eventType:event.type};const errors=[];for(const handler of eventHandlers)try{await handler(event)}catch(error){errors.push(error instanceof Error?error.message:String(error))}return{handled:!0,eventType:event.type,...errors.length>0?{errors}:{}}}export async function processWebhook(payload,signature,config){try{const event=await constructEventAsync(payload,signature,config.secret,config.tolerance),result=await handleWebhookEvent(event);if(result.errors&&result.errors.length>0)return{success:!1,eventType:result.eventType,error:result.errors.join("; ")};return{success:!0,eventType:result.eventType}}catch(error){return{success:!1,error:error instanceof Error?error.message:"Unknown error"}}}export function onPaymentIntent(handlers){if(handlers.succeeded)onWebhookEvent("payment_intent.succeeded",handlers.succeeded);if(handlers.failed)onWebhookEvent("payment_intent.payment_failed",handlers.failed);if(handlers.created)onWebhookEvent("payment_intent.created",handlers.created);if(handlers.canceled)onWebhookEvent("payment_intent.canceled",handlers.canceled)}export function onSubscription(handlers){if(handlers.created)onWebhookEvent("customer.subscription.created",handlers.created);if(handlers.updated)onWebhookEvent("customer.subscription.updated",handlers.updated);if(handlers.deleted)onWebhookEvent("customer.subscription.deleted",handlers.deleted);if(handlers.trialWillEnd)onWebhookEvent("customer.subscription.trial_will_end",handlers.trialWillEnd)}export function onInvoice(handlers){if(handlers.paid)onWebhookEvent("invoice.paid",handlers.paid);if(handlers.paymentFailed)onWebhookEvent("invoice.payment_failed",handlers.paymentFailed);if(handlers.created)onWebhookEvent("invoice.created",handlers.created);if(handlers.finalized)onWebhookEvent("invoice.finalized",handlers.finalized)}export function onCheckout(handlers){if(handlers.completed)onWebhookEvent("checkout.session.completed",handlers.completed);if(handlers.expired)onWebhookEvent("checkout.session.expired",handlers.expired)}export function onCharge(handlers){if(handlers.succeeded)onWebhookEvent("charge.succeeded",handlers.succeeded);if(handlers.failed)onWebhookEvent("charge.failed",handlers.failed);if(handlers.refunded)onWebhookEvent("charge.refunded",handlers.refunded);if(handlers.disputed)onWebhookEvent("charge.dispute.created",handlers.disputed)}export function getPaymentIntent(event){if(event.type.startsWith("payment_intent."))return event.data.object;return null}export function getSubscription(event){if(event.type.startsWith("customer.subscription."))return event.data.object;return null}export function getInvoice(event){if(event.type.startsWith("invoice."))return event.data.object;return null}export function getCheckoutSession(event){if(event.type.startsWith("checkout.session."))return event.data.object;return null}export function getCharge(event){if(event.type.startsWith("charge."))return event.data.object;return null}export function getCustomer(event){if(event.type.startsWith("customer.")&&!event.type.includes("subscription"))return event.data.object;return null}export const manageWebhook={onWebhookEvent,registerWebhookHandlers,constructEvent,constructEventAsync,handleWebhookEvent,processWebhook,onPaymentIntent,onSubscription,onInvoice,onCheckout,onCharge,getPaymentIntent,getSubscription,getInvoice,getCheckoutSession,getCharge,getCustomer};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/payments",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.72.56",
5
+ "version": "0.72.60",
6
6
  "description": "The Stacks payments package. Currently supporting Stripe.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -72,9 +72,9 @@
72
72
  }
73
73
  },
74
74
  "devDependencies": {
75
- "@stacksjs/config": "0.72.56",
75
+ "@stacksjs/config": "0.72.60",
76
76
  "better-dx": "^0.2.24",
77
- "@stacksjs/utils": "0.72.56",
77
+ "@stacksjs/utils": "0.72.60",
78
78
  "@stripe/stripe-js": "^9.10.0",
79
79
  "stripe": "22.3.2"
80
80
  }