@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.
Files changed (359) hide show
  1. package/CHANGELOG.md +28 -16
  2. package/README.md +130 -90
  3. package/dist/client/billing/checkout.d.ts +1 -1
  4. package/dist/client/billing/checkout.d.ts.map +1 -1
  5. package/dist/client/billing/checkout.js +7 -2
  6. package/dist/client/billing/checkout.js.map +1 -1
  7. package/dist/client/connect/paymentMethods.d.ts.map +1 -1
  8. package/dist/client/connect/paymentMethods.js.map +1 -1
  9. package/dist/client/connect/refundActor.d.ts.map +1 -1
  10. package/dist/client/connect/refundActor.js.map +1 -1
  11. package/dist/client/connect/refunds.d.ts.map +1 -1
  12. package/dist/client/connect/refunds.js.map +1 -1
  13. package/dist/client/connect/transfers.d.ts.map +1 -1
  14. package/dist/client/connect/transfers.js +15 -4
  15. package/dist/client/connect/transfers.js.map +1 -1
  16. package/dist/client/core/accountDefaults.d.ts +6 -0
  17. package/dist/client/core/accountDefaults.d.ts.map +1 -0
  18. package/dist/client/core/accountDefaults.js +15 -0
  19. package/dist/client/core/accountDefaults.js.map +1 -0
  20. package/dist/client/core/accounts.d.ts +1 -5
  21. package/dist/client/core/accounts.d.ts.map +1 -1
  22. package/dist/client/core/accounts.js +2 -14
  23. package/dist/client/core/accounts.js.map +1 -1
  24. package/dist/client/core/fees.d.ts.map +1 -1
  25. package/dist/client/core/fees.js +7 -2
  26. package/dist/client/core/fees.js.map +1 -1
  27. package/dist/client/index.d.ts +1 -1
  28. package/dist/client/index.d.ts.map +1 -1
  29. package/dist/client/products/prices.d.ts.map +1 -1
  30. package/dist/client/products/prices.js.map +1 -1
  31. package/dist/client/products/products.d.ts.map +1 -1
  32. package/dist/client/products/products.js +3 -1
  33. package/dist/client/products/products.js.map +1 -1
  34. package/dist/client/utils/owner.d.ts.map +1 -1
  35. package/dist/client/utils/owner.js +3 -1
  36. package/dist/client/utils/owner.js.map +1 -1
  37. package/dist/client/utils/stripeDashboardUrl.d.ts.map +1 -1
  38. package/dist/client/utils/stripeDashboardUrl.js.map +1 -1
  39. package/dist/client/webhooks/helpers.d.ts +10 -0
  40. package/dist/client/webhooks/helpers.d.ts.map +1 -1
  41. package/dist/client/webhooks/helpers.js +18 -0
  42. package/dist/client/webhooks/helpers.js.map +1 -1
  43. package/dist/client/webhooks/processors.d.ts.map +1 -1
  44. package/dist/client/webhooks/processors.js +10 -24
  45. package/dist/client/webhooks/processors.js.map +1 -1
  46. package/dist/component/_generated/component.d.ts +34 -0
  47. package/dist/component/_generated/component.d.ts.map +1 -1
  48. package/dist/component/billing/queries.d.ts +36 -0
  49. package/dist/component/billing/queries.d.ts.map +1 -1
  50. package/dist/component/billing/queries.js +10 -0
  51. package/dist/component/billing/queries.js.map +1 -1
  52. package/dist/component/billing/schema.d.ts +1 -0
  53. package/dist/component/billing/schema.d.ts.map +1 -1
  54. package/dist/component/billing/schema.js +1 -0
  55. package/dist/component/billing/schema.js.map +1 -1
  56. package/dist/component/connect/mutations.d.ts.map +1 -1
  57. package/dist/component/connect/mutations.js +28 -28
  58. package/dist/component/connect/mutations.js.map +1 -1
  59. package/dist/component/connect/schema.d.ts.map +1 -1
  60. package/dist/component/connect/schema.js.map +1 -1
  61. package/dist/component/lib/paymentSeller.d.ts +3 -0
  62. package/dist/component/lib/paymentSeller.d.ts.map +1 -0
  63. package/dist/component/lib/paymentSeller.js +10 -0
  64. package/dist/component/lib/paymentSeller.js.map +1 -0
  65. package/dist/component/lib/reversals.d.ts +10 -0
  66. package/dist/component/lib/reversals.d.ts.map +1 -1
  67. package/dist/component/lib/reversals.js +17 -0
  68. package/dist/component/lib/reversals.js.map +1 -1
  69. package/dist/component/schema.d.ts +1 -0
  70. package/dist/react/components/ConnectProvider.d.ts +1 -1
  71. package/dist/react/components/ConnectProvider.d.ts.map +1 -1
  72. package/dist/react/components/ConnectProvider.js +18 -4
  73. package/dist/react/components/ConnectProvider.js.map +1 -1
  74. package/dist/react/components/ConnectStatusBadge.d.ts.map +1 -1
  75. package/dist/react/components/ConnectStatusBadge.js.map +1 -1
  76. package/dist/react/components/EmbeddedDisputes.d.ts +1 -1
  77. package/dist/react/components/EmbeddedDisputes.d.ts.map +1 -1
  78. package/dist/react/components/EmbeddedDisputes.js +1 -1
  79. package/dist/react/components/EmbeddedDisputes.js.map +1 -1
  80. package/dist/react/components/SplitBreakdown.d.ts.map +1 -1
  81. package/dist/react/components/SplitBreakdown.js +12 -2
  82. package/dist/react/components/SplitBreakdown.js.map +1 -1
  83. package/dist/react/hooks/useCheckoutSession.d.ts.map +1 -1
  84. package/dist/react/hooks/useCheckoutSession.js.map +1 -1
  85. package/dist/react/hooks/useConfirmPayment.d.ts.map +1 -1
  86. package/dist/react/hooks/useConfirmPayment.js.map +1 -1
  87. package/dist/react/index.d.ts +1 -0
  88. package/dist/react/index.d.ts.map +1 -1
  89. package/dist/react/index.js +2 -0
  90. package/dist/react/index.js.map +1 -1
  91. package/dist/react/workflows/Account.d.ts +67 -0
  92. package/dist/react/workflows/Account.d.ts.map +1 -0
  93. package/dist/react/workflows/Account.js +74 -0
  94. package/dist/react/workflows/Account.js.map +1 -0
  95. package/dist/react/workflows/Billing.d.ts +60 -0
  96. package/dist/react/workflows/Billing.d.ts.map +1 -0
  97. package/dist/react/workflows/Billing.js +84 -0
  98. package/dist/react/workflows/Billing.js.map +1 -0
  99. package/dist/react/workflows/BillingPlans.d.ts +45 -0
  100. package/dist/react/workflows/BillingPlans.d.ts.map +1 -0
  101. package/dist/react/workflows/BillingPlans.js +51 -0
  102. package/dist/react/workflows/BillingPlans.js.map +1 -0
  103. package/dist/react/workflows/Checkout.d.ts +46 -0
  104. package/dist/react/workflows/Checkout.d.ts.map +1 -0
  105. package/dist/react/workflows/Checkout.js +61 -0
  106. package/dist/react/workflows/Checkout.js.map +1 -0
  107. package/dist/react/workflows/CheckoutChooser.d.ts +20 -0
  108. package/dist/react/workflows/CheckoutChooser.d.ts.map +1 -0
  109. package/dist/react/workflows/CheckoutChooser.js +24 -0
  110. package/dist/react/workflows/CheckoutChooser.js.map +1 -0
  111. package/dist/react/workflows/CheckoutForms.d.ts +26 -0
  112. package/dist/react/workflows/CheckoutForms.d.ts.map +1 -0
  113. package/dist/react/workflows/CheckoutForms.js +126 -0
  114. package/dist/react/workflows/CheckoutForms.js.map +1 -0
  115. package/dist/react/workflows/ClipboardButton.d.ts +17 -0
  116. package/dist/react/workflows/ClipboardButton.d.ts.map +1 -0
  117. package/dist/react/workflows/ClipboardButton.js +35 -0
  118. package/dist/react/workflows/ClipboardButton.js.map +1 -0
  119. package/dist/react/workflows/Collection.d.ts +30 -0
  120. package/dist/react/workflows/Collection.d.ts.map +1 -0
  121. package/dist/react/workflows/Collection.js +25 -0
  122. package/dist/react/workflows/Collection.js.map +1 -0
  123. package/dist/react/workflows/Collections.d.ts +56 -0
  124. package/dist/react/workflows/Collections.d.ts.map +1 -0
  125. package/dist/react/workflows/Collections.js +111 -0
  126. package/dist/react/workflows/Collections.js.map +1 -0
  127. package/dist/react/workflows/Connect.d.ts +19 -0
  128. package/dist/react/workflows/Connect.d.ts.map +1 -0
  129. package/dist/react/workflows/Connect.js +43 -0
  130. package/dist/react/workflows/Connect.js.map +1 -0
  131. package/dist/react/workflows/Costs.d.ts +48 -0
  132. package/dist/react/workflows/Costs.d.ts.map +1 -0
  133. package/dist/react/workflows/Costs.js +66 -0
  134. package/dist/react/workflows/Costs.js.map +1 -0
  135. package/dist/react/workflows/Disputes.d.ts +36 -0
  136. package/dist/react/workflows/Disputes.d.ts.map +1 -0
  137. package/dist/react/workflows/Disputes.js +74 -0
  138. package/dist/react/workflows/Disputes.js.map +1 -0
  139. package/dist/react/workflows/Earnings.d.ts +42 -0
  140. package/dist/react/workflows/Earnings.d.ts.map +1 -0
  141. package/dist/react/workflows/Earnings.js +38 -0
  142. package/dist/react/workflows/Earnings.js.map +1 -0
  143. package/dist/react/workflows/Financials.d.ts +43 -0
  144. package/dist/react/workflows/Financials.d.ts.map +1 -0
  145. package/dist/react/workflows/Financials.js +57 -0
  146. package/dist/react/workflows/Financials.js.map +1 -0
  147. package/dist/react/workflows/IntegrationSwitch.d.ts +23 -0
  148. package/dist/react/workflows/IntegrationSwitch.d.ts.map +1 -0
  149. package/dist/react/workflows/IntegrationSwitch.js +31 -0
  150. package/dist/react/workflows/IntegrationSwitch.js.map +1 -0
  151. package/dist/react/workflows/Onboarding.d.ts +56 -0
  152. package/dist/react/workflows/Onboarding.d.ts.map +1 -0
  153. package/dist/react/workflows/Onboarding.js +86 -0
  154. package/dist/react/workflows/Onboarding.js.map +1 -0
  155. package/dist/react/workflows/Overview.d.ts +51 -0
  156. package/dist/react/workflows/Overview.d.ts.map +1 -0
  157. package/dist/react/workflows/Overview.js +63 -0
  158. package/dist/react/workflows/Overview.js.map +1 -0
  159. package/dist/react/workflows/PaymentMethods.d.ts +35 -0
  160. package/dist/react/workflows/PaymentMethods.d.ts.map +1 -0
  161. package/dist/react/workflows/PaymentMethods.js +63 -0
  162. package/dist/react/workflows/PaymentMethods.js.map +1 -0
  163. package/dist/react/workflows/PaymentReceipt.d.ts +20 -0
  164. package/dist/react/workflows/PaymentReceipt.d.ts.map +1 -0
  165. package/dist/react/workflows/PaymentReceipt.js +24 -0
  166. package/dist/react/workflows/PaymentReceipt.js.map +1 -0
  167. package/dist/react/workflows/Payouts.d.ts +47 -0
  168. package/dist/react/workflows/Payouts.d.ts.map +1 -0
  169. package/dist/react/workflows/Payouts.js +87 -0
  170. package/dist/react/workflows/Payouts.js.map +1 -0
  171. package/dist/react/workflows/Products.d.ts +92 -0
  172. package/dist/react/workflows/Products.d.ts.map +1 -0
  173. package/dist/react/workflows/Products.js +179 -0
  174. package/dist/react/workflows/Products.js.map +1 -0
  175. package/dist/react/workflows/ReferralLinks.d.ts +26 -0
  176. package/dist/react/workflows/ReferralLinks.d.ts.map +1 -0
  177. package/dist/react/workflows/ReferralLinks.js +30 -0
  178. package/dist/react/workflows/ReferralLinks.js.map +1 -0
  179. package/dist/react/workflows/Refunds.d.ts +72 -0
  180. package/dist/react/workflows/Refunds.d.ts.map +1 -0
  181. package/dist/react/workflows/Refunds.js +95 -0
  182. package/dist/react/workflows/Refunds.js.map +1 -0
  183. package/dist/react/workflows/Setup.d.ts +50 -0
  184. package/dist/react/workflows/Setup.d.ts.map +1 -0
  185. package/dist/react/workflows/Setup.js +59 -0
  186. package/dist/react/workflows/Setup.js.map +1 -0
  187. package/dist/react/workflows/Storefront.d.ts +53 -0
  188. package/dist/react/workflows/Storefront.d.ts.map +1 -0
  189. package/dist/react/workflows/Storefront.js +44 -0
  190. package/dist/react/workflows/Storefront.js.map +1 -0
  191. package/dist/react/workflows/SubscriptionOverview.d.ts +13 -0
  192. package/dist/react/workflows/SubscriptionOverview.d.ts.map +1 -0
  193. package/dist/react/workflows/SubscriptionOverview.js +26 -0
  194. package/dist/react/workflows/SubscriptionOverview.js.map +1 -0
  195. package/dist/react/workflows/Subscriptions.d.ts +92 -0
  196. package/dist/react/workflows/Subscriptions.d.ts.map +1 -0
  197. package/dist/react/workflows/Subscriptions.js +149 -0
  198. package/dist/react/workflows/Subscriptions.js.map +1 -0
  199. package/dist/react/workflows/Tasks.d.ts +40 -0
  200. package/dist/react/workflows/Tasks.d.ts.map +1 -0
  201. package/dist/react/workflows/Tasks.js +113 -0
  202. package/dist/react/workflows/Tasks.js.map +1 -0
  203. package/dist/react/workflows/checkout-options.d.ts +37 -0
  204. package/dist/react/workflows/checkout-options.d.ts.map +1 -0
  205. package/dist/react/workflows/checkout-options.js +43 -0
  206. package/dist/react/workflows/checkout-options.js.map +1 -0
  207. package/dist/react/workflows/current-subscription.d.ts +11 -0
  208. package/dist/react/workflows/current-subscription.d.ts.map +1 -0
  209. package/dist/react/workflows/current-subscription.js +14 -0
  210. package/dist/react/workflows/current-subscription.js.map +1 -0
  211. package/dist/react/workflows/filters.d.ts +17 -0
  212. package/dist/react/workflows/filters.d.ts.map +1 -0
  213. package/dist/react/workflows/filters.js +23 -0
  214. package/dist/react/workflows/filters.js.map +1 -0
  215. package/dist/react/workflows/index.d.ts +70 -0
  216. package/dist/react/workflows/index.d.ts.map +1 -0
  217. package/dist/react/workflows/index.js +38 -0
  218. package/dist/react/workflows/index.js.map +1 -0
  219. package/dist/react/workflows/useWorkflowAction.d.ts +11 -0
  220. package/dist/react/workflows/useWorkflowAction.d.ts.map +1 -0
  221. package/dist/react/workflows/useWorkflowAction.js +68 -0
  222. package/dist/react/workflows/useWorkflowAction.js.map +1 -0
  223. package/dist/react/workflows/useWorkflowResource.d.ts +9 -0
  224. package/dist/react/workflows/useWorkflowResource.d.ts.map +1 -0
  225. package/dist/react/workflows/useWorkflowResource.js +67 -0
  226. package/dist/react/workflows/useWorkflowResource.js.map +1 -0
  227. package/docs/react-workflows-audit.md +66 -0
  228. package/docs/react-workflows.md +231 -0
  229. package/package.json +19 -3
  230. package/src/client/billing/checkout-ui-modes.test.ts +49 -0
  231. package/src/client/billing/checkout.ts +8 -3
  232. package/src/client/billing/invoices.test.ts +12 -6
  233. package/src/client/connect/paymentMethods.test.ts +3 -1
  234. package/src/client/connect/paymentMethods.ts +4 -1
  235. package/src/client/connect/refundActor.ts +1 -2
  236. package/src/client/connect/refunds.test.ts +35 -10
  237. package/src/client/connect/refunds.ts +4 -1
  238. package/src/client/connect/transfers.test.ts +66 -12
  239. package/src/client/connect/transfers.ts +32 -8
  240. package/src/client/core/accountDefaults.ts +15 -0
  241. package/src/client/core/accounts.ts +14 -17
  242. package/src/client/core/config.test.ts +2 -1
  243. package/src/client/core/descriptors.test.ts +6 -4
  244. package/src/client/core/fees.test.ts +20 -28
  245. package/src/client/core/fees.ts +9 -2
  246. package/src/client/index.test.ts +22 -22
  247. package/src/client/index.ts +1 -1
  248. package/src/client/products/prices.test.ts +8 -2
  249. package/src/client/products/prices.ts +4 -1
  250. package/src/client/products/products.test.ts +61 -20
  251. package/src/client/products/products.ts +3 -1
  252. package/src/client/utils/data.test.ts +3 -1
  253. package/src/client/utils/owner.test.ts +4 -1
  254. package/src/client/utils/owner.ts +5 -1
  255. package/src/client/utils/stripeDashboardUrl.ts +1 -4
  256. package/src/client/webhooks/handler.test.ts +16 -19
  257. package/src/client/webhooks/helpers.test.ts +26 -13
  258. package/src/client/webhooks/helpers.ts +23 -0
  259. package/src/client/webhooks/hooks.test.ts +1 -2
  260. package/src/client/webhooks/processors.test.ts +34 -34
  261. package/src/client/webhooks/processors.ts +9 -26
  262. package/src/client/webhooks.test.ts +1 -2
  263. package/src/component/_generated/api.ts +2 -0
  264. package/src/component/_generated/component.ts +46 -0
  265. package/src/component/billing/queries.ts +12 -0
  266. package/src/component/billing/schema.ts +1 -0
  267. package/src/component/connect/mutations.ts +34 -35
  268. package/src/component/connect/schema.ts +4 -3
  269. package/src/component/connect.test.ts +1 -5
  270. package/src/component/lib/paymentSeller.ts +15 -0
  271. package/src/component/lib/reversals.ts +30 -2
  272. package/src/component/seller-case-ownership.test.ts +61 -0
  273. package/src/component/store-subscriptions.test.ts +32 -0
  274. package/src/component/subscription-scoping.test.ts +5 -1
  275. package/src/component/triggers.test.ts +7 -4
  276. package/src/react/components/BuyerBillingView.render.test.tsx +7 -2
  277. package/src/react/components/ConnectProvider.live.test.tsx +61 -0
  278. package/src/react/components/ConnectProvider.tsx +18 -4
  279. package/src/react/components/ConnectStatusBadge.tsx +1 -4
  280. package/src/react/components/DisputeDetail.render.test.tsx +5 -1
  281. package/src/react/components/EarningsSummary.render.test.tsx +2 -6
  282. package/src/react/components/EmbeddedDisputes.render.test.tsx +7 -5
  283. package/src/react/components/EmbeddedDisputes.tsx +4 -1
  284. package/src/react/components/EvidenceForm.render.test.tsx +2 -8
  285. package/src/react/components/SplitBreakdown.render.test.tsx +28 -5
  286. package/src/react/components/SplitBreakdown.tsx +12 -2
  287. package/src/react/hooks/useCheckoutSession.ts +1 -2
  288. package/src/react/hooks/useConfirmPayment.ts +1 -2
  289. package/src/react/hooks/useEarnings.test.ts +43 -8
  290. package/src/react/hooks/useStripeMode.test.ts +5 -8
  291. package/src/react/index.ts +3 -0
  292. package/src/react/workflows/Account.test.tsx +31 -0
  293. package/src/react/workflows/Account.tsx +183 -0
  294. package/src/react/workflows/Billing.test.tsx +45 -0
  295. package/src/react/workflows/Billing.tsx +213 -0
  296. package/src/react/workflows/BillingPlans.test.tsx +31 -0
  297. package/src/react/workflows/BillingPlans.tsx +130 -0
  298. package/src/react/workflows/Checkout.test.tsx +118 -0
  299. package/src/react/workflows/Checkout.tsx +135 -0
  300. package/src/react/workflows/CheckoutChooser.test.tsx +44 -0
  301. package/src/react/workflows/CheckoutChooser.tsx +77 -0
  302. package/src/react/workflows/CheckoutForm.test.tsx +66 -0
  303. package/src/react/workflows/CheckoutForms.test.tsx +123 -0
  304. package/src/react/workflows/CheckoutForms.tsx +247 -0
  305. package/src/react/workflows/ClipboardButton.test.tsx +34 -0
  306. package/src/react/workflows/ClipboardButton.tsx +67 -0
  307. package/src/react/workflows/Collection.tsx +76 -0
  308. package/src/react/workflows/Collections.test.tsx +86 -0
  309. package/src/react/workflows/Collections.tsx +213 -0
  310. package/src/react/workflows/Connect.test.tsx +50 -0
  311. package/src/react/workflows/Connect.tsx +107 -0
  312. package/src/react/workflows/Costs.test.tsx +41 -0
  313. package/src/react/workflows/Costs.tsx +133 -0
  314. package/src/react/workflows/Disputes.test.tsx +25 -0
  315. package/src/react/workflows/Disputes.tsx +164 -0
  316. package/src/react/workflows/Earnings.test.ts +19 -0
  317. package/src/react/workflows/Earnings.tsx +84 -0
  318. package/src/react/workflows/Financials.test.tsx +35 -0
  319. package/src/react/workflows/Financials.tsx +117 -0
  320. package/src/react/workflows/IntegrationSwitch.test.tsx +36 -0
  321. package/src/react/workflows/IntegrationSwitch.tsx +63 -0
  322. package/src/react/workflows/Onboarding.test.tsx +75 -0
  323. package/src/react/workflows/Onboarding.tsx +171 -0
  324. package/src/react/workflows/Overview.test.tsx +57 -0
  325. package/src/react/workflows/Overview.tsx +123 -0
  326. package/src/react/workflows/PaymentMethods.test.tsx +60 -0
  327. package/src/react/workflows/PaymentMethods.tsx +117 -0
  328. package/src/react/workflows/PaymentReceipt.test.tsx +24 -0
  329. package/src/react/workflows/PaymentReceipt.tsx +46 -0
  330. package/src/react/workflows/Payouts.test.tsx +82 -0
  331. package/src/react/workflows/Payouts.tsx +212 -0
  332. package/src/react/workflows/Products.test.tsx +90 -0
  333. package/src/react/workflows/Products.tsx +377 -0
  334. package/src/react/workflows/ReferralLinks.test.tsx +39 -0
  335. package/src/react/workflows/ReferralLinks.tsx +75 -0
  336. package/src/react/workflows/Refunds.test.tsx +75 -0
  337. package/src/react/workflows/Refunds.tsx +223 -0
  338. package/src/react/workflows/Setup.test.tsx +25 -0
  339. package/src/react/workflows/Setup.tsx +166 -0
  340. package/src/react/workflows/Storefront.test.tsx +82 -0
  341. package/src/react/workflows/Storefront.tsx +138 -0
  342. package/src/react/workflows/SubscriptionOverview.test.tsx +27 -0
  343. package/src/react/workflows/SubscriptionOverview.tsx +48 -0
  344. package/src/react/workflows/Subscriptions.test.tsx +61 -0
  345. package/src/react/workflows/Subscriptions.tsx +282 -0
  346. package/src/react/workflows/Tasks.test.tsx +23 -0
  347. package/src/react/workflows/Tasks.tsx +199 -0
  348. package/src/react/workflows/checkout-options.ts +42 -0
  349. package/src/react/workflows/current-subscription.test.ts +29 -0
  350. package/src/react/workflows/current-subscription.ts +25 -0
  351. package/src/react/workflows/filters.test.ts +12 -0
  352. package/src/react/workflows/filters.ts +22 -0
  353. package/src/react/workflows/index.ts +238 -0
  354. package/src/react/workflows/native-interactions.test.tsx +73 -0
  355. package/src/react/workflows/public-workflows.test.tsx +216 -0
  356. package/src/react/workflows/useWorkflowAction.test.tsx +54 -0
  357. package/src/react/workflows/useWorkflowAction.ts +75 -0
  358. package/src/react/workflows/useWorkflowResource.test.tsx +41 -0
  359. 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, args);
