@fantastic.dev/better-stripe 0.7.0 → 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 (343) hide show
  1. package/CHANGELOG.md +23 -18
  2. package/README.md +122 -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 +1 -19
  45. package/dist/client/webhooks/processors.js.map +1 -1
  46. package/dist/component/connect/mutations.d.ts.map +1 -1
  47. package/dist/component/connect/mutations.js +4 -33
  48. package/dist/component/connect/mutations.js.map +1 -1
  49. package/dist/component/connect/schema.d.ts.map +1 -1
  50. package/dist/component/connect/schema.js.map +1 -1
  51. package/dist/component/lib/paymentSeller.d.ts +3 -0
  52. package/dist/component/lib/paymentSeller.d.ts.map +1 -0
  53. package/dist/component/lib/paymentSeller.js +10 -0
  54. package/dist/component/lib/paymentSeller.js.map +1 -0
  55. package/dist/component/lib/reversals.d.ts +10 -0
  56. package/dist/component/lib/reversals.d.ts.map +1 -1
  57. package/dist/component/lib/reversals.js +17 -0
  58. package/dist/component/lib/reversals.js.map +1 -1
  59. package/dist/react/components/ConnectProvider.d.ts +1 -1
  60. package/dist/react/components/ConnectProvider.d.ts.map +1 -1
  61. package/dist/react/components/ConnectProvider.js +18 -4
  62. package/dist/react/components/ConnectProvider.js.map +1 -1
  63. package/dist/react/components/ConnectStatusBadge.d.ts.map +1 -1
  64. package/dist/react/components/ConnectStatusBadge.js.map +1 -1
  65. package/dist/react/components/EmbeddedDisputes.d.ts +1 -1
  66. package/dist/react/components/EmbeddedDisputes.d.ts.map +1 -1
  67. package/dist/react/components/EmbeddedDisputes.js +1 -1
  68. package/dist/react/components/EmbeddedDisputes.js.map +1 -1
  69. package/dist/react/components/SplitBreakdown.d.ts.map +1 -1
  70. package/dist/react/components/SplitBreakdown.js +12 -2
  71. package/dist/react/components/SplitBreakdown.js.map +1 -1
  72. package/dist/react/hooks/useCheckoutSession.d.ts.map +1 -1
  73. package/dist/react/hooks/useCheckoutSession.js.map +1 -1
  74. package/dist/react/hooks/useConfirmPayment.d.ts.map +1 -1
  75. package/dist/react/hooks/useConfirmPayment.js.map +1 -1
  76. package/dist/react/index.d.ts +1 -0
  77. package/dist/react/index.d.ts.map +1 -1
  78. package/dist/react/index.js +2 -0
  79. package/dist/react/index.js.map +1 -1
  80. package/dist/react/workflows/Account.d.ts +67 -0
  81. package/dist/react/workflows/Account.d.ts.map +1 -0
  82. package/dist/react/workflows/Account.js +74 -0
  83. package/dist/react/workflows/Account.js.map +1 -0
  84. package/dist/react/workflows/Billing.d.ts +60 -0
  85. package/dist/react/workflows/Billing.d.ts.map +1 -0
  86. package/dist/react/workflows/Billing.js +84 -0
  87. package/dist/react/workflows/Billing.js.map +1 -0
  88. package/dist/react/workflows/BillingPlans.d.ts +45 -0
  89. package/dist/react/workflows/BillingPlans.d.ts.map +1 -0
  90. package/dist/react/workflows/BillingPlans.js +51 -0
  91. package/dist/react/workflows/BillingPlans.js.map +1 -0
  92. package/dist/react/workflows/Checkout.d.ts +46 -0
  93. package/dist/react/workflows/Checkout.d.ts.map +1 -0
  94. package/dist/react/workflows/Checkout.js +61 -0
  95. package/dist/react/workflows/Checkout.js.map +1 -0
  96. package/dist/react/workflows/CheckoutChooser.d.ts +20 -0
  97. package/dist/react/workflows/CheckoutChooser.d.ts.map +1 -0
  98. package/dist/react/workflows/CheckoutChooser.js +24 -0
  99. package/dist/react/workflows/CheckoutChooser.js.map +1 -0
  100. package/dist/react/workflows/CheckoutForms.d.ts +26 -0
  101. package/dist/react/workflows/CheckoutForms.d.ts.map +1 -0
  102. package/dist/react/workflows/CheckoutForms.js +126 -0
  103. package/dist/react/workflows/CheckoutForms.js.map +1 -0
  104. package/dist/react/workflows/ClipboardButton.d.ts +17 -0
  105. package/dist/react/workflows/ClipboardButton.d.ts.map +1 -0
  106. package/dist/react/workflows/ClipboardButton.js +35 -0
  107. package/dist/react/workflows/ClipboardButton.js.map +1 -0
  108. package/dist/react/workflows/Collection.d.ts +30 -0
  109. package/dist/react/workflows/Collection.d.ts.map +1 -0
  110. package/dist/react/workflows/Collection.js +25 -0
  111. package/dist/react/workflows/Collection.js.map +1 -0
  112. package/dist/react/workflows/Collections.d.ts +56 -0
  113. package/dist/react/workflows/Collections.d.ts.map +1 -0
  114. package/dist/react/workflows/Collections.js +111 -0
  115. package/dist/react/workflows/Collections.js.map +1 -0
  116. package/dist/react/workflows/Connect.d.ts +19 -0
  117. package/dist/react/workflows/Connect.d.ts.map +1 -0
  118. package/dist/react/workflows/Connect.js +43 -0
  119. package/dist/react/workflows/Connect.js.map +1 -0
  120. package/dist/react/workflows/Costs.d.ts +48 -0
  121. package/dist/react/workflows/Costs.d.ts.map +1 -0
  122. package/dist/react/workflows/Costs.js +66 -0
  123. package/dist/react/workflows/Costs.js.map +1 -0
  124. package/dist/react/workflows/Disputes.d.ts +36 -0
  125. package/dist/react/workflows/Disputes.d.ts.map +1 -0
  126. package/dist/react/workflows/Disputes.js +74 -0
  127. package/dist/react/workflows/Disputes.js.map +1 -0
  128. package/dist/react/workflows/Earnings.d.ts +42 -0
  129. package/dist/react/workflows/Earnings.d.ts.map +1 -0
  130. package/dist/react/workflows/Earnings.js +38 -0
  131. package/dist/react/workflows/Earnings.js.map +1 -0
  132. package/dist/react/workflows/Financials.d.ts +43 -0
  133. package/dist/react/workflows/Financials.d.ts.map +1 -0
  134. package/dist/react/workflows/Financials.js +57 -0
  135. package/dist/react/workflows/Financials.js.map +1 -0
  136. package/dist/react/workflows/IntegrationSwitch.d.ts +23 -0
  137. package/dist/react/workflows/IntegrationSwitch.d.ts.map +1 -0
  138. package/dist/react/workflows/IntegrationSwitch.js +31 -0
  139. package/dist/react/workflows/IntegrationSwitch.js.map +1 -0
  140. package/dist/react/workflows/Onboarding.d.ts +56 -0
  141. package/dist/react/workflows/Onboarding.d.ts.map +1 -0
  142. package/dist/react/workflows/Onboarding.js +86 -0
  143. package/dist/react/workflows/Onboarding.js.map +1 -0
  144. package/dist/react/workflows/Overview.d.ts +51 -0
  145. package/dist/react/workflows/Overview.d.ts.map +1 -0
  146. package/dist/react/workflows/Overview.js +63 -0
  147. package/dist/react/workflows/Overview.js.map +1 -0
  148. package/dist/react/workflows/PaymentMethods.d.ts +35 -0
  149. package/dist/react/workflows/PaymentMethods.d.ts.map +1 -0
  150. package/dist/react/workflows/PaymentMethods.js +63 -0
  151. package/dist/react/workflows/PaymentMethods.js.map +1 -0
  152. package/dist/react/workflows/PaymentReceipt.d.ts +20 -0
  153. package/dist/react/workflows/PaymentReceipt.d.ts.map +1 -0
  154. package/dist/react/workflows/PaymentReceipt.js +24 -0
  155. package/dist/react/workflows/PaymentReceipt.js.map +1 -0
  156. package/dist/react/workflows/Payouts.d.ts +47 -0
  157. package/dist/react/workflows/Payouts.d.ts.map +1 -0
  158. package/dist/react/workflows/Payouts.js +87 -0
  159. package/dist/react/workflows/Payouts.js.map +1 -0
  160. package/dist/react/workflows/Products.d.ts +92 -0
  161. package/dist/react/workflows/Products.d.ts.map +1 -0
  162. package/dist/react/workflows/Products.js +179 -0
  163. package/dist/react/workflows/Products.js.map +1 -0
  164. package/dist/react/workflows/ReferralLinks.d.ts +26 -0
  165. package/dist/react/workflows/ReferralLinks.d.ts.map +1 -0
  166. package/dist/react/workflows/ReferralLinks.js +30 -0
  167. package/dist/react/workflows/ReferralLinks.js.map +1 -0
  168. package/dist/react/workflows/Refunds.d.ts +72 -0
  169. package/dist/react/workflows/Refunds.d.ts.map +1 -0
  170. package/dist/react/workflows/Refunds.js +95 -0
  171. package/dist/react/workflows/Refunds.js.map +1 -0
  172. package/dist/react/workflows/Setup.d.ts +50 -0
  173. package/dist/react/workflows/Setup.d.ts.map +1 -0
  174. package/dist/react/workflows/Setup.js +59 -0
  175. package/dist/react/workflows/Setup.js.map +1 -0
  176. package/dist/react/workflows/Storefront.d.ts +53 -0
  177. package/dist/react/workflows/Storefront.d.ts.map +1 -0
  178. package/dist/react/workflows/Storefront.js +44 -0
  179. package/dist/react/workflows/Storefront.js.map +1 -0
  180. package/dist/react/workflows/SubscriptionOverview.d.ts +13 -0
  181. package/dist/react/workflows/SubscriptionOverview.d.ts.map +1 -0
  182. package/dist/react/workflows/SubscriptionOverview.js +26 -0
  183. package/dist/react/workflows/SubscriptionOverview.js.map +1 -0
  184. package/dist/react/workflows/Subscriptions.d.ts +92 -0
  185. package/dist/react/workflows/Subscriptions.d.ts.map +1 -0
  186. package/dist/react/workflows/Subscriptions.js +149 -0
  187. package/dist/react/workflows/Subscriptions.js.map +1 -0
  188. package/dist/react/workflows/Tasks.d.ts +40 -0
  189. package/dist/react/workflows/Tasks.d.ts.map +1 -0
  190. package/dist/react/workflows/Tasks.js +113 -0
  191. package/dist/react/workflows/Tasks.js.map +1 -0
  192. package/dist/react/workflows/checkout-options.d.ts +37 -0
  193. package/dist/react/workflows/checkout-options.d.ts.map +1 -0
  194. package/dist/react/workflows/checkout-options.js +43 -0
  195. package/dist/react/workflows/checkout-options.js.map +1 -0
  196. package/dist/react/workflows/current-subscription.d.ts +11 -0
  197. package/dist/react/workflows/current-subscription.d.ts.map +1 -0
  198. package/dist/react/workflows/current-subscription.js +14 -0
  199. package/dist/react/workflows/current-subscription.js.map +1 -0
  200. package/dist/react/workflows/filters.d.ts +17 -0
  201. package/dist/react/workflows/filters.d.ts.map +1 -0
  202. package/dist/react/workflows/filters.js +23 -0
  203. package/dist/react/workflows/filters.js.map +1 -0
  204. package/dist/react/workflows/index.d.ts +70 -0
  205. package/dist/react/workflows/index.d.ts.map +1 -0
  206. package/dist/react/workflows/index.js +38 -0
  207. package/dist/react/workflows/index.js.map +1 -0
  208. package/dist/react/workflows/useWorkflowAction.d.ts +11 -0
  209. package/dist/react/workflows/useWorkflowAction.d.ts.map +1 -0
  210. package/dist/react/workflows/useWorkflowAction.js +68 -0
  211. package/dist/react/workflows/useWorkflowAction.js.map +1 -0
  212. package/dist/react/workflows/useWorkflowResource.d.ts +9 -0
  213. package/dist/react/workflows/useWorkflowResource.d.ts.map +1 -0
  214. package/dist/react/workflows/useWorkflowResource.js +67 -0
  215. package/dist/react/workflows/useWorkflowResource.js.map +1 -0
  216. package/docs/react-workflows-audit.md +66 -0
  217. package/docs/react-workflows.md +231 -0
  218. package/package.json +19 -3
  219. package/src/client/billing/checkout-ui-modes.test.ts +49 -0
  220. package/src/client/billing/checkout.ts +8 -3
  221. package/src/client/billing/invoices.test.ts +12 -6
  222. package/src/client/connect/paymentMethods.test.ts +3 -1
  223. package/src/client/connect/paymentMethods.ts +4 -1
  224. package/src/client/connect/refundActor.ts +1 -2
  225. package/src/client/connect/refunds.test.ts +35 -10
  226. package/src/client/connect/refunds.ts +4 -1
  227. package/src/client/connect/transfers.test.ts +66 -12
  228. package/src/client/connect/transfers.ts +32 -8
  229. package/src/client/core/accountDefaults.ts +15 -0
  230. package/src/client/core/accounts.ts +14 -17
  231. package/src/client/core/config.test.ts +2 -1
  232. package/src/client/core/descriptors.test.ts +6 -4
  233. package/src/client/core/fees.test.ts +20 -28
  234. package/src/client/core/fees.ts +9 -2
  235. package/src/client/index.test.ts +22 -22
  236. package/src/client/index.ts +1 -1
  237. package/src/client/products/prices.test.ts +8 -2
  238. package/src/client/products/prices.ts +4 -1
  239. package/src/client/products/products.test.ts +61 -20
  240. package/src/client/products/products.ts +3 -1
  241. package/src/client/utils/data.test.ts +3 -1
  242. package/src/client/utils/owner.test.ts +4 -1
  243. package/src/client/utils/owner.ts +5 -1
  244. package/src/client/utils/stripeDashboardUrl.ts +1 -4
  245. package/src/client/webhooks/handler.test.ts +16 -19
  246. package/src/client/webhooks/helpers.test.ts +26 -13
  247. package/src/client/webhooks/helpers.ts +23 -0
  248. package/src/client/webhooks/hooks.test.ts +1 -2
  249. package/src/client/webhooks/processors.test.ts +18 -34
  250. package/src/client/webhooks/processors.ts +1 -23
  251. package/src/client/webhooks.test.ts +1 -2
  252. package/src/component/_generated/api.ts +2 -0
  253. package/src/component/connect/mutations.ts +5 -46
  254. package/src/component/connect/schema.ts +4 -3
  255. package/src/component/connect.test.ts +1 -5
  256. package/src/component/lib/paymentSeller.ts +15 -0
  257. package/src/component/lib/reversals.ts +30 -2
  258. package/src/component/subscription-scoping.test.ts +5 -1
  259. package/src/component/triggers.test.ts +7 -4
  260. package/src/react/components/BuyerBillingView.render.test.tsx +7 -2
  261. package/src/react/components/ConnectProvider.live.test.tsx +61 -0
  262. package/src/react/components/ConnectProvider.tsx +18 -4
  263. package/src/react/components/ConnectStatusBadge.tsx +1 -4
  264. package/src/react/components/DisputeDetail.render.test.tsx +5 -1
  265. package/src/react/components/EarningsSummary.render.test.tsx +2 -6
  266. package/src/react/components/EmbeddedDisputes.render.test.tsx +7 -5
  267. package/src/react/components/EmbeddedDisputes.tsx +4 -1
  268. package/src/react/components/EvidenceForm.render.test.tsx +2 -8
  269. package/src/react/components/SplitBreakdown.render.test.tsx +28 -5
  270. package/src/react/components/SplitBreakdown.tsx +12 -2
  271. package/src/react/hooks/useCheckoutSession.ts +1 -2
  272. package/src/react/hooks/useConfirmPayment.ts +1 -2
  273. package/src/react/hooks/useEarnings.test.ts +43 -8
  274. package/src/react/hooks/useStripeMode.test.ts +5 -8
  275. package/src/react/index.ts +3 -0
  276. package/src/react/workflows/Account.test.tsx +31 -0
  277. package/src/react/workflows/Account.tsx +183 -0
  278. package/src/react/workflows/Billing.test.tsx +45 -0
  279. package/src/react/workflows/Billing.tsx +213 -0
  280. package/src/react/workflows/BillingPlans.test.tsx +31 -0
  281. package/src/react/workflows/BillingPlans.tsx +130 -0
  282. package/src/react/workflows/Checkout.test.tsx +118 -0
  283. package/src/react/workflows/Checkout.tsx +135 -0
  284. package/src/react/workflows/CheckoutChooser.test.tsx +44 -0
  285. package/src/react/workflows/CheckoutChooser.tsx +77 -0
  286. package/src/react/workflows/CheckoutForm.test.tsx +66 -0
  287. package/src/react/workflows/CheckoutForms.test.tsx +123 -0
  288. package/src/react/workflows/CheckoutForms.tsx +247 -0
  289. package/src/react/workflows/ClipboardButton.test.tsx +34 -0
  290. package/src/react/workflows/ClipboardButton.tsx +67 -0
  291. package/src/react/workflows/Collection.tsx +76 -0
  292. package/src/react/workflows/Collections.test.tsx +86 -0
  293. package/src/react/workflows/Collections.tsx +213 -0
  294. package/src/react/workflows/Connect.test.tsx +50 -0
  295. package/src/react/workflows/Connect.tsx +107 -0
  296. package/src/react/workflows/Costs.test.tsx +41 -0
  297. package/src/react/workflows/Costs.tsx +133 -0
  298. package/src/react/workflows/Disputes.test.tsx +25 -0
  299. package/src/react/workflows/Disputes.tsx +164 -0
  300. package/src/react/workflows/Earnings.test.ts +19 -0
  301. package/src/react/workflows/Earnings.tsx +84 -0
  302. package/src/react/workflows/Financials.test.tsx +35 -0
  303. package/src/react/workflows/Financials.tsx +117 -0
  304. package/src/react/workflows/IntegrationSwitch.test.tsx +36 -0
  305. package/src/react/workflows/IntegrationSwitch.tsx +63 -0
  306. package/src/react/workflows/Onboarding.test.tsx +75 -0
  307. package/src/react/workflows/Onboarding.tsx +171 -0
  308. package/src/react/workflows/Overview.test.tsx +57 -0
  309. package/src/react/workflows/Overview.tsx +123 -0
  310. package/src/react/workflows/PaymentMethods.test.tsx +60 -0
  311. package/src/react/workflows/PaymentMethods.tsx +117 -0
  312. package/src/react/workflows/PaymentReceipt.test.tsx +24 -0
  313. package/src/react/workflows/PaymentReceipt.tsx +46 -0
  314. package/src/react/workflows/Payouts.test.tsx +82 -0
  315. package/src/react/workflows/Payouts.tsx +212 -0
  316. package/src/react/workflows/Products.test.tsx +90 -0
  317. package/src/react/workflows/Products.tsx +377 -0
  318. package/src/react/workflows/ReferralLinks.test.tsx +39 -0
  319. package/src/react/workflows/ReferralLinks.tsx +75 -0
  320. package/src/react/workflows/Refunds.test.tsx +75 -0
  321. package/src/react/workflows/Refunds.tsx +223 -0
  322. package/src/react/workflows/Setup.test.tsx +25 -0
  323. package/src/react/workflows/Setup.tsx +166 -0
  324. package/src/react/workflows/Storefront.test.tsx +82 -0
  325. package/src/react/workflows/Storefront.tsx +138 -0
  326. package/src/react/workflows/SubscriptionOverview.test.tsx +27 -0
  327. package/src/react/workflows/SubscriptionOverview.tsx +48 -0
  328. package/src/react/workflows/Subscriptions.test.tsx +61 -0
  329. package/src/react/workflows/Subscriptions.tsx +282 -0
  330. package/src/react/workflows/Tasks.test.tsx +23 -0
  331. package/src/react/workflows/Tasks.tsx +199 -0
  332. package/src/react/workflows/checkout-options.ts +42 -0
  333. package/src/react/workflows/current-subscription.test.ts +29 -0
  334. package/src/react/workflows/current-subscription.ts +25 -0
  335. package/src/react/workflows/filters.test.ts +12 -0
  336. package/src/react/workflows/filters.ts +22 -0
  337. package/src/react/workflows/index.ts +238 -0
  338. package/src/react/workflows/native-interactions.test.tsx +73 -0
  339. package/src/react/workflows/public-workflows.test.tsx +216 -0
  340. package/src/react/workflows/useWorkflowAction.test.tsx +54 -0
  341. package/src/react/workflows/useWorkflowAction.ts +75 -0
  342. package/src/react/workflows/useWorkflowResource.test.tsx +41 -0
  343. package/src/react/workflows/useWorkflowResource.ts +78 -0
