@fantastic.dev/better-stripe 0.7.0 → 0.8.1
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 +29 -18
- package/README.md +123 -91
- 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/disputes.d.ts +1 -1
- package/dist/client/connect/disputes.d.ts.map +1 -1
- package/dist/client/connect/disputes.js +12 -6
- package/dist/client/connect/disputes.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 +1 -19
- package/dist/client/webhooks/processors.js.map +1 -1
- package/dist/component/connect/mutations.d.ts.map +1 -1
- package/dist/component/connect/mutations.js +4 -33
- 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/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/DisputeDetail.d.ts +4 -1
- package/dist/react/components/DisputeDetail.d.ts.map +1 -1
- package/dist/react/components/DisputeDetail.js +12 -6
- package/dist/react/components/DisputeDetail.js.map +1 -1
- package/dist/react/components/DisputesList.d.ts.map +1 -1
- package/dist/react/components/DisputesList.js +2 -1
- package/dist/react/components/DisputesList.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 +2 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +3 -1
- 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 +48 -0
- package/dist/react/workflows/Payouts.d.ts.map +1 -0
- package/dist/react/workflows/Payouts.js +88 -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 +88 -0
- package/docs/react-workflows.md +234 -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/disputes.test.ts +15 -0
- package/src/client/connect/disputes.ts +13 -7
- 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 +18 -34
- package/src/client/webhooks/processors.ts +1 -23
- package/src/client/webhooks.test.ts +1 -2
- package/src/component/_generated/api.ts +2 -0
- package/src/component/connect/mutations.ts +5 -46
- 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/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/DisputeDetail.tsx +14 -5
- package/src/react/components/DisputesList.render.test.tsx +21 -0
- package/src/react/components/DisputesList.tsx +2 -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 +3 -10
- 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 +7 -1
- 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 +64 -0
- package/src/react/workflows/Disputes.tsx +173 -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 +112 -0
- package/src/react/workflows/Payouts.tsx +215 -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
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Example UI audit
|
|
2
|
+
|
|
3
|
+
Every financial/account page has a public React component or workflow hook in
|
|
4
|
+
`@fantastic.dev/better-stripe/react`. Native unstyled components implement the
|
|
5
|
+
shared workflows. The example binds authenticated Convex queries/actions and
|
|
6
|
+
uses render props or companion hooks to apply shadcn styling.
|
|
7
|
+
|
|
8
|
+
| Example page or adapter | Package UI and workflow ownership |
|
|
9
|
+
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
10
|
+
| Home and stores | `Storefront`, including store filtering, active catalog prices, purchase actions, and referral attribution |
|
|
11
|
+
| Checkout chooser | `CheckoutChooser`, `CHECKOUT_OPTIONS`, recurring-product compatibility and selection |
|
|
12
|
+
| Checkout session / PaymentIntent adapters | `Checkout`, `CheckoutElementsForm`, `PaymentIntentForm`, `CheckoutForm`, `EmbeddedCheckout`, including loading, retry, validation and confirmation |
|
|
13
|
+
| Checkout status | `CheckoutStatus`, `PaymentReceipt`, server/webhook confirmation |
|
|
14
|
+
| Customer overview | `SubscriptionOverview` |
|
|
15
|
+
| Customer subscription billing | `useSubscriptionManager`, `SubscriptionManager`, `BuyerBillingView`, `SubscriptionCard`, `Invoices`, `BillingPortalLink` |
|
|
16
|
+
| Customer invoices | `Invoices` |
|
|
17
|
+
| Customer payment methods | `usePaymentMethodsManager`, `PaymentMethods`, `PaymentMethodsList`, `AddCardForm`, Stripe providers |
|
|
18
|
+
| Seller overview | `PayoutOverview`, `AccountCreateCard`, `ConnectStatusBadge` |
|
|
19
|
+
| Seller and affiliate payouts | `Payouts`, `PayoutHistory`, live balances, upcoming date, history and pagination |
|
|
20
|
+
| Seller earnings | `EarningsSummary`, `PayoutSchedule`, `PayoutHistory`, `earningsFromBalance`, `useWorkflowResource` |
|
|
21
|
+
| Seller sales | `Sales` |
|
|
22
|
+
| Seller subscriptions | `Subscriptions`, `SubscriptionCard` |
|
|
23
|
+
| Seller and admin products | `useProductManager`, `Products`, `PriceCard`, product/price creation, editing and archiving |
|
|
24
|
+
| Seller account details | `useAccountManager`, `Account`, `AccountLoginCard`, `ConnectRequirements` |
|
|
25
|
+
| Seller onboarding / account setup | `useOnboarding`, `Onboarding`, `AccountCloseCard`, `DEFAULT_CONNECT_COUNTRIES` |
|
|
26
|
+
| Seller marketplace account | Account/onboarding hooks, `AccountConfigurations`, `ConnectStatusBadge`, `CheckoutStatus`, shared action lifecycle |
|
|
27
|
+
| Seller billing | `usePlanBilling`, `BillingPlans`, `EmbeddedCheckout`, `useInvoiceEstimate`, `InvoiceEstimate`, `useBalanceFunding`, `BalancePaymentSource` |
|
|
28
|
+
| Seller refunds | `useRefunds`, `Refunds`, `RefundHistory`, `PaymentDetails`, `CostRecovery` |
|
|
29
|
+
| Seller disputes | `useDisputeResponse`, `Disputes`, `DisputesList`, `DisputeDetail`, `EvidenceForm`, `ChargebackLedger`, `CostRecovery` |
|
|
30
|
+
| Affiliate earnings | `Earnings`, `EarningsSummary` |
|
|
31
|
+
| Affiliate referred sales | `ReferredSales`, store attribution and commission |
|
|
32
|
+
| Affiliate links | `useReferralLinks`, `ReferralLinks`, `ClipboardButton` |
|
|
33
|
+
| Admin overview | `Overview` |
|
|
34
|
+
| Admin subscriptions | `Subscriptions`, `useSubscriptionFilter` |
|
|
35
|
+
| Admin webhooks | `WebhookEvents`, `useWebhookFilters` |
|
|
36
|
+
| Admin setup | `useWebhookSetup`, `WebhookSetup`, `EnvironmentStatus`, `FixtureProgress`, `useTaskRunner`, `StripeSetup`, `ClipboardButton`, shared actions/resources |
|
|
37
|
+
| Admin sandbox testing | `useTaskRunner`, `SandboxTesting`, `WorkflowTasks` |
|
|
38
|
+
| Legacy affiliate split demo | `Checkout`, `SplitBreakdown`, `EarningsSummary`, bound package hook factories |
|
|
39
|
+
| Legacy destination-charge module | `Checkout`, `ChargeSummary`; the legacy public route currently resolves to the split demo |
|
|
40
|
+
| Integration presentation switch | `IntegrationSwitch`; only the active view mounts |
|
|
41
|
+
| Connect alternatives | `Connect` with account management, onboarding, payments/refunds, disputes, balances, payouts and notifications |
|
|
42
|
+
| Styled shared tables | `Collection` and domain collections; `WorkflowTable` only maps their state/columns to shadcn |
|
|
43
|
+
|
|
44
|
+
The example owns app branding, navigation, theme controls, the persona/store
|
|
45
|
+
switcher, route guards, URL state, and styling. It also owns its users and
|
|
46
|
+
server bindings, fee plans, referral-share policy, recovery billing rules,
|
|
47
|
+
sandbox scenario definitions, and authorization. These are application choices,
|
|
48
|
+
not prerequisites imposed by the public React package.
|
|
49
|
+
|
|
50
|
+
Some examples use companion hooks with styled markup instead of mounting the
|
|
51
|
+
native component. That markup changes presentation; the package owns the
|
|
52
|
+
workflow state, validation, duplicate-action handling, and async errors. Reusable
|
|
53
|
+
native components exist for consumers who do not want to write those renderers.
|
|
54
|
+
Connect and hosted Stripe UI remain available only where Stripe supports them.
|
|
55
|
+
|
|
56
|
+
## Verification
|
|
57
|
+
|
|
58
|
+
- Public-entry tests render native components without example providers, routing,
|
|
59
|
+
CSS classes, or inline styling and without calling server actions during render.
|
|
60
|
+
- Interaction tests exercise native product-price creation, partial refunds,
|
|
61
|
+
balance consent, checkout selection, and other workflow controllers.
|
|
62
|
+
- Account changes and duplicate actions have regression tests.
|
|
63
|
+
- Browser smoke coverage visits all five personas' pages and the integration views.
|
|
64
|
+
- Checkout tests complete referred guest purchases through all five integrations
|
|
65
|
+
in a Stripe sandbox and verify webhook receipts and settlement.
|
|
66
|
+
- `pnpm run check:all` enforces all repository gates, including Shadscan at 100.
|
|
67
|
+
|
|
68
|
+
## Follow-up audit
|
|
69
|
+
|
|
70
|
+
The final sandbox QA and follow-up audit checked every example route and its
|
|
71
|
+
adapters against the public React exports. Checkout delegates through the
|
|
72
|
+
session and PaymentIntent adapters. The remaining local state controls the
|
|
73
|
+
app's command menu, mobile sidebar, URL parameters, or selected demo price.
|
|
74
|
+
Financial actions use package workflow controllers or components.
|
|
75
|
+
|
|
76
|
+
The follow-up removed payout-status filtering from the example. Both native
|
|
77
|
+
`Payouts` and its render-prop example now consume the package's
|
|
78
|
+
`upcomingPayouts`, `previousPayouts`, and `nextPayout`. Regression tests cover
|
|
79
|
+
mixed payout statuses and arrival ordering. Dispute lists and detail views hide
|
|
80
|
+
stale evidence deadlines after a dispute leaves a response-required status.
|
|
81
|
+
|
|
82
|
+
Live browser checks cover reset/reseed, all persona routes, integration tabs,
|
|
83
|
+
five checkout integrations, saved-card add/remove and persistence, product
|
|
84
|
+
editing, subscription pause/resume, invoice estimates, balance-payment consent,
|
|
85
|
+
affiliate link copying, dispute evidence, and partial/remaining-balance refunds.
|
|
86
|
+
The tests use Stripe sandbox objects and await action results or webhook state.
|
|
87
|
+
Native public-entry tests also render the workflows without example providers,
|
|
88
|
+
CSS classes, inline styles, or example URLs.
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# React workflows
|
|
2
|
+
|
|
3
|
+
Import the example's reusable UI and workflow hooks from
|
|
4
|
+
`@fantastic.dev/better-stripe/react`. You do not need the example's route tree,
|
|
5
|
+
role provider, Tailwind, or shadcn components.
|
|
6
|
+
|
|
7
|
+
Components render semantic HTML without package CSS. Use their render props or
|
|
8
|
+
companion hooks to supply your own design system. Stripe iframe contents use
|
|
9
|
+
Stripe's `appearance` options and retain Stripe's own styling.
|
|
10
|
+
|
|
11
|
+
## Bind your backend
|
|
12
|
+
|
|
13
|
+
Pass authenticated server callbacks and query results to the components. This
|
|
14
|
+
keeps your user IDs, authorization, database schema, and business rules in your
|
|
15
|
+
application. The example's pages demonstrate Convex adapters for these callbacks.
|
|
16
|
+
A callback is an API contract, not an authorization boundary. The server must
|
|
17
|
+
check account ownership, price IDs, amounts, referral attribution, and permissions.
|
|
18
|
+
|
|
19
|
+
`scopeKey` identifies the authenticated account or customer. Change it when that
|
|
20
|
+
identity changes so pending responses cannot populate another account's UI.
|
|
21
|
+
For checkout, change `orderKey` when the customer, price, or attribution changes.
|
|
22
|
+
Do not put secret keys in these props. Browser code needs only a publishable key
|
|
23
|
+
and short-lived client secrets returned by your server.
|
|
24
|
+
|
|
25
|
+
## Choose a checkout
|
|
26
|
+
|
|
27
|
+
`Checkout` supports all five checkout integrations. It creates the session or
|
|
28
|
+
PaymentIntent, handles loading and retry, mounts the required Stripe provider,
|
|
29
|
+
and reports confirmation errors. Hosted Checkout waits for an explicit click.
|
|
30
|
+
`CheckoutChooser` renders the five choices and their pros and cons. It supports
|
|
31
|
+
controlled selection, render props, and a recurring-product compatibility notice.
|
|
32
|
+
`CHECKOUT_OPTIONS` also exports the descriptions.
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { Checkout } from "@fantastic.dev/better-stripe/react";
|
|
36
|
+
|
|
37
|
+
// createSession is your authenticated server binding. It must validate priceId.
|
|
38
|
+
function Purchase({ publishableKey, priceId, createSession }) {
|
|
39
|
+
return (
|
|
40
|
+
<Checkout
|
|
41
|
+
mode="custom"
|
|
42
|
+
publishableKey={publishableKey}
|
|
43
|
+
orderKey={priceId}
|
|
44
|
+
returnUrl={`${window.location.origin}/receipt?session_id={CHECKOUT_SESSION_ID}`}
|
|
45
|
+
createSession={({ mode, requestId }) =>
|
|
46
|
+
createSession({ priceId, uiMode: mode, requestId })
|
|
47
|
+
}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The callback returns `{ stripeSessionId, clientSecret?, url? }`. It must return
|
|
54
|
+
`url` for `redirect` and `clientSecret` for the other session modes. Use the
|
|
55
|
+
request ID for server idempotency. A user-triggered retry creates a new request
|
|
56
|
+
ID; also enforce application-level duplicate-order protection on the server.
|
|
57
|
+
|
|
58
|
+
| Mode | Stripe integration | Tradeoff |
|
|
59
|
+
| ---------------- | ------------------------------------- | ---------------------------------------------------------------------- |
|
|
60
|
+
| `redirect` | Hosted Checkout Session | Least UI work, leaves your app |
|
|
61
|
+
| `embedded` | Embedded Checkout Session | Complete Stripe checkout in your page, less layout control |
|
|
62
|
+
| `custom` | Checkout Session with Payment Element | Custom form layout with Checkout's session model |
|
|
63
|
+
| `payment-intent` | PaymentIntent with Payment Element | Payment control, application owns order and subscription orchestration |
|
|
64
|
+
| `form` | Preview Embedded Checkout Form | Compact Stripe form, requires the supported Stripe preview |
|
|
65
|
+
|
|
66
|
+
For `payment-intent`, provide `createPaymentIntent({ requestId })` instead of
|
|
67
|
+
`createSession`. Return `{ paymentIntentId, clientSecret }`. Payment Intents do
|
|
68
|
+
not create subscriptions. Stripe.js supplies the browser SDK and publishable-key
|
|
69
|
+
handling for these flows; it is not a separate server payment model.
|
|
70
|
+
|
|
71
|
+
Use `renderForm` on the custom and PaymentIntent modes to render your own email
|
|
72
|
+
input, `paymentElement`, error, and submit button. The preview `form` mode renders
|
|
73
|
+
Stripe's form and does not use that renderer. `children` replaces the outer
|
|
74
|
+
checkout frame and receives `content`, `isLoading`, `error`, and `retry`.
|
|
75
|
+
The lower-level `CheckoutElementsForm`, `PaymentIntentForm`, and `CheckoutForm`
|
|
76
|
+
are also exported for an existing client secret.
|
|
77
|
+
|
|
78
|
+
Only a server-confirmed payment or checkout session should grant access to the
|
|
79
|
+
product. Use `PaymentReceipt` or `CheckoutStatus` with webhook-backed query data;
|
|
80
|
+
a browser return URL alone does not prove payment.
|
|
81
|
+
|
|
82
|
+
## Headless or Stripe embedded
|
|
83
|
+
|
|
84
|
+
`Account`, `Onboarding`, `Disputes`, `Refunds`, `Earnings`, and `Payouts` accept
|
|
85
|
+
`presentation="embedded"` with Connect session props. Their default headless
|
|
86
|
+
presentation accepts domain-specific data and callbacks. `Connect` also exposes
|
|
87
|
+
account, onboarding, payments, refunds, disputes, balances, payouts, and
|
|
88
|
+
notifications widgets directly.
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
import { IntegrationSwitch, Payouts } from "@fantastic.dev/better-stripe/react";
|
|
92
|
+
|
|
93
|
+
function AccountPayouts({
|
|
94
|
+
accountId,
|
|
95
|
+
publishableKey,
|
|
96
|
+
loadPayouts,
|
|
97
|
+
createSession,
|
|
98
|
+
}) {
|
|
99
|
+
return (
|
|
100
|
+
<IntegrationSwitch
|
|
101
|
+
views={{
|
|
102
|
+
headless: <Payouts scopeKey={accountId} load={loadPayouts} />,
|
|
103
|
+
embedded: (
|
|
104
|
+
<Payouts
|
|
105
|
+
presentation="embedded"
|
|
106
|
+
scopeKey={accountId}
|
|
107
|
+
publishableKey={publishableKey}
|
|
108
|
+
fetchClientSecret={async () => (await createSession()).clientSecret}
|
|
109
|
+
/>
|
|
110
|
+
),
|
|
111
|
+
}}
|
|
112
|
+
/>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
The server creates an Account Session for the authenticated connected account
|
|
118
|
+
and enables the requested component and features. Session refresh uses the latest callback. Appearance and locale updates apply
|
|
119
|
+
to the active Connect instance without remounting it. Changing the publishable
|
|
120
|
+
key creates a new instance. `IntegrationSwitch` mounts only the active view and has
|
|
121
|
+
no router dependency. It also supports controlled `value`/`onValueChange` and
|
|
122
|
+
`components` and `hosted` views when your workflow has those alternatives.
|
|
123
|
+
|
|
124
|
+
Connect displays only the payment data supported for that connected account.
|
|
125
|
+
The example's platform-owned separate-charges-and-transfers ledger remains in
|
|
126
|
+
its headless sales/refund/dispute views. A Connect embed cannot turn that ledger
|
|
127
|
+
into connected-account-owned charges. Refunds use the Connect Payments widget;
|
|
128
|
+
there is no separate Connect refund catalog widget. Product management,
|
|
129
|
+
customer subscriptions, and platform billing do not have equivalent Connect
|
|
130
|
+
widgets. Use package UI or the hosted Billing Portal for those workflows.
|
|
131
|
+
|
|
132
|
+
## Component and hook reference
|
|
133
|
+
|
|
134
|
+
| Workflow | Unstyled components | Companion hooks/helpers |
|
|
135
|
+
| --------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
136
|
+
| Store browsing | `Storefront`, `PriceCard` | Store/product/price models and purchase callbacks |
|
|
137
|
+
| Checkout | `CheckoutChooser`, `Checkout`, `CheckoutElementsForm`, `PaymentIntentForm`, `CheckoutForm`, `EmbeddedCheckout` | `CHECKOUT_OPTIONS` |
|
|
138
|
+
| Receipts | `PaymentReceipt`, `CheckoutStatus` | Server-backed payment/session data |
|
|
139
|
+
| Earnings | `Earnings`, `EarningsSummary` | `earningsFromBalance` |
|
|
140
|
+
| Payouts | `Payouts`, `PayoutSchedule`, `PayoutHistory`, `PayoutOverview` | `getPayoutTotals` |
|
|
141
|
+
| Sales | `Sales`, `ReferredSales` | Server-authoritative economic rows |
|
|
142
|
+
| Refunds | `Refunds`, `RefundHistory` | `useRefunds`, `parseAmountCents` |
|
|
143
|
+
| Disputes | `Disputes`, `DisputesList`, `DisputeDetail`, `EvidenceForm`, `ChargebackLedger` | `useDisputeResponse` |
|
|
144
|
+
| Onboarding | `Onboarding` | `useOnboarding` |
|
|
145
|
+
| Accounts | `Account`, `AccountConfigurations` | `useAccountManager` |
|
|
146
|
+
| Product management | `Products` | `useProductManager` |
|
|
147
|
+
| Subscriptions | `Subscriptions`, `SubscriptionManager`, `SubscriptionOverview`, `SubscriptionCard` | `useSubscriptionManager`, `useSubscriptionFilter`, `currentSubscriptionFrom` |
|
|
148
|
+
| Billing | `BillingPlans`, `BillingPortal`, `InvoiceEstimate`, `Invoices`, `BalancePaymentSource` | `usePlanBilling`, `useInvoiceEstimate`, `useBalanceFunding` |
|
|
149
|
+
| Payment methods | `PaymentMethods`, `PaymentMethodsList`, `AddCardForm` | `usePaymentMethodsManager`, `toPaymentMethodItem` |
|
|
150
|
+
| Seller cost recovery | `CostRecovery` | Server-calculated outstanding/collected/invoiced amounts |
|
|
151
|
+
| Referral sharing | `ReferralLinks`, `ClipboardButton` | `useReferralLinks` |
|
|
152
|
+
| Admin | `Overview`, `WebhookEvents` | `useWebhookFilters`, `webhookQueryArgs` |
|
|
153
|
+
| Sandbox setup/testing | `StripeSetup`, `SandboxTesting`, `WorkflowTasks`, `WebhookSetup`, `EnvironmentStatus`, `FixtureProgress` | `useTaskRunner`, `useWebhookSetup` |
|
|
154
|
+
| Shared state/tables | `IntegrationSwitch`, `Collection` | `useWorkflowAction`, `useWorkflowResource` |
|
|
155
|
+
|
|
156
|
+
The example still owns its navigation, persona switcher, application branding,
|
|
157
|
+
server authorization, sandbox fixture definitions, and marketplace fee policy.
|
|
158
|
+
Its styled forms and tables consume package hooks/render props. The package's
|
|
159
|
+
default components implement those workflows without the example's providers.
|
|
160
|
+
The package does not seed or reset a Stripe account just because a component
|
|
161
|
+
mounts. Setup/testing tasks call the operations you explicitly bind.
|
|
162
|
+
|
|
163
|
+
## Data contracts and styling
|
|
164
|
+
|
|
165
|
+
`Payouts.load(cursor?)` returns a `PayoutSnapshot` with `balances`, `payouts`,
|
|
166
|
+
`upcoming`, and `nextCursor`. Each balance has `currency`, `available`, and
|
|
167
|
+
`pending`. Payout rows include `id`, `amount`, `currency`, `status`, `arrivalDate`,
|
|
168
|
+
and `created`. The component shows available and pending balances, the next
|
|
169
|
+
known payout and arrival date, upcoming payouts, and paginated previous payouts.
|
|
170
|
+
Render props expose `upcomingPayouts` sorted by arrival date,
|
|
171
|
+
`previousPayouts`, and `nextPayout`. Use these package-owned classifications
|
|
172
|
+
in custom UI; completed or failed payouts are excluded from upcoming payouts.
|
|
173
|
+
If Stripe has not provided an upcoming payout, the UI says so rather than
|
|
174
|
+
inventing a date.
|
|
175
|
+
|
|
176
|
+
Payout, invoice-estimate, cost, and webhook timestamps use Unix milliseconds.
|
|
177
|
+
Subscription period/trial fields use ISO date strings, matching the existing
|
|
178
|
+
subscription API. Convert raw Stripe Unix seconds in your adapter. Money values use integer minor units. The current decimal refund
|
|
179
|
+
input and price-formatting helpers use two decimal places, as in the USD
|
|
180
|
+
example. Supply custom rendering/input conversion for zero-decimal and
|
|
181
|
+
three-decimal currencies. Never combine balances across currencies.
|
|
182
|
+
|
|
183
|
+
Sale fees, affiliate shares, recovery costs, invoice estimates, and settlement
|
|
184
|
+
statuses come from server data. The UI does not recalculate the example's fee
|
|
185
|
+
policy or charge outstanding costs by itself. Balance funding requires explicit
|
|
186
|
+
consent and a server integration with Stripe's supported preview. Card fallback,
|
|
187
|
+
renewal recovery, and debt collection remain server business rules.
|
|
188
|
+
|
|
189
|
+
Use exported `*Props`, row models, and render-state types for typed adapters.
|
|
190
|
+
Tables accept optional columns and a `children(state)` renderer. Action hooks
|
|
191
|
+
expose pending, error, and results so your buttons and alerts share the same
|
|
192
|
+
validation and duplicate-submit handling as the native components.
|
|
193
|
+
|
|
194
|
+
```tsx
|
|
195
|
+
import { Invoices } from "@fantastic.dev/better-stripe/react";
|
|
196
|
+
|
|
197
|
+
function InvoiceList({ invoices }) {
|
|
198
|
+
return (
|
|
199
|
+
<Invoices rows={invoices}>
|
|
200
|
+
{({ rows, isLoading, isEmpty }) =>
|
|
201
|
+
isLoading ? (
|
|
202
|
+
<p>Loading invoices…</p>
|
|
203
|
+
) : isEmpty ? (
|
|
204
|
+
<p>No invoices yet.</p>
|
|
205
|
+
) : (
|
|
206
|
+
<ul>
|
|
207
|
+
{rows.map((row) => (
|
|
208
|
+
<li key={row.stripeInvoiceId}>{row.stripeInvoiceId}</li>
|
|
209
|
+
))}
|
|
210
|
+
</ul>
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
</Invoices>
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Default markup has `data-better-stripe` attributes for scoped CSS. Use render
|
|
219
|
+
props to replace markup with your design system, including labels and locale
|
|
220
|
+
formatting. A render function replaces the supplied markup; render its `content`
|
|
221
|
+
or `paymentElement` where those are part of the state's contract.
|
|
222
|
+
|
|
223
|
+
## Example coverage
|
|
224
|
+
|
|
225
|
+
See [the page audit](react-workflows-audit.md) for the mapping from every example
|
|
226
|
+
page to package components and hooks. `ChargeSummary` displays server-calculated
|
|
227
|
+
charge/fee/payout figures. `PaymentDetails` displays recorded charge and refund
|
|
228
|
+
state. `PayoutOverview` shows payout activity totals, which are separate from the
|
|
229
|
+
available and pending Stripe balances shown by `Payouts`.
|
|
230
|
+
|
|
231
|
+
`DEFAULT_CONNECT_COUNTRIES` provides the example's eight country choices and is
|
|
232
|
+
shared by its account pages and native `Onboarding`. Supply `countries` to limit
|
|
233
|
+
or expand the UI for your platform. This default is not a complete list of
|
|
234
|
+
Stripe-supported countries; your server must validate account eligibility.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fantastic.dev/better-stripe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
4
4
|
"description": "A Convex component for Stripe V2 Accounts API integration.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"stripe",
|
|
@@ -57,6 +57,8 @@
|
|
|
57
57
|
"files": [
|
|
58
58
|
"dist",
|
|
59
59
|
"src",
|
|
60
|
+
"docs/react-workflows.md",
|
|
61
|
+
"docs/react-workflows-audit.md",
|
|
60
62
|
"CHANGELOG.md",
|
|
61
63
|
"MIGRATION.md"
|
|
62
64
|
],
|
|
@@ -83,7 +85,18 @@
|
|
|
83
85
|
"prepublishOnly": "npm run clean && npm run build && npm run typecheck",
|
|
84
86
|
"test": "vitest run",
|
|
85
87
|
"test:watch": "vitest",
|
|
86
|
-
"test:coverage": "vitest run --coverage"
|
|
88
|
+
"test:coverage": "vitest run --coverage",
|
|
89
|
+
"check:design-system": "eslint --config eslint.design-system.config.mjs . --max-warnings 0",
|
|
90
|
+
"check:shadscan": "shadscan \"./example\" --json --fail-under 100 --no-roast --no-interactive",
|
|
91
|
+
"check:all": "repo-gates check-all",
|
|
92
|
+
"check:size": "repo-gates check-size",
|
|
93
|
+
"check:debt": "repo-gates check-debt",
|
|
94
|
+
"check:circular": "repo-gates check-circular",
|
|
95
|
+
"check:secrets": "repo-gates check-secrets",
|
|
96
|
+
"check:ci-parity": "repo-gates check-ci-parity",
|
|
97
|
+
"check:coverage": "repo-gates check-coverage",
|
|
98
|
+
"format:check": "pnpm run format",
|
|
99
|
+
"check:agents": "repo-gates check-agents"
|
|
87
100
|
},
|
|
88
101
|
"dependencies": {
|
|
89
102
|
"@stripe/connect-js": "^3.4.6",
|
|
@@ -95,6 +108,7 @@
|
|
|
95
108
|
"devDependencies": {
|
|
96
109
|
"@convex-dev/eslint-plugin": "^5.0.0",
|
|
97
110
|
"@edge-runtime/vm": "^5.0.0",
|
|
111
|
+
"@fantastic.dev/repo-gates": "^0.4.0",
|
|
98
112
|
"@testing-library/jest-dom": "^7.0.1",
|
|
99
113
|
"@testing-library/react": "^16.3.3",
|
|
100
114
|
"@testing-library/user-event": "^14.6.7",
|
|
@@ -113,7 +127,9 @@
|
|
|
113
127
|
"pretty-quick": "^4.2.2",
|
|
114
128
|
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
115
129
|
"typescript-eslint": "^8.71.1",
|
|
116
|
-
"vitest": "^5.0.3"
|
|
130
|
+
"vitest": "^5.0.3",
|
|
131
|
+
"@shadcn/lint": "0.1.5",
|
|
132
|
+
"@shadscan/cli": "0.7.0"
|
|
117
133
|
},
|
|
118
134
|
"peerDependencies": {
|
|
119
135
|
"convex": "^1.29.3",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { expect, it, vi } from "vitest";
|
|
2
|
+
import type Stripe from "stripe";
|
|
3
|
+
import type { Component, RunCtx } from "../helpers.js";
|
|
4
|
+
import { createCheckoutSession } from "./checkout.js";
|
|
5
|
+
for (const [mode, expected] of [
|
|
6
|
+
["custom", "elements"],
|
|
7
|
+
["form", "form"],
|
|
8
|
+
] as const)
|
|
9
|
+
it(`creates ${mode} checkout without hosted URLs`, async () => {
|
|
10
|
+
const create = vi.fn().mockResolvedValue({
|
|
11
|
+
id: "cs_test",
|
|
12
|
+
status: "open",
|
|
13
|
+
mode: "payment",
|
|
14
|
+
client_secret: "client_secret_test",
|
|
15
|
+
metadata: {},
|
|
16
|
+
expires_at: 1800000000,
|
|
17
|
+
});
|
|
18
|
+
const component = {
|
|
19
|
+
billing: {
|
|
20
|
+
mutations: {
|
|
21
|
+
upsertCheckoutSession: {
|
|
22
|
+
[Symbol.for("toReferencePath")]:
|
|
23
|
+
"betterStripe/billing/mutations/upsertCheckoutSession",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
} as unknown as Component;
|
|
28
|
+
await createCheckoutSession(
|
|
29
|
+
{ checkout: { sessions: { create } } } as unknown as Stripe,
|
|
30
|
+
component,
|
|
31
|
+
{
|
|
32
|
+
runQuery: vi.fn().mockResolvedValue(null),
|
|
33
|
+
runMutation: vi.fn(),
|
|
34
|
+
} as unknown as RunCtx,
|
|
35
|
+
{
|
|
36
|
+
userId: "user_1",
|
|
37
|
+
stripePriceId: "price_1",
|
|
38
|
+
mode: "payment",
|
|
39
|
+
uiMode: mode,
|
|
40
|
+
returnUrl: "https://app.test/return",
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
expect(create.mock.calls[0][0]).toMatchObject({
|
|
44
|
+
ui_mode: expected,
|
|
45
|
+
return_url: "https://app.test/return",
|
|
46
|
+
});
|
|
47
|
+
expect(create.mock.calls[0][0].success_url).toBeUndefined();
|
|
48
|
+
expect(create.mock.calls[0][0].cancel_url).toBeUndefined();
|
|
49
|
+
});
|
|
@@ -114,7 +114,7 @@ export async function createCheckoutSession(
|
|
|
114
114
|
orgId?: string;
|
|
115
115
|
stripePriceId: string;
|
|
116
116
|
mode: "payment" | "subscription" | "setup";
|
|
117
|
-
uiMode?: "embedded" | "redirect";
|
|
117
|
+
uiMode?: "embedded" | "redirect" | "custom" | "form";
|
|
118
118
|
quantity?: number;
|
|
119
119
|
returnUrl: string;
|
|
120
120
|
trialDays?: number;
|
|
@@ -295,8 +295,13 @@ export async function createCheckoutSession(
|
|
|
295
295
|
sessionParams.payment_intent_data = paymentIntentData;
|
|
296
296
|
}
|
|
297
297
|
|
|
298
|
-
if (uiMode === "embedded") {
|
|
299
|
-
sessionParams.ui_mode =
|
|
298
|
+
if (uiMode === "embedded" || uiMode === "custom" || uiMode === "form") {
|
|
299
|
+
sessionParams.ui_mode =
|
|
300
|
+
uiMode === "custom"
|
|
301
|
+
? "elements"
|
|
302
|
+
: uiMode === "form"
|
|
303
|
+
? "form"
|
|
304
|
+
: "embedded_page";
|
|
300
305
|
sessionParams.return_url = opts.returnUrl;
|
|
301
306
|
} else {
|
|
302
307
|
sessionParams.success_url = `${opts.returnUrl}?session_id={CHECKOUT_SESSION_ID}`;
|
|
@@ -75,7 +75,9 @@ describe("listInvoices", () => {
|
|
|
75
75
|
|
|
76
76
|
expect(result).toEqual([]);
|
|
77
77
|
const [ref, args] = ctx.runQuery.mock.calls[0];
|
|
78
|
-
expect(ref[TO_REF]).toBe(
|
|
78
|
+
expect(ref[TO_REF]).toBe(
|
|
79
|
+
refPath(component, "billing/queries/listInvoices"),
|
|
80
|
+
);
|
|
79
81
|
expect(args).toEqual({});
|
|
80
82
|
});
|
|
81
83
|
|
|
@@ -125,7 +127,9 @@ describe("listInvoicesByUser", () => {
|
|
|
125
127
|
|
|
126
128
|
expect(result).toBe(rows);
|
|
127
129
|
const [ref, args] = ctx.runQuery.mock.calls[0];
|
|
128
|
-
expect(ref[TO_REF]).toBe(
|
|
130
|
+
expect(ref[TO_REF]).toBe(
|
|
131
|
+
refPath(component, "billing/queries/listInvoices"),
|
|
132
|
+
);
|
|
129
133
|
expect(args).toEqual({ userId: "u_9" });
|
|
130
134
|
});
|
|
131
135
|
});
|
|
@@ -177,9 +181,9 @@ describe("upsertInvoice", () => {
|
|
|
177
181
|
it("throws when ctx has no runMutation (runMutationOrThrow guard)", async () => {
|
|
178
182
|
const ctx = { runQuery: vi.fn() } as unknown as RunCtx;
|
|
179
183
|
|
|
180
|
-
await expect(
|
|
181
|
-
|
|
182
|
-
)
|
|
184
|
+
await expect(upsertInvoice(makeComponent(), ctx, baseOpts)).rejects.toThrow(
|
|
185
|
+
/requires a Convex ctx with runMutation/,
|
|
186
|
+
);
|
|
183
187
|
});
|
|
184
188
|
});
|
|
185
189
|
|
|
@@ -189,7 +193,9 @@ describe("getInvoice", () => {
|
|
|
189
193
|
const row = { stripeInvoiceId: "in_4", status: "paid" };
|
|
190
194
|
const ctx = makeCtx(row);
|
|
191
195
|
|
|
192
|
-
const result = await getInvoice(component, ctx, {
|
|
196
|
+
const result = await getInvoice(component, ctx, {
|
|
197
|
+
stripeInvoiceId: "in_4",
|
|
198
|
+
});
|
|
193
199
|
|
|
194
200
|
expect(result).toBe(row);
|
|
195
201
|
const [ref, args] = ctx.runQuery.mock.calls[0];
|
|
@@ -73,6 +73,21 @@ describe("buildDisputeEvidence (BTS-31)", () => {
|
|
|
73
73
|
});
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
it("sends communication prose as text while preserving other context", () => {
|
|
77
|
+
expect(
|
|
78
|
+
buildDisputeEvidence({
|
|
79
|
+
additionalInfo: "Delivered",
|
|
80
|
+
customerCommunication: "Customer confirmed receipt",
|
|
81
|
+
}),
|
|
82
|
+
).toEqual({
|
|
83
|
+
uncategorized_text:
|
|
84
|
+
"Delivered\n\nCustomer communication:\nCustomer confirmed receipt",
|
|
85
|
+
});
|
|
86
|
+
expect(buildDisputeEvidence({ customerCommunication: "file_123" })).toEqual(
|
|
87
|
+
{ customer_communication: "file_123" },
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
|
|
76
91
|
it("omits unset categories", () => {
|
|
77
92
|
expect(buildDisputeEvidence({ productDescription: "X" })).toEqual({
|
|
78
93
|
product_description: "X",
|
|
@@ -260,9 +260,19 @@ export function buildDisputeEvidence(input: {
|
|
|
260
260
|
accessActivity?: string;
|
|
261
261
|
/** Off-platform context / anything else (Stripe: uncategorized_text). */
|
|
262
262
|
additionalInfo?: string;
|
|
263
|
-
/**
|
|
263
|
+
/** Communication prose is appended to text evidence; file_ IDs remain file evidence. */
|
|
264
264
|
customerCommunication?: string;
|
|
265
265
|
}): import("stripe").Stripe.DisputeUpdateParams.Evidence {
|
|
266
|
+
const communication = input.customerCommunication;
|
|
267
|
+
const file = communication?.startsWith("file_") ? communication : undefined;
|
|
268
|
+
const text = [
|
|
269
|
+
input.additionalInfo,
|
|
270
|
+
!file && communication
|
|
271
|
+
? `Customer communication:\n${communication}`
|
|
272
|
+
: undefined,
|
|
273
|
+
]
|
|
274
|
+
.filter(Boolean)
|
|
275
|
+
.join("\n\n");
|
|
266
276
|
return {
|
|
267
277
|
...(input.productDescription
|
|
268
278
|
? { product_description: input.productDescription }
|
|
@@ -270,12 +280,8 @@ export function buildDisputeEvidence(input: {
|
|
|
270
280
|
...(input.accessActivity
|
|
271
281
|
? { access_activity_log: input.accessActivity }
|
|
272
282
|
: {}),
|
|
273
|
-
...(
|
|
274
|
-
|
|
275
|
-
: {}),
|
|
276
|
-
...(input.customerCommunication
|
|
277
|
-
? { customer_communication: input.customerCommunication }
|
|
278
|
-
: {}),
|
|
283
|
+
...(text ? { uncategorized_text: text } : {}),
|
|
284
|
+
...(file ? { customer_communication: file } : {}),
|
|
279
285
|
};
|
|
280
286
|
}
|
|
281
287
|
|
|
@@ -60,7 +60,9 @@ describe("payment methods are keyed to the customer_account (BTS-19 reuse)", ()
|
|
|
60
60
|
|
|
61
61
|
it("detaches a payment method by id", async () => {
|
|
62
62
|
const stripe = makeStripe();
|
|
63
|
-
await detachPaymentMethod(asStripe(stripe), ctx, {
|
|
63
|
+
await detachPaymentMethod(asStripe(stripe), ctx, {
|
|
64
|
+
paymentMethodId: "pm_1",
|
|
65
|
+
});
|
|
64
66
|
expect(stripe.paymentMethods.detach).toHaveBeenCalledWith("pm_1");
|
|
65
67
|
});
|
|
66
68
|
});
|
|
@@ -51,5 +51,8 @@ export async function setDefaultPaymentMethod(
|
|
|
51
51
|
_ctx: RunCtx,
|
|
52
52
|
_opts: { stripeAccountId: string; paymentMethodId: string },
|
|
53
53
|
) {
|
|
54
|
-
throwStripeError(
|
|
54
|
+
throwStripeError(
|
|
55
|
+
"PAYMENT_METHOD_FAILED",
|
|
56
|
+
"[better-stripe] setDefaultPaymentMethod is not yet implemented for V2 Accounts. Use createBillingPortalSession() to let users manage payment methods.",
|
|
57
|
+
);
|
|
55
58
|
}
|
|
@@ -19,8 +19,7 @@ import type { SplitRecipientRole } from "../../component/lib/fees.js";
|
|
|
19
19
|
|
|
20
20
|
/** Who is initiating a refund. `accountId` is the seller's `acct_…` id. */
|
|
21
21
|
export type RefundActor =
|
|
22
|
-
| { type: "
|
|
23
|
-
| { type: "seller"; accountId: string };
|
|
22
|
+
{ type: "admin" } | { type: "seller"; accountId: string };
|
|
24
23
|
|
|
25
24
|
/**
|
|
26
25
|
* The subset of a payment's routing needed to authorize a seller refund, read
|