164
+ await ctx.db.patch("refunds", existing._id, record);
145
165
  } else {
146
- await ctx.db.insert("refunds", args);
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, args);
305
+ await ctx.db.patch("disputes", existing._id, record);
283
306
  } else {
284
- await ctx.db.insert("disputes", args);
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
- pendingFeeRefundFields,
39
- ).index("by_stripe_payment_intent_id", ["stripePaymentIntentId"]);
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
- | "pending"
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(leg.amount, Math.max(from, Math.round(leg.amount * fraction)));
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 = total > 0 ? Math.round((mode.amount * leg.amount) / total) : 0;
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
- { userId: "buyer_1", destinationAccountId: "acct_store_a", status: "active" },
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(api.webhooks.mutations.insertWebhookEvent, {
240
- stripeEventId: "evt_stale_001",
241
- eventType: "invoice.paid",
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, { subscriptions: [], paymentMethod: null }),
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", { "data-testid": "embedded-card" }),
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
- | "pending"
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: { dueBy: dispute.evidenceDueBy, daysRemaining: -2, isOverdue: true },
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 EXACT fetcher reference is handed over — the Connect runtime calls
77
- // it to obtain the createDisputeSession clientSecret; render must not.
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({ payment, className }: EmbeddedDisputesProps) {
28
+ export function EmbeddedDisputes({
29
+ payment,
30
+ className,
31
+ }: EmbeddedDisputesProps) {
29
32
  return (
30
33
  <div className={className}>
31
34
  {payment ? (