@@ -0,0 +1,216 @@
1
+ import { renderToStaticMarkup } from "react-dom/server";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import {
4
+ CheckoutChooser,
5
+ SubscriptionOverview,
6
+ PayoutHistory,
7
+ PayoutOverview,
8
+ ChargeSummary,
9
+ PaymentDetails,
10
+ Account,
11
+ Onboarding,
12
+ Payouts,
13
+ Refunds,
14
+ Products,
15
+ Subscriptions,
16
+ SubscriptionManager,
17
+ BillingPlans,
18
+ InvoiceEstimate,
19
+ BalancePaymentSource,
20
+ BillingPortal,
21
+ ReferralLinks,
22
+ Sales,
23
+ Invoices,
24
+ RefundHistory,
25
+ ReferredSales,
26
+ WebhookEvents,
27
+ ChargebackLedger,
28
+ CostRecovery,
29
+ Overview,
30
+ EnvironmentStatus,
31
+ StripeSetup,
32
+ SandboxTesting,
33
+ PaymentReceipt,
34
+ Earnings,
35
+ Storefront,
36
+ } from "../index.js";
37
+ import type { ReactNode } from "react";
38
+ const action = vi.fn(async () => null);
39
+ const account = {
40
+ stripeAccountId: "acct_public",
41
+ email: "seller@example.com",
42
+ country: "US",
43
+ onboardingStatus: "complete",
44
+ configurations: ["recipient"],
45
+ };
46
+ const subscription = {
47
+ stripeSubscriptionId: "sub_public",
48
+ status: "active",
49
+ isTrialing: false,
50
+ cancelAtPeriodEnd: false,
51
+ };
52
+ describe("public workflows without example providers, a router, or CSS", () => {
53
+ const cases: [string, ReactNode][] = [
54
+ ["CheckoutChooser", <CheckoutChooser />],
55
+ ["SubscriptionOverview", <SubscriptionOverview subscriptions={[]} />],
56
+ ["PayoutHistory", <PayoutHistory rows={[]} />],
57
+ ["PayoutOverview", <PayoutOverview payouts={[]} currency="usd" />],
58
+ [
59
+ "ChargeSummary",
60
+ <ChargeSummary
61
+ gross={1000}
62
+ fee={90}
63
+ net={910}
64
+ currency="usd"
65
+ reconciles
66
+ />,
67
+ ],
68
+ ["PaymentDetails", <PaymentDetails payment={null} />],
69
+ ["Account", <Account scopeKey="seller" account={account} />],
70
+ [
71
+ "Onboarding",
72
+ <Onboarding
73
+ scopeKey="seller"
74
+ account={null}
75
+ createAccount={async () => ({
76
+ onboardingUrl: "https://connect.stripe.com",
77
+ })}
78
+ continueOnboarding={async () => ({ url: "https://connect.stripe.com" })}
79
+ />,
80
+ ],
81
+ [
82
+ "Payouts",
83
+ <Payouts
84
+ scopeKey="seller"
85
+ load={async () => ({
86
+ balances: [],
87
+ payouts: [],
88
+ upcoming: [],
89
+ nextCursor: null,
90
+ })}
91
+ />,
92
+ ],
93
+ [
94
+ "Refunds",
95
+ <Refunds
96
+ scopeKey="seller"
97
+ issueRefund={async () => ({ stripeRefundId: "re_public" })}
98
+ />,
99
+ ],
100
+ [
101
+ "Products",
102
+ <Products
103
+ scopeKey="seller"
104
+ products={[]}
105
+ createProduct={action}
106
+ createPrice={action}
107
+ />,
108
+ ],
109
+ ["Subscriptions", <Subscriptions rows={[subscription]} />],
110
+ [
111
+ "SubscriptionManager",
112
+ <SubscriptionManager
113
+ scopeKey="buyer"
114
+ subscription={subscription}
115
+ onAction={action}
116
+ />,
117
+ ],
118
+ [
119
+ "BillingPlans",
120
+ <BillingPlans
121
+ scopeKey="seller"
122
+ publishableKey="pk_test_public"
123
+ plans={[
124
+ {
125
+ id: "starter",
126
+ name: "Starter",
127
+ monthlyAmount: 900,
128
+ currency: "usd",
129
+ },
130
+ ]}
131
+ createCheckout={async () => ({
132
+ stripeSessionId: "cs_public",
133
+ clientSecret: "cs_public_secret",
134
+ })}
135
+ createPortal={async () => "https://billing.stripe.com"}
136
+ />,
137
+ ],
138
+ [
139
+ "InvoiceEstimate",
140
+ <InvoiceEstimate
141
+ scopeKey="seller"
142
+ load={async () => ({
143
+ total: 900,
144
+ currency: "usd",
145
+ nextBillingAt: 1800000000000,
146
+ lines: [],
147
+ })}
148
+ />,
149
+ ],
150
+ [
151
+ "BalancePaymentSource",
152
+ <BalancePaymentSource
153
+ scopeKey="seller"
154
+ enabled={false}
155
+ change={action}
156
+ />,
157
+ ],
158
+ [
159
+ "BillingPortal",
160
+ <BillingPortal
161
+ createSession={async () => "https://billing.stripe.com"}
162
+ />,
163
+ ],
164
+ ["ReferralLinks", <ReferralLinks links={[]} />],
165
+ ["Sales", <Sales rows={[]} />],
166
+ ["Invoices", <Invoices rows={[]} />],
167
+ ["RefundHistory", <RefundHistory rows={[]} />],
168
+ ["ReferredSales", <ReferredSales rows={[]} />],
169
+ ["WebhookEvents", <WebhookEvents rows={[]} />],
170
+ ["CostRecovery", <CostRecovery rows={[]} />],
171
+ ["ChargebackLedger", <ChargebackLedger chargeback={null} />],
172
+ ["Overview", <Overview products={[]} subscriptions={[]} />],
173
+ [
174
+ "EnvironmentStatus",
175
+ <EnvironmentStatus
176
+ checks={[{ id: "secret", label: "Stripe key", configured: true }]}
177
+ />,
178
+ ],
179
+ [
180
+ "StripeSetup",
181
+ <StripeSetup tasks={[{ id: "sync", label: "Sync", run: action }]} />,
182
+ ],
183
+ [
184
+ "SandboxTesting",
185
+ <SandboxTesting tasks={[{ id: "seed", label: "Seed", run: action }]} />,
186
+ ],
187
+ [
188
+ "PaymentReceipt",
189
+ <PaymentReceipt
190
+ payment={{ status: "succeeded", amount: 2900, currency: "usd" }}
191
+ />,
192
+ ],
193
+ [
194
+ "Earnings",
195
+ <Earnings
196
+ gross={2900}
197
+ reversed={0}
198
+ net={2900}
199
+ paidOut={0}
200
+ payouts={[]}
201
+ />,
202
+ ],
203
+ ["Storefront", <Storefront stores={[]} />],
204
+ ];
205
+ it.each(cases)(
206
+ "%s renders unstyled native HTML independently",
207
+ (_name, component) => {
208
+ const markup = renderToStaticMarkup(component);
209
+ expect(markup.length).toBeGreaterThan(0);
210
+ expect(markup).not.toContain("class=");
211
+ expect(markup).not.toContain("style=");
212
+ expect(markup).not.toContain("localhost");
213
+ expect(action).not.toHaveBeenCalled();
214
+ },
215
+ );
216
+ });
@@ -0,0 +1,54 @@
1
+ // @vitest-environment jsdom
2
+ import { act, renderHook, cleanup } from "@testing-library/react";
3
+ import { afterEach, expect, it, vi } from "vitest";
4
+ import { useWorkflowAction } from "./useWorkflowAction.js";
5
+ afterEach(cleanup);
6
+ it("prevents duplicate requests and exposes pending, errors, and retry", async () => {
7
+ let reject!: (error: Error) => void;
8
+ const callback = vi.fn(
9
+ () =>
10
+ new Promise<string>((_resolve, fail) => {
11
+ reject = fail;
12
+ }),
13
+ );
14
+ const { result } = renderHook(() => useWorkflowAction(callback));
15
+ let first!: Promise<string | undefined>;
16
+ act(() => {
17
+ first = result.current.run();
18
+ });
19
+ expect(result.current.isPending).toBe(true);
20
+ await act(async () => {
21
+ await result.current.run();
22
+ });
23
+ expect(callback).toHaveBeenCalledOnce();
24
+ await act(async () => {
25
+ reject(new Error("Stripe declined"));
26
+ await first;
27
+ });
28
+ expect(result.current.error).toBe("Stripe declined");
29
+ expect(result.current.isPending).toBe(false);
30
+ });
31
+ it("does not publish an old account's action result after a scope change", async () => {
32
+ let resolve!: (value: string) => void;
33
+ const callback = vi.fn(
34
+ () =>
35
+ new Promise<string>((done) => {
36
+ resolve = done;
37
+ }),
38
+ );
39
+ const { result, rerender } = renderHook(
40
+ ({ scope }) => useWorkflowAction(callback, scope),
41
+ { initialProps: { scope: "seller_one" } },
42
+ );
43
+ let request!: Promise<string | undefined>;
44
+ act(() => {
45
+ request = result.current.run();
46
+ });
47
+ rerender({ scope: "seller_two" });
48
+ await act(async () => {
49
+ resolve("seller_one_secret");
50
+ await request;
51
+ });
52
+ expect(result.current.result).toBeUndefined();
53
+ expect(result.current.isPending).toBe(false);
54
+ });
@@ -0,0 +1,75 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ export type WorkflowActionState<T, Args extends unknown[]> = {
4
+ isPending: boolean;
5
+ error: string | null;
6
+ result: T | undefined;
7
+ /** Errors are exposed in state; failed and duplicate calls return undefined. */
8
+ run: (...args: Args) => Promise<T | undefined>;
9
+ reset: () => void;
10
+ };
11
+ /** Shared async action lifecycle. Scope identifies the authenticated account/resource, not authorization. */
12
+ export function useWorkflowAction<T, Args extends unknown[]>(
13
+ action: (...args: Args) => Promise<T>,
14
+ scope: string = "default",
15
+ ): WorkflowActionState<T, Args> {
16
+ const initial = {
17
+ scope,
18
+ isPending: false,
19
+ error: null as string | null,
20
+ result: undefined as T | undefined,
21
+ };
22
+ const [state, setState] = useState(initial);
23
+ if (state.scope !== scope) setState(initial);
24
+ const callback = useRef(action);
25
+ const lifecycle = useRef({ version: 0, mounted: false });
26
+ const lock = useRef<number | null>(null);
27
+ useEffect(() => {
28
+ callback.current = action;
29
+ }, [action]);
30
+ useEffect(() => {
31
+ const version = ++lifecycle.current.version;
32
+ lifecycle.current.mounted = true;
33
+ lock.current = null;
34
+ return () => {
35
+ if (lifecycle.current.version === version) {
36
+ lifecycle.current.mounted = false;
37
+ lifecycle.current.version++;
38
+ lock.current = null;
39
+ }
40
+ };
41
+ }, [scope]);
42
+ const reset = useCallback(() => {
43
+ if (lock.current !== null) return;
44
+ setState({ scope, isPending: false, error: null, result: undefined });
45
+ }, [scope]);
46
+ const run = useCallback(
47
+ async (...args: Args) => {
48
+ if (lock.current !== null) return undefined;
49
+ const version = lifecycle.current.version;
50
+ lock.current = version;
51
+ setState({ scope, isPending: true, error: null, result: undefined });
52
+ const current = () =>
53
+ lifecycle.current.mounted && lifecycle.current.version === version;
54
+ try {
55
+ const result = await callback.current(...args);
56
+ if (!current()) return undefined;
57
+ setState({ scope, isPending: false, error: null, result });
58
+ return result;
59
+ } catch (error) {
60
+ if (current())
61
+ setState({
62
+ scope,
63
+ isPending: false,
64
+ error: error instanceof Error ? error.message : String(error),
65
+ result: undefined,
66
+ });
67
+ return undefined;
68
+ } finally {
69
+ if (lock.current === version) lock.current = null;
70
+ }
71
+ },
72
+ [scope],
73
+ );
74
+ return { ...state, run, reset };
75
+ }
@@ -0,0 +1,41 @@
1
+ // @vitest-environment jsdom
2
+ import { StrictMode } from "react";
3
+ import { act, cleanup, renderHook, waitFor } from "@testing-library/react";
4
+ import { afterEach, expect, it, vi } from "vitest";
5
+ import { useWorkflowResource } from "./useWorkflowResource.js";
6
+ afterEach(cleanup);
7
+ it("initializes only once in StrictMode and permits an explicit retry", async () => {
8
+ const load = vi
9
+ .fn()
10
+ .mockRejectedValueOnce(new Error("Unavailable"))
11
+ .mockResolvedValueOnce("fresh");
12
+ const { result } = renderHook(() => useWorkflowResource(load), {
13
+ wrapper: StrictMode,
14
+ });
15
+ await waitFor(() => expect(result.current.error).toBe("Unavailable"));
16
+ expect(load).toHaveBeenCalledOnce();
17
+ act(() => result.current.refresh());
18
+ await waitFor(() => expect(result.current.data).toBe("fresh"));
19
+ expect(load).toHaveBeenCalledTimes(2);
20
+ });
21
+ it("ignores an old account's response and loads new account data", async () => {
22
+ let resolve!: (value: string) => void;
23
+ const load = vi
24
+ .fn()
25
+ .mockImplementationOnce(
26
+ () =>
27
+ new Promise<string>((done) => {
28
+ resolve = done;
29
+ }),
30
+ )
31
+ .mockResolvedValueOnce("new balance");
32
+ const { result, rerender } = renderHook(
33
+ ({ scope }) => useWorkflowResource(load, scope),
34
+ { initialProps: { scope: "one" } },
35
+ );
36
+ await waitFor(() => expect(load).toHaveBeenCalledOnce());
37
+ rerender({ scope: "two" });
38
+ await waitFor(() => expect(result.current.data).toBe("new balance"));
39
+ await act(async () => resolve("old balance"));
40
+ expect(result.current.data).toBe("new balance");
41
+ });
@@ -0,0 +1,78 @@
1
+ "use client";
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ /** Loads once per scope/refresh, including under React StrictMode. Stale requests cannot update another scope. */
4
+ export function useWorkflowResource<T>(
5
+ load: () => Promise<T>,
6
+ scope = "default",
7
+ ) {
8
+ const initial = {
9
+ scope,
10
+ attempt: 0,
11
+ data: undefined as T | undefined,
12
+ error: null as string | null,
13
+ isLoading: true,
14
+ };
15
+ const [state, setState] = useState(initial);
16
+ if (state.scope !== scope) setState(initial);
17
+ const loader = useRef(load);
18
+ const request = useRef<{
19
+ scope: string;
20
+ attempt: number;
21
+ promise: Promise<T>;
22
+ } | null>(null);
23
+ useEffect(() => {
24
+ loader.current = load;
25
+ }, [load]);
26
+ useEffect(() => {
27
+ let active = true;
28
+ if (
29
+ !request.current ||
30
+ request.current.scope !== scope ||
31
+ request.current.attempt !== state.attempt
32
+ ) {
33
+ request.current = {
34
+ scope,
35
+ attempt: state.attempt,
36
+ promise: Promise.resolve().then(() => loader.current()),
37
+ };
38
+ }
39
+ void request.current.promise
40
+ .then((data) => {
41
+ if (active)
42
+ setState((previous) => ({
43
+ ...previous,
44
+ data,
45
+ error: null,
46
+ isLoading: false,
47
+ }));
48
+ })
49
+ .catch((error: unknown) => {
50
+ if (active)
51
+ setState((previous) => ({
52
+ ...previous,
53
+ error: error instanceof Error ? error.message : String(error),
54
+ isLoading: false,
55
+ }));
56
+ });
57
+ return () => {
58
+ active = false;
59
+ };
60
+ }, [scope, state.attempt]);
61
+ const refresh = useCallback(
62
+ () =>
63
+ setState((previous) => ({
64
+ ...previous,
65
+ attempt: previous.attempt + 1,
66
+ isLoading: true,
67
+ error: null,
68
+ })),
69
+ [],
70
+ );
71
+ return {
72
+ revision: state.attempt,
73
+ data: state.data,
74
+ error: state.error,
75
+ isLoading: state.isLoading,
76
+ refresh,
77
+ };
78
+ }