@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,306 @@
1
+ # Affiliate commission clawbacks
2
+
3
+ Affiliate recovery extends the original Connect transfer ledger. It records
4
+ original commission economics, refund/dispute exposure, provider receipts,
5
+ unrecovered debt, future-commission offsets, and dispute-win restoration.
6
+ Seller processing and dispute-cost recovery remain separate.
7
+
8
+ ## Accounting and overlap
9
+
10
+ Each commission has an `affiliateObligations` row with its original charge,
11
+ available store/payment/invoice references, recipient, currency, and allocated
12
+ commission. Percentage and fixed commissions use the actual original allocation,
13
+ not current payout rules. Each recurring invoice is independent. Refunds do not
14
+ reset one-time subscription commission eligibility.
15
+
16
+ Finalized refund principal is the sum of live Stripe refunds whose status is
17
+ `succeeded`. Pending, failed, canceled, and action-required refunds are excluded;
18
+ `charge.amount_refunded` alone can include pending refunds.
19
+
20
+ Refund and monetary-dispute exposure share an original-principal axis. The
21
+ combined commission target is the larger cumulative successful-refund or active
22
+ monetary-dispute exposure, capped at the original charge, multiplied by the
23
+ original commission and rounded half up using integer arithmetic. This is a
24
+ conservative overlap policy: independently disjoint portions of a charge would
25
+ need additional provider allocation evidence. Warning/inquiry and prevented
26
+ payloads do not create monetary recovery.
27
+
28
+ For example, a 1,001-unit commission on a 10,000-unit charge has a 501-unit
29
+ finalized obligation after a successful 5,000-unit refund. A full-charge dispute
30
+ raises the combined target to 1,001 units, including 500 provisional units. A win
31
+ leaves the independent 501-unit refund deducted. A lost dispute finalizes its
32
+ existing exposure without another debit. Persisted terminal states prevent old
33
+ opening events from reopening a won dispute.
34
+
35
+ Net recovery is confirmed reversals plus applied future-commission offsets minus
36
+ confirmed restorations. Outstanding debt is the positive difference between the
37
+ current target and net recovery. Restoration owed is the excess actually
38
+ recovered over the current target. Unrecovered dispute debt disappears on a win;
39
+ only actual reversals or offsets can become restoration owed.
40
+
41
+ ## Provider operations and insufficient balance
42
+
43
+ `affiliateRecoveryOperations` stores immutable amounts and operation identities
44
+ before money moves. Outcomes distinguish `pending`, `unknown`,
45
+ `insufficient_balance`, `unsupported`, `failed`, `succeeded`, and `canceled`.
46
+ An unknown provider outcome retains its reservation and blocks another collection
47
+ or future commission release until receipt reconciliation finishes.
48
+
49
+ The client verifies the actual V2 Connect recipient's active
50
+ `configuration.recipient.capabilities.stripe_balance.stripe_transfers` capability
51
+ and the exact original transfer's destination, charge, currency and amount.
52
+ Reversals use that original transfer. Requests carry `bsRecoveryOperation`
53
+ metadata and a stable operation-specific idempotency key. Replay searches exact
54
+ provider receipts before issuing another request, including beyond the provider's
55
+ idempotency cache window. An unrelated aggregate reversal is not a receipt for
56
+ this operation. Confirmation records the receipt and accounting changes atomically.
57
+
58
+ A confirmed insufficient-balance response leaves durable debt instead of failing
59
+ indefinitely through webhook retries. Before a subsequent settlement creates an
60
+ affiliate transfer, the component atomically reserves the earning and applies
61
+ same-affiliate, same-currency debt offsets. Concurrent settlements cannot spend
62
+ one debt twice, and replay uses the original withheld/release amounts. A fully
63
+ withheld commission gets an earning record without a fabricated Stripe transfer.
64
+ Refunding that later commission creates its own obligation for the original full
65
+ commission, including units previously applied to older debt.
66
+
67
+ A later recovery attempt sizes itself from the remaining debt and reversible
68
+ provider funds. It cannot collect amounts already offset. Restorations use
69
+ platform-funded transfers, exact receipts and independent operation identities.
70
+ Funding, country/currency or capability failures remain visible and retryable;
71
+ failed restoration is not shown as paid.
72
+
73
+ Transfer reversal does not recall a completed bank payout. Available balance and
74
+ negative-balance behavior remain account/provider-specific. Global Payouts is
75
+ unsupported by this Connect recovery path and is never routed through a Connect
76
+ API by assumption. No card or bank debit is introduced.
77
+
78
+ ## Trusted server APIs
79
+
80
+ The host must authenticate callers and derive affiliate accounts server-side.
81
+ Operator retry, legacy review and maintenance endpoints must not be exposed as
82
+ unrestricted browser mutations.
83
+
84
+ ```ts
85
+ const snapshot = await stripe.affiliateRecovery.snapshot(ctx, {
86
+ affiliateAccountId: authorizedAffiliateAccountId,
87
+ currency: "usd",
88
+ paginationOpts: { numItems: 20, cursor: null },
89
+ });
90
+ const attempts = await stripe.affiliateRecovery.history(ctx, {
91
+ obligationId: authorizedObligationId,
92
+ paginationOpts: { numItems: 20, cursor: null },
93
+ });
94
+ // Authenticated operator only; reconciles receipts before attempting recovery.
95
+ await stripe.affiliateRecovery.retry(ctx, {
96
+ obligationId: authorizedObligationId,
97
+ });
98
+ ```
99
+
100
+ Snapshot responses contain an exact per-account/currency `balance` and a
101
+ paginated `obligations` result (`page`, `continueCursor`, `isDone`). The balance
102
+ contains original commission, cumulative reversed, offset and restored amounts,
103
+ outstanding debt, reserved recovery/restoration, restoration owed, withheld
104
+ future earnings and net payable. Net payable means platform-held commission
105
+ reserved for release; it is not the connected account's bank balance. Read
106
+ provider balances and bank payouts separately with `getPayoutSnapshot`.
107
+
108
+ Rows retain original references, exposure snapshots, original/released commission,
109
+ confirmed recovery/offset/restoration, debt, latest state/error, and reconciliation
110
+ flags. A fully withheld row can omit `stripeTransferId`. History includes operation
111
+ amounts, outcomes and confirmed receipt IDs. Paginate history; do not sum a preview
112
+ page for account totals.
113
+
114
+ `createPayout` uses an atomic release gate for accounts with affiliate recovery
115
+ balances. Supply a stable `idempotencyKey` and an optional host-authorized
116
+ `minimumAmount` in that currency (default one minor unit). Debt, uncertain money
117
+ movement and concurrent payout reservations block release. The configured minimum
118
+ is application policy, not a discovered Stripe regional floor; provider floors
119
+ and balance requirements are still enforced by Stripe. A payout receipt marks
120
+ submission, not arrival in a bank. Combined seller/affiliate releases through
121
+ `stripe.payoutPolicy.release` share this recovery reservation. Debt and unresolved
122
+ recovery block both reservation and the final provider attempt. An uncertain payout
123
+ retains the lock until a verified outcome or rejection; an unattempted claim can
124
+ be canceled. Direct payouts recheck recovery after receipt lookup and before
125
+ calling Stripe. Once a direct operation is 23 hours old, it requires receipt
126
+ reconciliation and cannot create another payout with an expired idempotency key.
127
+ Maintenance can confirm an existing payout receipt despite newly recorded debt;
128
+ confirmation does not erase that debt. Locks are scoped to the recipient and currency. Stripe-managed automatic bank payouts cannot
129
+ be intercepted by this gate; future commissions are offset before their Connect
130
+ transfers leave the platform.
131
+
132
+ ## Migration and operator reconciliation
133
+
134
+ Deploy the additive schema and matching component code together. Regenerate the
135
+ component and example bindings against the target deployment.
136
+
137
+ Call `components.betterStripe.settlement.mutations.migrateAffiliateObligations`
138
+ from an authenticated operator wrapper with:
139
+
140
+ ```ts
141
+ { paginationOpts: { numItems: 100, cursor: null } }
142
+ ```
143
+
144
+ Pass each returned `continueCursor` until `isDone`. Replay is safe. `migrated` and
145
+ `skipped` describe that page, including already-existing obligations; they are not
146
+ cumulative counters. The backfill uses immutable settlement allocations and
147
+ initializes account totals. Legacy legs without allocations are skipped for
148
+ manual source review rather than assigned invented original economics.
149
+
150
+ Existing reversals/reservations without attributable provenance set
151
+ `needsReconciliation=true`. They retain their confirmed balance, but automatic
152
+ collection/restoration is paused for review. An operator can select exact
153
+ commission-reversal and prior reinstatement receipts:
154
+
155
+ ```ts
156
+ await stripe.affiliateRecovery.reviewLegacy(ctx, {
157
+ obligationId: authorizedObligationId,
158
+ reversalIds: ["trr_original_commission_reversal"],
159
+ restorationTransferIds: [], // Include any prior dispute-win reinstatements.
160
+ note: "Reviewed original allocation and provider receipt history.",
161
+ });
162
+ ```
163
+
164
+ This verifies the original transfer, each selected receipt, live successful
165
+ refunds and the monetary dispute, then commits the reviewed attribution and note.
166
+ Choose commission principal receipts, not unrelated adjustments. More than one
167
+ monetary dispute on a legacy source requires manual allocation. Inspect the new
168
+ snapshot before retrying recovery. The older generic reversal-claim reclaimer
169
+ delegates tracked affiliate operations to this ledger; its release mode cannot
170
+ delete an affiliate exposure audit record.
171
+
172
+ ## Maintained reconciliation and bounds
173
+
174
+ Run both `reconcilePending` and `reconcilePayouts` for `pending` and `unknown`
175
+ states from a host cron. Pass `paginationOpts` and schedule the returned
176
+ `continueCursor` until `isDone`. The example's internal jobs run every five
177
+ minutes and process one row per invocation. Insufficient/unsupported recovery
178
+ remains collectible through future offsets; an operator can retry it after
179
+ account capability or funding changes.
180
+
181
+ Charge transfer/obligation reads and provider refund/receipt histories have
182
+ explicit bounds of 1,000 rows; exceeding a bound stops instead of applying partial
183
+ financial state. Offset transactions accept at most 1,000 open same-currency debt
184
+ rows. Snapshot, audit and migration queries are paginated with bounded pages.
185
+ Legacy review accepts at most 100 selected receipts and requires an operator note.
186
+
187
+ Subscribe to `refund.created`, `refund.updated`, `refund.failed`, and existing
188
+ `charge.dispute.created`, `.funds_withdrawn`, `.closed`, `.funds_reinstated` events.
189
+ Retain component financial records while events, provider operations or payouts
190
+ can still be retried.
191
+
192
+ ## Reusable React views and example
193
+
194
+ `AffiliateRecovery` from `@fantastic.dev/better-stripe/react` accepts `snapshot`,
195
+ `currency`, optional locale/source-link/reconcile callbacks and a render function.
196
+ Its unstyled default view and headless view expose the same metrics and
197
+ package-formatted adjustment rows. `AffiliateRecoveryHistory` displays outcomes
198
+ and receipts. Use them alongside earnings, referred sales and payouts; seller
199
+ cost recovery remains a separate view.
200
+
201
+ The example uses the existing demo persona picker. Recovery reads derive the
202
+ account from the selected affiliate's server-stored user record, and reject
203
+ requests for another affiliate's account or obligation. Admin personas can
204
+ inspect other affiliates and retry recovery only with a Stripe test-mode key.
205
+ These checks bind resources to a claimed demo persona. They do not authenticate
206
+ the caller or prove production ownership. Production hosts must authenticate
207
+ callers and derive their account and operator permissions server-side.
208
+
209
+ Visit `/demo/affiliate-recovery` for ten **simulated** scenarios covering orders,
210
+ recurring invoices, partial refunds, open/lost/won disputes, overlap, insufficient
211
+ balance after external payout, future offsets and unknown provider outcomes.
212
+ `affiliateRecoveryScenarios()` is exported from the testing package. These are
213
+ presentation fixtures, not fabricated sandbox or bank-payout receipts.
214
+
215
+ ## Stripe sandbox scenario driver
216
+
217
+ With the example deployed, its webhook endpoint registered, a test-mode key and
218
+ active distinct store/affiliate Connect recipients, run the internal fixture
219
+ from `example/`:
220
+
221
+ ```sh
222
+ pnpm exec convex run affiliateRecoverySandbox:seed '{"runKey":"recovery-partial-1","storeAccountId":"acct_store","affiliateAccountId":"acct_affiliate","scenario":"refund_partial"}'
223
+ ```
224
+
225
+ The driver creates a real test payment, settles the original allocation, creates
226
+ the selected refund and returns actual provider IDs/balances. A stable `runKey`
227
+ prevents duplicate payment/refund creation. `refund_full` covers a full refund;
228
+ `future_offset` creates the next commission against existing debt. For a recurring
229
+ invoice, supply its existing `paymentIntentId`, `invoiceId` and `subscriptionId`
230
+ from the subscription/test-clock fixtures so the driver verifies those links.
231
+
232
+ `dispute` uses Stripe's dispute-producing test payment method. The provider can
233
+ mark its charge disputed before the fixture settles. In that case the driver
234
+ returns `not_payable` and creates no affiliate transfer, so this is not evidence
235
+ of post-transfer clawback, dispute loss, or restoration. Use a provider-supported
236
+ post-settlement dispute workflow for those checks. Do not manufacture terminal
237
+ webhooks as proof that provider funds were restored.
238
+
239
+ `paid_out` uses Stripe's `pm_card_bypassPending` test method and first returns
240
+ `operator_step_required`. Run internal `affiliateRecoverySandbox:externalPayout`
241
+ with the same `runKey`, `affiliateAccountId` and actual affiliate
242
+ `stripeTransferId`. It verifies fixture provenance, checks actual available
243
+ balance and creates an external test payout for that transfer's amount. Replays
244
+ read the existing payout. Wait for actual `paid` status, then rerun `seed` with
245
+ its `completedPayoutId`. The driver verifies paid status, currency, amount and
246
+ creation order before requesting the refund. Unsupported payout/account controls
247
+ must be reported as blocked. Recovery may still succeed using other account
248
+ funds; a paid payout does not itself prove insufficient-balance debt.
249
+
250
+ If prior sandbox refunds/disputes depleted platform funding, internal
251
+ `affiliateRecoverySandbox:fundPlatform` creates a bounded test payment using
252
+ `runKey` and `amount` of at most 100,000 USD minor units. It returns the actual
253
+ payment and before/after available balances. Balance updates can be asynchronous.
254
+ Retain the funding receipt and do not label it commission recovery.
255
+
256
+ For isolated recurring sources, run internal
257
+ `affiliateRecoveryBillingSandbox:prepare` with a stable `runKey` and fixed
258
+ `frozenTime` Unix timestamp. Retain those exact arguments on replay. It creates
259
+ an isolated test-clock customer and monthly subscription and returns the actual
260
+ paid `invoiceId`, `paymentIntentId`, `subscriptionId`, `clockId` and `periodEnd`.
261
+ Pass the invoice/payment/subscription references to `seed` with a distinct run
262
+ key per invoice. `affiliateRecoveryBillingSandbox:advance` accepts that fixture's
263
+ `runKey`, `clockId` and a new `frozenTime`; after the clock finishes advancing,
264
+ rerun `prepare` to read the next paid invoice. Existing persona subscriptions
265
+ are not changed by these helpers.
266
+
267
+ The raw-payment fixture uses trusted internal settlement and does not establish
268
+ seller checkout ownership. For the seller refund UI, create a purchase through
269
+ the storefront so its server-selected merchant routing is present. Keep the
270
+ ownership guard intact. The example's fixed-rate settings use major currency
271
+ units, so `$10.01` is entered as `10.01`; component commission amounts and the
272
+ raw driver's 1,001-unit allocation use minor units.
273
+
274
+ The driver rejects live/missing Stripe keys. It makes real sandbox transactions
275
+ and does not delete their receipts. Record its JSON output and demo-persona
276
+ snapshots as release evidence; an API response alone does not establish a bank
277
+ payout recall.
278
+
279
+ ## Verification evidence
280
+
281
+ Automated integration tests execute the real component and client with an
282
+ idempotent provider fixture and exact-money assertions. They cover concurrent
283
+ offsets, fully withheld invoice refunds, timeout-after-success replay,
284
+ refund/dispute ordering, partial disputes, lost/won events, receipt matching,
285
+ payout reservations, migration and ownership enforcement. React tests verify
286
+ native/headless figures and unconfirmed restoration states.
287
+
288
+ [Verification report](evidence/affiliate-recovery-verification.md),
289
+ [UI recording](evidence/affiliate-recovery.webm) and
290
+ [screenshot](evidence/affiliate-recovery.png) show simulated fixtures and both
291
+ presentations. Reproduce with the frontend running, from `example/`:
292
+
293
+ ```sh
294
+ node scripts/record-affiliate-recovery.mjs
295
+ ```
296
+
297
+ Use `PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH` for a system Chromium installation.
298
+ The recording requires a Playwright-compatible FFmpeg executable.
299
+
300
+ For account preview prerequisites, see [Accounts v2 setup](accounts-v2-preview.md).
301
+
302
+ Deployment-backed generation and sandbox verification status are recorded in
303
+ the verification report. The simulated artifacts do not establish account-specific
304
+ negative-balance behavior or successful external-payout recall. Before release,
305
+ verify actual supported Connect accounts, currencies, insufficient-balance and
306
+ restoration behavior in a configured sandbox, and retain the provider receipts.
@@ -174,6 +174,54 @@ Host apps should translate known codes into safe recovery instructions and a
174
174
  settings link. Do not log or blindly render raw provider messages. Authorize
