@fantastic.dev/better-stripe 0.23.2 → 0.25.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 (358) hide show
  1. package/CHANGELOG.md +27 -2
  2. package/README.md +46 -5
  3. package/dist/client/affiliateRecovery/disputes.d.ts +18 -0
  4. package/dist/client/affiliateRecovery/disputes.d.ts.map +1 -0
  5. package/dist/client/affiliateRecovery/disputes.js +33 -0
  6. package/dist/client/affiliateRecovery/disputes.js.map +1 -0
  7. package/dist/client/affiliateRecovery/engine.d.ts +29 -0
  8. package/dist/client/affiliateRecovery/engine.d.ts.map +1 -0
  9. package/dist/client/affiliateRecovery/engine.js +116 -0
  10. package/dist/client/affiliateRecovery/engine.js.map +1 -0
  11. package/dist/client/affiliateRecovery/payoutGate.d.ts +24 -0
  12. package/dist/client/affiliateRecovery/payoutGate.d.ts.map +1 -0
  13. package/dist/client/affiliateRecovery/payoutGate.js +30 -0
  14. package/dist/client/affiliateRecovery/payoutGate.js.map +1 -0
  15. package/dist/client/affiliateRecovery/provider.d.ts +14 -0
  16. package/dist/client/affiliateRecovery/provider.d.ts.map +1 -0
  17. package/dist/client/affiliateRecovery/provider.js +96 -0
  18. package/dist/client/affiliateRecovery/provider.js.map +1 -0
  19. package/dist/client/affiliateRecovery/review.d.ts +28 -0
  20. package/dist/client/affiliateRecovery/review.d.ts.map +1 -0
  21. package/dist/client/affiliateRecovery/review.js +86 -0
  22. package/dist/client/affiliateRecovery/review.js.map +1 -0
  23. package/dist/client/affiliateRecovery/validators.d.ts +402 -0
  24. package/dist/client/affiliateRecovery/validators.d.ts.map +1 -0
  25. package/dist/client/affiliateRecovery/validators.js +27 -0
  26. package/dist/client/affiliateRecovery/validators.js.map +1 -0
  27. package/dist/client/affiliateRecovery.d.ts +131 -0
  28. package/dist/client/affiliateRecovery.d.ts.map +1 -0
  29. package/dist/client/affiliateRecovery.js +69 -0
  30. package/dist/client/affiliateRecovery.js.map +1 -0
  31. package/dist/client/billing/checkout.d.ts +3 -43
  32. package/dist/client/billing/checkout.d.ts.map +1 -1
  33. package/dist/client/billing/checkout.js +5 -260
  34. package/dist/client/billing/checkout.js.map +1 -1
  35. package/dist/client/billing/checkoutRequest.d.ts +129 -0
  36. package/dist/client/billing/checkoutRequest.d.ts.map +1 -0
  37. package/dist/client/billing/checkoutRequest.js +263 -0
  38. package/dist/client/billing/checkoutRequest.js.map +1 -0
  39. package/dist/client/billing/preparedCheckout.d.ts +22 -0
  40. package/dist/client/billing/preparedCheckout.d.ts.map +1 -0
  41. package/dist/client/billing/preparedCheckout.js +86 -0
  42. package/dist/client/billing/preparedCheckout.js.map +1 -0
  43. package/dist/client/checkoutRequests.d.ts +80 -0
  44. package/dist/client/checkoutRequests.d.ts.map +1 -0
  45. package/dist/client/checkoutRequests.js +28 -0
  46. package/dist/client/checkoutRequests.js.map +1 -0
  47. package/dist/client/connect/commissionReceipts.d.ts +4 -0
  48. package/dist/client/connect/commissionReceipts.d.ts.map +1 -0
  49. package/dist/client/connect/commissionReceipts.js +17 -0
  50. package/dist/client/connect/commissionReceipts.js.map +1 -0
  51. package/dist/client/connect/payoutAdoptionTestHelpers.d.ts +958 -2
  52. package/dist/client/connect/payoutAdoptionTestHelpers.d.ts.map +1 -1
  53. package/dist/client/connect/payoutCollection.d.ts +21 -0
  54. package/dist/client/connect/payoutCollection.d.ts.map +1 -0
  55. package/dist/client/connect/payoutCollection.js +47 -0
  56. package/dist/client/connect/payoutCollection.js.map +1 -0
  57. package/dist/client/connect/payoutExecutionTestHelpers.d.ts +1805 -0
  58. package/dist/client/connect/payoutExecutionTestHelpers.d.ts.map +1 -0
  59. package/dist/client/connect/payoutExecutionTestHelpers.js +194 -0
  60. package/dist/client/connect/payoutExecutionTestHelpers.js.map +1 -0
  61. package/dist/client/connect/payoutSyncTestHelpers.d.ts +479 -1
  62. package/dist/client/connect/payoutSyncTestHelpers.d.ts.map +1 -1
  63. package/dist/client/connect/payoutWorker.d.ts +48 -0
  64. package/dist/client/connect/payoutWorker.d.ts.map +1 -0
  65. package/dist/client/connect/payoutWorker.js +78 -0
  66. package/dist/client/connect/payoutWorker.js.map +1 -0
  67. package/dist/client/connect/payouts.d.ts +3 -1
  68. package/dist/client/connect/payouts.d.ts.map +1 -1
  69. package/dist/client/connect/payouts.js +45 -12
  70. package/dist/client/connect/payouts.js.map +1 -1
  71. package/dist/client/connect/refundPrincipal.d.ts +4 -0
  72. package/dist/client/connect/refundPrincipal.d.ts.map +1 -0
  73. package/dist/client/connect/refundPrincipal.js +21 -0
  74. package/dist/client/connect/refundPrincipal.js.map +1 -0
  75. package/dist/client/connect/reversalExecution.d.ts +47 -0
  76. package/dist/client/connect/reversalExecution.d.ts.map +1 -0
  77. package/dist/client/connect/reversalExecution.js +84 -0
  78. package/dist/client/connect/reversalExecution.js.map +1 -0
  79. package/dist/client/connect/transfers.d.ts +8 -4
  80. package/dist/client/connect/transfers.d.ts.map +1 -1
  81. package/dist/client/connect/transfers.js +52 -57
  82. package/dist/client/connect/transfers.js.map +1 -1
  83. package/dist/client/index.d.ts +7 -11
  84. package/dist/client/index.d.ts.map +1 -1
  85. package/dist/client/index.js +10 -10
  86. package/dist/client/index.js.map +1 -1
  87. package/dist/client/payoutPolicy.d.ts +67 -0
  88. package/dist/client/payoutPolicy.d.ts.map +1 -1
  89. package/dist/client/payoutPolicy.js +10 -0
  90. package/dist/client/payoutPolicy.js.map +1 -1
  91. package/dist/client/readContracts.d.ts +11 -1
  92. package/dist/client/readContracts.d.ts.map +1 -1
  93. package/dist/client/readContracts.js +10 -0
  94. package/dist/client/readContracts.js.map +1 -1
  95. package/dist/client/settlement/execution.d.ts.map +1 -1
  96. package/dist/client/settlement/execution.js +30 -3
  97. package/dist/client/settlement/execution.js.map +1 -1
  98. package/dist/client/settlement/reconciliation.d.ts.map +1 -1
  99. package/dist/client/settlement/reconciliation.js +16 -2
  100. package/dist/client/settlement/reconciliation.js.map +1 -1
  101. package/dist/client/webhooks/disputeRecovery.d.ts +4 -0
  102. package/dist/client/webhooks/disputeRecovery.d.ts.map +1 -0
  103. package/dist/client/webhooks/disputeRecovery.js +40 -0
  104. package/dist/client/webhooks/disputeRecovery.js.map +1 -0
  105. package/dist/client/webhooks/processors.d.ts.map +1 -1
  106. package/dist/client/webhooks/processors.js +14 -29
  107. package/dist/client/webhooks/processors.js.map +1 -1
  108. package/dist/component/_generated/component.d.ts +784 -0
  109. package/dist/component/_generated/component.d.ts.map +1 -1
  110. package/dist/component/affiliateEarnings/mutations.d.ts +22 -0
  111. package/dist/component/affiliateEarnings/mutations.d.ts.map +1 -0
  112. package/dist/component/affiliateEarnings/mutations.js +160 -0
  113. package/dist/component/affiliateEarnings/mutations.js.map +1 -0
  114. package/dist/component/affiliatePayouts/mutations.d.ts +25 -0
  115. package/dist/component/affiliatePayouts/mutations.d.ts.map +1 -0
  116. package/dist/component/affiliatePayouts/mutations.js +104 -0
  117. package/dist/component/affiliatePayouts/mutations.js.map +1 -0
  118. package/dist/component/affiliatePayouts/queries.d.ts +23 -0
  119. package/dist/component/affiliatePayouts/queries.d.ts.map +1 -0
  120. package/dist/component/affiliatePayouts/queries.js +23 -0
  121. package/dist/component/affiliatePayouts/queries.js.map +1 -0
  122. package/dist/component/affiliatePayouts/recipientGuard.d.ts +12 -0
  123. package/dist/component/affiliatePayouts/recipientGuard.d.ts.map +1 -0
  124. package/dist/component/affiliatePayouts/recipientGuard.js +26 -0
  125. package/dist/component/affiliatePayouts/recipientGuard.js.map +1 -0
  126. package/dist/component/affiliateRecovery/accounting.d.ts +28 -0
  127. package/dist/component/affiliateRecovery/accounting.d.ts.map +1 -0
  128. package/dist/component/affiliateRecovery/accounting.js +71 -0
  129. package/dist/component/affiliateRecovery/accounting.js.map +1 -0
  130. package/dist/component/affiliateRecovery/mutations.d.ts +65 -0
  131. package/dist/component/affiliateRecovery/mutations.d.ts.map +1 -0
  132. package/dist/component/affiliateRecovery/mutations.js +250 -0
  133. package/dist/component/affiliateRecovery/mutations.js.map +1 -0
  134. package/dist/component/affiliateRecovery/queries.d.ts +305 -0
  135. package/dist/component/affiliateRecovery/queries.d.ts.map +1 -0
  136. package/dist/component/affiliateRecovery/queries.js +113 -0
  137. package/dist/component/affiliateRecovery/queries.js.map +1 -0
  138. package/dist/component/affiliateRecovery/schema.d.ts +171 -0
  139. package/dist/component/affiliateRecovery/schema.d.ts.map +1 -0
  140. package/dist/component/affiliateRecovery/schema.js +71 -0
  141. package/dist/component/affiliateRecovery/schema.js.map +1 -0
  142. package/dist/component/connect/mutations.d.ts +36 -23
  143. package/dist/component/connect/mutations.d.ts.map +1 -1
  144. package/dist/component/connect/mutations.js +7 -124
  145. package/dist/component/connect/mutations.js.map +1 -1
  146. package/dist/component/connect/queries.d.ts +10 -0
  147. package/dist/component/connect/queries.d.ts.map +1 -1
  148. package/dist/component/connect/queries.js +3 -40
  149. package/dist/component/connect/queries.js.map +1 -1
  150. package/dist/component/connect/reversalClaims.d.ts +169 -0
  151. package/dist/component/connect/reversalClaims.d.ts.map +1 -0
  152. package/dist/component/connect/reversalClaims.js +176 -0
  153. package/dist/component/connect/reversalClaims.js.map +1 -0
  154. package/dist/component/connect/reversalDiagnostics.d.ts +59 -0
  155. package/dist/component/connect/reversalDiagnostics.d.ts.map +1 -0
  156. package/dist/component/connect/reversalDiagnostics.js +50 -0
  157. package/dist/component/connect/reversalDiagnostics.js.map +1 -0
  158. package/dist/component/connect/reversalReceipts.d.ts +27 -0
  159. package/dist/component/connect/reversalReceipts.d.ts.map +1 -0
  160. package/dist/component/connect/reversalReceipts.js +85 -0
  161. package/dist/component/connect/reversalReceipts.js.map +1 -0
  162. package/dist/component/connect/schema.d.ts +31 -1
  163. package/dist/component/connect/schema.d.ts.map +1 -1
  164. package/dist/component/connect/schema.js +3 -1
  165. package/dist/component/connect/schema.js.map +1 -1
  166. package/dist/component/connect/validators.d.ts +49 -1
  167. package/dist/component/connect/validators.d.ts.map +1 -1
  168. package/dist/component/connect/validators.js +2 -0
  169. package/dist/component/connect/validators.js.map +1 -1
  170. package/dist/component/core/mutations.d.ts.map +1 -1
  171. package/dist/component/core/mutations.js +2 -0
  172. package/dist/component/core/mutations.js.map +1 -1
  173. package/dist/component/core/resetSafety.d.ts +4 -0
  174. package/dist/component/core/resetSafety.d.ts.map +1 -0
  175. package/dist/component/core/resetSafety.js +54 -0
  176. package/dist/component/core/resetSafety.js.map +1 -0
  177. package/dist/component/earnings/triggers.d.ts +828 -2
  178. package/dist/component/earnings/triggers.d.ts.map +1 -1
  179. package/dist/component/earnings/triggers.js +2 -0
  180. package/dist/component/earnings/triggers.js.map +1 -1
  181. package/dist/component/payoutPolicy/schema.d.ts +2 -0
  182. package/dist/component/payoutPolicy/schema.d.ts.map +1 -1
  183. package/dist/component/payoutPolicy/schema.js +3 -1
  184. package/dist/component/payoutPolicy/schema.js.map +1 -1
  185. package/dist/component/payoutRelease/mutations.d.ts.map +1 -1
  186. package/dist/component/payoutRelease/mutations.js +7 -1
  187. package/dist/component/payoutRelease/mutations.js.map +1 -1
  188. package/dist/component/payoutRelease/queries.d.ts.map +1 -1
  189. package/dist/component/payoutRelease/queries.js +3 -1
  190. package/dist/component/payoutRelease/queries.js.map +1 -1
  191. package/dist/component/payoutRelease/schema.d.ts +1 -0
  192. package/dist/component/payoutRelease/schema.d.ts.map +1 -1
  193. package/dist/component/payoutRelease/schema.js +1 -0
  194. package/dist/component/payoutRelease/schema.js.map +1 -1
  195. package/dist/component/payoutSnapshots/localState.d.ts +89 -0
  196. package/dist/component/payoutSnapshots/localState.d.ts.map +1 -0
  197. package/dist/component/payoutSnapshots/localState.js +186 -0
  198. package/dist/component/payoutSnapshots/localState.js.map +1 -0
  199. package/dist/component/payoutSnapshots/mutations.d.ts +108 -0
  200. package/dist/component/payoutSnapshots/mutations.d.ts.map +1 -0
  201. package/dist/component/payoutSnapshots/mutations.js +263 -0
  202. package/dist/component/payoutSnapshots/mutations.js.map +1 -0
  203. package/dist/component/payoutSnapshots/revisions.d.ts +12 -0
  204. package/dist/component/payoutSnapshots/revisions.d.ts.map +1 -0
  205. package/dist/component/payoutSnapshots/revisions.js +173 -0
  206. package/dist/component/payoutSnapshots/revisions.js.map +1 -0
  207. package/dist/component/payoutSnapshots/schema.d.ts +285 -0
  208. package/dist/component/payoutSnapshots/schema.d.ts.map +1 -0
  209. package/dist/component/payoutSnapshots/schema.js +108 -0
  210. package/dist/component/payoutSnapshots/schema.js.map +1 -0
  211. package/dist/component/payoutSnapshots/scope.d.ts +7 -0
  212. package/dist/component/payoutSnapshots/scope.d.ts.map +1 -0
  213. package/dist/component/payoutSnapshots/scope.js +8 -0
  214. package/dist/component/payoutSnapshots/scope.js.map +1 -0
  215. package/dist/component/payoutWorker/helpers.d.ts +30 -0
  216. package/dist/component/payoutWorker/helpers.d.ts.map +1 -0
  217. package/dist/component/payoutWorker/helpers.js +21 -0
  218. package/dist/component/payoutWorker/helpers.js.map +1 -0
  219. package/dist/component/payoutWorker/mutations.d.ts +68 -0
  220. package/dist/component/payoutWorker/mutations.d.ts.map +1 -0
  221. package/dist/component/payoutWorker/mutations.js +161 -0
  222. package/dist/component/payoutWorker/mutations.js.map +1 -0
  223. package/dist/component/payoutWorker/queries.d.ts +123 -0
  224. package/dist/component/payoutWorker/queries.d.ts.map +1 -0
  225. package/dist/component/payoutWorker/queries.js +61 -0
  226. package/dist/component/payoutWorker/queries.js.map +1 -0
  227. package/dist/component/payoutWorker/schema.d.ts +91 -0
  228. package/dist/component/payoutWorker/schema.d.ts.map +1 -0
  229. package/dist/component/payoutWorker/schema.js +27 -0
  230. package/dist/component/payoutWorker/schema.js.map +1 -0
  231. package/dist/component/schema.d.ts +479 -1
  232. package/dist/component/schema.js +19 -0
  233. package/dist/component/schema.js.map +1 -1
  234. package/dist/component/settlement/clawbackSchema.d.ts +161 -0
  235. package/dist/component/settlement/clawbackSchema.d.ts.map +1 -0
  236. package/dist/component/settlement/clawbackSchema.js +73 -0
  237. package/dist/component/settlement/clawbackSchema.js.map +1 -0
  238. package/dist/component/settlement/clawbacks.d.ts +55 -0
  239. package/dist/component/settlement/clawbacks.d.ts.map +1 -0
  240. package/dist/component/settlement/clawbacks.js +146 -0
  241. package/dist/component/settlement/clawbacks.js.map +1 -0
  242. package/dist/component/settlement/mutations.d.ts +16 -0
  243. package/dist/component/settlement/mutations.d.ts.map +1 -1
  244. package/dist/component/settlement/mutations.js +48 -0
  245. package/dist/component/settlement/mutations.js.map +1 -1
  246. package/dist/component/settlement/queries.d.ts +53 -0
  247. package/dist/component/settlement/queries.d.ts.map +1 -1
  248. package/dist/component/settlement/queries.js +26 -0
  249. package/dist/component/settlement/queries.js.map +1 -1
  250. package/dist/react/workflows/AffiliateRecovery.d.ts +46 -0
  251. package/dist/react/workflows/AffiliateRecovery.d.ts.map +1 -0
  252. package/dist/react/workflows/AffiliateRecovery.js +84 -0
  253. package/dist/react/workflows/AffiliateRecovery.js.map +1 -0
  254. package/dist/react/workflows/index.d.ts +2 -0
  255. package/dist/react/workflows/index.d.ts.map +1 -1
  256. package/dist/react/workflows/index.js +1 -0
  257. package/dist/react/workflows/index.js.map +1 -1
  258. package/dist/testing/affiliate-recovery.d.ts +10 -0
  259. package/dist/testing/affiliate-recovery.d.ts.map +1 -0
  260. package/dist/testing/affiliate-recovery.js +126 -0
  261. package/dist/testing/affiliate-recovery.js.map +1 -0
  262. package/dist/testing/index.d.ts +2 -0
  263. package/dist/testing/index.d.ts.map +1 -1
  264. package/dist/testing/index.js +1 -0
  265. package/dist/testing/index.js.map +1 -1
  266. package/docs/affiliate-clawbacks.md +306 -0
  267. package/docs/read-contracts.md +48 -0
  268. package/docs/settlement.md +145 -1
  269. package/package.json +2 -1
  270. package/src/client/affiliateRecovery/disputes.ts +62 -0
  271. package/src/client/affiliateRecovery/engine.ts +196 -0
  272. package/src/client/affiliateRecovery/payoutGate.ts +65 -0
  273. package/src/client/affiliateRecovery/provider.ts +127 -0
  274. package/src/client/affiliateRecovery/review.ts +117 -0
  275. package/src/client/affiliateRecovery/validators.ts +38 -0
  276. package/src/client/affiliateRecovery.ts +173 -0
  277. package/src/client/billing/checkout.ts +11 -359
  278. package/src/client/billing/checkoutRequest.ts +362 -0
  279. package/src/client/billing/prepared-checkout.test.ts +430 -0
  280. package/src/client/billing/preparedCheckout.ts +143 -0
  281. package/src/client/checkoutRequests.ts +40 -0
  282. package/src/client/connect/commissionReceipts.test.ts +157 -0
  283. package/src/client/connect/commissionReceipts.ts +23 -0
  284. package/src/client/connect/payoutCollection.test.ts +74 -0
  285. package/src/client/connect/payoutCollection.ts +82 -0
  286. package/src/client/connect/payoutExecution.test.ts +1 -211
  287. package/src/client/connect/payoutExecutionTestHelpers.ts +213 -0
  288. package/src/client/connect/payoutWorker.test.ts +145 -0
  289. package/src/client/connect/payoutWorker.ts +144 -0
  290. package/src/client/connect/payouts.ts +75 -15
  291. package/src/client/connect/refundPrincipal.test.ts +46 -0
  292. package/src/client/connect/refundPrincipal.ts +26 -0
  293. package/src/client/connect/reversalExecution.ts +130 -0
  294. package/src/client/connect/transfers.test.ts +3 -3
  295. package/src/client/connect/transfers.ts +93 -92
  296. package/src/client/index.ts +16 -28
  297. package/src/client/payoutPolicy.ts +26 -1
  298. package/src/client/readContracts.ts +23 -0
  299. package/src/client/settlement/execution.test.ts +5 -0
  300. package/src/client/settlement/execution.ts +50 -3
  301. package/src/client/settlement/reconciliation.ts +20 -2
  302. package/src/client/webhooks/disputeRecovery.ts +74 -0
  303. package/src/client/webhooks/processors.test.ts +36 -53
  304. package/src/client/webhooks/processors.ts +18 -31
  305. package/src/component/_generated/api.ts +40 -0
  306. package/src/component/_generated/component.ts +975 -1
  307. package/src/component/affiliate-clawbacks.test.ts +370 -0
  308. package/src/component/affiliate-component-pagination.test.ts +83 -0
  309. package/src/component/affiliate-direct-payout.test.ts +160 -0
  310. package/src/component/affiliate-recovery-lifecycle.test.ts +587 -0
  311. package/src/component/affiliateEarnings/mutations.ts +196 -0
  312. package/src/component/affiliatePayouts/mutations.ts +121 -0
  313. package/src/component/affiliatePayouts/queries.ts +28 -0
  314. package/src/component/affiliatePayouts/recipientGuard.ts +42 -0
  315. package/src/component/affiliateRecovery/accounting.ts +111 -0
  316. package/src/component/affiliateRecovery/mutations.ts +275 -0
  317. package/src/component/affiliateRecovery/queries.ts +138 -0
  318. package/src/component/affiliateRecovery/schema.ts +86 -0
  319. package/src/component/connect/mutations.ts +9 -160
  320. package/src/component/connect/queries.ts +4 -47
  321. package/src/component/connect/reversalClaims.ts +232 -0
  322. package/src/component/connect/reversalDiagnostics.ts +61 -0
  323. package/src/component/connect/reversalReceipts.ts +147 -0
  324. package/src/component/connect/schema.ts +3 -3
  325. package/src/component/connect/validators.ts +2 -0
  326. package/src/component/core/mutations.ts +2 -0
  327. package/src/component/core/resetSafety.ts +67 -0
  328. package/src/component/earnings/triggers.ts +2 -0
  329. package/src/component/payout-recovery-integration.test.ts +172 -0
  330. package/src/component/payout-reset-safety.test.ts +148 -0
  331. package/src/component/payout-revisions.test.ts +125 -0
  332. package/src/component/payout-snapshots.test.ts +395 -0
  333. package/src/component/payout-worker.test.ts +165 -0
  334. package/src/component/payoutPolicy/schema.ts +3 -1
  335. package/src/component/payoutRelease/mutations.ts +10 -1
  336. package/src/component/payoutRelease/queries.ts +3 -1
  337. package/src/component/payoutRelease/schema.ts +1 -0
  338. package/src/component/payoutSnapshots/localState.ts +238 -0
  339. package/src/component/payoutSnapshots/mutations.ts +275 -0
  340. package/src/component/payoutSnapshots/revisions.ts +247 -0
  341. package/src/component/payoutSnapshots/schema.ts +125 -0
  342. package/src/component/payoutSnapshots/scope.ts +7 -0
  343. package/src/component/payoutWorker/helpers.ts +30 -0
  344. package/src/component/payoutWorker/mutations.ts +181 -0
  345. package/src/component/payoutWorker/queries.ts +64 -0
  346. package/src/component/payoutWorker/schema.ts +26 -0
  347. package/src/component/public.test.ts +2 -2
  348. package/src/component/schema.ts +36 -0
  349. package/src/component/settlement/clawbackSchema.ts +78 -0
  350. package/src/component/settlement/clawbacks.ts +233 -0
  351. package/src/component/settlement/mutations.ts +54 -0
  352. package/src/component/settlement/queries.ts +35 -0
  353. package/src/component/summary-arithmetic.test.ts +9 -4
  354. package/src/react/workflows/AffiliateRecovery.test.tsx +106 -0
  355. package/src/react/workflows/AffiliateRecovery.tsx +273 -0
  356. package/src/react/workflows/index.ts +9 -0
  357. package/src/testing/affiliate-recovery.ts +137 -0
  358. package/src/testing/index.ts +2 -0
