@fantastic.dev/better-stripe 0.23.1 → 0.24.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 (287) hide show
  1. package/CHANGELOG.md +26 -2
  2. package/README.md +40 -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/connect/commissionReceipts.d.ts +4 -0
  32. package/dist/client/connect/commissionReceipts.d.ts.map +1 -0
  33. package/dist/client/connect/commissionReceipts.js +17 -0
  34. package/dist/client/connect/commissionReceipts.js.map +1 -0
  35. package/dist/client/connect/payoutAdoptionTestHelpers.d.ts +536 -2
  36. package/dist/client/connect/payoutAdoptionTestHelpers.d.ts.map +1 -1
  37. package/dist/client/connect/payoutSync.d.ts +32 -0
  38. package/dist/client/connect/payoutSync.d.ts.map +1 -0
  39. package/dist/client/connect/payoutSync.js +48 -0
  40. package/dist/client/connect/payoutSync.js.map +1 -0
  41. package/dist/client/connect/payoutSyncTestHelpers.d.ts +1509 -0
  42. package/dist/client/connect/payoutSyncTestHelpers.d.ts.map +1 -0
  43. package/dist/client/connect/payoutSyncTestHelpers.js +62 -0
  44. package/dist/client/connect/payoutSyncTestHelpers.js.map +1 -0
  45. package/dist/client/connect/payoutSyncValidation.d.ts +16 -0
  46. package/dist/client/connect/payoutSyncValidation.d.ts.map +1 -0
  47. package/dist/client/connect/payoutSyncValidation.js +54 -0
  48. package/dist/client/connect/payoutSyncValidation.js.map +1 -0
  49. package/dist/client/connect/payouts.d.ts +3 -1
  50. package/dist/client/connect/payouts.d.ts.map +1 -1
  51. package/dist/client/connect/payouts.js +45 -12
  52. package/dist/client/connect/payouts.js.map +1 -1
  53. package/dist/client/connect/refundPrincipal.d.ts +4 -0
  54. package/dist/client/connect/refundPrincipal.d.ts.map +1 -0
  55. package/dist/client/connect/refundPrincipal.js +21 -0
  56. package/dist/client/connect/refundPrincipal.js.map +1 -0
  57. package/dist/client/connect/reversalExecution.d.ts +47 -0
  58. package/dist/client/connect/reversalExecution.d.ts.map +1 -0
  59. package/dist/client/connect/reversalExecution.js +84 -0
  60. package/dist/client/connect/reversalExecution.js.map +1 -0
  61. package/dist/client/connect/transfers.d.ts +8 -4
  62. package/dist/client/connect/transfers.d.ts.map +1 -1
  63. package/dist/client/connect/transfers.js +52 -57
  64. package/dist/client/connect/transfers.js.map +1 -1
  65. package/dist/client/index.d.ts +29 -9
  66. package/dist/client/index.d.ts.map +1 -1
  67. package/dist/client/index.js +9 -6
  68. package/dist/client/index.js.map +1 -1
  69. package/dist/client/readContracts.d.ts +8 -0
  70. package/dist/client/readContracts.d.ts.map +1 -1
  71. package/dist/client/readContracts.js +7 -0
  72. package/dist/client/readContracts.js.map +1 -1
  73. package/dist/client/settlement/execution.d.ts.map +1 -1
  74. package/dist/client/settlement/execution.js +30 -3
  75. package/dist/client/settlement/execution.js.map +1 -1
  76. package/dist/client/settlement/reconciliation.d.ts.map +1 -1
  77. package/dist/client/settlement/reconciliation.js +16 -2
  78. package/dist/client/settlement/reconciliation.js.map +1 -1
  79. package/dist/client/webhooks/disputeRecovery.d.ts +4 -0
  80. package/dist/client/webhooks/disputeRecovery.d.ts.map +1 -0
  81. package/dist/client/webhooks/disputeRecovery.js +40 -0
  82. package/dist/client/webhooks/disputeRecovery.js.map +1 -0
  83. package/dist/client/webhooks/processors.d.ts.map +1 -1
  84. package/dist/client/webhooks/processors.js +14 -29
  85. package/dist/client/webhooks/processors.js.map +1 -1
  86. package/dist/component/_generated/component.d.ts +560 -0
  87. package/dist/component/_generated/component.d.ts.map +1 -1
  88. package/dist/component/affiliateEarnings/mutations.d.ts +22 -0
  89. package/dist/component/affiliateEarnings/mutations.d.ts.map +1 -0
  90. package/dist/component/affiliateEarnings/mutations.js +160 -0
  91. package/dist/component/affiliateEarnings/mutations.js.map +1 -0
  92. package/dist/component/affiliatePayouts/mutations.d.ts +25 -0
  93. package/dist/component/affiliatePayouts/mutations.d.ts.map +1 -0
  94. package/dist/component/affiliatePayouts/mutations.js +104 -0
  95. package/dist/component/affiliatePayouts/mutations.js.map +1 -0
  96. package/dist/component/affiliatePayouts/queries.d.ts +23 -0
  97. package/dist/component/affiliatePayouts/queries.d.ts.map +1 -0
  98. package/dist/component/affiliatePayouts/queries.js +23 -0
  99. package/dist/component/affiliatePayouts/queries.js.map +1 -0
  100. package/dist/component/affiliatePayouts/recipientGuard.d.ts +12 -0
  101. package/dist/component/affiliatePayouts/recipientGuard.d.ts.map +1 -0
  102. package/dist/component/affiliatePayouts/recipientGuard.js +26 -0
  103. package/dist/component/affiliatePayouts/recipientGuard.js.map +1 -0
  104. package/dist/component/affiliateRecovery/accounting.d.ts +28 -0
  105. package/dist/component/affiliateRecovery/accounting.d.ts.map +1 -0
  106. package/dist/component/affiliateRecovery/accounting.js +71 -0
  107. package/dist/component/affiliateRecovery/accounting.js.map +1 -0
  108. package/dist/component/affiliateRecovery/mutations.d.ts +65 -0
  109. package/dist/component/affiliateRecovery/mutations.d.ts.map +1 -0
  110. package/dist/component/affiliateRecovery/mutations.js +250 -0
  111. package/dist/component/affiliateRecovery/mutations.js.map +1 -0
  112. package/dist/component/affiliateRecovery/queries.d.ts +305 -0
  113. package/dist/component/affiliateRecovery/queries.d.ts.map +1 -0
  114. package/dist/component/affiliateRecovery/queries.js +113 -0
  115. package/dist/component/affiliateRecovery/queries.js.map +1 -0
  116. package/dist/component/affiliateRecovery/schema.d.ts +171 -0
  117. package/dist/component/affiliateRecovery/schema.d.ts.map +1 -0
  118. package/dist/component/affiliateRecovery/schema.js +71 -0
  119. package/dist/component/affiliateRecovery/schema.js.map +1 -0
  120. package/dist/component/connect/mutations.d.ts +36 -23
  121. package/dist/component/connect/mutations.d.ts.map +1 -1
  122. package/dist/component/connect/mutations.js +11 -151
  123. package/dist/component/connect/mutations.js.map +1 -1
  124. package/dist/component/connect/payoutWrites.d.ts +21 -0
  125. package/dist/component/connect/payoutWrites.d.ts.map +1 -0
  126. package/dist/component/connect/payoutWrites.js +19 -0
  127. package/dist/component/connect/payoutWrites.js.map +1 -0
  128. package/dist/component/connect/queries.d.ts +10 -0
  129. package/dist/component/connect/queries.d.ts.map +1 -1
  130. package/dist/component/connect/queries.js +3 -40
  131. package/dist/component/connect/queries.js.map +1 -1
  132. package/dist/component/connect/reversalClaims.d.ts +169 -0
  133. package/dist/component/connect/reversalClaims.d.ts.map +1 -0
  134. package/dist/component/connect/reversalClaims.js +176 -0
  135. package/dist/component/connect/reversalClaims.js.map +1 -0
  136. package/dist/component/connect/reversalDiagnostics.d.ts +59 -0
  137. package/dist/component/connect/reversalDiagnostics.d.ts.map +1 -0
  138. package/dist/component/connect/reversalDiagnostics.js +50 -0
  139. package/dist/component/connect/reversalDiagnostics.js.map +1 -0
  140. package/dist/component/connect/reversalReceipts.d.ts +27 -0
  141. package/dist/component/connect/reversalReceipts.d.ts.map +1 -0
  142. package/dist/component/connect/reversalReceipts.js +85 -0
  143. package/dist/component/connect/reversalReceipts.js.map +1 -0
  144. package/dist/component/connect/schema.d.ts +31 -1
  145. package/dist/component/connect/schema.d.ts.map +1 -1
  146. package/dist/component/connect/schema.js +3 -1
  147. package/dist/component/connect/schema.js.map +1 -1
  148. package/dist/component/connect/validators.d.ts +49 -1
  149. package/dist/component/connect/validators.d.ts.map +1 -1
  150. package/dist/component/connect/validators.js +2 -0
  151. package/dist/component/connect/validators.js.map +1 -1
  152. package/dist/component/earnings/triggers.d.ts +454 -2
  153. package/dist/component/earnings/triggers.d.ts.map +1 -1
  154. package/dist/component/payoutRelease/mutations.d.ts.map +1 -1
  155. package/dist/component/payoutRelease/mutations.js +6 -0
  156. package/dist/component/payoutRelease/mutations.js.map +1 -1
  157. package/dist/component/payoutRelease/queries.d.ts.map +1 -1
  158. package/dist/component/payoutRelease/queries.js +3 -1
  159. package/dist/component/payoutRelease/queries.js.map +1 -1
  160. package/dist/component/payoutSync/helpers.d.ts +44 -0
  161. package/dist/component/payoutSync/helpers.d.ts.map +1 -0
  162. package/dist/component/payoutSync/helpers.js +60 -0
  163. package/dist/component/payoutSync/helpers.js.map +1 -0
  164. package/dist/component/payoutSync/mutations.d.ts +51 -0
  165. package/dist/component/payoutSync/mutations.d.ts.map +1 -0
  166. package/dist/component/payoutSync/mutations.js +88 -0
  167. package/dist/component/payoutSync/mutations.js.map +1 -0
  168. package/dist/component/payoutSync/queries.d.ts +16 -0
  169. package/dist/component/payoutSync/queries.d.ts.map +1 -0
  170. package/dist/component/payoutSync/queries.js +11 -0
  171. package/dist/component/payoutSync/queries.js.map +1 -0
  172. package/dist/component/payoutSync/schema.d.ts +46 -0
  173. package/dist/component/payoutSync/schema.d.ts.map +1 -0
  174. package/dist/component/payoutSync/schema.js +22 -0
  175. package/dist/component/payoutSync/schema.js.map +1 -0
  176. package/dist/component/payoutSync/validators.d.ts +137 -0
  177. package/dist/component/payoutSync/validators.d.ts.map +1 -0
  178. package/dist/component/payoutSync/validators.js +19 -0
  179. package/dist/component/payoutSync/validators.js.map +1 -0
  180. package/dist/component/schema.d.ts +268 -1
  181. package/dist/component/schema.js +11 -0
  182. package/dist/component/schema.js.map +1 -1
  183. package/dist/component/settlement/clawbackSchema.d.ts +161 -0
  184. package/dist/component/settlement/clawbackSchema.d.ts.map +1 -0
  185. package/dist/component/settlement/clawbackSchema.js +73 -0
  186. package/dist/component/settlement/clawbackSchema.js.map +1 -0
  187. package/dist/component/settlement/clawbacks.d.ts +55 -0
  188. package/dist/component/settlement/clawbacks.d.ts.map +1 -0
  189. package/dist/component/settlement/clawbacks.js +146 -0
  190. package/dist/component/settlement/clawbacks.js.map +1 -0
  191. package/dist/component/settlement/mutations.d.ts +16 -0
  192. package/dist/component/settlement/mutations.d.ts.map +1 -1
  193. package/dist/component/settlement/mutations.js +48 -0
  194. package/dist/component/settlement/mutations.js.map +1 -1
  195. package/dist/component/settlement/queries.d.ts +53 -0
  196. package/dist/component/settlement/queries.d.ts.map +1 -1
  197. package/dist/component/settlement/queries.js +26 -0
  198. package/dist/component/settlement/queries.js.map +1 -1
  199. package/dist/react/workflows/AffiliateRecovery.d.ts +46 -0
  200. package/dist/react/workflows/AffiliateRecovery.d.ts.map +1 -0
  201. package/dist/react/workflows/AffiliateRecovery.js +84 -0
  202. package/dist/react/workflows/AffiliateRecovery.js.map +1 -0
  203. package/dist/react/workflows/index.d.ts +2 -0
  204. package/dist/react/workflows/index.d.ts.map +1 -1
  205. package/dist/react/workflows/index.js +1 -0
  206. package/dist/react/workflows/index.js.map +1 -1
  207. package/dist/testing/affiliate-recovery.d.ts +10 -0
  208. package/dist/testing/affiliate-recovery.d.ts.map +1 -0
  209. package/dist/testing/affiliate-recovery.js +126 -0
  210. package/dist/testing/affiliate-recovery.js.map +1 -0
  211. package/dist/testing/index.d.ts +2 -0
  212. package/dist/testing/index.d.ts.map +1 -1
  213. package/dist/testing/index.js +1 -0
  214. package/dist/testing/index.js.map +1 -1
  215. package/docs/affiliate-clawbacks.md +306 -0
  216. package/docs/read-contracts.md +40 -5
  217. package/docs/settlement.md +17 -0
  218. package/package.json +2 -1
  219. package/src/client/affiliateRecovery/disputes.ts +62 -0
  220. package/src/client/affiliateRecovery/engine.ts +196 -0
  221. package/src/client/affiliateRecovery/payoutGate.ts +65 -0
  222. package/src/client/affiliateRecovery/provider.ts +127 -0
  223. package/src/client/affiliateRecovery/review.ts +117 -0
  224. package/src/client/affiliateRecovery/validators.ts +38 -0
  225. package/src/client/affiliateRecovery.ts +173 -0
  226. package/src/client/connect/commissionReceipts.test.ts +157 -0
  227. package/src/client/connect/commissionReceipts.ts +23 -0
  228. package/src/client/connect/payoutSync.test.ts +313 -0
  229. package/src/client/connect/payoutSync.ts +93 -0
  230. package/src/client/connect/payoutSyncTestHelpers.ts +82 -0
  231. package/src/client/connect/payoutSyncValidation.ts +74 -0
  232. package/src/client/connect/payouts.ts +75 -15
  233. package/src/client/connect/refundPrincipal.test.ts +46 -0
  234. package/src/client/connect/refundPrincipal.ts +26 -0
  235. package/src/client/connect/reversalExecution.ts +130 -0
  236. package/src/client/connect/transfers.test.ts +3 -3
  237. package/src/client/connect/transfers.ts +93 -92
  238. package/src/client/index.ts +20 -18
  239. package/src/client/readContracts.ts +12 -0
  240. package/src/client/settlement/execution.test.ts +5 -0
  241. package/src/client/settlement/execution.ts +50 -3
  242. package/src/client/settlement/reconciliation.ts +20 -2
  243. package/src/client/webhooks/disputeRecovery.ts +74 -0
  244. package/src/client/webhooks/processors.test.ts +36 -53
  245. package/src/client/webhooks/processors.ts +18 -31
  246. package/src/component/_generated/api.ts +34 -0
  247. package/src/component/_generated/component.ts +696 -1
  248. package/src/component/affiliate-clawbacks.test.ts +370 -0
  249. package/src/component/affiliate-component-pagination.test.ts +83 -0
  250. package/src/component/affiliate-direct-payout.test.ts +160 -0
  251. package/src/component/affiliate-recovery-lifecycle.test.ts +587 -0
  252. package/src/component/affiliateEarnings/mutations.ts +196 -0
  253. package/src/component/affiliatePayouts/mutations.ts +121 -0
  254. package/src/component/affiliatePayouts/queries.ts +28 -0
  255. package/src/component/affiliatePayouts/recipientGuard.ts +42 -0
  256. package/src/component/affiliateRecovery/accounting.ts +111 -0
  257. package/src/component/affiliateRecovery/mutations.ts +275 -0
  258. package/src/component/affiliateRecovery/queries.ts +138 -0
  259. package/src/component/affiliateRecovery/schema.ts +86 -0
  260. package/src/component/connect/mutations.ts +13 -190
  261. package/src/component/connect/payoutWrites.ts +25 -0
  262. package/src/component/connect/queries.ts +4 -47
  263. package/src/component/connect/reversalClaims.ts +232 -0
  264. package/src/component/connect/reversalDiagnostics.ts +61 -0
  265. package/src/component/connect/reversalReceipts.ts +147 -0
  266. package/src/component/connect/schema.ts +3 -3
  267. package/src/component/connect/validators.ts +2 -0
  268. package/src/component/payout-recovery-integration.test.ts +172 -0
  269. package/src/component/payout-sync.test.ts +117 -0
  270. package/src/component/payoutRelease/mutations.ts +9 -0
  271. package/src/component/payoutRelease/queries.ts +3 -1
  272. package/src/component/payoutSync/helpers.ts +86 -0
  273. package/src/component/payoutSync/mutations.ts +102 -0
  274. package/src/component/payoutSync/queries.ts +10 -0
  275. package/src/component/payoutSync/schema.ts +25 -0
  276. package/src/component/payoutSync/validators.ts +21 -0
  277. package/src/component/schema.ts +20 -0
  278. package/src/component/settlement/clawbackSchema.ts +78 -0
  279. package/src/component/settlement/clawbacks.ts +233 -0
  280. package/src/component/settlement/mutations.ts +54 -0
  281. package/src/component/settlement/queries.ts +35 -0
  282. package/src/component/summary-arithmetic.test.ts +9 -4
  283. package/src/react/workflows/AffiliateRecovery.test.tsx +106 -0
  284. package/src/react/workflows/AffiliateRecovery.tsx +273 -0
  285. package/src/react/workflows/index.ts +9 -0
  286. package/src/testing/affiliate-recovery.ts +137 -0
  287. package/src/testing/index.ts +2 -0