175
175
  reads using the recipient's shared connected account.
176
176
 
177
+ ## Prepared Checkout requests
178
+
179
+ Use `betterStripe.checkoutRequests.prepare(ctx, options)` when a host purchase
180
+ intent must bind the exact provider request before creation or a plan change's
181
+ cancellation. Preparation performs only reads. It never provisions an account,
182
+ creates a Checkout Session or cancels a subscription. If a buyer needs a V2
183
+ customer account, register the host intent first, provision through the existing
184
+ package account operation with a stable account identity, then prepare using the
185
+ verified account reference.
186
+
187
+ Preparation returns a serializable versioned snapshot containing the final
188
+ `request`, component correlation `row`, captured rendering `options`, descriptor
189
+ and generated routing metadata. Persist the entire snapshot in the host's owned
190
+ intent before any subsequent provider write. The snapshot includes account or
191
+ customer email, server metadata, quantity, trial behavior, nested overrides and
192
+ resolved fees. Its contents may contain private data; do not return the snapshot
193
+ to a browser or log it.
194
+
195
+ Call `betterStripe.checkoutRequests.execute(ctx, { prepared, idempotencyKey })`
196
+ with that persisted snapshot and a stable intent-derived key. Execution validates
197
+ its correlation and deterministic rendering against the captured context, then
198
+ sends the stored request unchanged. It does not resolve current fee or descriptor
199
+ defaults. Necessary platform-price checks may still read the provider. If a key
200
+ was explicitly included during preparation, execution must use the same key.
201
+ Retries reuse the exact request and preserve the existing Checkout response shape
202
+ and component upsert. Missing or conflicting keys and inconsistent snapshots
203
+ fail before creation.
204
+
205
+ The host must authorize the buyer and catalog, bind the complete snapshot and key
206
+ immutably, validate fresh session eligibility and own recovery. Consistency
207
+ validation is not a signature or a replacement for host authorization. Never
208
+ accept a browser-supplied snapshot. An unknown provider outcome remains unknown;
209
+ use authoritative provider reads and saved references rather than blindly
210
+ recreating after an idempotency retention window. This API does not record paid
211
+ facts, award attribution, grant access or cancel a current plan automatically.
212
+
213
+ For a plan change, authorize and register the intent, prepare and bind a request
214
+ with no new trial, then perform any authorized cancellation before executing the
215
+ persisted request. Preserve cancellation and creation recovery separately. A
216
+ failed or lost response does not establish successful cancellation or payment.
217
+
218
+ The original `createCheckoutSession` uses the same maintained renderer and
219
+ submission path and retains its existing behavior. The prepared contract adds
220
+ strict correlation checks for the buyer, account and price and preserves
221
+ server-owned metadata and package-generated routing markers. Application React
222
+ callbacks remain authenticated host adapters. The package's unstyled React
223
+ checkout workflow and Vite example can use these callbacks with application styles.
224
+
177
225
  ## Publication and consumer acceptance