@@ -1,3 +1,4 @@
1
+ import { reconcileAffiliateCharge } from "../affiliateRecovery/engine.js";
1
2
  import {
2
3
  sourceTransfers,
3
4
  matchingTransfer,
@@ -60,13 +61,34 @@ export async function executeResolvedTransfers(
60
61
  transfers: saved.transfers,
61
62
  paymentId: saved.paymentId,
62
63
  };
64
+ const earnings = new Map<string, { _id: string; releaseAmount: number }>();
65
+ for (const leg of claim.transfers)
66
+ if (leg.role === "affiliate" && leg.amount > 0) {
67
+ const earning = (await runMutationOrThrow(
68
+ ctx,
69
+ componentRef(component, "affiliateEarnings/mutations/reserveEarning"),
70
+ {
71
+ sourceChargeId: claim.sourceChargeId,
72
+ affiliateAccountId: leg.destinationAccountId,
73
+ },
74
+ )) as { _id: string; releaseAmount: number } | undefined;
75
+ if (earning?._id) earnings.set(leg.destinationAccountId, earning);
76
+ }
77
+ const effective = claim.transfers.map((leg) =>
78
+ leg.role === "affiliate" && earnings.has(leg.destinationAccountId)
79
+ ? {
80
+ ...leg,
81
+ amount: earnings.get(leg.destinationAccountId)!.releaseAmount,
82
+ }
83
+ : leg,
84
+ );
63
85
  const existing = ((await ctx.runQuery(
64
86
  componentRef(component, "connect/queries/listTransfersByCharge"),
65
87
  { sourceChargeId: claim.sourceChargeId },
66
88
  )) ?? []) as Ledger[];
67
89
  let provider = await sourceTransfers(stripe, claim.sourceChargeId);
68
90
  if (
69
- claim.transfers.some(
91
+ effective.some(
70
92
  (leg) =>
71
93
  leg.amount > 0 &&
72
94
  !existing.some(
@@ -87,8 +109,20 @@ export async function executeResolvedTransfers(
87
109
  ];
88
110
  }
89
111
  const executedTransfers: SettlementResult["executedTransfers"] = [];
90
- for (const leg of claim.transfers) {
91
- if (leg.amount === 0) continue;
112
+ for (const leg of effective) {
113
+ const earning =
114
+ leg.role === "affiliate"
115
+ ? earnings.get(leg.destinationAccountId)
116
+ : undefined;
117
+ if (leg.amount === 0) {
118
+ if (earning)
119
+ await runMutationOrThrow(
120
+ ctx,
121
+ componentRef(component, "affiliateEarnings/mutations/confirmEarning"),
122
+ { earningId: earning._id },
123
+ );
124
+ continue;
125
+ }
92
126
  const recorded = existing.find(
93
127
  (t) =>
94
128
  t.destinationAccountId === leg.destinationAccountId &&
@@ -123,6 +157,12 @@ export async function executeResolvedTransfers(
123
157
  transferId = transfer.id;
124
158
  await recordSettlementTransfer(component, ctx, claim, leg, transfer);
125
159
  }
160
+ if (earning)
161
+ await runMutationOrThrow(
162
+ ctx,
163
+ componentRef(component, "affiliateEarnings/mutations/confirmEarning"),
164
+ { earningId: earning._id, stripeTransferId: transferId },
165
+ );
126
166
  executedTransfers.push({
127
167
  stripeTransferId: transferId,
128
168
  destinationAccountId: leg.destinationAccountId,
@@ -130,5 +170,12 @@ export async function executeResolvedTransfers(
130
170
  amount: leg.amount,
131
171
  });
132
172
  }
173
+ if (earnings.size)
174
+ await reconcileAffiliateCharge(
175
+ stripe,
176
+ component,
177
+ ctx,
178
+ claim.sourceChargeId,
179
+ );
133
180
  return { ...claim, status: "settled", executedTransfers };
134
181
  }
@@ -97,9 +97,26 @@ export async function recoverSettlementTransfers(
97
97
  { sourceChargeId },
98
98
  )) as ResolvedSettlement | null;
99
99
  if (!claim || typeof claim.sourceChargeId !== "string") return;
100
+ const effective = [];
101
+ for (const leg of claim.transfers) {
102
+ const earning =
103
+ leg.role === "affiliate"
104
+ ? ((await ctx.runQuery(
105
+ componentRef(component, "affiliateRecovery/queries/getEarning"),
106
+ { sourceChargeId, affiliateAccountId: leg.destinationAccountId },
107
+ )) as { releaseAmount?: number } | null)
108
+ : null;
109
+ effective.push({
110
+ ...leg,
111
+ amount:
112
+ typeof earning?.releaseAmount === "number"
113
+ ? earning.releaseAmount
114
+ : leg.amount,
115
+ });
116
+ }
100
117
  let provider = await sourceTransfers(stripe, sourceChargeId);
101
118
  if (
102
- claim.transfers.some(
119
+ effective.some(
103
120
  (leg) => leg.amount > 0 && !matchingTransfer(provider, claim, leg),
104
121
  )
105
122
  )
@@ -111,7 +128,8 @@ export async function recoverSettlementTransfers(
111
128
  ].map((t) => [t.id, t]),
112
129
  ).values(),
113
130
  ];
114
- for (const leg of claim.transfers) {
131
+ for (const leg of effective) {
132
+ if (leg.amount === 0) continue;
115
133
  const transfer = matchingTransfer(provider, claim, leg);
116
134
  if (transfer)
117
135
  await recordSettlementTransfer(component, ctx, claim, leg, transfer);
@@ -0,0 +1,74 @@
1
+ import { recoverSettlementTransfers } from "../settlement/reconciliation.js";
2
+ import { componentRef } from "./helpers.js";
3
+ import type Stripe from "stripe";
4
+ import type { WebhookContext } from "./helpers.js";
5
+ import {
6
+ reinstateTransfers,
7
+ reverseTransfersForDispute,
8
+ } from "../connect/transfers.js";
9
+ import { successfulRefundPrincipal } from "../connect/refundPrincipal.js";
10
+ export async function reconcileDisputeMoney(
11
+ whCtx: WebhookContext,
12
+ dispute: Stripe.Dispute,
13
+ event: string,
14
+ originalCharge?: Stripe.Charge,
15
+ ) {
16
+ if (dispute.status.startsWith("warning_") || dispute.status === "prevented")
17
+ return;
18
+ const chargeId =
19
+ typeof dispute.charge === "string" ? dispute.charge : dispute.charge?.id;
20
+ if (
21
+ !chargeId ||
22
+ !["created", "funds_withdrawn", "closed", "funds_reinstated"].includes(
23
+ event,
24
+ )
25
+ )
26
+ return;
27
+ await recoverSettlementTransfers(
28
+ whCtx.stripe,
29
+ whCtx.component,
30
+ whCtx.ctx,
31
+ chargeId,
32
+ );
33
+ const legs = await whCtx.ctx.runQuery(
34
+ componentRef(whCtx.component, "connect/queries/listTransfersByCharge"),
35
+ { sourceChargeId: chargeId },
36
+ );
37
+ const obligations = await whCtx.ctx.runQuery(
38
+ componentRef(
39
+ whCtx.component,
40
+ "affiliateRecovery/queries/chargeObligations",
41
+ ),
42
+ { sourceChargeId: chargeId },
43
+ );
44
+ if (
45
+ (!Array.isArray(legs) || !legs.length) &&
46
+ (!Array.isArray(obligations) || !obligations.length)
47
+ )
48
+ return;
49
+ const won = event === "funds_reinstated" || dispute.status === "won";
50
+ const charge =
51
+ originalCharge ?? (await whCtx.stripe.charges.retrieve(chargeId));
52
+ const refundedPrincipal = await successfulRefundPrincipal(
53
+ whCtx.stripe,
54
+ chargeId,
55
+ );
56
+ await reverseTransfersForDispute(whCtx.stripe, whCtx.component, whCtx.ctx, {
57
+ sourceChargeId: chargeId,
58
+ operationId: dispute.id,
59
+ chargeAmount: charge.amount,
60
+ amount: dispute.amount,
61
+ finalized: dispute.status === "lost",
62
+ disputeState: won ? "won" : dispute.status === "lost" ? "lost" : "open",
63
+ refundedPrincipal,
64
+ });
65
+ if (won)
66
+ await reinstateTransfers(whCtx.stripe, whCtx.component, whCtx.ctx, {
67
+ sourceChargeId: chargeId,
68
+ operationId: dispute.id,
69
+ currency: dispute.currency,
70
+ excludeAffiliates: true,
71
+ chargeAmount: charge.amount,
72
+ refundedPrincipal,
73
+ });
74
+ }
@@ -96,6 +96,13 @@ type MockReversal = {
96
96
 
97
97
  function makeStripe() {
98
98
  return {
99
+ refunds: {
100
+ list: vi.fn(() =>
101
+ (async function* () {
102
+ yield { amount: 5000, status: "succeeded" };
103
+ })(),
104
+ ),
105
+ },
99
106
  products: { retrieve: vi.fn() },
100
107
  subscriptions: {
101
108
  retrieve: vi.fn(),
@@ -1396,7 +1403,7 @@ describe("processEvent — split transfer engine (BTS-22)", () => {
1396
1403
  expect(data.statementDescriptor).toBe("ACME STORE");
1397
1404
  });
1398
1405
 
1399
- it("[BTS-26] still processes the dispute when the charge lookup fails (descriptor is best-effort)", async () => {
1406
+ it("records the dispute but retries recovery when the charge basis is unavailable", async () => {
1400
1407
  const stripe = makeStripe();
1401
1408
  stripe.charges.retrieve.mockRejectedValue(new Error("stripe down"));
1402
1409
  const ctx = makeCtx({
@@ -1411,26 +1418,28 @@ describe("processEvent — split transfer engine (BTS-22)", () => {
1411
1418
  });
1412
1419
  const whCtx = makeWhCtx({ stripe, ctx });
1413
1420
 
1414
- await processEvent(
1415
- whCtx,
1416
- event("charge.dispute.created", {
1417
- id: "dp_bf",
1418
- charge: "ch_1",
1419
- amount: 9000,
1420
- currency: "usd",
1421
- status: "needs_response",
1422
- reason: "fraudulent",
1423
- is_charge_refundable: true,
1424
- evidence_details: { due_by: 1700000000 },
1425
- metadata: {},
1426
- }),
1427
- );
1421
+ await expect(
1422
+ processEvent(
1423
+ whCtx,
1424
+ event("charge.dispute.created", {
1425
+ id: "dp_bf",
1426
+ charge: "ch_1",
1427
+ amount: 9000,
1428
+ currency: "usd",
1429
+ status: "needs_response",
1430
+ reason: "fraudulent",
1431
+ is_charge_refundable: true,
1432
+ evidence_details: { due_by: 1700000000 },
1433
+ metadata: {},
1434
+ }),
1435
+ ),
1436
+ ).rejects.toThrow("stripe down");
1428
1437
 
1429
- // Dispute still recorded (without a descriptor) and clawback still ran.
1438
+ // Record the dispute, but require an authoritative basis before recovery.
1430
1439
  const { path, data } = dispatchedPayload(whCtx.ctx);
1431
1440
  expect(path).toBe("betterStripe/connect/mutations/upsertDispute");
1432
1441
  expect(data.statementDescriptor).toBeUndefined();
1433
- expect(stripe.transfers.createReversal).toHaveBeenCalledTimes(1);
1442
+ expect(stripe.transfers.createReversal).not.toHaveBeenCalled();
1434
1443
  });
1435
1444
 
1436
1445
  it("[BTS-27] claws back a single-recipient transfer on dispute", async () => {
@@ -2338,7 +2347,6 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2338
2347
  : {}),
2339
2348
  },
2340
2349
  ];
2341
-
2342
2350
  const refundEvent = (overrides: Record<string, unknown> = {}) =>
2343
2351
  event("refund.created", {
2344
2352
  id: "re_1",
@@ -2350,7 +2358,6 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2350
2358
  metadata: {},
2351
2359
  ...overrides,
2352
2360
  });
2353
-
2354
2361
  it("reverses split-sale transfers pro-rata on a succeeded partial refund", async () => {
2355
2362
  const ctx = makeCtx({ query: ledgerLegs() });
2356
2363
  const stripe = makeStripe();
@@ -2360,10 +2367,7 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2360
2367
  amount_refunded: 5000,
2361
2368
  });
2362
2369
  const whCtx = makeWhCtx({ ctx, stripe });
2363
-
2364
2370
  await processEvent(whCtx, refundEvent());
2365
-
2366
- // 50% refunded → each leg reversed to 50% of its original amount.
2367
2371
  expect(stripe.transfers.createReversal).toHaveBeenCalledTimes(2);
2368
2372
  expect(stripe.transfers.createReversal).toHaveBeenCalledWith(
2369
2373
  "tr_s",
@@ -2376,19 +2380,21 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2376
2380
  { idempotencyKey: "bs_rev_re_1_tr_a" },
2377
2381
  );
2378
2382
  });
2379
-
2380
2383
  it("reverses the full transfer amounts on a full refund", async () => {
2381
2384
  const ctx = makeCtx({ query: ledgerLegs() });
2382
2385
  const stripe = makeStripe();
2386
+ stripe.refunds.list.mockImplementation(() =>
2387
+ (async function* () {
2388
+ yield { amount: 10000, status: "succeeded" };
2389
+ })(),
2390
+ );
2383
2391
  stripe.charges.retrieve.mockResolvedValue({
2384
2392
  id: "ch_1",
2385
2393
  amount: 10000,
2386
2394
  amount_refunded: 10000,
2387
2395
  });
2388
2396
  const whCtx = makeWhCtx({ ctx, stripe });
2389
-
2390
2397
  await processEvent(whCtx, refundEvent({ amount: 10000 }));
2391
-
2392
2398
  expect(stripe.transfers.createReversal).toHaveBeenCalledWith(
2393
2399
  "tr_s",
2394
2400
  { amount: 7000 },
@@ -2400,23 +2406,23 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2400
2406
  { idempotencyKey: "bs_rev_re_1_tr_a" },
2401
2407
  );
2402
2408
  });
2403
-
2404
2409
  it("a second partial refund reverses only the delta up to the new cumulative target", async () => {
2405
- // First refund (5000) already clawed back 3500/500 and was recorded.
2406
2410
  const ctx = makeCtx({
2407
2411
  query: ledgerLegs({ reversedStore: 3500, reversedAff: 500 }),
2408
2412
  });
2409
2413
  const stripe = makeStripe();
2414
+ stripe.refunds.list.mockImplementation(() =>
2415
+ (async function* () {
2416
+ yield { amount: 7000, status: "succeeded" };
2417
+ })(),
2418
+ );
2410
2419
  stripe.charges.retrieve.mockResolvedValue({
2411
2420
  id: "ch_1",
2412
2421
  amount: 10000,
2413
2422
  amount_refunded: 7000, // cumulative: 5000 + this refund's 2000
2414
2423
  });
2415
2424
  const whCtx = makeWhCtx({ ctx, stripe });
2416
-
2417
2425
  await processEvent(whCtx, refundEvent({ id: "re_2", amount: 2000 }));
2418
-
2419
- // Target 70% of each leg minus what's already reversed: 4900-3500, 700-500.
2420
2426
  expect(stripe.transfers.createReversal).toHaveBeenCalledWith(
2421
2427
  "tr_s",
2422
2428
  { amount: 1400 },
@@ -2428,7 +2434,6 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2428
2434
  { idempotencyKey: "bs_rev_re_2_tr_a" },
2429
2435
  );
2430
2436
  });
2431
-
2432
2437
  it("is idempotent — a redelivered refund event whose reversals are recorded reverses nothing", async () => {
2433
2438
  const ctx = makeCtx({
2434
2439
  query: ledgerLegs({ reversedStore: 3500, reversedAff: 500 }),
@@ -2440,36 +2445,24 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2440
2445
  amount_refunded: 5000,
2441
2446
  });
2442
2447
  const whCtx = makeWhCtx({ ctx, stripe });
2443
-
2444
2448
  await processEvent(whCtx, refundEvent());
2445
-
2446
- // Cumulative target (50%) already met on both legs — no delta, no calls.
2447
2449
  expect(stripe.transfers.createReversal).not.toHaveBeenCalled();
2448
2450
  });
2449
-
2450
2451
  it("skips clawback quietly for a refund on a non-split sale", async () => {
2451
2452
  const ctx = makeCtx({ query: [] });
2452
2453
  const stripe = makeStripe();
2453
2454
  const whCtx = makeWhCtx({ ctx, stripe });
2454
-
2455
2455
  await processEvent(whCtx, refundEvent());
2456
-
2457
- // No ledger legs → not a split sale (Stripe-native reverse_transfer covers
2458
- // destination charges). No charge lookup, no reversals, no throw.
2459
2456
  expect(stripe.charges.retrieve).not.toHaveBeenCalled();
2460
2457
  expect(stripe.transfers.createReversal).not.toHaveBeenCalled();
2461
2458
  });
2462
-
2463
2459
  it("does not claw back for a pending refund", async () => {
2464
2460
  const ctx = makeCtx({ query: ledgerLegs() });
2465
2461
  const stripe = makeStripe();
2466
2462
  const whCtx = makeWhCtx({ ctx, stripe });
2467
-
2468
2463
  await processEvent(whCtx, refundEvent({ status: "pending" }));
2469
-
2470
2464
  expect(stripe.transfers.createReversal).not.toHaveBeenCalled();
2471
2465
  });
2472
-
2473
2466
  it("propagates a reversal failure so the event is marked failed and Stripe retries", async () => {
2474
2467
  const ctx = makeCtx({ query: ledgerLegs() });
2475
2468
  const stripe = makeStripe();
@@ -2480,12 +2473,10 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2480
2473
  });
2481
2474
  stripe.transfers.createReversal.mockRejectedValue(new Error("stripe down"));
2482
2475
  const whCtx = makeWhCtx({ ctx, stripe });
2483
-
2484
2476
  await expect(processEvent(whCtx, refundEvent())).rejects.toThrow(
2485
2477
  "stripe down",
2486
2478
  );
2487
2479
  });
2488
-
2489
2480
  it("application_fee.refunded sets absolute fee totals on the linked payment", async () => {
2490
2481
  const stripe = makeStripe();
2491
2482
  stripe.charges.retrieve.mockResolvedValue({
@@ -2493,7 +2484,6 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2493
2484
  payment_intent: "pi_1",
2494
2485
  });
2495
2486
  const whCtx = makeWhCtx({ stripe });
2496
-
2497
2487
  const feeEvent = event("application_fee.refunded", {
2498
2488
  id: "fee_1",
2499
2489
  charge: "ch_1",
@@ -2502,7 +2492,6 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2502
2492
  currency: "usd",
2503
2493
  });
2504
2494
  await processEvent(whCtx, feeEvent);
2505
-
2506
2495
  const calls = whCtx.ctx.runMutation.mock.calls;
2507
2496
  const feeCall = calls.find(
2508
2497
  (c) =>
@@ -2510,15 +2499,11 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2510
2499
  "betterStripe/connect/mutations/recordPaymentFeeRefund",
2511
2500
  );
2512
2501
  expect(feeCall).toBeDefined();
2513
- // Absolute cumulative values straight from Stripe — never incremented, so
2514
- // a redelivery (or a createRefund-triggered duplicate) can't double-count.
2515
2502
  expect(feeCall![1]).toEqual({
2516
2503
  stripePaymentIntentId: "pi_1",
2517
2504
  feeCollectedAmount: 160,
2518
2505
  feeRefundedAmount: 160,
2519
2506
  });
2520
-
2521
- // Redelivery writes the identical absolute state.
2522
2507
  await processEvent(whCtx, feeEvent);
2523
2508
  const feeCalls = whCtx.ctx.runMutation.mock.calls.filter(
2524
2509
  (c) =>
@@ -2528,7 +2513,6 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2528
2513
  expect(feeCalls).toHaveLength(2);
2529
2514
  expect(feeCalls[1][1]).toEqual(feeCalls[0][1]);
2530
2515
  });
2531
-
2532
2516
  it("application_fee.refunded skips quietly when the charge has no payment intent", async () => {
2533
2517
  const stripe = makeStripe();
2534
2518
  stripe.charges.retrieve.mockResolvedValue({
@@ -2536,7 +2520,6 @@ describe("processEvent — refunds: split clawback + fee-refund denormalization
2536
2520
  payment_intent: null,
2537
2521
  });
2538
2522
  const whCtx = makeWhCtx({ stripe });
2539
-
2540
2523
  await expect(
2541
2524
  processEvent(
2542
2525
  whCtx,
@@ -1,3 +1,5 @@
1
+ import { reconcileDisputeMoney } from "./disputeRecovery.js";
2
+ import { successfulRefundPrincipal } from "../connect/refundPrincipal.js";
1
3
  import { subscriptionRouting } from "../billing/subscriptionRouting.js";
2
4
  import { cancelsAtPeriodEnd } from "../billing/subscriptionCancellation.js";
3
5
  import type Stripe from "stripe";
@@ -5,8 +7,6 @@ import type Stripe from "stripe";
5
7
  import type { SplitRecipient } from "../../component/lib/fees.js";
6
8
  import {
7
9
  createSplitTransfers,
8
- reinstateTransfers,
9
- reverseTransfers,
10
10
  reverseTransfersForRefund,
11
11
  } from "../connect/transfers.js";
12
12
  import { validateStatementDescriptorSuffix } from "../core/descriptors.js";
@@ -989,15 +989,24 @@ async function handleRefundEvent(
989
989
  componentRef(whCtx.component, "connect/queries/listTransfersByCharge"),
990
990
  { sourceChargeId: chargeId },
991
991
  )) ?? []) as unknown[];
992
- if (legs.length === 0) return; // not a split sale
992
+ if (legs.length === 0) {
993
+ const obligations = (await whCtx.ctx.runQuery(
994
+ componentRef(
995
+ whCtx.component,
996
+ "affiliateRecovery/queries/chargeObligations",
997
+ ),
998
+ { sourceChargeId: chargeId },
999
+ )) as unknown[] | null;
1000
+ if (!obligations?.length) return;
1001
+ }
993
1002
 
994
- // Fresh charge read for the authoritative cumulative amount_refunded.
1003
+ // Fetch succeeded refunds: charge.amount_refunded can include pending funds.
995
1004
  const charge = await whCtx.stripe.charges.retrieve(chargeId);
996
1005
  await reverseTransfersForRefund(whCtx.stripe, whCtx.component, whCtx.ctx, {
997
1006
  sourceChargeId: chargeId,
998
1007
  refundId: refund.id,
999
1008
  chargeAmount: charge.amount,
1000
- amountRefunded: charge.amount_refunded ?? refund.amount,
1009
+ amountRefunded: await successfulRefundPrincipal(whCtx.stripe, chargeId),
1001
1010
  });
1002
1011
  }
1003
1012
 
@@ -1054,9 +1063,11 @@ async function handleDisputeEvent(
1054
1063
  // best-effort: this is optional metadata, so a transient charge-lookup failure
1055
1064
  // must never abort the critical dispute side effects (upsert, clawback, cancel).
1056
1065
  let statementDescriptor: string | undefined;
1066
+ let originalCharge: Stripe.Charge | undefined;
1057
1067
  if (lastEvent === "created" && chargeId) {
1058
1068
  try {
1059
- const charge = await whCtx.stripe.charges.retrieve(chargeId);
1069
+ const charge = (originalCharge =
1070
+ await whCtx.stripe.charges.retrieve(chargeId));
1060
1071
  statementDescriptor =
1061
1072
  charge?.calculated_statement_descriptor ??
1062
1073
  charge?.statement_descriptor ??
@@ -1082,31 +1093,7 @@ async function handleDisputeEvent(
1082
1093
  metadata: dispute.metadata ?? undefined,
1083
1094
  });
1084
1095
 
1085
- // Clawback (BTS-27): when a dispute is first opened, reverse the transfers
1086
- // funded by the disputed charge pro-rata to the disputed amount, so recipients
1087
- // bear their share (losses_collector=application leaves the platform with the
1088
- // rest). Idempotent via the dispute id; reinstated by BTS-29 if the dispute is
1089
- // won. Only on `created` — other dispute events don't move funds here.
1090
- if (lastEvent === "created" && chargeId) {
1091
- await reverseTransfers(whCtx.stripe, whCtx.component, whCtx.ctx, {
1092
- sourceChargeId: chargeId,
1093
- amount: dispute.amount,
1094
- operationId: dispute.id,
1095
- });
1096
- }
1097
-
1098
- // Reinstatement (BTS-29): when the dispute is won (or funds are explicitly
1099
- // reinstated), pay recipients back the amounts clawed back on `created`.
1100
- const isWon =
1101
- lastEvent === "funds_reinstated" ||
1102
- (lastEvent === "closed" && dispute.status === "won");
1103
- if (isWon && chargeId) {
1104
- await reinstateTransfers(whCtx.stripe, whCtx.component, whCtx.ctx, {
1105
- sourceChargeId: chargeId,
1106
- operationId: dispute.id,
1107
- currency: dispute.currency,
1108
- });
1109
- }
1096
+ await reconcileDisputeMoney(whCtx, dispute, lastEvent, originalCharge);
1110
1097
 
1111
1098
  // Auto-cancel the disputed subscription (BTS-28, default on). Resolve the
1112
1099
  // subscription from the dispute's PaymentIntent (invoice payment → invoice →
@@ -8,15 +8,26 @@
8
8
  * @module
9
9
  */
10
10
 
11
+ import type * as affiliateEarnings_mutations from "../affiliateEarnings/mutations.js";
12
+ import type * as affiliatePayouts_mutations from "../affiliatePayouts/mutations.js";
13
+ import type * as affiliatePayouts_queries from "../affiliatePayouts/queries.js";
14
+ import type * as affiliatePayouts_recipientGuard from "../affiliatePayouts/recipientGuard.js";
15
+ import type * as affiliateRecovery_accounting from "../affiliateRecovery/accounting.js";
16
+ import type * as affiliateRecovery_mutations from "../affiliateRecovery/mutations.js";
17
+ import type * as affiliateRecovery_queries from "../affiliateRecovery/queries.js";
11
18
  import type * as billing_mutations from "../billing/mutations.js";
12
19
  import type * as billing_queries from "../billing/queries.js";
13
20
  import type * as billing_validators from "../billing/validators.js";
14
21
  import type * as connect_mutations from "../connect/mutations.js";
15
22
  import type * as connect_payoutWrites from "../connect/payoutWrites.js";
16
23
  import type * as connect_queries from "../connect/queries.js";
24
+ import type * as connect_reversalClaims from "../connect/reversalClaims.js";
25
+ import type * as connect_reversalDiagnostics from "../connect/reversalDiagnostics.js";
26
+ import type * as connect_reversalReceipts from "../connect/reversalReceipts.js";
17
27
  import type * as connect_validators from "../connect/validators.js";
18
28
  import type * as core_mutations from "../core/mutations.js";
19
29
  import type * as core_queries from "../core/queries.js";
30
+ import type * as core_resetSafety from "../core/resetSafety.js";
20
31
  import type * as core_validators from "../core/validators.js";
21
32
  import type * as costRecovery_claims from "../costRecovery/claims.js";
22
33
  import type * as costRecovery_completion from "../costRecovery/completion.js";
@@ -46,14 +57,23 @@ import type * as payoutRelease_helpers from "../payoutRelease/helpers.js";
46
57
  import type * as payoutRelease_mutations from "../payoutRelease/mutations.js";
47
58
  import type * as payoutRelease_observation from "../payoutRelease/observation.js";
48
59
  import type * as payoutRelease_queries from "../payoutRelease/queries.js";
60
+ import type * as payoutSnapshots_localState from "../payoutSnapshots/localState.js";
61
+ import type * as payoutSnapshots_mutations from "../payoutSnapshots/mutations.js";
62
+ import type * as payoutSnapshots_revisions from "../payoutSnapshots/revisions.js";
63
+ import type * as payoutSnapshots_scope from "../payoutSnapshots/scope.js";
49
64
  import type * as payoutSync_helpers from "../payoutSync/helpers.js";
50
65
  import type * as payoutSync_mutations from "../payoutSync/mutations.js";
51
66
  import type * as payoutSync_queries from "../payoutSync/queries.js";
52
67
  import type * as payoutSync_validators from "../payoutSync/validators.js";
68
+ import type * as payoutWorker_helpers from "../payoutWorker/helpers.js";
69
+ import type * as payoutWorker_mutations from "../payoutWorker/mutations.js";
70
+ import type * as payoutWorker_queries from "../payoutWorker/queries.js";
53
71
  import type * as products_mutations from "../products/mutations.js";
54
72
  import type * as products_queries from "../products/queries.js";
55
73
  import type * as products_validators from "../products/validators.js";
56
74
  import type * as refundHistory_queries from "../refundHistory/queries.js";
75
+ import type * as settlement_clawbackSchema from "../settlement/clawbackSchema.js";
76
+ import type * as settlement_clawbacks from "../settlement/clawbacks.js";
57
77
  import type * as settlement_mutations from "../settlement/mutations.js";
58
78
  import type * as settlement_queries from "../settlement/queries.js";
59
79
  import type * as webhooks_mutations from "../webhooks/mutations.js";
@@ -68,15 +88,26 @@ import type {
68
88
  import { anyApi, componentsGeneric } from "convex/server";
69
89
 
70
90
  const fullApi: ApiFromModules<{
91
+ "affiliateEarnings/mutations": typeof affiliateEarnings_mutations;
92
+ "affiliatePayouts/mutations": typeof affiliatePayouts_mutations;
93
+ "affiliatePayouts/queries": typeof affiliatePayouts_queries;
94
+ "affiliatePayouts/recipientGuard": typeof affiliatePayouts_recipientGuard;
95
+ "affiliateRecovery/accounting": typeof affiliateRecovery_accounting;
96
+ "affiliateRecovery/mutations": typeof affiliateRecovery_mutations;
97
+ "affiliateRecovery/queries": typeof affiliateRecovery_queries;
71
98
  "billing/mutations": typeof billing_mutations;
72
99
  "billing/queries": typeof billing_queries;
73
100
  "billing/validators": typeof billing_validators;
74
101
  "connect/mutations": typeof connect_mutations;
75
102
  "connect/payoutWrites": typeof connect_payoutWrites;
76
103
  "connect/queries": typeof connect_queries;
104
+ "connect/reversalClaims": typeof connect_reversalClaims;
105
+ "connect/reversalDiagnostics": typeof connect_reversalDiagnostics;
106
+ "connect/reversalReceipts": typeof connect_reversalReceipts;
77
107
  "connect/validators": typeof connect_validators;
78
108
  "core/mutations": typeof core_mutations;
79
109
  "core/queries": typeof core_queries;
110
+ "core/resetSafety": typeof core_resetSafety;
80
111
  "core/validators": typeof core_validators;
81
112
  "costRecovery/claims": typeof costRecovery_claims;
82
113
  "costRecovery/completion": typeof costRecovery_completion;
@@ -106,14 +137,23 @@ const fullApi: ApiFromModules<{
106
137
  "payoutRelease/mutations": typeof payoutRelease_mutations;
107
138
  "payoutRelease/observation": typeof payoutRelease_observation;
108
139
  "payoutRelease/queries": typeof payoutRelease_queries;
140
+ "payoutSnapshots/localState": typeof payoutSnapshots_localState;
141
+ "payoutSnapshots/mutations": typeof payoutSnapshots_mutations;
142
+ "payoutSnapshots/revisions": typeof payoutSnapshots_revisions;
143
+ "payoutSnapshots/scope": typeof payoutSnapshots_scope;
109
144
  "payoutSync/helpers": typeof payoutSync_helpers;
110
145
  "payoutSync/mutations": typeof payoutSync_mutations;
111
146
  "payoutSync/queries": typeof payoutSync_queries;
112
147
  "payoutSync/validators": typeof payoutSync_validators;
148
+ "payoutWorker/helpers": typeof payoutWorker_helpers;
149
+ "payoutWorker/mutations": typeof payoutWorker_mutations;
150
+ "payoutWorker/queries": typeof payoutWorker_queries;
113
151
  "products/mutations": typeof products_mutations;
114
152
  "products/queries": typeof products_queries;
115
153
  "products/validators": typeof products_validators;
116
154
  "refundHistory/queries": typeof refundHistory_queries;
155
+ "settlement/clawbackSchema": typeof settlement_clawbackSchema;
156
+ "settlement/clawbacks": typeof settlement_clawbacks;
117
157
  "settlement/mutations": typeof settlement_mutations;
118
158
  "settlement/queries": typeof settlement_queries;
119
159
  "webhooks/mutations": typeof webhooks_mutations;