@@ -0,0 +1,169 @@
1
+ import type { MutationCtx } from "../_generated/server.js";
2
+ import { commissionExposureValidator } from "../settlement/clawbackSchema.js";
3
+ import type { Infer } from "convex/values";
4
+ /** How `claimReversalSlices` sizes each leg's slice. */
5
+ declare const reversalModeValidator: import("convex/values").VUnion<{
6
+ kind: "full";
7
+ } | {
8
+ kind: "percent";
9
+ percent: number;
10
+ } | {
11
+ amount: number;
12
+ kind: "amount";
13
+ } | {
14
+ amountRefunded: number;
15
+ chargeAmount: number;
16
+ kind: "fraction";
17
+ }, [import("convex/values").VObject<{
18
+ kind: "full";
19
+ }, {
20
+ kind: import("convex/values").VLiteral<"full", "required">;
21
+ }, "required", "kind">, import("convex/values").VObject<{
22
+ kind: "percent";
23
+ percent: number;
24
+ }, {
25
+ kind: import("convex/values").VLiteral<"percent", "required">;
26
+ percent: import("convex/values").VFloat64<number, "required">;
27
+ }, "required", "kind" | "percent">, import("convex/values").VObject<{
28
+ amount: number;
29
+ kind: "amount";
30
+ }, {
31
+ kind: import("convex/values").VLiteral<"amount", "required">;
32
+ amount: import("convex/values").VFloat64<number, "required">;
33
+ }, "required", "amount" | "kind">, import("convex/values").VObject<{
34
+ amountRefunded: number;
35
+ chargeAmount: number;
36
+ kind: "fraction";
37
+ }, {
38
+ kind: import("convex/values").VLiteral<"fraction", "required">;
39
+ chargeAmount: import("convex/values").VFloat64<number, "required">;
40
+ amountRefunded: import("convex/values").VFloat64<number, "required">;
41
+ }, "required", "amountRefunded" | "chargeAmount" | "kind">], "required", "amount" | "amountRefunded" | "chargeAmount" | "kind" | "percent">;
42
+ /**
43
+ * Atomically claim reversal slices for one operation (a dispute or refund
44
+ * clawback) BEFORE any money moves (BTS-63). Runs in a single transaction, so
45
+ * concurrent operations serialize here instead of racing between the ledger
46
+ * read and the Stripe call:
47
+ *
48
+ * - First claim for an `operationId`: computes slices against each leg's
49
+ * claim frontier (`max(reversedAmount, reversalClaimedAmount)`), advances
50
+ * the frontier, and records the slices — atomically. A concurrent distinct
51
+ * operation claiming the same target gets an EMPTY claim, not a duplicate.
52
+ * - Any later call with the same `operationId` (webhook redelivery, retry
53
+ * after a partial failure) replays the recorded slices verbatim, so the
54
+ * caller re-sends byte-identical Stripe params under the same idempotency
55
+ * keys no matter how the ledger moved in between.
56
+ *
57
+ * Each returned slice carries the leg's current CONFIRMED `reversedAmount` so
58
+ * the executor can skip slices whose money already moved and was recorded.
59
+ */
60
+ export declare const claimReversalSlicesDefinition: {
61
+ args: {
62
+ operationId: import("convex/values").VString<string, "required">;
63
+ sourceChargeId: import("convex/values").VString<string, "required">;
64
+ mode: import("convex/values").VUnion<{
65
+ kind: "full";
66
+ } | {
67
+ kind: "percent";
68
+ percent: number;
69
+ } | {
70
+ amount: number;
71
+ kind: "amount";
72
+ } | {
73
+ amountRefunded: number;
74
+ chargeAmount: number;
75
+ kind: "fraction";
76
+ }, [import("convex/values").VObject<{
77
+ kind: "full";
78
+ }, {
79
+ kind: import("convex/values").VLiteral<"full", "required">;
80
+ }, "required", "kind">, import("convex/values").VObject<{
81
+ kind: "percent";
82
+ percent: number;
83
+ }, {
84
+ kind: import("convex/values").VLiteral<"percent", "required">;
85
+ percent: import("convex/values").VFloat64<number, "required">;
86
+ }, "required", "kind" | "percent">, import("convex/values").VObject<{
87
+ amount: number;
88
+ kind: "amount";
89
+ }, {
90
+ kind: import("convex/values").VLiteral<"amount", "required">;
91
+ amount: import("convex/values").VFloat64<number, "required">;
92
+ }, "required", "amount" | "kind">, import("convex/values").VObject<{
93
+ amountRefunded: number;
94
+ chargeAmount: number;
95
+ kind: "fraction";
96
+ }, {
97
+ kind: import("convex/values").VLiteral<"fraction", "required">;
98
+ chargeAmount: import("convex/values").VFloat64<number, "required">;
99
+ amountRefunded: import("convex/values").VFloat64<number, "required">;
100
+ }, "required", "amountRefunded" | "chargeAmount" | "kind">], "required", "amount" | "amountRefunded" | "chargeAmount" | "kind" | "percent">;
101
+ commissionExposure: import("convex/values").VObject<{
102
+ chargeAmount: number;
103
+ disputeId?: string | undefined;
104
+ disputeState?: "lost" | "open" | "won" | undefined;
105
+ finalized: boolean;
106
+ kind: "dispute" | "refund";
107
+ principal: number;
108
+ refundId?: string | undefined;
109
+ refundedPrincipal?: number | undefined;
110
+ } | undefined, {
111
+ kind: import("convex/values").VUnion<"dispute" | "refund", [import("convex/values").VLiteral<"refund", "required">, import("convex/values").VLiteral<"dispute", "required">], "required", never>;
112
+ chargeAmount: import("convex/values").VFloat64<number, "required">;
113
+ principal: import("convex/values").VFloat64<number, "required">;
114
+ finalized: import("convex/values").VBoolean<boolean, "required">;
115
+ disputeState: import("convex/values").VUnion<"lost" | "open" | "won" | undefined, [import("convex/values").VLiteral<"open", "required">, import("convex/values").VLiteral<"lost", "required">, import("convex/values").VLiteral<"won", "required">], "optional", never>;
116
+ disputeId: import("convex/values").VString<string | undefined, "optional">;
117
+ refundedPrincipal: import("convex/values").VFloat64<number | undefined, "optional">;
118
+ refundId: import("convex/values").VString<string | undefined, "optional">;
119
+ }, "optional", "chargeAmount" | "disputeId" | "disputeState" | "finalized" | "kind" | "principal" | "refundId" | "refundedPrincipal">;
120
+ };
121
+ returns: import("convex/values").VObject<{
122
+ replay: boolean;
123
+ slices: {
124
+ commissionTracked?: boolean | undefined;
125
+ confirmed: number;
126
+ from: number;
127
+ stripeTransferId: string;
128
+ to: number;
129
+ }[];
130
+ }, {
131
+ replay: import("convex/values").VBoolean<boolean, "required">;
132
+ slices: import("convex/values").VArray<{
133
+ commissionTracked?: boolean | undefined;
134
+ confirmed: number;
135
+ from: number;
136
+ stripeTransferId: string;
137
+ to: number;
138
+ }[], import("convex/values").VObject<{
139
+ commissionTracked?: boolean | undefined;
140
+ confirmed: number;
141
+ from: number;
142
+ stripeTransferId: string;
143
+ to: number;
144
+ }, {
145
+ stripeTransferId: import("convex/values").VString<string, "required">;
146
+ from: import("convex/values").VFloat64<number, "required">;
147
+ to: import("convex/values").VFloat64<number, "required">;
148
+ confirmed: import("convex/values").VFloat64<number, "required">;
149
+ commissionTracked: import("convex/values").VBoolean<boolean | undefined, "optional">;
150
+ }, "required", "commissionTracked" | "confirmed" | "from" | "stripeTransferId" | "to">, "required">;
151
+ }, "required", "replay" | "slices">;
152
+ handler: (ctx: MutationCtx, args: {
153
+ operationId: string;
154
+ sourceChargeId: string;
155
+ mode: Infer<typeof reversalModeValidator>;
156
+ commissionExposure?: Infer<typeof commissionExposureValidator>;
157
+ }) => Promise<{
158
+ replay: boolean;
159
+ slices: {
160
+ confirmed: number;
161
+ commissionTracked?: boolean | undefined;
162
+ from: number;
163
+ stripeTransferId: string;
164
+ to: number;
165
+ }[];
166
+ }>;
167
+ };
168
+ export {};
169
+ //# sourceMappingURL=reversalClaims.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversalClaims.d.ts","sourceRoot":"","sources":["../../../src/component/connect/reversalClaims.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAM3D,OAAO,EAAE,2BAA2B,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,wDAAwD;AACxD,QAAA,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2IAS1B,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,6BAA6B;IACxC,IAAI;QACF,WAAW;QACX,cAAc;QACd,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QACJ,kBAAkB;;;;;;;;;;;;;;;;;;;;IAEpB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAYP,OAAO,QACA,WAAW,QACV;QACJ,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,IAAI,EAAE,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;QAC1C,kBAAkB,CAAC,EAAE,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;KAChE;;;;;;;;;;CAsKJ,CAAC"}
@@ -0,0 +1,176 @@
1
+ import { v } from "convex/values";
2
+ import { computeReversalSlices } from "../lib/reversals.js";
3
+ import { applyCommissionExposure, applyObligationExposure, } from "../settlement/clawbacks.js";
4
+ import { commissionExposureValidator } from "../settlement/clawbackSchema.js";
5
+ /** How `claimReversalSlices` sizes each leg's slice. */
6
+ const reversalModeValidator = v.union(v.object({ kind: v.literal("full") }), v.object({ kind: v.literal("percent"), percent: v.number() }), v.object({ kind: v.literal("amount"), amount: v.number() }), v.object({
7
+ kind: v.literal("fraction"),
8
+ chargeAmount: v.number(),
9
+ amountRefunded: v.number(),
10
+ }));
11
+ /**
12
+ * Atomically claim reversal slices for one operation (a dispute or refund
13
+ * clawback) BEFORE any money moves (BTS-63). Runs in a single transaction, so
14
+ * concurrent operations serialize here instead of racing between the ledger
15
+ * read and the Stripe call:
16
+ *
17
+ * - First claim for an `operationId`: computes slices against each leg's
18
+ * claim frontier (`max(reversedAmount, reversalClaimedAmount)`), advances
19
+ * the frontier, and records the slices — atomically. A concurrent distinct
20
+ * operation claiming the same target gets an EMPTY claim, not a duplicate.
21
+ * - Any later call with the same `operationId` (webhook redelivery, retry
22
+ * after a partial failure) replays the recorded slices verbatim, so the
23
+ * caller re-sends byte-identical Stripe params under the same idempotency
24
+ * keys no matter how the ledger moved in between.
25
+ *
26
+ * Each returned slice carries the leg's current CONFIRMED `reversedAmount` so
27
+ * the executor can skip slices whose money already moved and was recorded.
28
+ */
29
+ export const claimReversalSlicesDefinition = {
30
+ args: {
31
+ operationId: v.string(),
32
+ sourceChargeId: v.string(),
33
+ mode: reversalModeValidator,
34
+ commissionExposure: v.optional(commissionExposureValidator),
35
+ },
36
+ returns: v.object({
37
+ replay: v.boolean(),
38
+ slices: v.array(v.object({
39
+ stripeTransferId: v.string(),
40
+ from: v.number(),
41
+ to: v.number(),
42
+ confirmed: v.number(),
43
+ commissionTracked: v.optional(v.boolean()),
44
+ })),
45
+ }),
46
+ handler: async (ctx, args) => {
47
+ const confirmedFor = async (stripeTransferId) => {
48
+ const row = await ctx.db
49
+ .query("transfers")
50
+ .withIndex("by_stripe_transfer_id", (q) => q.eq("stripeTransferId", stripeTransferId))
51
+ .first();
52
+ return row?.reversedAmount ?? 0;
53
+ };
54
+ const isAffiliate = async (stripeTransferId) => {
55
+ const row = await ctx.db
56
+ .query("transfers")
57
+ .withIndex("by_stripe_transfer_id", (q) => q.eq("stripeTransferId", stripeTransferId))
58
+ .unique();
59
+ return row?.role === "affiliate";
60
+ };
61
+ // Fail atomically rather than commit a partial recovery beyond the bound.
62
+ const chargeRows = await ctx.db
63
+ .query("transfers")
64
+ .withIndex("by_source_charge_id", (q) => q.eq("sourceChargeId", args.sourceChargeId))
65
+ .take(1001);
66
+ if (chargeRows.length > 1000)
67
+ throw new Error("Charge transfer recovery limit exceeded.");
68
+ const rows = chargeRows.filter((t) => !t.reinstatement);
69
+ const existingOp = await ctx.db
70
+ .query("transferReversalOps")
71
+ .withIndex("by_operation_id", (q) => q.eq("operationId", args.operationId))
72
+ .first();
73
+ const exposure = existingOp?.commissionExposure && args.commissionExposure
74
+ ? {
75
+ ...existingOp.commissionExposure,
76
+ finalized: existingOp.commissionExposure.finalized ||
77
+ args.commissionExposure.finalized,
78
+ disputeState: args.commissionExposure.disputeState ??
79
+ existingOp.commissionExposure.disputeState,
80
+ refundedPrincipal: args.commissionExposure.refundedPrincipal,
81
+ }
82
+ : existingOp
83
+ ? undefined
84
+ : args.commissionExposure;
85
+ const targets = new Map();
86
+ if (exposure) {
87
+ for (const transfer of rows)
88
+ if (transfer.role === "affiliate")
89
+ targets.set(transfer.stripeTransferId, await applyCommissionExposure(ctx, transfer, exposure));
90
+ const untransferred = await ctx.db
91
+ .query("affiliateObligations")
92
+ .withIndex("by_charge", (q) => q.eq("sourceChargeId", args.sourceChargeId))
93
+ .take(1001);
94
+ if (untransferred.length > 1000)
95
+ throw new Error("Affiliate obligation limit exceeded.");
96
+ for (const row of untransferred)
97
+ if (!row.stripeTransferId)
98
+ await applyObligationExposure(ctx, row, exposure);
99
+ }
100
+ if (existingOp) {
101
+ if (existingOp.sourceChargeId !== args.sourceChargeId)
102
+ throw new Error("Reversal operation source identity cannot change.");
103
+ if (existingOp.commissionExposure && args.commissionExposure) {
104
+ if (existingOp.commissionExposure.kind !== args.commissionExposure.kind ||
105
+ existingOp.commissionExposure.chargeAmount !==
106
+ args.commissionExposure.chargeAmount)
107
+ throw new Error("Commission operation identity cannot change.");
108
+ if (exposure)
109
+ await ctx.db.patch("transferReversalOps", existingOp._id, {
110
+ commissionExposure: exposure,
111
+ });
112
+ }
113
+ const slices = [];
114
+ for (const s of existingOp.slices) {
115
+ slices.push({
116
+ ...s,
117
+ confirmed: await confirmedFor(s.stripeTransferId),
118
+ ...(existingOp.commissionExposure
119
+ ? { commissionTracked: await isAffiliate(s.stripeTransferId) }
120
+ : {}),
121
+ });
122
+ }
123
+ return { replay: true, slices };
124
+ }
125
+ const byId = new Map(rows.map((r) => [r.stripeTransferId, r]));
126
+ let slices = computeReversalSlices(rows.map((t) => ({
127
+ stripeTransferId: t.stripeTransferId,
128
+ amount: t.amount,
129
+ frontier: Math.max(t.reversedAmount ?? 0, t.reversalClaimedAmount ?? 0),
130
+ })), args.mode);
131
+ if (args.commissionExposure) {
132
+ // Keep the shipped seller/other paths; affiliates converge on original
133
+ // commission exposure rather than a second incremental dispute debit.
134
+ const affiliates = rows.filter((t) => t.role === "affiliate");
135
+ slices = slices.filter((s) => byId.get(s.stripeTransferId).role !== "affiliate");
136
+ for (const transfer of affiliates) {
137
+ const target = Math.min(transfer.amount, targets.get(transfer.stripeTransferId) ?? 0);
138
+ const from = Math.max(transfer.reversedAmount ?? 0, transfer.reversalClaimedAmount ?? 0);
139
+ if (target > from)
140
+ slices.push({
141
+ stripeTransferId: transfer.stripeTransferId,
142
+ from,
143
+ to: target,
144
+ });
145
+ }
146
+ }
147
+ for (const s of slices) {
148
+ await ctx.db.patch("transfers", byId.get(s.stripeTransferId)._id, {
149
+ reversalClaimedAmount: s.to,
150
+ });
151
+ }
152
+ // Record the operation even when it claims nothing, so a redelivery is a
153
+ // deterministic no-op instead of a recomputation against newer state.
154
+ await ctx.db.insert("transferReversalOps", {
155
+ operationId: args.operationId,
156
+ sourceChargeId: args.sourceChargeId,
157
+ slices,
158
+ ...(args.commissionExposure
159
+ ? { commissionExposure: args.commissionExposure }
160
+ : {}),
161
+ });
162
+ return {
163
+ replay: false,
164
+ slices: slices.map((s) => ({
165
+ ...s,
166
+ confirmed: byId.get(s.stripeTransferId).reversedAmount ?? 0,
167
+ ...(args.commissionExposure
168
+ ? {
169
+ commissionTracked: byId.get(s.stripeTransferId).role === "affiliate",
170
+ }
171
+ : {}),
172
+ })),
173
+ };
174
+ },
175
+ };
176
+ //# sourceMappingURL=reversalClaims.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversalClaims.js","sourceRoot":"","sources":["../../../src/component/connect/reversalClaims.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import type { QueryCtx } from "../_generated/server.js";
2
+ export declare const listWedgedReversalClaimsDefinition: {
3
+ args: {};
4
+ returns: import("convex/values").VArray<{
5
+ amount: number;
6
+ blockingOps: {
7
+ from: number;
8
+ operationId: string;
9
+ to: number;
10
+ }[];
11
+ reversalClaimedAmount: number;
12
+ reversedAmount: number;
13
+ sourceChargeId?: string | undefined;
14
+ stripeTransferId: string;
15
+ }[], import("convex/values").VObject<{
16
+ amount: number;
17
+ blockingOps: {
18
+ from: number;
19
+ operationId: string;
20
+ to: number;
21
+ }[];
22
+ reversalClaimedAmount: number;
23
+ reversedAmount: number;
24
+ sourceChargeId?: string | undefined;
25
+ stripeTransferId: string;
26
+ }, {
27
+ stripeTransferId: import("convex/values").VString<string, "required">;
28
+ sourceChargeId: import("convex/values").VString<string | undefined, "optional">;
29
+ amount: import("convex/values").VFloat64<number, "required">;
30
+ reversedAmount: import("convex/values").VFloat64<number, "required">;
31
+ reversalClaimedAmount: import("convex/values").VFloat64<number, "required">;
32
+ blockingOps: import("convex/values").VArray<{
33
+ from: number;
34
+ operationId: string;
35
+ to: number;
36
+ }[], import("convex/values").VObject<{
37
+ from: number;
38
+ operationId: string;
39
+ to: number;
40
+ }, {
41
+ operationId: import("convex/values").VString<string, "required">;
42
+ from: import("convex/values").VFloat64<number, "required">;
43
+ to: import("convex/values").VFloat64<number, "required">;
44
+ }, "required", "from" | "operationId" | "to">, "required">;
45
+ }, "required", "amount" | "blockingOps" | "reversalClaimedAmount" | "reversedAmount" | "sourceChargeId" | "stripeTransferId">, "required">;
46
+ handler: (ctx: QueryCtx) => Promise<{
47
+ stripeTransferId: string;
48
+ sourceChargeId: string | undefined;
49
+ amount: number;
50
+ reversedAmount: number;
51
+ reversalClaimedAmount: number;
52
+ blockingOps: {
53
+ operationId: string;
54
+ from: number;
55
+ to: number;
56
+ }[];
57
+ }[]>;
58
+ };
59
+ //# sourceMappingURL=reversalDiagnostics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversalDiagnostics.d.ts","sourceRoot":"","sources":["../../../src/component/connect/reversalDiagnostics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAIxD,eAAO,MAAM,kCAAkC;IAC7C,IAAI;IACJ,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IACP,OAAO,QAAc,QAAQ;;;;;;;yBA6BV,MAAM;kBAAQ,MAAM;gBAAM,MAAM;;;CAuBpD,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { v } from "convex/values";
2
+ import { wedgedReversalClaimValidator } from "./validators.js";
3
+ export const listWedgedReversalClaimsDefinition = {
4
+ args: {},
5
+ returns: v.array(wedgedReversalClaimValidator),
6
+ handler: async (ctx) => {
7
+ // Collect the wedged legs first.
8
+ const wedged = [];
9
+ for await (const tr of ctx.db.query("transfers")) {
10
+ const tracked = tr.role === "affiliate"
11
+ ? await ctx.db
12
+ .query("affiliateObligations")
13
+ .withIndex("by_transfer", (q) => q.eq("stripeTransferId", tr.stripeTransferId))
14
+ .unique()
15
+ : null;
16
+ if (tracked?.accounted)
17
+ continue;
18
+ if ((tr.reversalClaimedAmount ?? 0) > (tr.reversedAmount ?? 0)) {
19
+ wedged.push(tr);
20
+ }
21
+ }
22
+ if (wedged.length === 0)
23
+ return [];
24
+ const wedgedIds = new Set(wedged.map((t) => t.stripeTransferId));
25
+ // Index the ops that hold an unexecuted slice on a wedged leg. A slice is
26
+ // unexecuted when its `to` exceeds the leg's confirmed `reversedAmount`.
27
+ const confirmedById = new Map(wedged.map((t) => [t.stripeTransferId, t.reversedAmount ?? 0]));
28
+ const blockersByLeg = new Map();
29
+ for await (const op of ctx.db.query("transferReversalOps")) {
30
+ for (const s of op.slices) {
31
+ if (!wedgedIds.has(s.stripeTransferId))
32
+ continue;
33
+ if (s.to <= (confirmedById.get(s.stripeTransferId) ?? 0))
34
+ continue;
35
+ const list = blockersByLeg.get(s.stripeTransferId) ?? [];
36
+ list.push({ operationId: op.operationId, from: s.from, to: s.to });
37
+ blockersByLeg.set(s.stripeTransferId, list);
38
+ }
39
+ }
40
+ return wedged.map((t) => ({
41
+ stripeTransferId: t.stripeTransferId,
42
+ sourceChargeId: t.sourceChargeId,
43
+ amount: t.amount,
44
+ reversedAmount: t.reversedAmount ?? 0,
45
+ reversalClaimedAmount: t.reversalClaimedAmount ?? 0,
46
+ blockingOps: (blockersByLeg.get(t.stripeTransferId) ?? []).sort((a, b) => a.from - b.from),
47
+ }));
48
+ },
49
+ };
50
+ //# sourceMappingURL=reversalDiagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversalDiagnostics.js","sourceRoot":"","sources":["../../../src/component/connect/reversalDiagnostics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { MutationCtx } from "../_generated/server.js";
2
+ export declare const recordTransferReversalDefinition: {
3
+ args: {
4
+ stripeTransferId: import("convex/values").VString<string, "required">;
5
+ reversedAmount: import("convex/values").VFloat64<number, "required">;
6
+ receipt: import("convex/values").VObject<{
7
+ amount: number;
8
+ operationId: string;
9
+ stripeReversalId: string;
10
+ } | undefined, {
11
+ stripeReversalId: import("convex/values").VString<string, "required">;
12
+ operationId: import("convex/values").VString<string, "required">;
13
+ amount: import("convex/values").VFloat64<number, "required">;
14
+ }, "optional", "amount" | "operationId" | "stripeReversalId">;
15
+ };
16
+ returns: import("convex/values").VNull<null, "required">;
17
+ handler: (ctx: MutationCtx, args: {
18
+ stripeTransferId: string;
19
+ reversedAmount: number;
20
+ receipt?: {
21
+ stripeReversalId: string;
22
+ operationId: string;
23
+ amount: number;
24
+ };
25
+ }) => Promise<null>;
26
+ };
27
+ //# sourceMappingURL=reversalReceipts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversalReceipts.d.ts","sourceRoot":"","sources":["../../../src/component/connect/reversalReceipts.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAiE3D,eAAO,MAAM,gCAAgC;IAC3C,IAAI;QACF,gBAAgB;QAChB,cAAc;QACd,OAAO;;;;;;;;;;IAQT,OAAO;IACP,OAAO,QACA,WAAW,QACV;QACJ,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,EAAE,MAAM,CAAC;QACvB,OAAO,CAAC,EAAE;YACR,gBAAgB,EAAE,MAAM,CAAC;YACzB,WAAW,EAAE,MAAM,CAAC;YACpB,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH;CAuDJ,CAAC"}
@@ -0,0 +1,85 @@
1
+ import { updateObligation } from "../affiliateRecovery/accounting.js";
2
+ import { v } from "convex/values";
3
+ import { deriveReversalState } from "../lib/reversals.js";
4
+ async function recordCommissionReceipt(ctx, transfer, reversedAmount, receipt) {
5
+ const op = await ctx.db
6
+ .query("transferReversalOps")
7
+ .withIndex("by_operation_id", (q) => q.eq("operationId", receipt.operationId))
8
+ .unique();
9
+ const slice = op?.slices.find((s) => s.stripeTransferId === transfer.stripeTransferId);
10
+ if (transfer.role !== "affiliate" ||
11
+ !op?.commissionExposure ||
12
+ !slice ||
13
+ receipt.amount !== slice.to - slice.from ||
14
+ reversedAmount !== slice.to ||
15
+ !receipt.stripeReversalId)
16
+ throw new Error("Commission reversal receipt does not match its reserved operation.");
17
+ const priorOperationReceipt = await ctx.db
18
+ .query("affiliateReversalReceipts")
19
+ .withIndex("by_transfer_operation", (q) => q
20
+ .eq("stripeTransferId", transfer.stripeTransferId)
21
+ .eq("operationId", receipt.operationId))
22
+ .unique();
23
+ if (priorOperationReceipt &&
24
+ priorOperationReceipt.stripeReversalId !== receipt.stripeReversalId)
25
+ throw new Error("Commission operation already has a different reversal receipt.");
26
+ const existing = await ctx.db
27
+ .query("affiliateReversalReceipts")
28
+ .withIndex("by_receipt", (q) => q.eq("stripeReversalId", receipt.stripeReversalId))
29
+ .unique();
30
+ if (existing) {
31
+ if (existing.stripeTransferId !== transfer.stripeTransferId ||
32
+ existing.operationId !== receipt.operationId ||
33
+ existing.amount !== receipt.amount)
34
+ throw new Error("Commission reversal receipt identity cannot change.");
35
+ }
36
+ else {
37
+ await ctx.db.insert("affiliateReversalReceipts", {
38
+ ...receipt,
39
+ stripeTransferId: transfer.stripeTransferId,
40
+ });
41
+ }
42
+ }
43
+ export const recordTransferReversalDefinition = {
44
+ args: {
45
+ stripeTransferId: v.string(),
46
+ reversedAmount: v.number(),
47
+ receipt: v.optional(v.object({
48
+ stripeReversalId: v.string(),
49
+ operationId: v.string(),
50
+ amount: v.number(),
51
+ })),
52
+ },
53
+ returns: v.null(),
54
+ handler: async (ctx, args) => {
55
+ const transfer = await ctx.db
56
+ .query("transfers")
57
+ .withIndex("by_stripe_transfer_id", (q) => q.eq("stripeTransferId", args.stripeTransferId))
58
+ .first();
59
+ if (!transfer) {
60
+ throw new Error(`Cannot record reversal: no transfer found for ${args.stripeTransferId}`);
61
+ }
62
+ // `reversedAmount` is a cumulative total (matches Stripe's
63
+ // `Transfer.amount_reversed`). Keep it monotonic so a stale/out-of-order
64
+ // event can't shrink it or undo a full reversal.
65
+ const reversedAmount = Math.max(transfer.reversedAmount ?? 0, args.reversedAmount);
66
+ const derived = deriveReversalState(transfer.amount, reversedAmount, transfer.status);
67
+ if (!Number.isSafeInteger(reversedAmount) ||
68
+ reversedAmount < 0 ||
69
+ reversedAmount > transfer.amount)
70
+ throw new Error("Invalid confirmed transfer reversal amount.");
71
+ if (args.receipt)
72
+ await recordCommissionReceipt(ctx, transfer, args.reversedAmount, args.receipt);
73
+ await ctx.db.patch("transfers", transfer._id, derived);
74
+ const obligation = await ctx.db
75
+ .query("affiliateObligations")
76
+ .withIndex("by_transfer", (q) => q.eq("stripeTransferId", args.stripeTransferId))
77
+ .unique();
78
+ if (obligation)
79
+ await updateObligation(ctx, obligation, {
80
+ recoveredAmount: reversedAmount,
81
+ });
82
+ return null;
83
+ },
84
+ };
85
+ //# sourceMappingURL=reversalReceipts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reversalReceipts.js","sourceRoot":"","sources":["../../../src/component/connect/reversalReceipts.ts"],"names":[],"mappings":"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"}