@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.
Files changed (359) hide show
  1. package/CHANGELOG.md +29 -18
  2. package/README.md +123 -91
  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/disputes.d.ts +1 -1
  8. package/dist/client/connect/disputes.d.ts.map +1 -1
  9. package/dist/client/connect/disputes.js +12 -6
  10. package/dist/client/connect/disputes.js.map +1 -1
  11. package/dist/client/connect/paymentMethods.d.ts.map +1 -1
  12. package/dist/client/connect/paymentMethods.js.map +1 -1
  13. package/dist/client/connect/refundActor.d.ts.map +1 -1
  14. package/dist/client/connect/refundActor.js.map +1 -1
  15. package/dist/client/connect/refunds.d.ts.map +1 -1
  16. package/dist/client/connect/refunds.js.map +1 -1
  17. package/dist/client/connect/transfers.d.ts.map +1 -1
  18. package/dist/client/connect/transfers.js +15 -4
  19. package/dist/client/connect/transfers.js.map +1 -1
  20. package/dist/client/core/accountDefaults.d.ts +6 -0
  21. package/dist/client/core/accountDefaults.d.ts.map +1 -0
  22. package/dist/client/core/accountDefaults.js +15 -0
  23. package/dist/client/core/accountDefaults.js.map +1 -0
  24. package/dist/client/core/accounts.d.ts +1 -5
  25. package/dist/client/core/accounts.d.ts.map +1 -1
  26. package/dist/client/core/accounts.js +2 -14
  27. package/dist/client/core/accounts.js.map +1 -1
  28. package/dist/client/core/fees.d.ts.map +1 -1
  29. package/dist/client/core/fees.js +7 -2
  30. package/dist/client/core/fees.js.map +1 -1
  31. package/dist/client/index.d.ts +1 -1
  32. package/dist/client/index.d.ts.map +1 -1
  33. package/dist/client/products/prices.d.ts.map +1 -1
  34. package/dist/client/products/prices.js.map +1 -1
  35. package/dist/client/products/products.d.ts.map +1 -1
  36. package/dist/client/products/products.js +3 -1
  37. package/dist/client/products/products.js.map +1 -1
  38. package/dist/client/utils/owner.d.ts.map +1 -1
  39. package/dist/client/utils/owner.js +3 -1
  40. package/dist/client/utils/owner.js.map +1 -1
  41. package/dist/client/utils/stripeDashboardUrl.d.ts.map +1 -1
  42. package/dist/client/utils/stripeDashboardUrl.js.map +1 -1
  43. package/dist/client/webhooks/helpers.d.ts +10 -0
  44. package/dist/client/webhooks/helpers.d.ts.map +1 -1
  45. package/dist/client/webhooks/helpers.js +18 -0
  46. package/dist/client/webhooks/helpers.js.map +1 -1
  47. package/dist/client/webhooks/processors.d.ts.map +1 -1
  48. package/dist/client/webhooks/processors.js +1 -19
  49. package/dist/client/webhooks/processors.js.map +1 -1
  50. package/dist/component/connect/mutations.d.ts.map +1 -1
  51. package/dist/component/connect/mutations.js +4 -33
  52. package/dist/component/connect/mutations.js.map +1 -1
  53. package/dist/component/connect/schema.d.ts.map +1 -1
  54. package/dist/component/connect/schema.js.map +1 -1
  55. package/dist/component/lib/paymentSeller.d.ts +3 -0
  56. package/dist/component/lib/paymentSeller.d.ts.map +1 -0
  57. package/dist/component/lib/paymentSeller.js +10 -0
  58. package/dist/component/lib/paymentSeller.js.map +1 -0
  59. package/dist/component/lib/reversals.d.ts +10 -0
  60. package/dist/component/lib/reversals.d.ts.map +1 -1
  61. package/dist/component/lib/reversals.js +17 -0
  62. package/dist/component/lib/reversals.js.map +1 -1
  63. package/dist/react/components/ConnectProvider.d.ts +1 -1
  64. package/dist/react/components/ConnectProvider.d.ts.map +1 -1
  65. package/dist/react/components/ConnectProvider.js +18 -4
  66. package/dist/react/components/ConnectProvider.js.map +1 -1
  67. package/dist/react/components/ConnectStatusBadge.d.ts.map +1 -1
  68. package/dist/react/components/ConnectStatusBadge.js.map +1 -1
  69. package/dist/react/components/DisputeDetail.d.ts +4 -1
  70. package/dist/react/components/DisputeDetail.d.ts.map +1 -1
  71. package/dist/react/components/DisputeDetail.js +12 -6
  72. package/dist/react/components/DisputeDetail.js.map +1 -1
  73. package/dist/react/components/DisputesList.d.ts.map +1 -1
  74. package/dist/react/components/DisputesList.js +2 -1
  75. package/dist/react/components/DisputesList.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 +2 -1
  88. package/dist/react/index.d.ts.map +1 -1
  89. package/dist/react/index.js +3 -1
  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 +48 -0
  168. package/dist/react/workflows/Payouts.d.ts.map +1 -0
  169. package/dist/react/workflows/Payouts.js +88 -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 +88 -0
  228. package/docs/react-workflows.md +234 -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/disputes.test.ts +15 -0
  234. package/src/client/connect/disputes.ts +13 -7
  235. package/src/client/connect/paymentMethods.test.ts +3 -1
  236. package/src/client/connect/paymentMethods.ts +4 -1
  237. package/src/client/connect/refundActor.ts +1 -2
  238. package/src/client/connect/refunds.test.ts +35 -10
  239. package/src/client/connect/refunds.ts +4 -1
  240. package/src/client/connect/transfers.test.ts +66 -12
  241. package/src/client/connect/transfers.ts +32 -8
  242. package/src/client/core/accountDefaults.ts +15 -0
  243. package/src/client/core/accounts.ts +14 -17
  244. package/src/client/core/config.test.ts +2 -1
  245. package/src/client/core/descriptors.test.ts +6 -4
  246. package/src/client/core/fees.test.ts +20 -28
  247. package/src/client/core/fees.ts +9 -2
  248. package/src/client/index.test.ts +22 -22
  249. package/src/client/index.ts +1 -1
  250. package/src/client/products/prices.test.ts +8 -2
  251. package/src/client/products/prices.ts +4 -1
  252. package/src/client/products/products.test.ts +61 -20
  253. package/src/client/products/products.ts +3 -1
  254. package/src/client/utils/data.test.ts +3 -1
  255. package/src/client/utils/owner.test.ts +4 -1
  256. package/src/client/utils/owner.ts +5 -1
  257. package/src/client/utils/stripeDashboardUrl.ts +1 -4
  258. package/src/client/webhooks/handler.test.ts +16 -19
  259. package/src/client/webhooks/helpers.test.ts +26 -13
  260. package/src/client/webhooks/helpers.ts +23 -0
  261. package/src/client/webhooks/hooks.test.ts +1 -2
  262. package/src/client/webhooks/processors.test.ts +18 -34
  263. package/src/client/webhooks/processors.ts +1 -23
  264. package/src/client/webhooks.test.ts +1 -2
  265. package/src/component/_generated/api.ts +2 -0
  266. package/src/component/connect/mutations.ts +5 -46
  267. package/src/component/connect/schema.ts +4 -3
  268. package/src/component/connect.test.ts +1 -5
  269. package/src/component/lib/paymentSeller.ts +15 -0
  270. package/src/component/lib/reversals.ts +30 -2
  271. package/src/component/subscription-scoping.test.ts +5 -1
  272. package/src/component/triggers.test.ts +7 -4
  273. package/src/react/components/BuyerBillingView.render.test.tsx +7 -2
  274. package/src/react/components/ConnectProvider.live.test.tsx +61 -0
  275. package/src/react/components/ConnectProvider.tsx +18 -4
  276. package/src/react/components/ConnectStatusBadge.tsx +1 -4
  277. package/src/react/components/DisputeDetail.render.test.tsx +5 -1
  278. package/src/react/components/DisputeDetail.tsx +14 -5
  279. package/src/react/components/DisputesList.render.test.tsx +21 -0
  280. package/src/react/components/DisputesList.tsx +2 -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 +3 -10
  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 +7 -1
  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 +64 -0
  315. package/src/react/workflows/Disputes.tsx +173 -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 +112 -0
  331. package/src/react/workflows/Payouts.tsx +215 -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
