@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,130 @@
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 { findCommissionReversal } from "./commissionReceipts.js";
6
+
7
+ export type ClaimedSlice = {
8
+ stripeTransferId: string;
9
+ /** Cumulative reversed amount this slice starts from. */
10
+ from: number;
11
+ /** Cumulative reversed amount this slice raises the leg to. */
12
+ to: number;
13
+ /** The leg's confirmed `reversedAmount` at claim time. */
14
+ confirmed: number;
15
+ commissionTracked?: boolean;
16
+ };
17
+
18
+ export type ReversalClaim = { replay: boolean; slices: ClaimedSlice[] };
19
+
20
+ /**
21
+ * Execute the slices an operation claimed via `claimReversalSlices` (BTS-63).
22
+ * The claim already reserved this money atomically, so all that's left is
23
+ * moving it: one `bs_rev_<operationId>_<transferId>` reversal per slice, then
24
+ * confirming the new cumulative total in the ledger. A replayed claim always
25
+ * re-sends byte-identical params under the same key, which Stripe answers
26
+ * from its idempotency cache without moving money twice.
27
+ *
28
+ * Because Stripe prunes idempotency keys after ~24h (and a crash can land
29
+ * between the Stripe call and the ledger confirm), a replay first checks the
30
+ * transfer's live `amount_reversed`: if the slice's money already moved, it
31
+ * just confirms the ledger instead of re-sending the reversal.
32
+ *
33
+ * A slice only executes once every predecessor slice on its leg is confirmed
34
+ * (`confirmed ≥ from`). Without that gate, a sibling operation landing behind
35
+ * a transiently-failed claim would execute and confirm PAST the hole; the
36
+ * failed operation's retry would then see `confirmed ≥ to` and silently skip
37
+ * — its money would never move while the ledger says it did. Throwing instead
38
+ * fails this operation's webhook event, and at-least-once delivery retries
39
+ * both operations until the predecessor fills its hole and each claimed slice
40
+ * has actually moved. The ledger's `reversedAmount` therefore always covers a
41
+ * solid, hole-free prefix of the reversed axis — which is exactly what makes
42
+ * the `confirmed`/`amount_reversed` checks above sound.
43
+ */
44
+ export async function executeClaimedSlices(
45
+ stripe: Stripe,
46
+ component: Component,
47
+ ctx: RunCtx,
48
+ operationId: string,
49
+ claim: ReversalClaim,
50
+ ): Promise<{ reversals: { stripeTransferId: string; amount: number }[] }> {
51
+ const reversals: { stripeTransferId: string; amount: number }[] = [];
52
+ for (const slice of claim.slices) {
53
+ const receiptAmount = slice.to - slice.from;
54
+ if (slice.commissionTracked && claim.replay) {
55
+ const receipt = await findCommissionReversal(
56
+ stripe,
57
+ slice.stripeTransferId,
58
+ operationId,
59
+ receiptAmount,
60
+ );
61
+ if (receipt) {
62
+ await runMutationOrThrow(
63
+ ctx,
64
+ componentRef(component, "connect/mutations/recordTransferReversal"),
65
+ {
66
+ stripeTransferId: slice.stripeTransferId,
67
+ reversedAmount: slice.to,
68
+ receipt: {
69
+ stripeReversalId: receipt.id,
70
+ operationId,
71
+ amount: receiptAmount,
72
+ },
73
+ },
74
+ );
75
+ continue;
76
+ }
77
+ if (slice.confirmed >= slice.to)
78
+ throw new Error("Commission reversal requires receipt reconciliation.");
79
+ }
80
+ if (slice.confirmed >= slice.to) continue; // executed and recorded already
81
+
82
+ if (slice.confirmed < slice.from) {
83
+ throw new Error(
84
+ `reversal slice [${slice.from},${slice.to}) on ${slice.stripeTransferId} ` +
85
+ `blocked: predecessor claim unexecuted (confirmed=${slice.confirmed})`,
86
+ );
87
+ }
88
+
89
+ if (claim.replay && !slice.commissionTracked) {
90
+ const transfer = await stripe.transfers.retrieve(slice.stripeTransferId);
91
+ if ((transfer.amount_reversed ?? 0) >= slice.to) {
92
+ // The money moved on a previous attempt that died before confirming.
93
+ await runMutationOrThrow(
94
+ ctx,
95
+ componentRef(component, "connect/mutations/recordTransferReversal"),
96
+ {
97
+ stripeTransferId: slice.stripeTransferId,
98
+ reversedAmount: slice.to,
99
+ },
100
+ );
101
+ continue;
102
+ }
103
+ }
104
+
105
+ const amount = slice.to - slice.from;
106
+ const receipt = await stripe.transfers.createReversal(
107
+ slice.stripeTransferId,
108
+ {
109
+ amount,
110
+ ...(slice.commissionTracked
111
+ ? { metadata: { bsReversalOperation: operationId } }
112
+ : {}),
113
+ },
114
+ { idempotencyKey: `bs_rev_${operationId}_${slice.stripeTransferId}` },
115
+ );
116
+ await runMutationOrThrow(
117
+ ctx,
118
+ componentRef(component, "connect/mutations/recordTransferReversal"),
119
+ {
120
+ stripeTransferId: slice.stripeTransferId,
121
+ reversedAmount: slice.to,
122
+ ...(slice.commissionTracked
123
+ ? { receipt: { stripeReversalId: receipt.id, operationId, amount } }
124
+ : {}),
125
+ },
126
+ );
127
+ reversals.push({ stripeTransferId: slice.stripeTransferId, amount });
128
+ }
129
+ return { reversals };
130
+ }
@@ -350,8 +350,8 @@ describe("createSplitTransfers engine (BTS-22)", () => {
350
350
  destination: "acct_aff",
351
351
  });
