@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
@@ -0,0 +1,78 @@
1
+ import { runMutationOrThrow } from "../helpers.js";
2
+ import { componentRef } from "../webhooks/helpers.js";
3
+ /** Host cron only. No method on this worker represents a customer withdrawal request. */
4
+ export class PayoutWorkerClient {
5
+ component;
6
+ release;
7
+ reconcile;
8
+ constructor(component, release, reconcile) {
9
+ this.component = component;
10
+ this.release = release;
11
+ this.reconcile = reconcile;
12
+ }
13
+ get(ctx, scope) {
14
+ return ctx.runQuery(componentRef(this.component, "payoutWorker/queries/get"), {
15
+ accountId: scope.accountId,
16
+ ownerKey: scope.ownerKey,
17
+ currency: scope.currency,
18
+ });
19
+ }
20
+ policies(ctx, paginationOpts) {
21
+ return ctx.runQuery(componentRef(this.component, "payoutWorker/queries/policies"), { paginationOpts });
22
+ }
23
+ recovering(ctx, paginationOpts) {
24
+ return ctx.runQuery(componentRef(this.component, "payoutWorker/queries/recovering"), { paginationOpts });
25
+ }
26
+ changing(ctx, paginationOpts) {
27
+ return ctx.runQuery(componentRef(this.component, "payoutWorker/queries/changing"), { paginationOpts });
28
+ }
29
+ async run(ctx, opts) {
30
+ if (!Number.isSafeInteger(opts.independentLiabilities) ||
31
+ opts.independentLiabilities < 0 ||
32
+ (opts.maxPages !== undefined &&
33
+ (!Number.isInteger(opts.maxPages) ||
34
+ opts.maxPages < 1 ||
35
+ opts.maxPages > 100)))
36
+ throw new Error("Invalid automatic payout liabilities or page budget.");
37
+ const scope = {
38
+ accountId: opts.accountId,
39
+ ownerKey: opts.ownerKey,
40
+ currency: opts.currency,
41
+ };
42
+ const started = (await runMutationOrThrow(ctx, componentRef(this.component, "payoutWorker/mutations/begin"), {
43
+ ...scope,
44
+ cadenceMs: opts.cadenceMs ?? 300000,
45
+ }));
46
+ if (started.status === "held")
47
+ return started;
48
+ const operationKey = started.job.operationKey;
49
+ const finish = (reason) => runMutationOrThrow(ctx, componentRef(this.component, "payoutWorker/mutations/finish"), { ...scope, operationKey, generation: started.job.generation, reason });
50
+ let payout;
51
+ try {
52
+ payout = started.reconcileOnly
53
+ ? await this.reconcile(ctx, {
54
+ ...scope,
55
+ operationKey,
56
+ maxPages: opts.maxPages,
57
+ })
58
+ : await this.release(ctx, {
59
+ ...scope,
60
+ operationKey,
61
+ independentLiabilities: opts.independentLiabilities,
62
+ maxPages: opts.maxPages,
63
+ });
64
+ }
65
+ catch (error) {
66
+ try {
67
+ await finish("worker_error");
68
+ }
69
+ catch (completionError) {
70
+ throw new AggregateError([error, completionError], "Payout worker outcome requires reconciliation.");
71
+ }
72
+ throw error;
73
+ }
74
+ const reason = payout.status === "held" ? payout.reason : payout.claim.status;
75
+ return { status: "completed", job: await finish(reason), payout };
76
+ }
77
+ }
78
+ //# sourceMappingURL=payoutWorker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"payoutWorker.js","sourceRoot":"","sources":["../../../src/client/connect/payoutWorker.ts"],"names":[],"mappings":"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"}
@@ -27,6 +27,8 @@ export declare function getAccountBalance(stripe: Stripe, opts: {
27
27
  stripeAccountId: string;
28
28
  }): Promise<AccountBalance[]>;