@@ -50,17 +50,21 @@ function makeComponent(): Component {
50
50
  * product row (for updateProduct's account lookup); `account` is the store's
51
51
  * account record; both default to null.
52
52
  */
53
- function makeCtx(opts: {
54
- product?: { _id?: string; accountId?: string } | null;
55
- account?: { statementDescriptor?: string } | null;
56
- mutation?: unknown;
57
- } = {}) {
58
- const runQuery = vi.fn().mockImplementation((refObj: Record<symbol, string>) => {
59
- const path = refObj[TO_REF] ?? "";
60
- if (path.includes("getAccountByStripeId")) return opts.account ?? null;
61
- if (path.includes("getProductByStripeId")) return opts.product ?? null;
62
- return null;
63
- });
53
+ function makeCtx(
54
+ opts: {
55
+ product?: { _id?: string; accountId?: string } | null;
56
+ account?: { statementDescriptor?: string } | null;
57
+ mutation?: unknown;
58
+ } = {},
59
+ ) {
60
+ const runQuery = vi
61
+ .fn()
62
+ .mockImplementation((refObj: Record<symbol, string>) => {
63
+ const path = refObj[TO_REF] ?? "";
64
+ if (path.includes("getAccountByStripeId")) return opts.account ?? null;
65
+ if (path.includes("getProductByStripeId")) return opts.product ?? null;
66
+ return null;
67
+ });
64
68
  const runMutation = vi.fn().mockResolvedValue(opts.mutation ?? undefined);
65
69
  return { runQuery, runMutation } as unknown as RunCtx & {
66
70
  runQuery: ReturnType<typeof vi.fn>;
@@ -115,7 +119,10 @@ describe("createProduct", () => {
115
119
  name: "Widget",
116
120
  });
117
121
 
118
- expect(result).toEqual({ productId: "internal_1", stripeProductId: "prod_1" });
122
+ expect(result).toEqual({
123
+ productId: "internal_1",
124
+ stripeProductId: "prod_1",
125
+ });
119
126
  // active defaults to true when omitted
120
127
  expect(stripe.products.create.mock.calls[0][0].active).toBe(true);
121
128
  });
@@ -261,7 +268,9 @@ describe("createProduct — per-store statement descriptor (BTS-67)", () => {
261
268
  ).toBeUndefined();
262
269
  // The account query is never made when there's no store.
263
270
  expect(ctx.runQuery).not.toHaveBeenCalledWith(
264
- expect.objectContaining({ [TO_REF]: "betterStripe/core/queries/getAccountByStripeId" }),
271
+ expect.objectContaining({
272
+ [TO_REF]: "betterStripe/core/queries/getAccountByStripeId",
273
+ }),
265
274
  expect.anything(),
266
275
  );
267
276
  });
@@ -312,7 +321,9 @@ describe("deactivateProduct / deleteProduct", () => {
312
321
 
313
322
  describe("read delegators", () => {
314
323
  it("getProduct returns the queried row", async () => {
315
- const ctx = { runQuery: vi.fn().mockResolvedValue({ _id: "x" }) } as unknown as RunCtx;
324
+ const ctx = {
325
+ runQuery: vi.fn().mockResolvedValue({ _id: "x" }),
326
+ } as unknown as RunCtx;
316
327
  expect(await getProduct(makeComponent(), ctx, { productId: "x" })).toEqual({
317
328
  _id: "x",
318
329
  });
@@ -377,7 +388,13 @@ describe("syncAllProducts", () => {
377
388
  const stripe = makeStripe();
378
389
  stripe.products.list.mockReturnValue(
379
390
  asyncIterable([
380
- { id: "prod_1", name: "A", description: null, active: true, metadata: {} },
391
+ {
392
+ id: "prod_1",
393
+ name: "A",
394
+ description: null,
395
+ active: true,
396
+ metadata: {},
397
+ },
381
398
  ]),
382
399
  );
383
400
  // two prices for the SAME product → product should be looked up once (cache)
@@ -408,7 +425,11 @@ describe("syncAllProducts", () => {
408
425
  runQuery,
409
426
  } as unknown as RunCtx;
410
427
 
411
- const result = await syncAllProducts(asStripe(stripe), makeComponent(), ctx);
428
+ const result = await syncAllProducts(
429
+ asStripe(stripe),
430
+ makeComponent(),
431
+ ctx,
432
+ );
412
433
 
413
434
  expect(result).toEqual({
414
435
  productsSynced: 1,
@@ -441,7 +462,11 @@ describe("syncAllProducts", () => {
441
462
  runQuery: vi.fn().mockResolvedValue(null), // product not found
442
463
  } as unknown as RunCtx;
443
464
 
444
- const result = await syncAllProducts(asStripe(stripe), makeComponent(), ctx);
465
+ const result = await syncAllProducts(
466
+ asStripe(stripe),
467
+ makeComponent(),
468
+ ctx,
469
+ );
445
470
 
446
471
  expect(result.pricesSynced).toBe(0);
447
472
  expect(result.errorCount).toBe(0); // skipped, not errored
@@ -452,8 +477,20 @@ describe("syncAllProducts", () => {
452
477
  const stripe = makeStripe();
453
478
  stripe.products.list.mockReturnValue(
454
479
  asyncIterable([
455
- { id: "prod_ok", name: "A", description: null, active: true, metadata: {} },
456
- { id: "prod_bad", name: "B", description: null, active: true, metadata: {} },
480
+ {
481
+ id: "prod_ok",
482
+ name: "A",
483
+ description: null,
484
+ active: true,
485
+ metadata: {},
486
+ },
487
+ {
488
+ id: "prod_bad",
489
+ name: "B",
490
+ description: null,
491
+ active: true,
492
+ metadata: {},
493
+ },
457
494
  ]),
458
495
  );
459
496
  stripe.prices.list.mockReturnValue(asyncIterable([]));
@@ -466,7 +503,11 @@ describe("syncAllProducts", () => {
466
503
  runQuery: vi.fn(),
467
504
  } as unknown as RunCtx;
468
505
 
469
- const result = await syncAllProducts(asStripe(stripe), makeComponent(), ctx);
506
+ const result = await syncAllProducts(
507
+ asStripe(stripe),
508
+ makeComponent(),
509
+ ctx,
510
+ );
470
511
 
471
512
  expect(result.productsSynced).toBe(1);
472
513
  expect(result.errorCount).toBe(1);
@@ -79,7 +79,9 @@ export async function createProduct(
79
79
  description: opts.description ?? undefined,
80
80
  active: opts.active ?? true,
81
81
  metadata: opts.metadata ?? undefined,
82
- ...(statementDescriptor ? { statement_descriptor: statementDescriptor } : {}),
82
+ ...(statementDescriptor
83
+ ? { statement_descriptor: statementDescriptor }
84
+ : {}),
83
85
  });
84
86
 
85
87
  await runMutationOrThrow(
@@ -54,6 +54,8 @@ describe("clearAll", () => {
54
54
  runMutation: vi.fn().mockRejectedValue(new Error("table locked")),
55
55
  } as unknown as RunCtx;
56
56
 
57
- await expect(clearAll(makeComponent(), ctx)).rejects.toThrow("table locked");
57
+ await expect(clearAll(makeComponent(), ctx)).rejects.toThrow(
58
+ "table locked",
59
+ );
58
60
  });
59
61
  });
@@ -17,7 +17,10 @@ describe("resolveOwnerAccount", () => {
17
17
 
18
18
  it("falls back to customer.id for an expanded customer object", () => {
19
19
  expect(
20
- resolveOwnerAccount({ customer_account: null, customer: { id: "cus_x" } }),
20
+ resolveOwnerAccount({
21
+ customer_account: null,
22
+ customer: { id: "cus_x" },
23
+ }),
21
24
  ).toBe("cus_x");
22
25
  });
23
26
 
@@ -20,7 +20,11 @@ export type CustomerOwned = {
20
20
  export function resolveOwnerAccount(obj: CustomerOwned): string | null {
21
21
  if (obj.customer_account) return obj.customer_account;
22
22
  if (typeof obj.customer === "string") return obj.customer;
23
- if (obj.customer && typeof obj.customer === "object" && "id" in obj.customer) {
23
+ if (
24
+ obj.customer &&
25
+ typeof obj.customer === "object" &&
26
+ "id" in obj.customer
27
+ ) {
24
28
  return obj.customer.id ?? null;
25
29
  }
26
30
  return null;
@@ -8,10 +8,7 @@ export const StripeDashboardResourcePath = {
8
8
  } as const;
9
9
 
10
10
  export type StripeDashboardResourceType =
11
- | "product"
12
- | "price"
13
- | "customer"
14
- | "subscription";
11
+ "product" | "price" | "customer" | "subscription";
15
12
 
16
13
  export type StripeMode = "test" | "live";
17
14
 
@@ -1,20 +1,18 @@
1
1
  // @vitest-environment edge-runtime
2
2
  /**
3
- * Tests for `handleWebhookRequest` — the top-level webhook entrypoint that
4
- * owns request validation, signature verification (routing V1 vs. V2 by event
5
- * type prefix), the atomic dedup ledger, the sync dispatch into the processor,
6
- * and the success/failure HTTP contract.
7
- *
8
- * We exercise the function DIRECTLY (not via registerRoutes), mocking the
9
- * Stripe SDK module so `getStripeClient()` yields a controllable client:
10
- * - V1 verification → `webhooks.constructEventAsync`
11
- * - V2 verification → `parseEventNotificationAsync` (NEVER constructEventAsync;
12
- * stripe-node v22 rejects thin payloads passed to constructEventAsync)
13
- * - V2 account re-fetch → `v2.core.accounts.retrieve`
14
- * Every assertion is on the response status/body and on which component
15
- * mutation/query refs were invoked per branch.
3
+ * Exercises handleWebhookRequest directly with a controllable Stripe mock.
4
+ * Checks V1/V2 signature routing, account re-fetch, deduplication, processor
5
+ * dispatch, and HTTP responses, including the invoked component references.
16
6
  */
17
- import { type Mock, afterEach, beforeEach, describe, expect, it, vi } from "vitest";
7
+ import {
8
+ type Mock,
9
+ afterEach,
10
+ beforeEach,
11
+ describe,
12
+ expect,
13
+ it,
14
+ vi,
15
+ } from "vitest";
18
16
 
19
17
  import type { Component } from "../helpers.js";
20
18
  import type { RegisterRoutesConfig, WebhookActionCtx } from "../types.js";
@@ -97,7 +95,9 @@ function makeCtx(
97
95
  } as unknown as WebhookActionCtx & { runMutation: Mock; runQuery: Mock };
98
96
  }
99
97
 
100
- function baseConfig(over?: Partial<RegisterRoutesConfig>): RegisterRoutesConfig {
98
+ function baseConfig(
99
+ over?: Partial<RegisterRoutesConfig>,
100
+ ): RegisterRoutesConfig {
101
101
  return {
102
102
  stripeSecretKey: "sk_test_123",
103
103
  webhookSecret: "whsec_test",
@@ -105,10 +105,7 @@ function baseConfig(over?: Partial<RegisterRoutesConfig>): RegisterRoutesConfig
105
105
  } as RegisterRoutesConfig;
106
106
  }
107
107
 
108
- function makeRequest(
109
- body: unknown,
110
- headers?: Record<string, string>,
111
- ): Request {
108
+ function makeRequest(body: unknown, headers?: Record<string, string>): Request {
112
109
  return new Request("https://example.com/stripe/webhook", {
113
110
  method: "POST",
114
111
  body: typeof body === "string" ? body : JSON.stringify(body),
@@ -122,22 +122,29 @@ describe("deriveTrialFields", () => {
122
122
 
123
123
  it("marks isTrialing true only when status is exactly 'trialing'", () => {
124
124
  expect(
125
- deriveTrialFields(sub({ status: "trialing", trial_start: null, trial_end: null }))
126
- .isTrialing,
125
+ deriveTrialFields(
126
+ sub({ status: "trialing", trial_start: null, trial_end: null }),
127
+ ).isTrialing,
127
128
  ).toBe(true);
128
129
  expect(
129
- deriveTrialFields(sub({ status: "active", trial_start: null, trial_end: null }))
130
- .isTrialing,
130
+ deriveTrialFields(
131
+ sub({ status: "active", trial_start: null, trial_end: null }),
132
+ ).isTrialing,
131
133
  ).toBe(false);
132
134
  expect(
133
- deriveTrialFields(sub({ status: "past_due", trial_start: null, trial_end: null }))
134
- .isTrialing,
135
+ deriveTrialFields(
136
+ sub({ status: "past_due", trial_start: null, trial_end: null }),
137
+ ).isTrialing,
135
138
  ).toBe(false);
136
139
  });
137
140
 
138
141
  it("converts trial_start/trial_end epochs to ISO strings", () => {
139
142
  const result = deriveTrialFields(
140
- sub({ status: "trialing", trial_start: 1704067200, trial_end: 1704153600 }),
143
+ sub({
144
+ status: "trialing",
145
+ trial_start: 1704067200,
146
+ trial_end: 1704153600,
147
+ }),
141
148
  );
142
149
  expect(result.trialStart).toBe("2024-01-01T00:00:00.000Z");
143
150
  expect(result.trialEnd).toBe("2024-01-02T00:00:00.000Z");
@@ -154,7 +161,9 @@ describe("deriveTrialFields", () => {
154
161
 
155
162
  describe("componentRef", () => {
156
163
  it("returns the ref via direct property lookup when the path exists", () => {
157
- const component = makeComponent({ paths: ["billing/queries/getSubscription"] });
164
+ const component = makeComponent({
165
+ paths: ["billing/queries/getSubscription"],
166
+ });
158
167
  const result = componentRef(component, "billing/queries/getSubscription");
159
168
  expect((result as any)[TO_REF]).toBe(
160
169
  "betterStripe/billing/queries/getSubscription",
@@ -172,7 +181,9 @@ describe("componentRef", () => {
172
181
 
173
182
  it("throws when neither the path nor an anchor ref is available", () => {
174
183
  const component = makeComponent({ withAnchor: false });
175
- expect(() => componentRef(component, "billing/mutations/upsertInvoice")).toThrow(
184
+ expect(() =>
185
+ componentRef(component, "billing/mutations/upsertInvoice"),
186
+ ).toThrow(
176
187
  /Cannot resolve component path: billing\/mutations\/upsertInvoice/,
177
188
  );
178
189
  });
@@ -208,7 +219,9 @@ describe("componentRef", () => {
208
219
 
209
220
  describe("getComponentRef", () => {
210
221
  it("resolves a mapped export via direct property lookup", () => {
211
- const component = makeComponent({ paths: ["billing/queries/getSubscription"] });
222
+ const component = makeComponent({
223
+ paths: ["billing/queries/getSubscription"],
224
+ });
212
225
  const result = getComponentRef(component, "billing", "getSubscription");
213
226
  expect((result as any)[TO_REF]).toBe(
214
227
  "betterStripe/billing/queries/getSubscription",
@@ -235,9 +248,9 @@ describe("getComponentRef", () => {
235
248
 
236
249
  it("throws when no anchor ref exists on the component", () => {
237
250
  const component = makeComponent({ withAnchor: false });
238
- expect(() => getComponentRef(component, "billing", "upsertInvoice")).toThrow(
239
- /Cannot resolve component ref for upsertInvoice/,
240
- );
251
+ expect(() =>
252
+ getComponentRef(component, "billing", "upsertInvoice"),
253
+ ).toThrow(/Cannot resolve component ref for upsertInvoice/);
241
254
  });
242
255
  });
243
256
 
@@ -275,3 +275,26 @@ export type WebhookContext = {
275
275
  stripe: Stripe;
276
276
  webhookSecret: string;
277
277
  };
278
+
279
+ /**
280
+ * Fee/transfer fields (BTS-11) captured off a PaymentIntent for denormalization
281
+ * onto the `payments` row. Returns `{}` when the charge carried no fee/transfer.
282
+ */
283
+ export function feeRoutingFromPaymentIntent(pi: Stripe.PaymentIntent): {
284
+ chargeType?: "destination";
285
+ destinationAccountId?: string;
286
+ applicationFeeAmount?: number;
287
+ feeCollectedAmount?: number;
288
+ } {
289
+ const dest = pi.transfer_data?.destination;
290
+ const destinationAccountId = typeof dest === "string" ? dest : dest?.id;
291
+ const fee = pi.application_fee_amount ?? undefined;
292
+ if (!destinationAccountId && fee === undefined) return {};
293
+ return {
294
+ chargeType: "destination",
295
+ ...(destinationAccountId ? { destinationAccountId } : {}),
296
+ ...(fee !== undefined
297
+ ? { applicationFeeAmount: fee, feeCollectedAmount: fee }
298
+ : {}),
299
+ };
300
+ }
@@ -40,8 +40,7 @@ function makeWhCtx(opts?: {
40
40
  return {
41
41
  ctx: {
42
42
  runQuery: vi.fn().mockResolvedValue(opts?.doc ?? null),
43
- scheduler:
44
- opts?.withScheduler === false ? undefined : { runAfter },
43
+ scheduler: opts?.withScheduler === false ? undefined : { runAfter },
45
44
  },
46
45
  component: makeComponent(),
47
46
  stripe: {} as never,
@@ -1,17 +1,7 @@
1
1
  // @vitest-environment edge-runtime
2
2
  /**
3
- * Tests for the webhook event processor — the field-normalization surface that
4
- * turns Stripe wire objects into component upsert payloads. This is the riskiest
5
- * correctness area in the library: a wrong default or a mishandled
6
- * string-vs-object union silently corrupts a row with no error. We drive each
7
- * event type through `processEvent` and assert the EXACT payload handed to the
8
- * component mutation, covering every union branch, the `userId: ""` sentinel,
9
- * trial derivation, the payment-status collapse, and the checkout metadata
10
- * merge.
11
- *
12
- * `whCtx` is built WITHOUT `config.webhooks`, so `dispatchUpsert` routes through
13
- * `ctx.runMutation(componentRef(component, <path>), data)` — letting us read the
14
- * normalized payload straight off the runMutation mock.
3
+ * Drives Stripe event normalization through processEvent and checks the payloads
4
+ * passed to component mutations, including owner, fee, and trial fields.
15
5
  */
16
6
  import type Stripe from "stripe";
17
7
  import { beforeEach, describe, expect, it, vi } from "vitest";
@@ -24,34 +14,28 @@ const TO_REF = Symbol.for("toReferencePath");
24
14
 
25
15
  /** Fake component exposing every query/mutation ref processors.ts resolves. */
26
16
  function makeComponent() {
27
- const ref = (path: string) => ({ [TO_REF]: `betterStripe/${path}` });
17
+ const refs = (namespace: string, names: string[]) =>
18
+ Object.fromEntries(
19
+ names.map((name) => [
20
+ name,
21
+ { [TO_REF]: `betterStripe/${namespace}/${name}` },
22
+ ]),
23
+ );
28
24
  return {
29
25
  products: {
30
- queries: {
31
- getProductByStripeId: ref("products/queries/getProductByStripeId"),
32
- },
33
- mutations: {
34
- upsertProduct: ref("products/mutations/upsertProduct"),
35
- upsertPrice: ref("products/mutations/upsertPrice"),
36
- },
26
+ queries: refs("products/queries", ["getProductByStripeId"]),
27
+ mutations: refs("products/mutations", ["upsertProduct", "upsertPrice"]),
37
28
  },
38
29
  billing: {
39
- queries: {
40
- getCheckoutSessionByStripeId: ref(
41
- "billing/queries/getCheckoutSessionByStripeId",
42
- ),
43
- },
44
- mutations: {
45
- upsertSubscription: ref("billing/mutations/upsertSubscription"),
46
- upsertCheckoutSession: ref("billing/mutations/upsertCheckoutSession"),
47
- upsertInvoice: ref("billing/mutations/upsertInvoice"),
48
- },
30
+ queries: refs("billing/queries", ["getCheckoutSessionByStripeId"]),
31
+ mutations: refs("billing/mutations", [
32
+ "upsertSubscription",
33
+ "upsertCheckoutSession",
34
+ "upsertInvoice",
35
+ ]),
49
36
  },
50
37
  connect: {
51
- mutations: {
52
- upsertPayment: ref("connect/mutations/upsertPayment"),
53
- upsertPayout: ref("connect/mutations/upsertPayout"),
54
- },
38
+ mutations: refs("connect/mutations", ["upsertPayment", "upsertPayout"]),
55
39
  },
56
40
  };
57
41
  }
@@ -15,6 +15,7 @@ import { resolveOwnerAccount } from "../utils/owner.js";
15
15
  import {
16
16
  type WebhookContext,
17
17
  componentRef,
18
+ feeRoutingFromPaymentIntent,
18
19
  deriveTrialFields,
19
20
  dispatchUpsert,
20
21
  epochToIso,
@@ -297,29 +298,6 @@ async function handleCheckoutEvent(
297
298
  });
298
299
  }
299
300
 
300
- /**
301
- * Fee/transfer fields (BTS-11) captured off a PaymentIntent for denormalization
302
- * onto the `payments` row. Returns `{}` when the charge carried no fee/transfer.
303
- */
304
- function feeRoutingFromPaymentIntent(pi: Stripe.PaymentIntent): {
305
- chargeType?: "destination";
306
- destinationAccountId?: string;
307
- applicationFeeAmount?: number;
308
- feeCollectedAmount?: number;
309
- } {
310
- const dest = pi.transfer_data?.destination;
311
- const destinationAccountId = typeof dest === "string" ? dest : dest?.id;
312
- const fee = pi.application_fee_amount ?? undefined;
313
- if (!destinationAccountId && fee === undefined) return {};
314
- return {
315
- chargeType: "destination",
316
- ...(destinationAccountId ? { destinationAccountId } : {}),
317
- ...(fee !== undefined
318
- ? { applicationFeeAmount: fee, feeCollectedAmount: fee }
319
- : {}),
320
- };
321
- }
322
-
323
301
  /**
324
302
  * Apply a fixed/tier platform fee to a subscription invoice before it finalizes
325
303
  * (BTS-51). Percent-only fees ride on the subscription's `application_fee_percent`
@@ -37,8 +37,7 @@ vi.mock("stripe", () => {
37
37
 
38
38
  // Mock httpActionGeneric to capture the raw handler
39
39
  let _capturedHandler:
40
- | ((ctx: any, request: Request) => Promise<Response>)
41
- | undefined;
40
+ ((ctx: any, request: Request) => Promise<Response>) | undefined;
42
41
 
43
42
  vi.mock("convex/server", () => ({
44
43
  httpActionGeneric: (fn: any) => fn,
@@ -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;
@@ -1,9 +1,10 @@
1
1
  import { v } from "convex/values";
2
2
 
3
3
  import type { Doc, Id } from "../_generated/dataModel";
4
- import { mutation, type MutationCtx } from "../_generated/server";
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,23 +13,7 @@ import {
12
13
  transferFields,
13
14
  } from "./validators";
14
15
 
15
- async function paymentSeller(
16
- ctx: MutationCtx,
17
- stripePaymentIntentId?: string,
18
- ): Promise<string | undefined> {
19
- if (!stripePaymentIntentId) return undefined;
20
- const payment = await ctx.db
21
- .query("payments")
22
- .withIndex("by_stripe_payment_intent_id", (q) =>
23
- q.eq("stripePaymentIntentId", stripePaymentIntentId),
24
- )
25
- .first();
26
- return payment?.destinationAccountId;
27
- }
28
-
29
- // =============================================================================
30
- // PAYMENT MUTATIONS
31
- // =============================================================================
16
+ // Payment mutations
32
17
 
33
18
  export const upsertPayment = mutation({
34
19
  args: {
@@ -125,9 +110,7 @@ export const upsertPayment = mutation({
125
110
  },
126
111
  });
127
112
 
128
- // =============================================================================
129
- // PAYOUT MUTATIONS
130
- // =============================================================================
113
+ // Payout mutations
131
114
 
132
115
  export const upsertPayout = mutation({
133
116
  args: {
@@ -332,30 +315,6 @@ export const upsertDispute = mutation({
332
315
  // TRANSFER MUTATIONS (ledger — BTS-12)
333
316
  // =============================================================================
334
317
 
335
- /**
336
- * Derive reversal status + transfer status from a (transfer amount, cumulative
337
- * reversed amount) pair. Shared by upsert and reversal so the three reversal
338
- * fields can never drift.
339
- */
340
- function deriveReversalState(
341
- amount: number,
342
- reversedAmount: number,
343
- baseStatus: "pending" | "paid" | "failed" | "reversed",
344
- ) {
345
- const reversalStatus =
346
- reversedAmount <= 0
347
- ? undefined
348
- : reversedAmount >= amount
349
- ? ("fully_reversed" as const)
350
- : ("partially_reversed" as const);
351
- return {
352
- reversedAmount: reversedAmount > 0 ? reversedAmount : undefined,
353
- reversalStatus,
354
- status:
355
- reversalStatus === "fully_reversed" ? ("reversed" as const) : baseStatus,
356
- };
357
- }
358
-
359
318
  export const upsertTransfer = mutation({
360
319
  args: transferFields,
361
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
+ }