178
226
 
179
227
  A source merge does not activate an API in a published package. DOJO-908,
@@ -76,6 +76,23 @@ The Vite example exposes a [fee-first allocation preview](http://localhost:5173/
76
76
  from Admin → Testing Utilities. Its illustrative inputs use the public helper
77
77
  and the package React `SplitBreakdown`; they do not alter store settings.
78
78
 
79
+ ## Affiliate commission recovery
80
+
81
+ Refund and monetary-dispute recovery uses each original affiliate transfer's
82
+ allocated commission, including fixed amounts, rather than current payout rules.
83
+ Successful refunds accumulate independently for each original invoice payment;
84
+ refunds do not reset one-time subscription eligibility. Refund and dispute
85
+ exposure share the same original-principal axis, capped at the original commission.
86
+ New affiliate reversal operations retain exact provider receipt references and
87
+ separate reserved funds from confirmed recovery.
88
+
89
+ The recovery ledger reserves same-currency debt offsets before future affiliate
90
+ transfers leave the platform, including fully withheld commissions with no Stripe
91
+ transfer. Won disputes restore actual reversals/offsets while retaining independent
92
+ refunds. Unknown outcomes retain reservations until exact receipt reconciliation. Before migrating or
93
+ using these records, read the [clawback API, migration and reconciliation guide](affiliate-clawbacks.md).
94
+ Seller cost recovery remains separate from affiliate commission principal.
95
+
79
96
  ## Subscription commission terms
80
97
 
81
98
  ```ts
@@ -516,4 +533,131 @@ shorten the pending operation's deadline. `migration_required.adoptionReason`
516
533
  explains unknown history or an expired holding period. This flow does not enable
517
534
  Dashboard accounts with withdrawal bypasses, Global Payouts, unsupported source
518
535
  rails, unknown numeric provider floors or accounts beyond the current atomic
519
- snapshot bounds. It installs no host cron or UI.
536
+ snapshot bounds. Activation itself does not install a host cron or UI.
537
+
538
+ ## Automatic recipient worker
539
+
540
+ `stripe.payoutPolicy.worker` runs authorized custom policies from a host cron.
541
+ It invokes the maintained release and reconciliation APIs, including their live
542
+ schedule, source-maturity, history, fee and balance checks. A worker lease never
543
+ replaces the financial payout claim.
544
+
545
+ ```ts
546
+ const result = await stripe.payoutPolicy.worker.run(ctx, {
547
+ accountId,
548
+ ownerKey,
549
+ currency,
550
+ // Resolve all off-provider debts and reserves for this owner/currency first.
551
+ // Do not count Stripe receipt debits twice.
552
+ independentLiabilities,
553
+ cadenceMs: 300_000,
554
+ });
555
+ const job = await stripe.payoutPolicy.worker.get(ctx, {
556
+ accountId,
557
+ ownerKey,
558
+ currency,
559
+ });
560
+ // job.nextAttemptAt is the next application attempt, not a bank arrival date.
561
+ ```
562
+
563
+ The default retry cadence is five minutes; hosts can configure one minute to
564
+ one day. Concurrent callers share a ten-minute lease. A crashed worker resumes
565
+ the same operation ID. Unknown provider outcomes retain their attempted claim
566
+ and reconcile on later runs, including after a recipient opts out. They never
567
+ trigger a blind payout recreation. Expired worker leases permit observation
568
+ retries; they do not release monetary reservations. A generation check prevents
569
+ an older worker from replacing a newer worker's result. Completion replays keep
570
+ the original next attempt time.
571
+
572
+ Affiliate clawback debt, pending recoveries/restorations and competing affiliate
573
+ payout reservations hold fresh worker attempts with `affiliate_recovery_pending`.
574
+ The recipient claim boundary checks the same recovery lock again atomically
575
+ before reservation and immediately before the provider attempt. Existing unknown
576
+ attempts continue to reconcile even when new recovery debt arrives. Do not add
577
+ the same affiliate debt to `independentLiabilities` again; that option is for
578
+ separate host liabilities.
579
+
580
+ The host must page all four queues, using bounded pages and scheduling each
581
+ recipient/currency independently:
582
+
583
+ - `worker.policies(ctx, paginationOpts)` discovers ready custom policies.
584
+ - `worker.recovering(ctx, paginationOpts)` discovers retained operations,
585
+ including recipients who switched back to Stripe-managed payouts.
586
+ - `worker.changing(ctx, paginationOpts)` discovers pending schedule operations
587
+ to retry through `payoutPolicy.apply`.
588
+ - `payoutPolicy.due(ctx, paginationOpts)` discovers expired holding deadlines
589
+ to restore through `payoutPolicy.expire`.
590
+
591
+ Authorize the host's owner/account mapping before each action. Read outstanding
592
+ liabilities again before every attempt. In the example, uncollected seller cost
593
+ reservations remain withheld even while attached to an unpaid invoice. Confirmed
594
+ collections are already reflected in the store's transferred amount. Additional
595
+ host liability scopes must be included when adopting this worker in another app.
596
+
597
+ The example's `convex/crons.ts` installs a five-minute dispatcher. Its internal
598
+ actions in `convex/payoutWorkers.ts` page these queues and use the package APIs;
599
+ they do not call the Stripe SDK directly. Stripe-managed recipients continue to
600
+ use Stripe's automatic schedule. Custom activation still requires explicit
601
+ consent and verified exclusive payout control. The worker preserves the current
602
+ release/adoption history limits and reports held results when those limits are
603
+ exceeded. It does not yet consume the resumable local manifest described below.
604
+
605
+ These are server worker APIs, not manual withdrawal actions for a customer UI.
606
+ `worker.get` exposes the latest reason, attempt time and next application attempt
607
+ for an authorized host to display. Bank availability, pending funds and bank
608
+ arrival dates come from the recipient payout snapshot API.
609
+
610
+ ## Resumable local collections
611
+
612
+ An authorized host worker can collect the local recipient ledger in bounded
613
+ steps, retaining its cursor and step number across restarts:
614
+
615
+ ```ts
616
+ let state = await stripe.payoutPolicy.collectSnapshot(ctx, {
617
+ accountId,
618
+ ownerKey,
619
+ operationKey: collectionKey,
620
+ expectedRevision: policy?.revision ?? -1,
621
+ });
622
+ state = await stripe.payoutPolicy.collectSnapshot(ctx, {
623
+ accountId,
624
+ ownerKey,
625
+ operationKey: collectionKey,
626
+ expectedRevision: policy?.revision ?? -1,
627
+ expectedStep: state.step,
628
+ batchSize: 25,
629
+ });
630
+ ```
631
+
632
+ Repeat bounded calls until `phase` reaches `local_ready` or `invalidated`.
633
+ Duplicate step submissions preserve cursor progress. Sources, source allocations,
634
+ payout fees and payout claims are copied across pages, with no 100-row limit on the local
635
+ collection. New positive funding can be deferred to a later collection; refunds,
636
+ reservations, payouts and fees enter an ordered account risk journal. The worker
637
+ repairs changed entries and checks claim/source allocation rollups before local
638
+ completion. Missing journal events, orphaned sources and changed policy identity
639
+ stop collection with an explicit reason.
640
+
641
+ `local_ready` describes a read-only local manifest. Complete provider receipts,
642
+ provider history and monetary claim binding are still required before a payout.
643
+ These local APIs do not remove the current bounded release/adoption limits by
644
+ themselves. Provider-history continuation and scalable claim execution remain
645
+ under implementation.
646
+
647
+ After a read-only collection is no longer needed, repeatedly call
648
+ `discardSnapshot(ctx, { accountId, ownerKey, operationKey: collectionKey })` until
649
+ it returns `null`. Cleanup removes only collection caches. Read-only collection
650
+ leases last 24 hours. Financially bound collections reject read-only cleanup and
651
+ expiry; payout claims and their source reservations keep their own lifecycle.
652
+
653
+ ### Development reset safeguards
654
+
655
+ `clearAllTables` is a development/test utility. It rejects active or changing
656
+ payout schedules, unresolved reserved/submitted claims, financially bound
657
+ collections and known pending/in-transit provider payouts. The host must quiesce
658
+ provider writers and verify live provider state before invoking reset. Restore
659
+ schedules through the policy APIs and reconcile unresolved operations first.
660
+ Pending or unknown direct affiliate payouts and recovery operations also block
661
+ reset, preserving the receipts and obligations needed for reconciliation.
662
+ The guard preserves the restoration and payout records until that work is done.
663
+ Read-only cache collections can be cleared with the other development data.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fantastic.dev/better-stripe",
3
- "version": "0.23.2",
3
+ "version": "0.25.0",
4
4
  "description": "A Convex component for Stripe V2 Accounts API integration.",
5
5
  "keywords": [
6
6
  "stripe",
@@ -59,6 +59,7 @@
59
59
  "src",
60
60
  "docs/react-workflows.md",
61
61
  "docs/settlement.md",
62
+ "docs/affiliate-clawbacks.md",
62
63
  "docs/accounts-v2-preview.md",
63
64
  "docs/react-workflows-audit.md",
64
65
  "CHANGELOG.md",
@@ -0,0 +1,62 @@
1
+ import type Stripe from "stripe";
2
+ import type { Component, RunCtx } from "../helpers.js";
3
+ import { runMutationOrThrow } from "../helpers.js";
4
+ import { componentRef } from "../webhooks/helpers.js";
5
+ import { recoverSettlementTransfers } from "../settlement/reconciliation.js";
6
+ import {
7
+ executeClaimedSlices,
8
+ type ReversalClaim,
9
+ } from "../connect/reversalExecution.js";
10
+ import { reconcileAffiliateCharge } from "./engine.js";
11
+
12
+ /** Record proportional original commission exposure for a monetary dispute. */
13
+ export async function reverseTransfersForDispute(
14
+ stripe: Stripe,
15
+ component: Component,
16
+ ctx: RunCtx,
17
+ opts: {
18
+ sourceChargeId: string;
19
+ operationId: string;
20
+ chargeAmount: number;
21
+ amount: number;
22
+ finalized: boolean;
23
+ disputeState?: "open" | "lost" | "won";
24
+ refundedPrincipal?: number;
25
+ },
26
+ ) {
27
+ await recoverSettlementTransfers(stripe, component, ctx, opts.sourceChargeId);
28
+ const claim = (await runMutationOrThrow(
29
+ ctx,
30
+ componentRef(component, "connect/mutations/claimReversalSlices"),
31
+ {
32
+ sourceChargeId: opts.sourceChargeId,
33
+ operationId: opts.operationId,
34
+ mode:
35
+ opts.disputeState === "won"
36
+ ? {
37
+ kind: "fraction",
38
+ chargeAmount: opts.chargeAmount,
39
+ amountRefunded: 0,
40
+ }
41
+ : { kind: "amount", amount: opts.amount },
42
+ commissionExposure: {
43
+ kind: "dispute",
44
+ chargeAmount: opts.chargeAmount,
45
+ principal: opts.amount,
46
+ finalized: opts.finalized,
47
+ disputeState: opts.disputeState,
48
+ refundedPrincipal: opts.refundedPrincipal,
49
+ disputeId: opts.operationId,
50
+ },
51
+ },
52
+ )) as ReversalClaim;
53
+ const result = await executeClaimedSlices(
54
+ stripe,
55
+ component,
56
+ ctx,
57
+ opts.operationId,
58
+ { ...claim, slices: claim.slices.filter((s) => !s.commissionTracked) },
59
+ );
60
+ await reconcileAffiliateCharge(stripe, component, ctx, opts.sourceChargeId);
61
+ return result;
62
+ }