352
352
  // ledger rows
353
- expect(ctx.runMutation).toHaveBeenCalledTimes(3);
354
- expect(ctx.runMutation.mock.calls[1][1]).toMatchObject({
353
+ expect(ctx.runMutation).toHaveBeenCalledTimes(4);
354
+ expect(ctx.runMutation.mock.calls[2][1]).toMatchObject({
355
355
  sourceChargeId: "ch_1",
356
356
  destinationAccountId: "acct_store",
357
357
  amount: 8000,
@@ -380,7 +380,7 @@ describe("createSplitTransfers engine (BTS-22)", () => {
380
380
  });
381
381
 
382
382
  expect(stripe.transfers.create).toHaveBeenCalledTimes(3);
383
- expect(ctx.runMutation).toHaveBeenCalledTimes(4);
383
+ expect(ctx.runMutation).toHaveBeenCalledTimes(5);
384
384
  });
385
385
 
386
386
  it("skips zero-amount transfers", async () => {
@@ -1,3 +1,9 @@
1
+ import { reconcileAffiliateCharge } from "../affiliateRecovery/engine.js";
2
+ import {
3
+ executeClaimedSlices,
4
+ type ClaimedSlice,
5
+ type ReversalClaim,
6
+ } from "./reversalExecution.js";
1
7
  import { recoverSettlementTransfers } from "../settlement/reconciliation.js";
2
8
  import { executeResolvedTransfers } from "../settlement/execution.js";
3
9
  import type Stripe from "stripe";
@@ -19,90 +25,22 @@ type LedgerTransfer = {
19
25
  currency?: string;
20
26
  };
21
27
 
22
- type ClaimedSlice = {
23
- stripeTransferId: string;
24
- /** Cumulative reversed amount this slice starts from. */
25
- from: number;
26
- /** Cumulative reversed amount this slice raises the leg to. */
27
- to: number;
28
- /** The leg's confirmed `reversedAmount` at claim time. */
29
- confirmed: number;
30
- };
31
-
32
- type ReversalClaim = { replay: boolean; slices: ClaimedSlice[] };
33
-
34
- /**
35
- * Execute the slices an operation claimed via `claimReversalSlices` (BTS-63).
36
- * The claim already reserved this money atomically, so all that's left is
37
- * moving it: one `bs_rev_<operationId>_<transferId>` reversal per slice, then
38
- * confirming the new cumulative total in the ledger. A replayed claim always
39
- * re-sends byte-identical params under the same key, which Stripe answers
40
- * from its idempotency cache without moving money twice.
41
- *
42
- * Because Stripe prunes idempotency keys after ~24h (and a crash can land
43
- * between the Stripe call and the ledger confirm), a replay first checks the
44
- * transfer's live `amount_reversed`: if the slice's money already moved, it
45
- * just confirms the ledger instead of re-sending the reversal.
46
- *
47
- * A slice only executes once every predecessor slice on its leg is confirmed
48
- * (`confirmed ≥ from`). Without that gate, a sibling operation landing behind
49
- * a transiently-failed claim would execute and confirm PAST the hole; the
50
- * failed operation's retry would then see `confirmed ≥ to` and silently skip
51
- * — its money would never move while the ledger says it did. Throwing instead
52
- * fails this operation's webhook event, and at-least-once delivery retries
53
- * both operations until the predecessor fills its hole and each claimed slice
54
- * has actually moved. The ledger's `reversedAmount` therefore always covers a
55
- * solid, hole-free prefix of the reversed axis — which is exactly what makes
56
- * the `confirmed`/`amount_reversed` checks above sound.
57
- */
58
- async function executeClaimedSlices(
59
- stripe: Stripe,
28
+ async function trackedAffiliateTransfers(
60
29
  component: Component,
61
30
  ctx: RunCtx,
62
- operationId: string,
63
- claim: ReversalClaim,
64
- ): Promise<{ reversals: { stripeTransferId: string; amount: number }[] }> {
65
- const reversals: { stripeTransferId: string; amount: number }[] = [];
66
- for (const slice of claim.slices) {
67
- if (slice.confirmed >= slice.to) continue; // executed and recorded already
68
-
69
- if (slice.confirmed < slice.from) {
70
- throw new Error(
71
- `reversal slice [${slice.from},${slice.to}) on ${slice.stripeTransferId} ` +
72
- `blocked: predecessor claim unexecuted (confirmed=${slice.confirmed})`,
73
- );
74
- }
75
-
76
- if (claim.replay) {
77
- const transfer = await stripe.transfers.retrieve(slice.stripeTransferId);
78
- if ((transfer.amount_reversed ?? 0) >= slice.to) {
79
- // The money moved on a previous attempt that died before confirming.
80
- await runMutationOrThrow(
81
- ctx,
82
- componentRef(component, "connect/mutations/recordTransferReversal"),
83
- {
84
- stripeTransferId: slice.stripeTransferId,
85
- reversedAmount: slice.to,
86
- },
87
- );
88
- continue;
89
- }
90
- }
91
-
92
- const amount = slice.to - slice.from;
93
- await stripe.transfers.createReversal(
94
- slice.stripeTransferId,
95
- { amount },
96
- { idempotencyKey: `bs_rev_${operationId}_${slice.stripeTransferId}` },
97
- );
98
- await runMutationOrThrow(
99
- ctx,
100
- componentRef(component, "connect/mutations/recordTransferReversal"),
101
- { stripeTransferId: slice.stripeTransferId, reversedAmount: slice.to },
102
- );
103
- reversals.push({ stripeTransferId: slice.stripeTransferId, amount });
104
- }
105
- return { reversals };
31
+ sourceChargeId: string,
32
+ ) {
33
+ const rows = (await ctx.runQuery(
34
+ componentRef(component, "affiliateRecovery/queries/chargeObligations"),
35
+ { sourceChargeId },
36
+ )) as { accounted?: boolean; stripeTransferId?: string }[] | null;
37
+ return new Set(
38
+ Array.isArray(rows)
39
+ ? rows
40
+ .filter((row) => row.accounted && row.stripeTransferId)
41
+ .map((row) => row.stripeTransferId!)
42
+ : [],
43
+ );
106
44
  }
107
45
 
108
46
  /** A wedged reversal claim surfaced by {@link listWedgedReversalClaims}. */
@@ -120,6 +58,7 @@ type ReversalOpRecord = {
120
58
  sourceChargeId: string;
121
59
  slices: { stripeTransferId: string; from: number; to: number }[];
122
60
  _creationTime: number;
61
+ commissionExposure?: { kind: "refund" | "dispute" };
123
62
  };
124
63
 
125
64
  /** Stripe prunes idempotency keys after ~24h; a release must wait past this. */
@@ -212,19 +151,43 @@ export async function reclaimReversalClaim(
212
151
  const leg = (await ctx.runQuery(
213
152
  componentRef(component, "connect/queries/getTransferByStripeId"),
214
153
  { stripeTransferId: s.stripeTransferId },
215
- )) as { reversedAmount?: number } | null;
216
- slices.push({ ...s, confirmed: leg?.reversedAmount ?? 0 });
154
+ )) as { reversedAmount?: number; role?: string } | null;
155
+ slices.push({
156
+ ...s,
157
+ confirmed: leg?.reversedAmount ?? 0,
158
+ ...(op.commissionExposure
159
+ ? { commissionTracked: leg?.role === "affiliate" }
160
+ : {}),
161
+ });
217
162
  }
163
+ const tracked = op.commissionExposure
164
+ ? null
165
+ : await trackedAffiliateTransfers(component, ctx, op.sourceChargeId);
166
+ const usesRecoveryLedger = !!op.commissionExposure || !!tracked?.size;
218
167
  const { reversals } = await executeClaimedSlices(
219
168
  stripe,
220
169
  component,
221
170
  ctx,
222
171
  op.operationId,
223
- { replay: true, slices },
172
+ {
173
+ replay: true,
174
+ slices: slices.filter(
175
+ (s) => !s.commissionTracked && !tracked?.has(s.stripeTransferId),
176
+ ),
177
+ },
224
178
  );
179
+ if (usesRecoveryLedger)
180
+ await reconcileAffiliateCharge(stripe, component, ctx, op.sourceChargeId);
225
181
  return { mode: "reexecute", reversals };
226
182
  }
227
183
 
184
+ if (
185
+ op.commissionExposure ||
186
+ (await trackedAffiliateTransfers(component, ctx, op.sourceChargeId)).size
187
+ )
188
+ throw new Error(
189
+ "Affiliate exposure audit claims cannot be released; use affiliateRecovery.retry or reviewLegacy.",
190
+ );
228
191
  // release: age-gate against the idempotency window, then verify live Stripe.
229
192
  const minAgeMs = opts.minAgeMs ?? REVERSAL_IDEMPOTENCY_WINDOW_MS;
230
193
  const now = opts.now ?? Date.now();
@@ -306,6 +269,13 @@ export async function reverseTransfers(
306
269
  }
307
270
 
308
271
  await recoverSettlementTransfers(stripe, component, ctx, opts.sourceChargeId);
272
+ if (
273
+ (await trackedAffiliateTransfers(component, ctx, opts.sourceChargeId)).size
274
+ )
275
+ throw new Error(
276
+ "Use affiliateRecovery.retry for tracked affiliate commission recovery.",
277
+ );
278
+
309
279
  if (opts.operationId) {
310
280
  const claim = (await runMutationOrThrow(
311
281
  ctx,
@@ -389,9 +359,9 @@ export async function reverseTransfers(
389
359
  }
390
360
 
391
361
  /**
392
- * Reverse a split sale's transfers pro-rata to the cumulatively refunded
393
- * amount (BTS-34) — the refund counterpart of the dispute clawback. Every leg
394
- * converges on a cumulative reversal TARGET, `round(leg × amountRefunded /
362
+ * Reverse a split sale's transfers pro-rata to cumulative succeeded refunds.
363
+ * Affiliate legs retain the larger refund/dispute commission exposure. Other
364
+ * legs converge on a cumulative reversal TARGET, `round(leg × amountRefunded /
395
365
  * chargeAmount)`, and only the delta above the ledger's recorded
396
366
  * `reversedAmount` is reversed. Delta-to-target (rather than percent-of-
397
367
  * original like {@link reverseTransfers}) is what makes at-least-once webhook
@@ -416,7 +386,7 @@ export async function reverseTransfersForRefund(
416
386
  refundId: string;
417
387
  /** The original charge amount (minor units). */
418
388
  chargeAmount: number;
419
- /** Stripe's cumulative `charge.amount_refunded`, including this refund. */
389
+ /** Cumulative principal of succeeded refunds; exclude pending/failed refunds. */
420
390
  amountRefunded: number;
421
391
  },
422
392
  ): Promise<{ reversals: { stripeTransferId: string; amount: number }[] }> {
@@ -431,6 +401,13 @@ export async function reverseTransfersForRefund(
431
401
  {
432
402
  operationId: opts.refundId,
433
403
  sourceChargeId: opts.sourceChargeId,
404
+ commissionExposure: {
405
+ kind: "refund",
406
+ refundId: opts.refundId,
407
+ chargeAmount: opts.chargeAmount,
408
+ principal: opts.amountRefunded,
409
+ finalized: true,
410
+ },
434
411
  mode: {
435
412
  kind: "fraction" as const,
436
413
  chargeAmount: opts.chargeAmount,
@@ -438,9 +415,19 @@ export async function reverseTransfersForRefund(
438
415
  },
439
416
  },
440
417
  )) as ReversalClaim;
441
- return executeClaimedSlices(stripe, component, ctx, opts.refundId, claim);
418
+ const result = await executeClaimedSlices(
419
+ stripe,
420
+ component,
421
+ ctx,
422
+ opts.refundId,
423
+ { ...claim, slices: claim.slices.filter((s) => !s.commissionTracked) },
424
+ );
425
+ await reconcileAffiliateCharge(stripe, component, ctx, opts.sourceChargeId);
426
+ return result;
442
427
  }
443
428
 
429
+ export { reverseTransfersForDispute } from "../affiliateRecovery/disputes.js";
430
+
444
431
  /**
445
432
  * Webhook-driven split transfer engine (BTS-22). After a charge succeeds for a
446
433
  * separate-charges sale, fan funds out to each split recipient: compute the
@@ -489,7 +476,14 @@ export async function reinstateTransfers(
489
476
  stripe: Stripe,
490
477
  component: Component,
491
478
  ctx: RunCtx,
492
- opts: { sourceChargeId: string; operationId: string; currency: string },
479
+ opts: {
480
+ sourceChargeId: string;
481
+ operationId: string;
482
+ currency: string;
483
+ excludeAffiliates?: boolean;
484
+ chargeAmount?: number;
485
+ refundedPrincipal?: number;
486
+ },
493
487
  ): Promise<{ reinstated: { destinationAccountId: string; amount: number }[] }> {
494
488
  const transfers = ((await ctx.runQuery(
495
489
  componentRef(component, "connect/queries/listTransfersByCharge"),
@@ -498,7 +492,14 @@ export async function reinstateTransfers(
498
492
 
499
493
  const reinstated: { destinationAccountId: string; amount: number }[] = [];
500
494
  for (const t of transfers) {
501
- const amount = t.reversedAmount ?? 0;
495
+ if (opts.excludeAffiliates && t.role === "affiliate") continue;
496
+ const independentRefund = opts.chargeAmount
497
+ ? Math.round(
498
+ t.amount *
499
+ Math.min(1, (opts.refundedPrincipal ?? 0) / opts.chargeAmount),
500
+ )
501
+ : 0;
502
+ const amount = Math.max(0, (t.reversedAmount ?? 0) - independentRefund);
502
503
  if (amount <= 0) continue; // nothing was clawed back from this leg
503
504
  // Use the original leg's currency; fall back to the dispute currency for
504
505
  // legacy rows that predate the stored currency — never assume USD.
@@ -1,3 +1,7 @@
1
+ import { AffiliateRecoveryClient } from "./affiliateRecovery.js";
2
+ export * from "./affiliateRecovery.js";
3
+ import { CheckoutRequestClient } from "./checkoutRequests.js";
4
+ export type { PreparedCheckoutSession } from "./billing/preparedCheckout.js";
1
5
  import * as payoutSyncImpl from "./connect/payoutSync.js";
2
6
  export type {
3
7
  PayoutSyncOptions,
@@ -81,7 +85,6 @@ export type {
81
85
  import { internalActionGeneric, internalMutationGeneric } from "convex/server";
82
86
  import { v } from "convex/values";
83
87
  import Stripe from "stripe";
84
-
85
88
  import type { ComponentApi } from "../component/_generated/component.js";
86
89
  import type { DisputeStatus } from "../component/connect/validators.js";
87
90
  import type { SplitRecipient } from "../component/lib/fees.js";
@@ -145,7 +148,6 @@ import type { AsyncHookName, TriggerDispatcherName } from "./types/triggers.js";
145
148
  import * as dataImpl from "./utils/data.js";
146
149
  import type { StripeMode } from "./utils/stripeDashboardUrl.js";
147
150
  import * as webhookEndpointsImpl from "./utils/webhookEndpoints.js";
148
-
149
151
  // Re-export standalone webhook registration
150
152
  export { registerRoutes } from "./webhooks.js";
151
153
  export {
@@ -154,13 +156,11 @@ export {
154
156
  STRIPE_DASHBOARD_BASE_URL,
155
157
  StripeDashboardResourcePath,
156
158
  } from "./utils/stripeDashboardUrl.js";
157
-
158
159
  // Re-export payment method utilities
159
160
  export {
160
161
  getPaymentMethodCard,
161
162
  getPaymentMethodOwner,
162
163
  } from "./connect/paymentMethodUtils.js";
163
-
164
164
  // Re-export webhook event constants and types
165
165
  export {
166
166
  ALL_BETTER_STRIPE_EVENTS,
@@ -171,7 +171,6 @@ export type {
171
171
  BetterStripeV2WebhookEvent,
172
172
  BetterStripeWebhookEvent,
173
173
  } from "./utils/webhookEndpoints.js";
174
-
175
174
  // Re-export types for consumers
176
175
  export type {
177
176
  BetterStripeOptions,
@@ -210,7 +209,6 @@ export type {
210
209
  V2ThinEvent,
211
210
  WebhookActionCtx,
212
211
  } from "./types.js";
213
-
214
212
  export type BetterStripeComponent = ComponentApi;
215
213
 
216
214
  // BETTER STRIPE CLIENT
@@ -684,6 +682,14 @@ export class BetterStripe extends ReadContractClient {
684
682
  }
685
683
 
686
684
  // CHECKOUT METHODS
685
+ get checkoutRequests() {
686
+ return new CheckoutRequestClient(
687
+ this.component,
688
+ () => this.stripe(),
689
+ (fee) => this.resolveFee(fee),
690
+ this._statementDescriptorSuffix,
691
+ );
692
+ }
687
693
 
688
694
  async createCheckoutSession(ctx: RunCtx, opts: CreateCheckoutSessionOptions) {
689
695
  const { fee, ...rest } = opts;
@@ -703,27 +709,6 @@ export class BetterStripe extends ReadContractClient {
703
709
  );
704
710
  }
705
711
 
706
- async getCheckoutSession(
707
- ctx: RunCtx,
708
- opts: { sessionId: string },
709
- ): Promise<StripeComponentCheckoutSession | null> {
710
- return checkoutImpl.getCheckoutSession(this.component, ctx, opts);
711
- }
712
-
713
- async getCheckoutSessionByStripeId(
714
- ctx: RunCtx,
715
- opts: { stripeSessionId: string },
716
- ): Promise<StripeComponentCheckoutSession | null> {
717
- return checkoutImpl.getCheckoutSessionByStripeId(this.component, ctx, opts);
718
- }
719
-
720
- async listCheckoutSessionsByUser(
721
- ctx: RunCtx,
722
- opts: { userId: string; status?: string },
723
- ): Promise<StripeComponentCheckoutSession[]> {
724
- return checkoutImpl.listCheckoutSessionsByUser(this.component, ctx, opts);
725
- }
726
-
727
712
  async upsertCheckoutSession(
728
713
  ctx: RunCtx,
729
714
  opts: {
@@ -1151,7 +1136,7 @@ export class BetterStripe extends ReadContractClient {
1151
1136
  // PAYOUT METHODS
1152
1137
 
1153
1138
  async createPayout(ctx: RunCtx, opts: payoutsImpl.CreatePayoutOptions) {
1154
- return payoutsImpl.createPayout(this.stripe(), ctx, opts);
1139
+ return payoutsImpl.createPayout(this.stripe(), ctx, opts, this.component);
1155
1140
  }
1156
1141
 
1157
1142
  /**
@@ -1257,6 +1242,9 @@ export class BetterStripe extends ReadContractClient {
1257
1242
  ) {
1258
1243
  return providerReads.getCouponFromStripe(this.stripe(), opts);
1259
1244
  }
1245
+ get affiliateRecovery() {
1246
+ return new AffiliateRecoveryClient(this.component, () => this.stripe());
1247
+ }
1260
1248
  get payoutPolicy() {
1261
1249
  return new PayoutPolicyClient(this.component, () => this.stripe());
1262
1250
  }
@@ -1,3 +1,12 @@
1
+ import { PayoutWorkerClient } from "./connect/payoutWorker.js";
2
+ export type * from "./connect/payoutWorker.js";
3
+ import {
4
+ collectPayoutSnapshot,
5
+ discardPayoutSnapshot,
6
+ type PayoutCollectionOptions,
7
+ type PayoutCollectionScope,
8
+ } from "./connect/payoutCollection.js";
9
+ export type * from "./connect/payoutCollection.js";
1
10
  import { collectAdoptionProof } from "./connect/payoutActivationProof.js";
2
11
  import {
3
12
  adoptRecipientPayouts,
@@ -97,10 +106,26 @@ const toProvider = (
97
106
  });
98
107
  /** Host authenticates owner/policy/consent. Provider I/O stays in this package. */
99
108
  export class PayoutPolicyClient {
109
+ readonly worker: PayoutWorkerClient;
100
110
  constructor(
101
111
  private readonly component: Component,
102
112
  private readonly provider: () => Stripe,
103
- ) {}
113
+ ) {
114
+ this.worker = new PayoutWorkerClient(
115
+ component,
116
+ (ctx, opts) => this.release(ctx, opts),
117
+ (ctx, opts) => this.reconcilePayout(ctx, opts),
118
+ );
119
+ }
120
+ collectSnapshot(ctx: RunCtx, opts: PayoutCollectionOptions) {
121
+ return collectPayoutSnapshot(this.component, ctx, opts);
122
+ }
123
+ discardSnapshot(
124
+ ctx: RunCtx,
125
+ opts: PayoutCollectionScope & { batchSize?: number },
126
+ ) {
127
+ return discardPayoutSnapshot(this.component, ctx, opts);
128
+ }
104
129
  adoptPayouts(ctx: RunCtx, opts: PayoutAdoptionOptions) {
105
130
  return adoptRecipientPayouts(this.provider(), this.component, ctx, opts);
106
131
  }
@@ -1,9 +1,11 @@
1
+ import * as checkoutImpl from "./billing/checkout.js";
1
2
  import * as payoutsImpl from "./connect/payouts.js";
2
3
  import type { ComponentApi } from "../component/_generated/component.js";
3
4
  import type { PaginationOptions, PaginationResult } from "convex/server";
4
5
  import type { Component, RunCtx } from "./helpers.js";
5
6
  import type { PayoutStatus } from "../component/connect/validators.js";
6
7
  import type {
8
+ StripeComponentCheckoutSession,
7
9
  StripeComponentPayout,
8
10
  StripeComponentProduct,
9
11
  StripeComponentPrice,
@@ -52,6 +54,27 @@ export class ReadContractClient {
52
54
  );
53
55
  }
54
56
 
57
+ async getCheckoutSession(
58
+ ctx: RunCtx,
59
+ opts: { sessionId: string },
60
+ ): Promise<StripeComponentCheckoutSession | null> {
61
+ return checkoutImpl.getCheckoutSession(this.component, ctx, opts);
62
+ }
63
+
64
+ async getCheckoutSessionByStripeId(
65
+ ctx: RunCtx,
66
+ opts: { stripeSessionId: string },
67
+ ): Promise<StripeComponentCheckoutSession | null> {
68
+ return checkoutImpl.getCheckoutSessionByStripeId(this.component, ctx, opts);
69
+ }
70
+
71
+ async listCheckoutSessionsByUser(
72
+ ctx: RunCtx,
73
+ opts: { userId: string; status?: string },
74
+ ): Promise<StripeComponentCheckoutSession[]> {
75
+ return checkoutImpl.listCheckoutSessionsByUser(this.component, ctx, opts);
76
+ }
77
+
55
78
  async getPayout(ctx: RunCtx, opts: { payoutId: string }) {
56
79
  return payoutsImpl.getPayout(this.component, ctx, opts);
57
80
  }
@@ -26,6 +26,11 @@ it("recovers provider success after a ledger failure even without an idempotency
26
26
  async (r: Record<symbol, string>, args: Record<string, unknown>) => {
27
27
  if (r[TO_REF].endsWith("/reserveSettlementAllocation"))
28
28
  return claimed ?? (claimed = { ...args });
29
+ if (
30
+ r[TO_REF].includes("affiliateRecovery/") ||
31
+ r[TO_REF].includes("affiliateEarnings/")
32
+ )
33
+ return undefined;
29
34
  if (fail) {
30
35
  fail = false;
31
36
  throw new Error("ledger unavailable");