29
29
  export type CreatePayoutOptions = {
30
+ /** Host-authorized minimum in the payout currency. */
31
+ minimumAmount?: number;
30
32
  stripeAccountId: string;
31
33
  amount: number;
32
34
  currency?: string;
@@ -34,7 +36,7 @@ export type CreatePayoutOptions = {
34
36
  /** Stripe idempotency key for retry-safe payout creation. */
35
37
  idempotencyKey?: string;
36
38
  };
37
- export declare function createPayout(stripe: Stripe, _ctx: RunCtx, opts: CreatePayoutOptions): Promise<{
39
+ export declare function createPayout(stripe: Stripe, ctx: RunCtx, opts: CreatePayoutOptions, component?: Component): Promise<{
38
40
  stripePayoutId: string;
39
41
  }>;
40
42
  export declare function getPayout(component: Component, ctx: RunCtx, opts: {
@@ -1 +1 @@
1
- {"version":3,"file":"payouts.d.ts","sourceRoot":"","sources":["../../../src/client/connect/payouts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAOvD;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,GAChC,OAAO,CAAC,cAAc,EAAE,CAAC,CAiB3B;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,mBAAmB;;GAgB1B;AAED,wBAAsB,SAAS,CAC7B,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,gBAM3B;AAED,wBAAsB,WAAW,CAC/B,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,gBAO3E"}
1
+ {"version":3,"file":"payouts.d.ts","sourceRoot":"","sources":["../../../src/client/connect/payouts.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAOvD;;;;;;GAMG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IAAE,eAAe,EAAE,MAAM,CAAA;CAAE,GAChC,OAAO,CAAC,cAAc,EAAE,CAAC,CAiB3B;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,sDAAsD;IACtD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,6DAA6D;IAC7D,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,mBAAmB,EACzB,SAAS,CAAC,EAAE,SAAS;;GAmEtB;AAED,wBAAsB,SAAS,CAC7B,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,gBAM3B;AAED,wBAAsB,WAAW,CAC/B,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,gBAO3E"}
@@ -1,3 +1,5 @@
1
+ import { reserveAffiliatePayout, completeAffiliatePayout, reconcileAffiliatePayout, } from "../affiliateRecovery/payoutGate.js";
2
+ import { classifyRecoveryError } from "../affiliateRecovery/provider.js";
1
3
  import { componentRef } from "../webhooks/helpers.js";
2
4
  /**
3
5
  * Retrieve a connected account's balance (BTS-65), scoped to that account via
@@ -26,18 +28,49 @@ export async function getAccountBalance(stripe, opts) {
26
28
  entryFor(p.currency).pending += p.amount;
27
29
  return [...byCurrency.values()];
28
30
  }
29
- export async function createPayout(stripe, _ctx, opts) {
30
- const payout = await stripe.payouts.create({
31
- amount: opts.amount,
32
- currency: opts.currency ?? "usd",
33
- metadata: opts.metadata ?? undefined,
34
- }, {
35
- stripeAccount: opts.stripeAccountId,
36
- ...(opts.idempotencyKey !== undefined
37
- ? { idempotencyKey: opts.idempotencyKey }
38
- : {}),
39
- });
40
- return { stripePayoutId: payout.id };
31
+ export async function createPayout(stripe, ctx, opts, component) {
32
+ const release = component
33
+ ? await reserveAffiliatePayout(component, ctx, opts)
34
+ : null;
35
+ if (release?.state === "submitted")
36
+ return { stripePayoutId: release.stripePayoutId };
37
+ if (release?.state === "failed")
38
+ throw new Error("Affiliate payout failed; use a new authorized operation key.");
39
+ try {
40
+ if (release) {
41
+ const receiptId = await reconcileAffiliatePayout(stripe, release);
42
+ if (receiptId) {
43
+ await completeAffiliatePayout(component, ctx, release.operationKey, "submitted", receiptId);
44
+ return { stripePayoutId: receiptId };
45
+ }
46
+ }
47
+ if (release) {
48
+ if (Date.now() - release.createdAt >= 23 * 60 * 60 * 1000)
49
+ throw new Error("Affiliate payout idempotency window expired; reconcile the provider receipt before retrying.");
50
+ // Receipt lookup may yield while a refund records new debt.
51
+ await reserveAffiliatePayout(component, ctx, opts);
52
+ }
53
+ const payout = await stripe.payouts.create({
54
+ amount: opts.amount,
55
+ currency: opts.currency ?? "usd",
56
+ metadata: release
57
+ ? { ...opts.metadata, bsAffiliatePayout: release._id }
58
+ : (opts.metadata ?? undefined),
59
+ }, {
60
+ stripeAccount: opts.stripeAccountId,
61
+ ...(opts.idempotencyKey !== undefined
62
+ ? { idempotencyKey: opts.idempotencyKey }
63
+ : {}),
64
+ });
65
+ if (release)
66
+ await completeAffiliatePayout(component, ctx, release.operationKey, "submitted", payout.id);
67
+ return { stripePayoutId: payout.id };
68
+ }
69
+ catch (error) {
70
+ if (release)
71
+ await completeAffiliatePayout(component, ctx, release.operationKey, classifyRecoveryError(error).state === "unknown" ? "unknown" : "failed");
72
+ throw error;
73
+ }
41
74
  }
42
75
  export async function getPayout(component, ctx, opts) {
43
76
  return ctx.runQuery(componentRef(component, "connect/queries/getPayout"), opts);
@@ -1 +1 @@
1
- {"version":3,"file":"payouts.js","sourceRoot":"","sources":["../../../src/client/connect/payouts.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAqBtD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAAc,EACd,IAAiC;IAEjC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE;QACvD,aAAa,EAAE,IAAI,CAAC,eAAe;KACpC,CAAC,CAAC;IAEH,MAAM,UAAU,GAAG,IAAI,GAAG,EAA0B,CAAC;IACrD,MAAM,QAAQ,GAAG,CAAC,QAAgB,EAAkB,EAAE;QACpD,IAAI,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,KAAK,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC;YAC/C,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,SAAS;QAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC;IAC9E,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO;QAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC;IAC1E,OAAO,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;AAClC,CAAC;AAWD,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,MAAc,EACd,IAAY,EACZ,IAAyB;IAEzB,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,MAAM,CACxC;QACE,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,KAAK;QAChC,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,SAAS;KACrC,EACD;QACE,aAAa,EAAE,IAAI,CAAC,eAAe;QACnC,GAAG,CAAC,IAAI,CAAC,cAAc,KAAK,SAAS;YACnC,CAAC,CAAC,EAAE,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE;YACzC,CAAC,CAAC,EAAE,CAAC;KACR,CACF,CAAC;IACF,OAAO,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,SAAoB,EACpB,GAAW,EACX,IAA0B;IAE1B,OAAO,GAAG,CAAC,QAAQ,CACjB,YAAY,CAAC,SAAS,EAAE,2BAA2B,CAAC,EACpD,IAAI,CACL,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAoB,EACpB,GAAW,EACX,IAA0E;IAE1E,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC;IAChD,OAAO,GAAG,CAAC,QAAQ,CAAC,YAAY,CAAC,SAAS,EAAE,6BAA6B,CAAC,EAAE;QAC1E,GAAG,IAAI;QACP,GAAG,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzE,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"payouts.js","sourceRoot":"","sources":["../../../src/client/connect/payouts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type Stripe from "stripe";
2
+ /** Charge.amount_refunded also includes pending refunds; only success is final. */
3
+ export declare function successfulRefundPrincipal(stripe: Stripe, chargeId: string): Promise<number>;
4
+ //# sourceMappingURL=refundPrincipal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refundPrincipal.d.ts","sourceRoot":"","sources":["../../../src/client/connect/refundPrincipal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AAEjC,mFAAmF;AACnF,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,mBAoBjB"}
@@ -0,0 +1,21 @@
1
+ /** Charge.amount_refunded also includes pending refunds; only success is final. */
2
+ export async function successfulRefundPrincipal(stripe, chargeId) {
3
+ let principal = 0;
4
+ let count = 0;
5
+ for await (const refund of stripe.refunds.list({
6
+ charge: chargeId,
7
+ limit: 100,
8
+ })) {
9
+ if (++count > 1000)
10
+ throw new Error("Successful refund lookup limit exceeded.");
11
+ if (refund.status !== "succeeded")
12
+ continue;
13
+ if (!Number.isSafeInteger(refund.amount) ||
14
+ refund.amount < 0 ||
15
+ !Number.isSafeInteger(principal + refund.amount))
16
+ throw new Error("Invalid successful refund principal.");
17
+ principal += refund.amount;
18
+ }
19
+ return principal;
20
+ }
21
+ //# sourceMappingURL=refundPrincipal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refundPrincipal.js","sourceRoot":"","sources":["../../../src/client/connect/refundPrincipal.ts"],"names":[],"mappings":"AAEA,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,MAAc,EACd,QAAgB;IAEhB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;QAC7C,MAAM,EAAE,QAAQ;QAChB,KAAK,EAAE,GAAG;KACX,CAAC,EAAE,CAAC;QACH,IAAI,EAAE,KAAK,GAAG,IAAI;YAChB,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;QAC9D,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW;YAAE,SAAS;QAC5C,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC;YACpC,MAAM,CAAC,MAAM,GAAG,CAAC;YACjB,CAAC,MAAM,CAAC,aAAa,CAAC,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;YAEhD,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;QAC1D,SAAS,IAAI,MAAM,CAAC,MAAM,CAAC;IAC7B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,47 @@
1
+ import type Stripe from "stripe";
2
+ import type { Component, RunCtx } from "../helpers.js";
3
+ export type ClaimedSlice = {
4
+ stripeTransferId: string;
5
+ /** Cumulative reversed amount this slice starts from. */
6
+ from: number;
7
+ /** Cumulative reversed amount this slice raises the leg to. */
8
+ to: number;
9
+ /** The leg's confirmed `reversedAmount` at claim time. */
10
+ confirmed: number;
11
+ commissionTracked?: boolean;
12
+ };
13
+ export type ReversalClaim = {
14
+ replay: boolean;
15
+ slices: ClaimedSlice[];
16
+ };
17
+ /**
18
+ * Execute the slices an operation claimed via `claimReversalSlices` (BTS-63).
19
+ * The claim already reserved this money atomically, so all that's left is
20
+ * moving it: one `bs_rev_<operationId>_<transferId>` reversal per slice, then
21
+ * confirming the new cumulative total in the ledger. A replayed claim always
22
+ * re-sends byte-identical params under the same key, which Stripe answers
23
+ * from its idempotency cache without moving money twice.
24
+ *
25
+ * Because Stripe prunes idempotency keys after ~24h (and a crash can land
26
+ * between the Stripe call and the ledger confirm), a replay first checks the
27
+ * transfer's live `amount_reversed`: if the slice's money already moved, it
28
+ * just confirms the ledger instead of re-sending the reversal.
29
+ *
30
+ * A slice only executes once every predecessor slice on its leg is confirmed
31
+ * (`confirmed ≥ from`). Without that gate, a sibling operation landing behind
32
+ * a transiently-failed claim would execute and confirm PAST the hole; the
33
+ * failed operation's retry would then see `confirmed ≥ to` and silently skip
34
+ * — its money would never move while the ledger says it did. Throwing instead
35
+ * fails this operation's webhook event, and at-least-once delivery retries
36
+ * both operations until the predecessor fills its hole and each claimed slice
37
+ * has actually moved. The ledger's `reversedAmount` therefore always covers a
38
+ * solid, hole-free prefix of the reversed axis — which is exactly what makes
39
+ * the `confirmed`/`amount_reversed` checks above sound.
40
+ */
41
+ export declare function executeClaimedSlices(stripe: Stripe, component: Component, ctx: RunCtx, operationId: string, claim: ReversalClaim): Promise<{
42
+ reversals: {
43
+ stripeTransferId: string;
44
+ amount: number;
45
+ }[];
46
+ }>;
47
+ //# sourceMappingURL=reversalExecution.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversalExecution.d.ts","sourceRoot":"","sources":["../../../src/client/connect/reversalExecution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAKvD,MAAM,MAAM,YAAY,GAAG;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yDAAyD;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAC;IACX,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,YAAY,EAAE,CAAA;CAAE,CAAC;AAExE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC;IAAE,SAAS,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,CAgFxE"}
@@ -0,0 +1,84 @@
1
+ import { runMutationOrThrow } from "../helpers.js";
2
+ import { componentRef } from "../webhooks/helpers.js";
3
+ import { findCommissionReversal } from "./commissionReceipts.js";
4
+ /**
5
+ * Execute the slices an operation claimed via `claimReversalSlices` (BTS-63).
6
+ * The claim already reserved this money atomically, so all that's left is
7
+ * moving it: one `bs_rev_<operationId>_<transferId>` reversal per slice, then
8
+ * confirming the new cumulative total in the ledger. A replayed claim always
9
+ * re-sends byte-identical params under the same key, which Stripe answers
10
+ * from its idempotency cache without moving money twice.
11
+ *
12
+ * Because Stripe prunes idempotency keys after ~24h (and a crash can land
13
+ * between the Stripe call and the ledger confirm), a replay first checks the
14
+ * transfer's live `amount_reversed`: if the slice's money already moved, it
15
+ * just confirms the ledger instead of re-sending the reversal.
16
+ *
17
+ * A slice only executes once every predecessor slice on its leg is confirmed
18
+ * (`confirmed ≥ from`). Without that gate, a sibling operation landing behind
19
+ * a transiently-failed claim would execute and confirm PAST the hole; the
20
+ * failed operation's retry would then see `confirmed ≥ to` and silently skip
21
+ * — its money would never move while the ledger says it did. Throwing instead
22
+ * fails this operation's webhook event, and at-least-once delivery retries
23
+ * both operations until the predecessor fills its hole and each claimed slice
24
+ * has actually moved. The ledger's `reversedAmount` therefore always covers a
25
+ * solid, hole-free prefix of the reversed axis — which is exactly what makes
26
+ * the `confirmed`/`amount_reversed` checks above sound.
27
+ */
28
+ export async function executeClaimedSlices(stripe, component, ctx, operationId, claim) {
29
+ const reversals = [];
30
+ for (const slice of claim.slices) {
31
+ const receiptAmount = slice.to - slice.from;
32
+ if (slice.commissionTracked && claim.replay) {
33
+ const receipt = await findCommissionReversal(stripe, slice.stripeTransferId, operationId, receiptAmount);
34
+ if (receipt) {
35
+ await runMutationOrThrow(ctx, componentRef(component, "connect/mutations/recordTransferReversal"), {
36
+ stripeTransferId: slice.stripeTransferId,
37
+ reversedAmount: slice.to,
38
+ receipt: {
39
+ stripeReversalId: receipt.id,
40
+ operationId,
41
+ amount: receiptAmount,
42
+ },
43
+ });
44
+ continue;
45
+ }
46
+ if (slice.confirmed >= slice.to)
47
+ throw new Error("Commission reversal requires receipt reconciliation.");
48
+ }
49
+ if (slice.confirmed >= slice.to)
50
+ continue; // executed and recorded already
51
+ if (slice.confirmed < slice.from) {
52
+ throw new Error(`reversal slice [${slice.from},${slice.to}) on ${slice.stripeTransferId} ` +
53
+ `blocked: predecessor claim unexecuted (confirmed=${slice.confirmed})`);
54
+ }
55
+ if (claim.replay && !slice.commissionTracked) {
56
+ const transfer = await stripe.transfers.retrieve(slice.stripeTransferId);
57
+ if ((transfer.amount_reversed ?? 0) >= slice.to) {
58
+ // The money moved on a previous attempt that died before confirming.
59
+ await runMutationOrThrow(ctx, componentRef(component, "connect/mutations/recordTransferReversal"), {
60
+ stripeTransferId: slice.stripeTransferId,
61
+ reversedAmount: slice.to,
62
+ });
63
+ continue;
64
+ }
65
+ }
66
+ const amount = slice.to - slice.from;
67
+ const receipt = await stripe.transfers.createReversal(slice.stripeTransferId, {
68
+ amount,
69
+ ...(slice.commissionTracked
70
+ ? { metadata: { bsReversalOperation: operationId } }
71
+ : {}),
72
+ }, { idempotencyKey: `bs_rev_${operationId}_${slice.stripeTransferId}` });
73
+ await runMutationOrThrow(ctx, componentRef(component, "connect/mutations/recordTransferReversal"), {
74
+ stripeTransferId: slice.stripeTransferId,
75
+ reversedAmount: slice.to,
76
+ ...(slice.commissionTracked
77
+ ? { receipt: { stripeReversalId: receipt.id, operationId, amount } }
78
+ : {}),
79
+ });
80
+ reversals.push({ stripeTransferId: slice.stripeTransferId, amount });
81
+ }
82
+ return { reversals };
83
+ }
84
+ //# sourceMappingURL=reversalExecution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversalExecution.js","sourceRoot":"","sources":["../../../src/client/connect/reversalExecution.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAejE;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAc,EACd,SAAoB,EACpB,GAAW,EACX,WAAmB,EACnB,KAAoB;IAEpB,MAAM,SAAS,GAAmD,EAAE,CAAC;IACrE,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;QACjC,MAAM,aAAa,GAAG,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;QAC5C,IAAI,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,MAAM,sBAAsB,CAC1C,MAAM,EACN,KAAK,CAAC,gBAAgB,EACtB,WAAW,EACX,aAAa,CACd,CAAC;YACF,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,kBAAkB,CACtB,GAAG,EACH,YAAY,CAAC,SAAS,EAAE,0CAA0C,CAAC,EACnE;oBACE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;oBACxC,cAAc,EAAE,KAAK,CAAC,EAAE;oBACxB,OAAO,EAAE;wBACP,gBAAgB,EAAE,OAAO,CAAC,EAAE;wBAC5B,WAAW;wBACX,MAAM,EAAE,aAAa;qBACtB;iBACF,CACF,CAAC;gBACF,SAAS;YACX,CAAC;YACD,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,EAAE;gBAC7B,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,EAAE;YAAE,SAAS,CAAC,gCAAgC;QAE3E,IAAI,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CACb,mBAAmB,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE,QAAQ,KAAK,CAAC,gBAAgB,GAAG;gBACxE,oDAAoD,KAAK,CAAC,SAAS,GAAG,CACzE,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC7C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YACzE,IAAI,CAAC,QAAQ,CAAC,eAAe,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;gBAChD,qEAAqE;gBACrE,MAAM,kBAAkB,CACtB,GAAG,EACH,YAAY,CAAC,SAAS,EAAE,0CAA0C,CAAC,EACnE;oBACE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;oBACxC,cAAc,EAAE,KAAK,CAAC,EAAE;iBACzB,CACF,CAAC;gBACF,SAAS;YACX,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC;QACrC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,cAAc,CACnD,KAAK,CAAC,gBAAgB,EACtB;YACE,MAAM;YACN,GAAG,CAAC,KAAK,CAAC,iBAAiB;gBACzB,CAAC,CAAC,EAAE,QAAQ,EAAE,EAAE,mBAAmB,EAAE,WAAW,EAAE,EAAE;gBACpD,CAAC,CAAC,EAAE,CAAC;SACR,EACD,EAAE,cAAc,EAAE,UAAU,WAAW,IAAI,KAAK,CAAC,gBAAgB,EAAE,EAAE,CACtE,CAAC;QACF,MAAM,kBAAkB,CACtB,GAAG,EACH,YAAY,CAAC,SAAS,EAAE,0CAA0C,CAAC,EACnE;YACE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;YACxC,cAAc,EAAE,KAAK,CAAC,EAAE;YACxB,GAAG,CAAC,KAAK,CAAC,iBAAiB;gBACzB,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,EAAE,OAAO,CAAC,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE;gBACpE,CAAC,CAAC,EAAE,CAAC;SACR,CACF,CAAC;QACF,SAAS,CAAC,IAAI,CAAC,EAAE,gBAAgB,EAAE,KAAK,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC"}
@@ -104,9 +104,9 @@ export declare function reverseTransfers(stripe: Stripe, component: Component, c
104
104
  }[];
105
105
  }>;
106
106
  /**
107
- * Reverse a split sale's transfers pro-rata to the cumulatively refunded
108
- * amount (BTS-34) — the refund counterpart of the dispute clawback. Every leg
109
- * converges on a cumulative reversal TARGET, `round(leg × amountRefunded /
107
+ * Reverse a split sale's transfers pro-rata to cumulative succeeded refunds.
108
+ * Affiliate legs retain the larger refund/dispute commission exposure. Other
109
+ * legs converge on a cumulative reversal TARGET, `round(leg × amountRefunded /
110
110
  * chargeAmount)`, and only the delta above the ledger's recorded
111
111
  * `reversedAmount` is reversed. Delta-to-target (rather than percent-of-
112
112
  * original like {@link reverseTransfers}) is what makes at-least-once webhook
@@ -127,7 +127,7 @@ export declare function reverseTransfersForRefund(stripe: Stripe, component: Com
127
127
  refundId: string;
128
128
  /** The original charge amount (minor units). */
129
129
  chargeAmount: number;
130
- /** Stripe's cumulative `charge.amount_refunded`, including this refund. */
130
+ /** Cumulative principal of succeeded refunds; exclude pending/failed refunds. */
131
131
  amountRefunded: number;
132
132
  }): Promise<{
133
133
  reversals: {
@@ -135,6 +135,7 @@ export declare function reverseTransfersForRefund(stripe: Stripe, component: Com
135
135
  amount: number;
136
136
  }[];
137
137
  }>;
138
+ export { reverseTransfersForDispute } from "../affiliateRecovery/disputes.js";
138
139
  /**
139
140
  * Webhook-driven split transfer engine (BTS-22). After a charge succeeds for a
140
141
  * separate-charges sale, fan funds out to each split recipient: compute the
@@ -163,6 +164,9 @@ export declare function reinstateTransfers(stripe: Stripe, component: Component,
163
164
  sourceChargeId: string;
164
165
  operationId: string;
165
166
  currency: string;
167
+ excludeAffiliates?: boolean;
168
+ chargeAmount?: number;
169
+ refundedPrincipal?: number;
166
170
  }): Promise<{
167
171
  reinstated: {
168
172
  destinationAccountId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"transfers.d.ts","sourceRoot":"","sources":["../../../src/client/connect/transfers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transfers.d.ts","sourceRoot":"","sources":["../../../src/client/connect/transfers.ts"],"names":[],"mappings":"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"}
@@ -1,58 +1,17 @@
1
+ import { reconcileAffiliateCharge } from "../affiliateRecovery/engine.js";
2
+ import { executeClaimedSlices, } from "./reversalExecution.js";
1
3
  import { recoverSettlementTransfers } from "../settlement/reconciliation.js";
2
4
  import { executeResolvedTransfers } from "../settlement/execution.js";
3
5
  import { computeSplit } from "../core/fees.js";
4
6
  import { runMutationOrThrow } from "../helpers.js";
5
7
  import { componentRef } from "../webhooks/helpers.js";
6
- /**
7
- * Execute the slices an operation claimed via `claimReversalSlices` (BTS-63).
8
- * The claim already reserved this money atomically, so all that's left is
9
- * moving it: one `bs_rev_<operationId>_<transferId>` reversal per slice, then
10
- * confirming the new cumulative total in the ledger. A replayed claim always
11
- * re-sends byte-identical params under the same key, which Stripe answers
12
- * from its idempotency cache without moving money twice.
13
- *
14
- * Because Stripe prunes idempotency keys after ~24h (and a crash can land
15
- * between the Stripe call and the ledger confirm), a replay first checks the
16
- * transfer's live `amount_reversed`: if the slice's money already moved, it
17
- * just confirms the ledger instead of re-sending the reversal.
18
- *
19
- * A slice only executes once every predecessor slice on its leg is confirmed
20
- * (`confirmed ≥ from`). Without that gate, a sibling operation landing behind
21
- * a transiently-failed claim would execute and confirm PAST the hole; the
22
- * failed operation's retry would then see `confirmed ≥ to` and silently skip
23
- * — its money would never move while the ledger says it did. Throwing instead
24
- * fails this operation's webhook event, and at-least-once delivery retries
25
- * both operations until the predecessor fills its hole and each claimed slice
26
- * has actually moved. The ledger's `reversedAmount` therefore always covers a
27
- * solid, hole-free prefix of the reversed axis — which is exactly what makes
28
- * the `confirmed`/`amount_reversed` checks above sound.
29
- */
30
- async function executeClaimedSlices(stripe, component, ctx, operationId, claim) {
31
- const reversals = [];
32
- for (const slice of claim.slices) {
33
- if (slice.confirmed >= slice.to)
34
- continue; // executed and recorded already
35
- if (slice.confirmed < slice.from) {
36
- throw new Error(`reversal slice [${slice.from},${slice.to}) on ${slice.stripeTransferId} ` +
37
- `blocked: predecessor claim unexecuted (confirmed=${slice.confirmed})`);
38
- }
39
- if (claim.replay) {
40
- const transfer = await stripe.transfers.retrieve(slice.stripeTransferId);
41
- if ((transfer.amount_reversed ?? 0) >= slice.to) {
42
- // The money moved on a previous attempt that died before confirming.
43
- await runMutationOrThrow(ctx, componentRef(component, "connect/mutations/recordTransferReversal"), {
44
- stripeTransferId: slice.stripeTransferId,
45
- reversedAmount: slice.to,
46
- });
47
- continue;
48
- }
49
- }
50
- const amount = slice.to - slice.from;
51
- await stripe.transfers.createReversal(slice.stripeTransferId, { amount }, { idempotencyKey: `bs_rev_${operationId}_${slice.stripeTransferId}` });
52
- await runMutationOrThrow(ctx, componentRef(component, "connect/mutations/recordTransferReversal"), { stripeTransferId: slice.stripeTransferId, reversedAmount: slice.to });
53
- reversals.push({ stripeTransferId: slice.stripeTransferId, amount });
54
- }
55
- return { reversals };
8
+ async function trackedAffiliateTransfers(component, ctx, sourceChargeId) {
9
+ const rows = (await ctx.runQuery(componentRef(component, "affiliateRecovery/queries/chargeObligations"), { sourceChargeId }));
10
+ return new Set(Array.isArray(rows)
11
+ ? rows
12
+ .filter((row) => row.accounted && row.stripeTransferId)
13
+ .map((row) => row.stripeTransferId)
14
+ : []);
56
15
  }
57
16
  /** Stripe prunes idempotency keys after ~24h; a release must wait past this. */
58
17
  const REVERSAL_IDEMPOTENCY_WINDOW_MS = 24 * 60 * 60 * 1000;
@@ -108,11 +67,29 @@ export async function reclaimReversalClaim(stripe, component, ctx, opts) {
108
67
  const slices = [];
109
68
  for (const s of op.slices) {
110
69
  const leg = (await ctx.runQuery(componentRef(component, "connect/queries/getTransferByStripeId"), { stripeTransferId: s.stripeTransferId }));
111
- slices.push({ ...s, confirmed: leg?.reversedAmount ?? 0 });
70
+ slices.push({
71
+ ...s,
72
+ confirmed: leg?.reversedAmount ?? 0,
73
+ ...(op.commissionExposure
74
+ ? { commissionTracked: leg?.role === "affiliate" }
75
+ : {}),
76
+ });
112
77
  }
113
- const { reversals } = await executeClaimedSlices(stripe, component, ctx, op.operationId, { replay: true, slices });
78
+ const tracked = op.commissionExposure
79
+ ? null
80
+ : await trackedAffiliateTransfers(component, ctx, op.sourceChargeId);
81
+ const usesRecoveryLedger = !!op.commissionExposure || !!tracked?.size;
82
+ const { reversals } = await executeClaimedSlices(stripe, component, ctx, op.operationId, {
83
+ replay: true,
84
+ slices: slices.filter((s) => !s.commissionTracked && !tracked?.has(s.stripeTransferId)),
85
+ });
86
+ if (usesRecoveryLedger)
87
+ await reconcileAffiliateCharge(stripe, component, ctx, op.sourceChargeId);
114
88
  return { mode: "reexecute", reversals };
115
89
  }
90
+ if (op.commissionExposure ||
91
+ (await trackedAffiliateTransfers(component, ctx, op.sourceChargeId)).size)
92
+ throw new Error("Affiliate exposure audit claims cannot be released; use affiliateRecovery.retry or reviewLegacy.");
116
93
  // release: age-gate against the idempotency window, then verify live Stripe.
117
94
  const minAgeMs = opts.minAgeMs ?? REVERSAL_IDEMPOTENCY_WINDOW_MS;
118
95
  const now = opts.now ?? Date.now();
@@ -169,6 +146,8 @@ export async function reverseTransfers(stripe, component, ctx, opts) {
169
146
  throw new Error("reverseTransfers: amount must be a non-negative integer");
170
147
  }
171
148
  await recoverSettlementTransfers(stripe, component, ctx, opts.sourceChargeId);
149
+ if ((await trackedAffiliateTransfers(component, ctx, opts.sourceChargeId)).size)
150
+ throw new Error("Use affiliateRecovery.retry for tracked affiliate commission recovery.");
172
151
  if (opts.operationId) {
173
152
  const claim = (await runMutationOrThrow(ctx, componentRef(component, "connect/mutations/claimReversalSlices"), {
174
153
  operationId: opts.operationId,
@@ -224,9 +203,9 @@ export async function reverseTransfers(stripe, component, ctx, opts) {
224
203
  return { reversals };
225
204
  }
226
205
  /**
227
- * Reverse a split sale's transfers pro-rata to the cumulatively refunded
228
- * amount (BTS-34) — the refund counterpart of the dispute clawback. Every leg
229
- * converges on a cumulative reversal TARGET, `round(leg × amountRefunded /
206
+ * Reverse a split sale's transfers pro-rata to cumulative succeeded refunds.
207
+ * Affiliate legs retain the larger refund/dispute commission exposure. Other
208
+ * legs converge on a cumulative reversal TARGET, `round(leg × amountRefunded /
230
209
  * chargeAmount)`, and only the delta above the ledger's recorded
231
210
  * `reversedAmount` is reversed. Delta-to-target (rather than percent-of-
232
211
  * original like {@link reverseTransfers}) is what makes at-least-once webhook
@@ -250,14 +229,24 @@ export async function reverseTransfersForRefund(stripe, component, ctx, opts) {
250
229
  const claim = (await runMutationOrThrow(ctx, componentRef(component, "connect/mutations/claimReversalSlices"), {
251
230
  operationId: opts.refundId,
252
231
  sourceChargeId: opts.sourceChargeId,
232
+ commissionExposure: {
233
+ kind: "refund",
234
+ refundId: opts.refundId,
235
+ chargeAmount: opts.chargeAmount,
236
+ principal: opts.amountRefunded,
237
+ finalized: true,
238
+ },
253
239
  mode: {
254
240
  kind: "fraction",
255
241
  chargeAmount: opts.chargeAmount,
256
242
  amountRefunded: opts.amountRefunded,
257
243
  },
258
244
  }));
259
- return executeClaimedSlices(stripe, component, ctx, opts.refundId, claim);
245
+ const result = await executeClaimedSlices(stripe, component, ctx, opts.refundId, { ...claim, slices: claim.slices.filter((s) => !s.commissionTracked) });
246
+ await reconcileAffiliateCharge(stripe, component, ctx, opts.sourceChargeId);
247
+ return result;
260
248
  }
249
+ export { reverseTransfersForDispute } from "../affiliateRecovery/disputes.js";
261
250
  /**
262
251
  * Webhook-driven split transfer engine (BTS-22). After a charge succeeds for a
263
252
  * separate-charges sale, fan funds out to each split recipient: compute the
@@ -291,7 +280,13 @@ export async function reinstateTransfers(stripe, component, ctx, opts) {
291
280
  const transfers = ((await ctx.runQuery(componentRef(component, "connect/queries/listTransfersByCharge"), { sourceChargeId: opts.sourceChargeId })) ?? []);
292
281
  const reinstated = [];
293
282
  for (const t of transfers) {
294
- const amount = t.reversedAmount ?? 0;
283
+ if (opts.excludeAffiliates && t.role === "affiliate")
284
+ continue;
285
+ const independentRefund = opts.chargeAmount
286
+ ? Math.round(t.amount *
287
+ Math.min(1, (opts.refundedPrincipal ?? 0) / opts.chargeAmount))
288
+ : 0;
289
+ const amount = Math.max(0, (t.reversedAmount ?? 0) - independentRefund);
295
290
  if (amount <= 0)
296
291
  continue; // nothing was clawed back from this leg
297
292
  // Use the original leg's currency; fall back to the dispute currency for