@fantastic.dev/better-stripe 0.6.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -16
- package/README.md +130 -90
- package/dist/client/billing/checkout.d.ts +1 -1
- package/dist/client/billing/checkout.d.ts.map +1 -1
- package/dist/client/billing/checkout.js +7 -2
- package/dist/client/billing/checkout.js.map +1 -1
- package/dist/client/connect/paymentMethods.d.ts.map +1 -1
- package/dist/client/connect/paymentMethods.js.map +1 -1
- package/dist/client/connect/refundActor.d.ts.map +1 -1
- package/dist/client/connect/refundActor.js.map +1 -1
- package/dist/client/connect/refunds.d.ts.map +1 -1
- package/dist/client/connect/refunds.js.map +1 -1
- package/dist/client/connect/transfers.d.ts.map +1 -1
- package/dist/client/connect/transfers.js +15 -4
- package/dist/client/connect/transfers.js.map +1 -1
- package/dist/client/core/accountDefaults.d.ts +6 -0
- package/dist/client/core/accountDefaults.d.ts.map +1 -0
- package/dist/client/core/accountDefaults.js +15 -0
- package/dist/client/core/accountDefaults.js.map +1 -0
- package/dist/client/core/accounts.d.ts +1 -5
- package/dist/client/core/accounts.d.ts.map +1 -1
- package/dist/client/core/accounts.js +2 -14
- package/dist/client/core/accounts.js.map +1 -1
- package/dist/client/core/fees.d.ts.map +1 -1
- package/dist/client/core/fees.js +7 -2
- package/dist/client/core/fees.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/products/prices.d.ts.map +1 -1
- package/dist/client/products/prices.js.map +1 -1
- package/dist/client/products/products.d.ts.map +1 -1
- package/dist/client/products/products.js +3 -1
- package/dist/client/products/products.js.map +1 -1
- package/dist/client/utils/owner.d.ts.map +1 -1
- package/dist/client/utils/owner.js +3 -1
- package/dist/client/utils/owner.js.map +1 -1
- package/dist/client/utils/stripeDashboardUrl.d.ts.map +1 -1
- package/dist/client/utils/stripeDashboardUrl.js.map +1 -1
- package/dist/client/webhooks/helpers.d.ts +10 -0
- package/dist/client/webhooks/helpers.d.ts.map +1 -1
- package/dist/client/webhooks/helpers.js +18 -0
- package/dist/client/webhooks/helpers.js.map +1 -1
- package/dist/client/webhooks/processors.d.ts.map +1 -1
- package/dist/client/webhooks/processors.js +10 -24
- package/dist/client/webhooks/processors.js.map +1 -1
- package/dist/component/_generated/component.d.ts +34 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/billing/queries.d.ts +36 -0
- package/dist/component/billing/queries.d.ts.map +1 -1
- package/dist/component/billing/queries.js +10 -0
- package/dist/component/billing/queries.js.map +1 -1
- package/dist/component/billing/schema.d.ts +1 -0
- package/dist/component/billing/schema.d.ts.map +1 -1
- package/dist/component/billing/schema.js +1 -0
- package/dist/component/billing/schema.js.map +1 -1
- package/dist/component/connect/mutations.d.ts.map +1 -1
- package/dist/component/connect/mutations.js +28 -28
- package/dist/component/connect/mutations.js.map +1 -1
- package/dist/component/connect/schema.d.ts.map +1 -1
- package/dist/component/connect/schema.js.map +1 -1
- package/dist/component/lib/paymentSeller.d.ts +3 -0
- package/dist/component/lib/paymentSeller.d.ts.map +1 -0
- package/dist/component/lib/paymentSeller.js +10 -0
- package/dist/component/lib/paymentSeller.js.map +1 -0
- package/dist/component/lib/reversals.d.ts +10 -0
- package/dist/component/lib/reversals.d.ts.map +1 -1
- package/dist/component/lib/reversals.js +17 -0
- package/dist/component/lib/reversals.js.map +1 -1
- package/dist/component/schema.d.ts +1 -0
- package/dist/react/components/ConnectProvider.d.ts +1 -1
- package/dist/react/components/ConnectProvider.d.ts.map +1 -1
- package/dist/react/components/ConnectProvider.js +18 -4
- package/dist/react/components/ConnectProvider.js.map +1 -1
- package/dist/react/components/ConnectStatusBadge.d.ts.map +1 -1
- package/dist/react/components/ConnectStatusBadge.js.map +1 -1
- package/dist/react/components/EmbeddedDisputes.d.ts +1 -1
- package/dist/react/components/EmbeddedDisputes.d.ts.map +1 -1
- package/dist/react/components/EmbeddedDisputes.js +1 -1
- package/dist/react/components/EmbeddedDisputes.js.map +1 -1
- package/dist/react/components/SplitBreakdown.d.ts.map +1 -1
- package/dist/react/components/SplitBreakdown.js +12 -2
- package/dist/react/components/SplitBreakdown.js.map +1 -1
- package/dist/react/hooks/useCheckoutSession.d.ts.map +1 -1
- package/dist/react/hooks/useCheckoutSession.js.map +1 -1
- package/dist/react/hooks/useConfirmPayment.d.ts.map +1 -1
- package/dist/react/hooks/useConfirmPayment.js.map +1 -1
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +2 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/workflows/Account.d.ts +67 -0
- package/dist/react/workflows/Account.d.ts.map +1 -0
- package/dist/react/workflows/Account.js +74 -0
- package/dist/react/workflows/Account.js.map +1 -0
- package/dist/react/workflows/Billing.d.ts +60 -0
- package/dist/react/workflows/Billing.d.ts.map +1 -0
- package/dist/react/workflows/Billing.js +84 -0
- package/dist/react/workflows/Billing.js.map +1 -0
- package/dist/react/workflows/BillingPlans.d.ts +45 -0
- package/dist/react/workflows/BillingPlans.d.ts.map +1 -0
- package/dist/react/workflows/BillingPlans.js +51 -0
- package/dist/react/workflows/BillingPlans.js.map +1 -0
- package/dist/react/workflows/Checkout.d.ts +46 -0
- package/dist/react/workflows/Checkout.d.ts.map +1 -0
- package/dist/react/workflows/Checkout.js +61 -0
- package/dist/react/workflows/Checkout.js.map +1 -0
- package/dist/react/workflows/CheckoutChooser.d.ts +20 -0
- package/dist/react/workflows/CheckoutChooser.d.ts.map +1 -0
- package/dist/react/workflows/CheckoutChooser.js +24 -0
- package/dist/react/workflows/CheckoutChooser.js.map +1 -0
- package/dist/react/workflows/CheckoutForms.d.ts +26 -0
- package/dist/react/workflows/CheckoutForms.d.ts.map +1 -0
- package/dist/react/workflows/CheckoutForms.js +126 -0
- package/dist/react/workflows/CheckoutForms.js.map +1 -0
- package/dist/react/workflows/ClipboardButton.d.ts +17 -0
- package/dist/react/workflows/ClipboardButton.d.ts.map +1 -0
- package/dist/react/workflows/ClipboardButton.js +35 -0
- package/dist/react/workflows/ClipboardButton.js.map +1 -0
- package/dist/react/workflows/Collection.d.ts +30 -0
- package/dist/react/workflows/Collection.d.ts.map +1 -0
- package/dist/react/workflows/Collection.js +25 -0
- package/dist/react/workflows/Collection.js.map +1 -0
- package/dist/react/workflows/Collections.d.ts +56 -0
- package/dist/react/workflows/Collections.d.ts.map +1 -0
- package/dist/react/workflows/Collections.js +111 -0
- package/dist/react/workflows/Collections.js.map +1 -0
- package/dist/react/workflows/Connect.d.ts +19 -0
- package/dist/react/workflows/Connect.d.ts.map +1 -0
- package/dist/react/workflows/Connect.js +43 -0
- package/dist/react/workflows/Connect.js.map +1 -0
- package/dist/react/workflows/Costs.d.ts +48 -0
- package/dist/react/workflows/Costs.d.ts.map +1 -0
- package/dist/react/workflows/Costs.js +66 -0
- package/dist/react/workflows/Costs.js.map +1 -0
- package/dist/react/workflows/Disputes.d.ts +36 -0
- package/dist/react/workflows/Disputes.d.ts.map +1 -0
- package/dist/react/workflows/Disputes.js +74 -0
- package/dist/react/workflows/Disputes.js.map +1 -0
- package/dist/react/workflows/Earnings.d.ts +42 -0
- package/dist/react/workflows/Earnings.d.ts.map +1 -0
- package/dist/react/workflows/Earnings.js +38 -0
- package/dist/react/workflows/Earnings.js.map +1 -0
- package/dist/react/workflows/Financials.d.ts +43 -0
- package/dist/react/workflows/Financials.d.ts.map +1 -0
- package/dist/react/workflows/Financials.js +57 -0
- package/dist/react/workflows/Financials.js.map +1 -0
- package/dist/react/workflows/IntegrationSwitch.d.ts +23 -0
- package/dist/react/workflows/IntegrationSwitch.d.ts.map +1 -0
- package/dist/react/workflows/IntegrationSwitch.js +31 -0
- package/dist/react/workflows/IntegrationSwitch.js.map +1 -0
- package/dist/react/workflows/Onboarding.d.ts +56 -0
- package/dist/react/workflows/Onboarding.d.ts.map +1 -0
- package/dist/react/workflows/Onboarding.js +86 -0
- package/dist/react/workflows/Onboarding.js.map +1 -0
- package/dist/react/workflows/Overview.d.ts +51 -0
- package/dist/react/workflows/Overview.d.ts.map +1 -0
- package/dist/react/workflows/Overview.js +63 -0
- package/dist/react/workflows/Overview.js.map +1 -0
- package/dist/react/workflows/PaymentMethods.d.ts +35 -0
- package/dist/react/workflows/PaymentMethods.d.ts.map +1 -0
- package/dist/react/workflows/PaymentMethods.js +63 -0
- package/dist/react/workflows/PaymentMethods.js.map +1 -0
- package/dist/react/workflows/PaymentReceipt.d.ts +20 -0
- package/dist/react/workflows/PaymentReceipt.d.ts.map +1 -0
- package/dist/react/workflows/PaymentReceipt.js +24 -0
- package/dist/react/workflows/PaymentReceipt.js.map +1 -0
- package/dist/react/workflows/Payouts.d.ts +47 -0
- package/dist/react/workflows/Payouts.d.ts.map +1 -0
- package/dist/react/workflows/Payouts.js +87 -0
- package/dist/react/workflows/Payouts.js.map +1 -0
- package/dist/react/workflows/Products.d.ts +92 -0
- package/dist/react/workflows/Products.d.ts.map +1 -0
- package/dist/react/workflows/Products.js +179 -0
- package/dist/react/workflows/Products.js.map +1 -0
- package/dist/react/workflows/ReferralLinks.d.ts +26 -0
- package/dist/react/workflows/ReferralLinks.d.ts.map +1 -0
- package/dist/react/workflows/ReferralLinks.js +30 -0
- package/dist/react/workflows/ReferralLinks.js.map +1 -0
- package/dist/react/workflows/Refunds.d.ts +72 -0
- package/dist/react/workflows/Refunds.d.ts.map +1 -0
- package/dist/react/workflows/Refunds.js +95 -0
- package/dist/react/workflows/Refunds.js.map +1 -0
- package/dist/react/workflows/Setup.d.ts +50 -0
- package/dist/react/workflows/Setup.d.ts.map +1 -0
- package/dist/react/workflows/Setup.js +59 -0
- package/dist/react/workflows/Setup.js.map +1 -0
- package/dist/react/workflows/Storefront.d.ts +53 -0
- package/dist/react/workflows/Storefront.d.ts.map +1 -0
- package/dist/react/workflows/Storefront.js +44 -0
- package/dist/react/workflows/Storefront.js.map +1 -0
- package/dist/react/workflows/SubscriptionOverview.d.ts +13 -0
- package/dist/react/workflows/SubscriptionOverview.d.ts.map +1 -0
- package/dist/react/workflows/SubscriptionOverview.js +26 -0
- package/dist/react/workflows/SubscriptionOverview.js.map +1 -0
- package/dist/react/workflows/Subscriptions.d.ts +92 -0
- package/dist/react/workflows/Subscriptions.d.ts.map +1 -0
- package/dist/react/workflows/Subscriptions.js +149 -0
- package/dist/react/workflows/Subscriptions.js.map +1 -0
- package/dist/react/workflows/Tasks.d.ts +40 -0
- package/dist/react/workflows/Tasks.d.ts.map +1 -0
- package/dist/react/workflows/Tasks.js +113 -0
- package/dist/react/workflows/Tasks.js.map +1 -0
- package/dist/react/workflows/checkout-options.d.ts +37 -0
- package/dist/react/workflows/checkout-options.d.ts.map +1 -0
- package/dist/react/workflows/checkout-options.js +43 -0
- package/dist/react/workflows/checkout-options.js.map +1 -0
- package/dist/react/workflows/current-subscription.d.ts +11 -0
- package/dist/react/workflows/current-subscription.d.ts.map +1 -0
- package/dist/react/workflows/current-subscription.js +14 -0
- package/dist/react/workflows/current-subscription.js.map +1 -0
- package/dist/react/workflows/filters.d.ts +17 -0
- package/dist/react/workflows/filters.d.ts.map +1 -0
- package/dist/react/workflows/filters.js +23 -0
- package/dist/react/workflows/filters.js.map +1 -0
- package/dist/react/workflows/index.d.ts +70 -0
- package/dist/react/workflows/index.d.ts.map +1 -0
- package/dist/react/workflows/index.js +38 -0
- package/dist/react/workflows/index.js.map +1 -0
- package/dist/react/workflows/useWorkflowAction.d.ts +11 -0
- package/dist/react/workflows/useWorkflowAction.d.ts.map +1 -0
- package/dist/react/workflows/useWorkflowAction.js +68 -0
- package/dist/react/workflows/useWorkflowAction.js.map +1 -0
- package/dist/react/workflows/useWorkflowResource.d.ts +9 -0
- package/dist/react/workflows/useWorkflowResource.d.ts.map +1 -0
- package/dist/react/workflows/useWorkflowResource.js +67 -0
- package/dist/react/workflows/useWorkflowResource.js.map +1 -0
- package/docs/react-workflows-audit.md +66 -0
- package/docs/react-workflows.md +231 -0
- package/package.json +19 -3
- package/src/client/billing/checkout-ui-modes.test.ts +49 -0
- package/src/client/billing/checkout.ts +8 -3
- package/src/client/billing/invoices.test.ts +12 -6
- package/src/client/connect/paymentMethods.test.ts +3 -1
- package/src/client/connect/paymentMethods.ts +4 -1
- package/src/client/connect/refundActor.ts +1 -2
- package/src/client/connect/refunds.test.ts +35 -10
- package/src/client/connect/refunds.ts +4 -1
- package/src/client/connect/transfers.test.ts +66 -12
- package/src/client/connect/transfers.ts +32 -8
- package/src/client/core/accountDefaults.ts +15 -0
- package/src/client/core/accounts.ts +14 -17
- package/src/client/core/config.test.ts +2 -1
- package/src/client/core/descriptors.test.ts +6 -4
- package/src/client/core/fees.test.ts +20 -28
- package/src/client/core/fees.ts +9 -2
- package/src/client/index.test.ts +22 -22
- package/src/client/index.ts +1 -1
- package/src/client/products/prices.test.ts +8 -2
- package/src/client/products/prices.ts +4 -1
- package/src/client/products/products.test.ts +61 -20
- package/src/client/products/products.ts +3 -1
- package/src/client/utils/data.test.ts +3 -1
- package/src/client/utils/owner.test.ts +4 -1
- package/src/client/utils/owner.ts +5 -1
- package/src/client/utils/stripeDashboardUrl.ts +1 -4
- package/src/client/webhooks/handler.test.ts +16 -19
- package/src/client/webhooks/helpers.test.ts +26 -13
- package/src/client/webhooks/helpers.ts +23 -0
- package/src/client/webhooks/hooks.test.ts +1 -2
- package/src/client/webhooks/processors.test.ts +34 -34
- package/src/client/webhooks/processors.ts +9 -26
- package/src/client/webhooks.test.ts +1 -2
- package/src/component/_generated/api.ts +2 -0
- package/src/component/_generated/component.ts +46 -0
- package/src/component/billing/queries.ts +12 -0
- package/src/component/billing/schema.ts +1 -0
- package/src/component/connect/mutations.ts +34 -35
- package/src/component/connect/schema.ts +4 -3
- package/src/component/connect.test.ts +1 -5
- package/src/component/lib/paymentSeller.ts +15 -0
- package/src/component/lib/reversals.ts +30 -2
- package/src/component/seller-case-ownership.test.ts +61 -0
- package/src/component/store-subscriptions.test.ts +32 -0
- package/src/component/subscription-scoping.test.ts +5 -1
- package/src/component/triggers.test.ts +7 -4
- package/src/react/components/BuyerBillingView.render.test.tsx +7 -2
- package/src/react/components/ConnectProvider.live.test.tsx +61 -0
- package/src/react/components/ConnectProvider.tsx +18 -4
- package/src/react/components/ConnectStatusBadge.tsx +1 -4
- package/src/react/components/DisputeDetail.render.test.tsx +5 -1
- package/src/react/components/EarningsSummary.render.test.tsx +2 -6
- package/src/react/components/EmbeddedDisputes.render.test.tsx +7 -5
- package/src/react/components/EmbeddedDisputes.tsx +4 -1
- package/src/react/components/EvidenceForm.render.test.tsx +2 -8
- package/src/react/components/SplitBreakdown.render.test.tsx +28 -5
- package/src/react/components/SplitBreakdown.tsx +12 -2
- package/src/react/hooks/useCheckoutSession.ts +1 -2
- package/src/react/hooks/useConfirmPayment.ts +1 -2
- package/src/react/hooks/useEarnings.test.ts +43 -8
- package/src/react/hooks/useStripeMode.test.ts +5 -8
- package/src/react/index.ts +3 -0
- package/src/react/workflows/Account.test.tsx +31 -0
- package/src/react/workflows/Account.tsx +183 -0
- package/src/react/workflows/Billing.test.tsx +45 -0
- package/src/react/workflows/Billing.tsx +213 -0
- package/src/react/workflows/BillingPlans.test.tsx +31 -0
- package/src/react/workflows/BillingPlans.tsx +130 -0
- package/src/react/workflows/Checkout.test.tsx +118 -0
- package/src/react/workflows/Checkout.tsx +135 -0
- package/src/react/workflows/CheckoutChooser.test.tsx +44 -0
- package/src/react/workflows/CheckoutChooser.tsx +77 -0
- package/src/react/workflows/CheckoutForm.test.tsx +66 -0
- package/src/react/workflows/CheckoutForms.test.tsx +123 -0
- package/src/react/workflows/CheckoutForms.tsx +247 -0
- package/src/react/workflows/ClipboardButton.test.tsx +34 -0
- package/src/react/workflows/ClipboardButton.tsx +67 -0
- package/src/react/workflows/Collection.tsx +76 -0
- package/src/react/workflows/Collections.test.tsx +86 -0
- package/src/react/workflows/Collections.tsx +213 -0
- package/src/react/workflows/Connect.test.tsx +50 -0
- package/src/react/workflows/Connect.tsx +107 -0
- package/src/react/workflows/Costs.test.tsx +41 -0
- package/src/react/workflows/Costs.tsx +133 -0
- package/src/react/workflows/Disputes.test.tsx +25 -0
- package/src/react/workflows/Disputes.tsx +164 -0
- package/src/react/workflows/Earnings.test.ts +19 -0
- package/src/react/workflows/Earnings.tsx +84 -0
- package/src/react/workflows/Financials.test.tsx +35 -0
- package/src/react/workflows/Financials.tsx +117 -0
- package/src/react/workflows/IntegrationSwitch.test.tsx +36 -0
- package/src/react/workflows/IntegrationSwitch.tsx +63 -0
- package/src/react/workflows/Onboarding.test.tsx +75 -0
- package/src/react/workflows/Onboarding.tsx +171 -0
- package/src/react/workflows/Overview.test.tsx +57 -0
- package/src/react/workflows/Overview.tsx +123 -0
- package/src/react/workflows/PaymentMethods.test.tsx +60 -0
- package/src/react/workflows/PaymentMethods.tsx +117 -0
- package/src/react/workflows/PaymentReceipt.test.tsx +24 -0
- package/src/react/workflows/PaymentReceipt.tsx +46 -0
- package/src/react/workflows/Payouts.test.tsx +82 -0
- package/src/react/workflows/Payouts.tsx +212 -0
- package/src/react/workflows/Products.test.tsx +90 -0
- package/src/react/workflows/Products.tsx +377 -0
- package/src/react/workflows/ReferralLinks.test.tsx +39 -0
- package/src/react/workflows/ReferralLinks.tsx +75 -0
- package/src/react/workflows/Refunds.test.tsx +75 -0
- package/src/react/workflows/Refunds.tsx +223 -0
- package/src/react/workflows/Setup.test.tsx +25 -0
- package/src/react/workflows/Setup.tsx +166 -0
- package/src/react/workflows/Storefront.test.tsx +82 -0
- package/src/react/workflows/Storefront.tsx +138 -0
- package/src/react/workflows/SubscriptionOverview.test.tsx +27 -0
- package/src/react/workflows/SubscriptionOverview.tsx +48 -0
- package/src/react/workflows/Subscriptions.test.tsx +61 -0
- package/src/react/workflows/Subscriptions.tsx +282 -0
- package/src/react/workflows/Tasks.test.tsx +23 -0
- package/src/react/workflows/Tasks.tsx +199 -0
- package/src/react/workflows/checkout-options.ts +42 -0
- package/src/react/workflows/current-subscription.test.ts +29 -0
- package/src/react/workflows/current-subscription.ts +25 -0
- package/src/react/workflows/filters.test.ts +12 -0
- package/src/react/workflows/filters.ts +22 -0
- package/src/react/workflows/index.ts +238 -0
- package/src/react/workflows/native-interactions.test.tsx +73 -0
- package/src/react/workflows/public-workflows.test.tsx +216 -0
- package/src/react/workflows/useWorkflowAction.test.tsx +54 -0
- package/src/react/workflows/useWorkflowAction.ts +75 -0
- package/src/react/workflows/useWorkflowResource.test.tsx +41 -0
- package/src/react/workflows/useWorkflowResource.ts +78 -0
|
@@ -19,6 +19,7 @@ import type * as core_queries from "../core/queries.js";
|
|
|
19
19
|
import type * as core_validators from "../core/validators.js";
|
|
20
20
|
import type * as lib_fees from "../lib/fees.js";
|
|
21
21
|
import type * as lib_idempotency from "../lib/idempotency.js";
|
|
22
|
+
import type * as lib_paymentSeller from "../lib/paymentSeller.js";
|
|
22
23
|
import type * as lib_reversals from "../lib/reversals.js";
|
|
23
24
|
import type * as lib_stripeFactory from "../lib/stripeFactory.js";
|
|
24
25
|
import type * as products_mutations from "../products/mutations.js";
|
|
@@ -47,6 +48,7 @@ const fullApi: ApiFromModules<{
|
|
|
47
48
|
"core/validators": typeof core_validators;
|
|
48
49
|
"lib/fees": typeof lib_fees;
|
|
49
50
|
"lib/idempotency": typeof lib_idempotency;
|
|
51
|
+
"lib/paymentSeller": typeof lib_paymentSeller;
|
|
50
52
|
"lib/reversals": typeof lib_reversals;
|
|
51
53
|
"lib/stripeFactory": typeof lib_stripeFactory;
|
|
52
54
|
"products/mutations": typeof products_mutations;
|
|
@@ -592,6 +592,52 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
|
|
|
592
592
|
}>,
|
|
593
593
|
Name
|
|
594
594
|
>;
|
|
595
|
+
listSubscriptionsByPrice: FunctionReference<
|
|
596
|
+
"query",
|
|
597
|
+
"internal",
|
|
598
|
+
{ priceId: string },
|
|
599
|
+
Array<{
|
|
600
|
+
_creationTime: number;
|
|
601
|
+
_id: string;
|
|
602
|
+
accountId?: string;
|
|
603
|
+
applicationFeeAmount?: number;
|
|
604
|
+
applicationFeePercent?: number;
|
|
605
|
+
cancelAtPeriodEnd: boolean;
|
|
606
|
+
canceledAt?: string;
|
|
607
|
+
chargeType?: "destination" | "separate";
|
|
608
|
+
currency?: string;
|
|
609
|
+
currentPeriodEnd?: string;
|
|
610
|
+
currentPeriodStart?: string;
|
|
611
|
+
destinationAccountId?: string;
|
|
612
|
+
feeCollectedAmount?: number;
|
|
613
|
+
feeRefundedAmount?: number;
|
|
614
|
+
isTrialing: boolean;
|
|
615
|
+
metadata?: any;
|
|
616
|
+
orgId?: string;
|
|
617
|
+
priceId?: string;
|
|
618
|
+
quantity?: number;
|
|
619
|
+
splitRecipients?: Array<{
|
|
620
|
+
amount?: number;
|
|
621
|
+
destinationAccountId: string;
|
|
622
|
+
percent?: number;
|
|
623
|
+
role: "store" | "affiliate" | "other";
|
|
624
|
+
}>;
|
|
625
|
+
status:
|
|
626
|
+
| "active"
|
|
627
|
+
| "trialing"
|
|
628
|
+
| "past_due"
|
|
629
|
+
| "canceled"
|
|
630
|
+
| "incomplete"
|
|
631
|
+
| "incomplete_expired"
|
|
632
|
+
| "unpaid"
|
|
633
|
+
| "paused";
|
|
634
|
+
stripeSubscriptionId: string;
|
|
635
|
+
trialEnd?: string;
|
|
636
|
+
trialStart?: string;
|
|
637
|
+
userId: string;
|
|
638
|
+
}>,
|
|
639
|
+
Name
|
|
640
|
+
>;
|
|
595
641
|
listSubscriptionsByUser: FunctionReference<
|
|
596
642
|
"query",
|
|
597
643
|
"internal",
|
|
@@ -376,3 +376,15 @@ export const listInvoices = query({
|
|
|
376
376
|
return await ctx.db.query("invoices").take(limit);
|
|
377
377
|
},
|
|
378
378
|
});
|
|
379
|
+
|
|
380
|
+
/** Seller subscriber lists use catalog prices, including referred subscriptions. */
|
|
381
|
+
export const listSubscriptionsByPrice = query({
|
|
382
|
+
args: { priceId: v.string() },
|
|
383
|
+
returns: v.array(subscriptionDocValidator),
|
|
384
|
+
handler: async (ctx, args) =>
|
|
385
|
+
ctx.db
|
|
386
|
+
.query("subscriptions")
|
|
387
|
+
.withIndex("by_price_id", (q) => q.eq("priceId", args.priceId))
|
|
388
|
+
.order("desc")
|
|
389
|
+
.take(100),
|
|
390
|
+
});
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
*/
|
|
12
12
|
export const subscriptionsTable = defineTable(subscriptionFields)
|
|
13
13
|
.index("by_stripe_subscription_id", ["stripeSubscriptionId"])
|
|
14
|
+
.index("by_price_id", ["priceId"])
|
|
14
15
|
.index("by_user_id", ["userId"])
|
|
15
16
|
.index("by_org_id", ["orgId"])
|
|
16
17
|
.index("by_status", ["status"])
|
|
@@ -3,7 +3,8 @@ import { v } from "convex/values";
|
|
|
3
3
|
import type { Doc, Id } from "../_generated/dataModel";
|
|
4
4
|
import { mutation } from "../_generated/server";
|
|
5
5
|
import { feeRoutingFields } from "../lib/fees";
|
|
6
|
-
import { computeReversalSlices } from "../lib/reversals";
|
|
6
|
+
import { computeReversalSlices, deriveReversalState } from "../lib/reversals";
|
|
7
|
+
import { paymentSeller } from "../lib/paymentSeller";
|
|
7
8
|
import {
|
|
8
9
|
disputeFields,
|
|
9
10
|
paymentStatusValidator,
|
|
@@ -12,9 +13,7 @@ import {
|
|
|
12
13
|
transferFields,
|
|
13
14
|
} from "./validators";
|
|
14
15
|
|
|
15
|
-
//
|
|
16
|
-
// PAYMENT MUTATIONS
|
|
17
|
-
// =============================================================================
|
|
16
|
+
// Payment mutations
|
|
18
17
|
|
|
19
18
|
export const upsertPayment = mutation({
|
|
20
19
|
args: {
|
|
@@ -87,13 +86,31 @@ export const upsertPayment = mutation({
|
|
|
87
86
|
}
|
|
88
87
|
}
|
|
89
88
|
|
|
89
|
+
// A refund/dispute can arrive before the platform charge has its seller
|
|
90
|
+
// routing metadata. Reconcile those case owners once routing is known.
|
|
91
|
+
const sellerAccountId =
|
|
92
|
+
args.destinationAccountId ?? existing?.destinationAccountId;
|
|
93
|
+
if (sellerAccountId) {
|
|
94
|
+
for (const table of ["refunds", "disputes"] as const) {
|
|
95
|
+
const cases = await ctx.db
|
|
96
|
+
.query(table)
|
|
97
|
+
.withIndex("by_stripe_payment_intent_id", (q) =>
|
|
98
|
+
q.eq("stripePaymentIntentId", args.stripePaymentIntentId),
|
|
99
|
+
)
|
|
100
|
+
.take(100);
|
|
101
|
+
for (const record of cases)
|
|
102
|
+
if (!record.accountId)
|
|
103
|
+
await ctx.db.patch(table, record._id, {
|
|
104
|
+
accountId: sellerAccountId,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
90
109
|
return null;
|
|
91
110
|
},
|
|
92
111
|
});
|
|
93
112
|
|
|
94
|
-
//
|
|
95
|
-
// PAYOUT MUTATIONS
|
|
96
|
-
// =============================================================================
|
|
113
|
+
// Payout mutations
|
|
97
114
|
|
|
98
115
|
export const upsertPayout = mutation({
|
|
99
116
|
args: {
|
|
@@ -140,10 +157,13 @@ export const upsertRefund = mutation({
|
|
|
140
157
|
)
|
|
141
158
|
.first();
|
|
142
159
|
|
|
160
|
+
const accountId =
|
|
161
|
+
args.accountId ?? (await paymentSeller(ctx, args.stripePaymentIntentId));
|
|
162
|
+
const record = { ...args, ...(accountId ? { accountId } : {}) };
|
|
143
163
|
if (existing) {
|
|
144
|
-
await ctx.db.patch("refunds", existing._id,
|
|
164
|
+
await ctx.db.patch("refunds", existing._id, record);
|
|
145
165
|
} else {
|
|
146
|
-
await ctx.db.insert("refunds",
|
|
166
|
+
await ctx.db.insert("refunds", record);
|
|
147
167
|
}
|
|
148
168
|
|
|
149
169
|
// Denormalize cumulative refund state onto the linked `payments` row so
|
|
@@ -278,10 +298,13 @@ export const upsertDispute = mutation({
|
|
|
278
298
|
)
|
|
279
299
|
.first();
|
|
280
300
|
|
|
301
|
+
const accountId =
|
|
302
|
+
args.accountId ?? (await paymentSeller(ctx, args.stripePaymentIntentId));
|
|
303
|
+
const record = { ...args, ...(accountId ? { accountId } : {}) };
|
|
281
304
|
if (existing) {
|
|
282
|
-
await ctx.db.patch("disputes", existing._id,
|
|
305
|
+
await ctx.db.patch("disputes", existing._id, record);
|
|
283
306
|
} else {
|
|
284
|
-
await ctx.db.insert("disputes",
|
|
307
|
+
await ctx.db.insert("disputes", record);
|
|
285
308
|
}
|
|
286
309
|
|
|
287
310
|
return null;
|
|
@@ -292,30 +315,6 @@ export const upsertDispute = mutation({
|
|
|
292
315
|
// TRANSFER MUTATIONS (ledger — BTS-12)
|
|
293
316
|
// =============================================================================
|
|
294
317
|
|
|
295
|
-
/**
|
|
296
|
-
* Derive reversal status + transfer status from a (transfer amount, cumulative
|
|
297
|
-
* reversed amount) pair. Shared by upsert and reversal so the three reversal
|
|
298
|
-
* fields can never drift.
|
|
299
|
-
*/
|
|
300
|
-
function deriveReversalState(
|
|
301
|
-
amount: number,
|
|
302
|
-
reversedAmount: number,
|
|
303
|
-
baseStatus: "pending" | "paid" | "failed" | "reversed",
|
|
304
|
-
) {
|
|
305
|
-
const reversalStatus =
|
|
306
|
-
reversedAmount <= 0
|
|
307
|
-
? undefined
|
|
308
|
-
: reversedAmount >= amount
|
|
309
|
-
? ("fully_reversed" as const)
|
|
310
|
-
: ("partially_reversed" as const);
|
|
311
|
-
return {
|
|
312
|
-
reversedAmount: reversedAmount > 0 ? reversedAmount : undefined,
|
|
313
|
-
reversalStatus,
|
|
314
|
-
status:
|
|
315
|
-
reversalStatus === "fully_reversed" ? ("reversed" as const) : baseStatus,
|
|
316
|
-
};
|
|
317
|
-
}
|
|
318
|
-
|
|
319
318
|
export const upsertTransfer = mutation({
|
|
320
319
|
args: transferFields,
|
|
321
320
|
returns: v.null(),
|
|
@@ -34,9 +34,10 @@ export const payoutsTable = defineTable(payoutFields)
|
|
|
34
34
|
* (BTS-103). One row per payment intent; consumed and deleted by
|
|
35
35
|
* `upsertPayment`'s insert branch.
|
|
36
36
|
*/
|
|
37
|
-
export const pendingFeeRefundsTable = defineTable(
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
export const pendingFeeRefundsTable = defineTable(pendingFeeRefundFields).index(
|
|
38
|
+
"by_stripe_payment_intent_id",
|
|
39
|
+
["stripePaymentIntentId"],
|
|
40
|
+
);
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Refunds. Compound status indexes follow Plan 002: filtered list queries
|
|
@@ -15,11 +15,7 @@ describe("connect — refunds", () => {
|
|
|
15
15
|
stripePaymentIntentId?: string;
|
|
16
16
|
accountId?: string;
|
|
17
17
|
status:
|
|
18
|
-
| "
|
|
19
|
-
| "requires_action"
|
|
20
|
-
| "succeeded"
|
|
21
|
-
| "failed"
|
|
22
|
-
| "canceled";
|
|
18
|
+
"pending" | "requires_action" | "succeeded" | "failed" | "canceled";
|
|
23
19
|
},
|
|
24
20
|
) => {
|
|
25
21
|
await t.mutation(api.connect.mutations.upsertRefund, {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MutationCtx } from "../_generated/server";
|
|
2
|
+
|
|
3
|
+
export async function paymentSeller(
|
|
4
|
+
ctx: MutationCtx,
|
|
5
|
+
stripePaymentIntentId?: string,
|
|
6
|
+
): Promise<string | undefined> {
|
|
7
|
+
if (!stripePaymentIntentId) return undefined;
|
|
8
|
+
const payment = await ctx.db
|
|
9
|
+
.query("payments")
|
|
10
|
+
.withIndex("by_stripe_payment_intent_id", (q) =>
|
|
11
|
+
q.eq("stripePaymentIntentId", stripePaymentIntentId),
|
|
12
|
+
)
|
|
13
|
+
.first();
|
|
14
|
+
return payment?.destinationAccountId;
|
|
15
|
+
}
|
|
@@ -64,10 +64,14 @@ export function computeReversalSlices(
|
|
|
64
64
|
);
|
|
65
65
|
break;
|
|
66
66
|
case "fraction":
|
|
67
|
-
to = Math.min(
|
|
67
|
+
to = Math.min(
|
|
68
|
+
leg.amount,
|
|
69
|
+
Math.max(from, Math.round(leg.amount * fraction)),
|
|
70
|
+
);
|
|
68
71
|
break;
|
|
69
72
|
case "amount": {
|
|
70
|
-
const prorata =
|
|
73
|
+
const prorata =
|
|
74
|
+
total > 0 ? Math.round((mode.amount * leg.amount) / total) : 0;
|
|
71
75
|
const take = Math.max(0, Math.min(prorata, budget, leg.amount - from));
|
|
72
76
|
budget -= take;
|
|
73
77
|
to = from + take;
|
|
@@ -111,3 +115,27 @@ export function computeReversalSlices(
|
|
|
111
115
|
|
|
112
116
|
return slices;
|
|
113
117
|
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Derive reversal status + transfer status from a (transfer amount, cumulative
|
|
121
|
+
* reversed amount) pair. Shared by upsert and reversal so the three reversal
|
|
122
|
+
* fields can never drift.
|
|
123
|
+
*/
|
|
124
|
+
export function deriveReversalState(
|
|
125
|
+
amount: number,
|
|
126
|
+
reversedAmount: number,
|
|
127
|
+
baseStatus: "pending" | "paid" | "failed" | "reversed",
|
|
128
|
+
) {
|
|
129
|
+
const reversalStatus =
|
|
130
|
+
reversedAmount <= 0
|
|
131
|
+
? undefined
|
|
132
|
+
: reversedAmount >= amount
|
|
133
|
+
? ("fully_reversed" as const)
|
|
134
|
+
: ("partially_reversed" as const);
|
|
135
|
+
return {
|
|
136
|
+
reversedAmount: reversedAmount > 0 ? reversedAmount : undefined,
|
|
137
|
+
reversalStatus,
|
|
138
|
+
status:
|
|
139
|
+
reversalStatus === "fully_reversed" ? ("reversed" as const) : baseStatus,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { convexTest } from "convex-test";
|
|
2
|
+
import { expect, it } from "vitest";
|
|
3
|
+
import { api } from "./_generated/api";
|
|
4
|
+
import schema from "./schema";
|
|
5
|
+
const modules = import.meta.glob("./**/*.*s");
|
|
6
|
+
const payment = {
|
|
7
|
+
stripePaymentIntentId: "pi_sale",
|
|
8
|
+
userId: "customer",
|
|
9
|
+
amount: 10000,
|
|
10
|
+
currency: "usd",
|
|
11
|
+
status: "succeeded" as const,
|
|
12
|
+
destinationAccountId: "acct_store",
|
|
13
|
+
chargeType: "separate" as const,
|
|
14
|
+
};
|
|
15
|
+
const refund = {
|
|
16
|
+
stripeRefundId: "re_sale",
|
|
17
|
+
stripePaymentIntentId: "pi_sale",
|
|
18
|
+
amount: 1000,
|
|
19
|
+
currency: "usd",
|
|
20
|
+
status: "succeeded" as const,
|
|
21
|
+
};
|
|
22
|
+
const dispute = {
|
|
23
|
+
stripeDisputeId: "dp_sale",
|
|
24
|
+
stripePaymentIntentId: "pi_sale",
|
|
25
|
+
amount: 10000,
|
|
26
|
+
currency: "usd",
|
|
27
|
+
status: "needs_response" as const,
|
|
28
|
+
reason: "product_not_received",
|
|
29
|
+
isChargeRefundable: false,
|
|
30
|
+
};
|
|
31
|
+
it("attributes refunds and disputes to the seller instead of the purchasing customer", async () => {
|
|
32
|
+
const t = convexTest(schema, modules);
|
|
33
|
+
await t.mutation(api.connect.mutations.upsertPayment, payment);
|
|
34
|
+
await t.mutation(api.connect.mutations.upsertRefund, refund);
|
|
35
|
+
await t.mutation(api.connect.mutations.upsertDispute, dispute);
|
|
36
|
+
expect(
|
|
37
|
+
await t.query(api.connect.queries.listRefunds, { accountId: "acct_store" }),
|
|
38
|
+
).toHaveLength(1);
|
|
39
|
+
expect(
|
|
40
|
+
await t.query(api.connect.queries.listDisputes, {
|
|
41
|
+
accountId: "acct_store",
|
|
42
|
+
}),
|
|
43
|
+
).toHaveLength(1);
|
|
44
|
+
expect(
|
|
45
|
+
await t.query(api.connect.queries.listRefunds, { accountId: "acct_other" }),
|
|
46
|
+
).toHaveLength(0);
|
|
47
|
+
});
|
|
48
|
+
it("reconciles cases delivered before the seller's settlement metadata", async () => {
|
|
49
|
+
const t = convexTest(schema, modules);
|
|
50
|
+
await t.mutation(api.connect.mutations.upsertRefund, refund);
|
|
51
|
+
await t.mutation(api.connect.mutations.upsertDispute, dispute);
|
|
52
|
+
await t.mutation(api.connect.mutations.upsertPayment, payment);
|
|
53
|
+
expect(
|
|
54
|
+
await t.query(api.connect.queries.listRefunds, { accountId: "acct_store" }),
|
|
55
|
+
).toHaveLength(1);
|
|
56
|
+
expect(
|
|
57
|
+
await t.query(api.connect.queries.listDisputes, {
|
|
58
|
+
accountId: "acct_store",
|
|
59
|
+
}),
|
|
60
|
+
).toHaveLength(1);
|
|
61
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { convexTest } from "convex-test";
|
|
2
|
+
import { expect, it } from "vitest";
|
|
3
|
+
import { api } from "./_generated/api";
|
|
4
|
+
import schema from "./schema";
|
|
5
|
+
const modules = import.meta.glob("./**/*.*s");
|
|
6
|
+
it("scopes seller subscriptions by catalog price for both destination and split sales", async () => {
|
|
7
|
+
const t = convexTest(schema, modules);
|
|
8
|
+
await t.run(async (ctx) => {
|
|
9
|
+
for (const [id, priceId] of [
|
|
10
|
+
["sub_direct", "price_seller"],
|
|
11
|
+
["sub_referred", "price_seller"],
|
|
12
|
+
["sub_other", "price_other"],
|
|
13
|
+
]) {
|
|
14
|
+
await ctx.db.insert("subscriptions", {
|
|
15
|
+
stripeSubscriptionId: id,
|
|
16
|
+
priceId,
|
|
17
|
+
userId: "customer",
|
|
18
|
+
status: "active",
|
|
19
|
+
cancelAtPeriodEnd: false,
|
|
20
|
+
isTrialing: false,
|
|
21
|
+
isCollectionPaused: false,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
const rows = await t.query(api.billing.queries.listSubscriptionsByPrice, {
|
|
26
|
+
priceId: "price_seller",
|
|
27
|
+
});
|
|
28
|
+
expect(rows.map((s) => s.stripeSubscriptionId).sort()).toEqual([
|
|
29
|
+
"sub_direct",
|
|
30
|
+
"sub_referred",
|
|
31
|
+
]);
|
|
32
|
+
});
|
|
@@ -64,7 +64,11 @@ describe("per-store subscription scoping (BTS-19)", () => {
|
|
|
64
64
|
|
|
65
65
|
const active = await t.query(
|
|
66
66
|
api.billing.queries.listSubscriptionsByUserAndStore,
|
|
67
|
-
{
|
|
67
|
+
{
|
|
68
|
+
userId: "buyer_1",
|
|
69
|
+
destinationAccountId: "acct_store_a",
|
|
70
|
+
status: "active",
|
|
71
|
+
},
|
|
68
72
|
);
|
|
69
73
|
expect(active.map((s) => s.stripeSubscriptionId)).toEqual(["sub_active"]);
|
|
70
74
|
});
|
|
@@ -236,10 +236,13 @@ describe("webhook event ledger", () => {
|
|
|
236
236
|
it("fresh processing dedupes", async () => {
|
|
237
237
|
const t = convexTest(schema, modules);
|
|
238
238
|
|
|
239
|
-
const first = await t.mutation(
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
const first = await t.mutation(
|
|
240
|
+
api.webhooks.mutations.insertWebhookEvent,
|
|
241
|
+
{
|
|
242
|
+
stripeEventId: "evt_stale_001",
|
|
243
|
+
eventType: "invoice.paid",
|
|
244
|
+
},
|
|
245
|
+
);
|
|
243
246
|
expect(first).toBe("inserted");
|
|
244
247
|
|
|
245
248
|
// Immediate second insert — row is fresh processing, must dedupe.
|
|
@@ -69,7 +69,10 @@ describe("BuyerBillingView", () => {
|
|
|
69
69
|
|
|
70
70
|
it("renders the empty label with no subscriptions and no saved card", () => {
|
|
71
71
|
const html = renderToStaticMarkup(
|
|
72
|
-
createElement(BuyerBillingView, {
|
|
72
|
+
createElement(BuyerBillingView, {
|
|
73
|
+
subscriptions: [],
|
|
74
|
+
paymentMethod: null,
|
|
75
|
+
}),
|
|
73
76
|
);
|
|
74
77
|
expect(html).toContain("No billing yet");
|
|
75
78
|
});
|
|
@@ -122,7 +125,9 @@ describe("BuyerBillingView", () => {
|
|
|
122
125
|
createElement(BuyerBillingView, {
|
|
123
126
|
subscriptions: [activeSub],
|
|
124
127
|
paymentMethod,
|
|
125
|
-
updateCardSlot: createElement("div", {
|
|
128
|
+
updateCardSlot: createElement("div", {
|
|
129
|
+
"data-testid": "embedded-card",
|
|
130
|
+
}),
|
|
126
131
|
}),
|
|
127
132
|
);
|
|
128
133
|
expect(html).toContain('data-testid="embedded-card"');
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
2
|
+
import { cleanup, render } from "@testing-library/react";
|
|
3
|
+
import { afterEach, expect, it, vi } from "vitest";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
const stripe = vi.hoisted(() => ({ initialize: vi.fn(), update: vi.fn() }));
|
|
6
|
+
vi.mock("@stripe/connect-js/pure.js", () => ({
|
|
7
|
+
loadConnectAndInitialize: stripe.initialize,
|
|
8
|
+
}));
|
|
9
|
+
vi.mock("@stripe/connect-js", () => ({
|
|
10
|
+
loadConnectAndInitialize: stripe.initialize,
|
|
11
|
+
}));
|
|
12
|
+
vi.mock("@stripe/react-connect-js", () => ({
|
|
13
|
+
ConnectComponentsProvider: ({ children }: { children: ReactNode }) =>
|
|
14
|
+
children,
|
|
15
|
+
}));
|
|
16
|
+
import { ConnectProvider } from "./ConnectProvider.js";
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
cleanup();
|
|
19
|
+
vi.clearAllMocks();
|
|
20
|
+
});
|
|
21
|
+
it("updates appearance and locale while retaining the active Connect session", async () => {
|
|
22
|
+
stripe.initialize.mockReturnValue({ update: stripe.update });
|
|
23
|
+
const first = vi.fn(async () => "first_session");
|
|
24
|
+
const next = vi.fn(async () => "refreshed_session");
|
|
25
|
+
const { rerender } = render(
|
|
26
|
+
<ConnectProvider
|
|
27
|
+
publishableKey="pk_test_one"
|
|
28
|
+
fetchClientSecret={first}
|
|
29
|
+
locale="en"
|
|
30
|
+
/>,
|
|
31
|
+
);
|
|
32
|
+
const fetch = stripe.initialize.mock.calls[0][0].fetchClientSecret;
|
|
33
|
+
expect(await fetch()).toBe("first_session");
|
|
34
|
+
rerender(
|
|
35
|
+
<ConnectProvider
|
|
36
|
+
publishableKey="pk_test_one"
|
|
37
|
+
fetchClientSecret={next}
|
|
38
|
+
locale="fr"
|
|
39
|
+
appearance={{ variables: { colorPrimary: "#123456" } }}
|
|
40
|
+
/>,
|
|
41
|
+
);
|
|
42
|
+
expect(stripe.initialize).toHaveBeenCalledTimes(1);
|
|
43
|
+
expect(stripe.update).toHaveBeenLastCalledWith({
|
|
44
|
+
locale: "fr",
|
|
45
|
+
appearance: { variables: { colorPrimary: "#123456" } },
|
|
46
|
+
});
|
|
47
|
+
expect(await fetch()).toBe("refreshed_session");
|
|
48
|
+
expect(next).toHaveBeenCalledTimes(1);
|
|
49
|
+
});
|
|
50
|
+
it("creates a separate Connect instance when the publishable key changes", () => {
|
|
51
|
+
stripe.initialize.mockReturnValue({ update: stripe.update });
|
|
52
|
+
const fetch = async () => "session";
|
|
53
|
+
const { rerender } = render(
|
|
54
|
+
<ConnectProvider publishableKey="pk_test_one" fetchClientSecret={fetch} />,
|
|
55
|
+
);
|
|
56
|
+
rerender(
|
|
57
|
+
<ConnectProvider publishableKey="pk_test_two" fetchClientSecret={fetch} />,
|
|
58
|
+
);
|
|
59
|
+
expect(stripe.initialize).toHaveBeenCalledTimes(2);
|
|
60
|
+
expect(stripe.initialize.mock.calls[1][0].publishableKey).toBe("pk_test_two");
|
|
61
|
+
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { type ReactNode, useState } from "react";
|
|
3
|
+
import { type ReactNode, useEffect, useRef, useState } from "react";
|
|
4
4
|
|
|
5
5
|
import type { IStripeConnectInitParams } from "@stripe/connect-js";
|
|
6
|
-
import { loadConnectAndInitialize } from "@stripe/connect-js";
|
|
6
|
+
import { loadConnectAndInitialize } from "@stripe/connect-js/pure.js";
|
|
7
7
|
import { ConnectComponentsProvider } from "@stripe/react-connect-js";
|
|
8
8
|
|
|
9
9
|
export type ConnectProviderProps = {
|
|
@@ -32,24 +32,38 @@ export type ConnectProviderProps = {
|
|
|
32
32
|
* ConnectJS renders client-only iframes; on the server this component renders
|
|
33
33
|
* its tree but the embedded surfaces only materialize in the browser.
|
|
34
34
|
*/
|
|
35
|
-
export function ConnectProvider({
|
|
35
|
+
export function ConnectProvider(props: ConnectProviderProps) {
|
|
36
|
+
return <ConnectInstanceProvider key={props.publishableKey} {...props} />;
|
|
37
|
+
}
|
|
38
|
+
function ConnectInstanceProvider({
|
|
36
39
|
publishableKey,
|
|
37
40
|
fetchClientSecret,
|
|
38
41
|
appearance,
|
|
39
42
|
locale,
|
|
40
43
|
children,
|
|
41
44
|
}: ConnectProviderProps) {
|
|
45
|
+
const fetcher = useRef(fetchClientSecret);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
fetcher.current = fetchClientSecret;
|
|
48
|
+
}, [fetchClientSecret]);
|
|
42
49
|
// Lazy useState initializer: exactly one Connect instance per mount, stable
|
|
43
50
|
// across re-renders (loadConnectAndInitialize returns synchronously).
|
|
44
51
|
const [connectInstance] = useState(() =>
|
|
45
52
|
loadConnectAndInitialize({
|
|
46
53
|
publishableKey,
|
|
47
|
-
fetchClientSecret,
|
|
54
|
+
fetchClientSecret: () => fetcher.current(),
|
|
48
55
|
...(appearance !== undefined ? { appearance } : {}),
|
|
49
56
|
...(locale !== undefined ? { locale } : {}),
|
|
50
57
|
}),
|
|
51
58
|
);
|
|
52
59
|
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (appearance !== undefined || locale !== undefined)
|
|
62
|
+
connectInstance.update({
|
|
63
|
+
...(appearance !== undefined ? { appearance } : {}),
|
|
64
|
+
...(locale !== undefined ? { locale } : {}),
|
|
65
|
+
});
|
|
66
|
+
}, [connectInstance, appearance, locale]);
|
|
53
67
|
return (
|
|
54
68
|
<ConnectComponentsProvider connectInstance={connectInstance}>
|
|
55
69
|
{children}
|
|
@@ -3,10 +3,7 @@
|
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
|
|
5
5
|
export type ConnectStatus =
|
|
6
|
-
| "
|
|
7
|
-
| "in_progress"
|
|
8
|
-
| "complete"
|
|
9
|
-
| "restricted";
|
|
6
|
+
"pending" | "in_progress" | "complete" | "restricted";
|
|
10
7
|
|
|
11
8
|
export type ConnectStatusDetails = {
|
|
12
9
|
detailsSubmitted: boolean;
|
|
@@ -74,7 +74,11 @@ describe("DisputeDetail", () => {
|
|
|
74
74
|
createElement(DisputeDetail, {
|
|
75
75
|
dispute: {
|
|
76
76
|
...dispute,
|
|
77
|
-
countdown: {
|
|
77
|
+
countdown: {
|
|
78
|
+
dueBy: dispute.evidenceDueBy,
|
|
79
|
+
daysRemaining: -2,
|
|
80
|
+
isOverdue: true,
|
|
81
|
+
},
|
|
78
82
|
},
|
|
79
83
|
}),
|
|
80
84
|
);
|
|
@@ -73,9 +73,7 @@ describe("EarningsSummary", () => {
|
|
|
73
73
|
});
|
|
74
74
|
|
|
75
75
|
it("renders gross, reversals, net, and paid-out amounts", () => {
|
|
76
|
-
const html = renderToStaticMarkup(
|
|
77
|
-
createElement(EarningsSummary, earnings),
|
|
78
|
-
);
|
|
76
|
+
const html = renderToStaticMarkup(createElement(EarningsSummary, earnings));
|
|
79
77
|
expect(html).toContain("Gross");
|
|
80
78
|
expect(html).toContain("$105.00");
|
|
81
79
|
// Honest label per the BTS-36 review — NOT "Fees".
|
|
@@ -89,9 +87,7 @@ describe("EarningsSummary", () => {
|
|
|
89
87
|
});
|
|
90
88
|
|
|
91
89
|
it("announces the latest payout with amount and status", () => {
|
|
92
|
-
const html = renderToStaticMarkup(
|
|
93
|
-
createElement(EarningsSummary, earnings),
|
|
94
|
-
);
|
|
90
|
+
const html = renderToStaticMarkup(createElement(EarningsSummary, earnings));
|
|
95
91
|
// po_latest (newest _creationTime) wins over po_old.
|
|
96
92
|
expect(html).toContain("Latest payout of $40.00 — in_transit");
|
|
97
93
|
});
|
|
@@ -21,12 +21,15 @@ const loadConnectAndInitialize = vi.fn(
|
|
|
21
21
|
}),
|
|
22
22
|
);
|
|
23
23
|
|
|
24
|
-
vi.mock("@stripe/connect-js", () => ({
|
|
24
|
+
vi.mock("@stripe/connect-js/pure.js", () => ({
|
|
25
25
|
loadConnectAndInitialize: (initParams: unknown) =>
|
|
26
26
|
loadConnectAndInitialize(initParams as Record<string, unknown>),
|
|
27
27
|
}));
|
|
28
28
|
|
|
29
|
-
vi.mock("@stripe/react-connect-js", () => ({
|
|
29
|
+
vi.mock("@stripe/react-connect-js", async () => ({
|
|
30
|
+
...(await vi.importActual<typeof import("@stripe/react-connect-js")>(
|
|
31
|
+
"@stripe/react-connect-js",
|
|
32
|
+
)),
|
|
30
33
|
ConnectComponentsProvider: ({
|
|
31
34
|
connectInstance,
|
|
32
35
|
children,
|
|
@@ -73,9 +76,8 @@ describe("ConnectProvider", () => {
|
|
|
73
76
|
expect(loadConnectAndInitialize).toHaveBeenCalledTimes(1);
|
|
74
77
|
const initParams = loadConnectAndInitialize.mock.calls[0][0];
|
|
75
78
|
expect(initParams.publishableKey).toBe("pk_test_123");
|
|
76
|
-
// The
|
|
77
|
-
|
|
78
|
-
expect(initParams.fetchClientSecret).toBe(fetchClientSecret);
|
|
79
|
+
// The Connect runtime receives a lazy fetcher. Rendering does not request a session.
|
|
80
|
+
expect(initParams.fetchClientSecret).toEqual(expect.any(Function));
|
|
79
81
|
expect(fetchClientSecret).not.toHaveBeenCalled();
|
|
80
82
|
// Provider rendered with an instance, children inside.
|
|
81
83
|
expect(html).toContain('data-testid="connect-provider"');
|
|
@@ -25,7 +25,10 @@ export type EmbeddedDisputesProps = {
|
|
|
25
25
|
* Must be rendered inside a {@link ConnectProvider} whose `fetchClientSecret`
|
|
26
26
|
* returns that session's `clientSecret`.
|
|
27
27
|
*/
|
|
28
|
-
export function EmbeddedDisputes({
|
|
28
|
+
export function EmbeddedDisputes({
|
|
29
|
+
payment,
|
|
30
|
+
className,
|
|
31
|
+
}: EmbeddedDisputesProps) {
|
|
29
32
|
return (
|
|
30
33
|
<div className={className}>
|
|
31
34
|
{payment ? (
|