@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.
- package/CHANGELOG.md +27 -2
- package/README.md +46 -5
- package/dist/client/affiliateRecovery/disputes.d.ts +18 -0
- package/dist/client/affiliateRecovery/disputes.d.ts.map +1 -0
- package/dist/client/affiliateRecovery/disputes.js +33 -0
- package/dist/client/affiliateRecovery/disputes.js.map +1 -0
- package/dist/client/affiliateRecovery/engine.d.ts +29 -0
- package/dist/client/affiliateRecovery/engine.d.ts.map +1 -0
- package/dist/client/affiliateRecovery/engine.js +116 -0
- package/dist/client/affiliateRecovery/engine.js.map +1 -0
- package/dist/client/affiliateRecovery/payoutGate.d.ts +24 -0
- package/dist/client/affiliateRecovery/payoutGate.d.ts.map +1 -0
- package/dist/client/affiliateRecovery/payoutGate.js +30 -0
- package/dist/client/affiliateRecovery/payoutGate.js.map +1 -0
- package/dist/client/affiliateRecovery/provider.d.ts +14 -0
- package/dist/client/affiliateRecovery/provider.d.ts.map +1 -0
- package/dist/client/affiliateRecovery/provider.js +96 -0
- package/dist/client/affiliateRecovery/provider.js.map +1 -0
- package/dist/client/affiliateRecovery/review.d.ts +28 -0
- package/dist/client/affiliateRecovery/review.d.ts.map +1 -0
- package/dist/client/affiliateRecovery/review.js +86 -0
- package/dist/client/affiliateRecovery/review.js.map +1 -0
- package/dist/client/affiliateRecovery/validators.d.ts +402 -0
- package/dist/client/affiliateRecovery/validators.d.ts.map +1 -0
- package/dist/client/affiliateRecovery/validators.js +27 -0
- package/dist/client/affiliateRecovery/validators.js.map +1 -0
- package/dist/client/affiliateRecovery.d.ts +131 -0
- package/dist/client/affiliateRecovery.d.ts.map +1 -0
- package/dist/client/affiliateRecovery.js +69 -0
- package/dist/client/affiliateRecovery.js.map +1 -0
- package/dist/client/billing/checkout.d.ts +3 -43
- package/dist/client/billing/checkout.d.ts.map +1 -1
- package/dist/client/billing/checkout.js +5 -260
- package/dist/client/billing/checkout.js.map +1 -1
- package/dist/client/billing/checkoutRequest.d.ts +129 -0
- package/dist/client/billing/checkoutRequest.d.ts.map +1 -0
- package/dist/client/billing/checkoutRequest.js +263 -0
- package/dist/client/billing/checkoutRequest.js.map +1 -0
- package/dist/client/billing/preparedCheckout.d.ts +22 -0
- package/dist/client/billing/preparedCheckout.d.ts.map +1 -0
- package/dist/client/billing/preparedCheckout.js +86 -0
- package/dist/client/billing/preparedCheckout.js.map +1 -0
- package/dist/client/checkoutRequests.d.ts +80 -0
- package/dist/client/checkoutRequests.d.ts.map +1 -0
- package/dist/client/checkoutRequests.js +28 -0
- package/dist/client/checkoutRequests.js.map +1 -0
- package/dist/client/connect/commissionReceipts.d.ts +4 -0
- package/dist/client/connect/commissionReceipts.d.ts.map +1 -0
- package/dist/client/connect/commissionReceipts.js +17 -0
- package/dist/client/connect/commissionReceipts.js.map +1 -0
- package/dist/client/connect/payoutAdoptionTestHelpers.d.ts +958 -2
- package/dist/client/connect/payoutAdoptionTestHelpers.d.ts.map +1 -1
- package/dist/client/connect/payoutCollection.d.ts +21 -0
- package/dist/client/connect/payoutCollection.d.ts.map +1 -0
- package/dist/client/connect/payoutCollection.js +47 -0
- package/dist/client/connect/payoutCollection.js.map +1 -0
- package/dist/client/connect/payoutExecutionTestHelpers.d.ts +1805 -0
- package/dist/client/connect/payoutExecutionTestHelpers.d.ts.map +1 -0
- package/dist/client/connect/payoutExecutionTestHelpers.js +194 -0
- package/dist/client/connect/payoutExecutionTestHelpers.js.map +1 -0
- package/dist/client/connect/payoutSyncTestHelpers.d.ts +479 -1
- package/dist/client/connect/payoutSyncTestHelpers.d.ts.map +1 -1
- package/dist/client/connect/payoutWorker.d.ts +48 -0
- package/dist/client/connect/payoutWorker.d.ts.map +1 -0
- package/dist/client/connect/payoutWorker.js +78 -0
- package/dist/client/connect/payoutWorker.js.map +1 -0
- package/dist/client/connect/payouts.d.ts +3 -1
- package/dist/client/connect/payouts.d.ts.map +1 -1
- package/dist/client/connect/payouts.js +45 -12
- package/dist/client/connect/payouts.js.map +1 -1
- package/dist/client/connect/refundPrincipal.d.ts +4 -0
- package/dist/client/connect/refundPrincipal.d.ts.map +1 -0
- package/dist/client/connect/refundPrincipal.js +21 -0
- package/dist/client/connect/refundPrincipal.js.map +1 -0
- package/dist/client/connect/reversalExecution.d.ts +47 -0
- package/dist/client/connect/reversalExecution.d.ts.map +1 -0
- package/dist/client/connect/reversalExecution.js +84 -0
- package/dist/client/connect/reversalExecution.js.map +1 -0
- package/dist/client/connect/transfers.d.ts +8 -4
- package/dist/client/connect/transfers.d.ts.map +1 -1
- package/dist/client/connect/transfers.js +52 -57
- package/dist/client/connect/transfers.js.map +1 -1
- package/dist/client/index.d.ts +7 -11
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +10 -10
- package/dist/client/index.js.map +1 -1
- package/dist/client/payoutPolicy.d.ts +67 -0
- package/dist/client/payoutPolicy.d.ts.map +1 -1
- package/dist/client/payoutPolicy.js +10 -0
- package/dist/client/payoutPolicy.js.map +1 -1
- package/dist/client/readContracts.d.ts +11 -1
- package/dist/client/readContracts.d.ts.map +1 -1
- package/dist/client/readContracts.js +10 -0
- package/dist/client/readContracts.js.map +1 -1
- package/dist/client/settlement/execution.d.ts.map +1 -1
- package/dist/client/settlement/execution.js +30 -3
- package/dist/client/settlement/execution.js.map +1 -1
- package/dist/client/settlement/reconciliation.d.ts.map +1 -1
- package/dist/client/settlement/reconciliation.js +16 -2
- package/dist/client/settlement/reconciliation.js.map +1 -1
- package/dist/client/webhooks/disputeRecovery.d.ts +4 -0
- package/dist/client/webhooks/disputeRecovery.d.ts.map +1 -0
- package/dist/client/webhooks/disputeRecovery.js +40 -0
- package/dist/client/webhooks/disputeRecovery.js.map +1 -0
- package/dist/client/webhooks/processors.d.ts.map +1 -1
- package/dist/client/webhooks/processors.js +14 -29
- package/dist/client/webhooks/processors.js.map +1 -1
- package/dist/component/_generated/component.d.ts +784 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/affiliateEarnings/mutations.d.ts +22 -0
- package/dist/component/affiliateEarnings/mutations.d.ts.map +1 -0
- package/dist/component/affiliateEarnings/mutations.js +160 -0
- package/dist/component/affiliateEarnings/mutations.js.map +1 -0
- package/dist/component/affiliatePayouts/mutations.d.ts +25 -0
- package/dist/component/affiliatePayouts/mutations.d.ts.map +1 -0
- package/dist/component/affiliatePayouts/mutations.js +104 -0
- package/dist/component/affiliatePayouts/mutations.js.map +1 -0
- package/dist/component/affiliatePayouts/queries.d.ts +23 -0
- package/dist/component/affiliatePayouts/queries.d.ts.map +1 -0
- package/dist/component/affiliatePayouts/queries.js +23 -0
- package/dist/component/affiliatePayouts/queries.js.map +1 -0
- package/dist/component/affiliatePayouts/recipientGuard.d.ts +12 -0
- package/dist/component/affiliatePayouts/recipientGuard.d.ts.map +1 -0
- package/dist/component/affiliatePayouts/recipientGuard.js +26 -0
- package/dist/component/affiliatePayouts/recipientGuard.js.map +1 -0
- package/dist/component/affiliateRecovery/accounting.d.ts +28 -0
- package/dist/component/affiliateRecovery/accounting.d.ts.map +1 -0
- package/dist/component/affiliateRecovery/accounting.js +71 -0
- package/dist/component/affiliateRecovery/accounting.js.map +1 -0
- package/dist/component/affiliateRecovery/mutations.d.ts +65 -0
- package/dist/component/affiliateRecovery/mutations.d.ts.map +1 -0
- package/dist/component/affiliateRecovery/mutations.js +250 -0
- package/dist/component/affiliateRecovery/mutations.js.map +1 -0
- package/dist/component/affiliateRecovery/queries.d.ts +305 -0
- package/dist/component/affiliateRecovery/queries.d.ts.map +1 -0
- package/dist/component/affiliateRecovery/queries.js +113 -0
- package/dist/component/affiliateRecovery/queries.js.map +1 -0
- package/dist/component/affiliateRecovery/schema.d.ts +171 -0
- package/dist/component/affiliateRecovery/schema.d.ts.map +1 -0
- package/dist/component/affiliateRecovery/schema.js +71 -0
- package/dist/component/affiliateRecovery/schema.js.map +1 -0
- package/dist/component/connect/mutations.d.ts +36 -23
- package/dist/component/connect/mutations.d.ts.map +1 -1
- package/dist/component/connect/mutations.js +7 -124
- package/dist/component/connect/mutations.js.map +1 -1
- package/dist/component/connect/queries.d.ts +10 -0
- package/dist/component/connect/queries.d.ts.map +1 -1
- package/dist/component/connect/queries.js +3 -40
- package/dist/component/connect/queries.js.map +1 -1
- package/dist/component/connect/reversalClaims.d.ts +169 -0
- package/dist/component/connect/reversalClaims.d.ts.map +1 -0
- package/dist/component/connect/reversalClaims.js +176 -0
- package/dist/component/connect/reversalClaims.js.map +1 -0
- package/dist/component/connect/reversalDiagnostics.d.ts +59 -0
- package/dist/component/connect/reversalDiagnostics.d.ts.map +1 -0
- package/dist/component/connect/reversalDiagnostics.js +50 -0
- package/dist/component/connect/reversalDiagnostics.js.map +1 -0
- package/dist/component/connect/reversalReceipts.d.ts +27 -0
- package/dist/component/connect/reversalReceipts.d.ts.map +1 -0
- package/dist/component/connect/reversalReceipts.js +85 -0
- package/dist/component/connect/reversalReceipts.js.map +1 -0
- package/dist/component/connect/schema.d.ts +31 -1
- package/dist/component/connect/schema.d.ts.map +1 -1
- package/dist/component/connect/schema.js +3 -1
- package/dist/component/connect/schema.js.map +1 -1
- package/dist/component/connect/validators.d.ts +49 -1
- package/dist/component/connect/validators.d.ts.map +1 -1
- package/dist/component/connect/validators.js +2 -0
- package/dist/component/connect/validators.js.map +1 -1
- package/dist/component/core/mutations.d.ts.map +1 -1
- package/dist/component/core/mutations.js +2 -0
- package/dist/component/core/mutations.js.map +1 -1
- package/dist/component/core/resetSafety.d.ts +4 -0
- package/dist/component/core/resetSafety.d.ts.map +1 -0
- package/dist/component/core/resetSafety.js +54 -0
- package/dist/component/core/resetSafety.js.map +1 -0
- package/dist/component/earnings/triggers.d.ts +828 -2
- package/dist/component/earnings/triggers.d.ts.map +1 -1
- package/dist/component/earnings/triggers.js +2 -0
- package/dist/component/earnings/triggers.js.map +1 -1
- package/dist/component/payoutPolicy/schema.d.ts +2 -0
- package/dist/component/payoutPolicy/schema.d.ts.map +1 -1
- package/dist/component/payoutPolicy/schema.js +3 -1
- package/dist/component/payoutPolicy/schema.js.map +1 -1
- package/dist/component/payoutRelease/mutations.d.ts.map +1 -1
- package/dist/component/payoutRelease/mutations.js +7 -1
- package/dist/component/payoutRelease/mutations.js.map +1 -1
- package/dist/component/payoutRelease/queries.d.ts.map +1 -1
- package/dist/component/payoutRelease/queries.js +3 -1
- package/dist/component/payoutRelease/queries.js.map +1 -1
- package/dist/component/payoutRelease/schema.d.ts +1 -0
- package/dist/component/payoutRelease/schema.d.ts.map +1 -1
- package/dist/component/payoutRelease/schema.js +1 -0
- package/dist/component/payoutRelease/schema.js.map +1 -1
- package/dist/component/payoutSnapshots/localState.d.ts +89 -0
- package/dist/component/payoutSnapshots/localState.d.ts.map +1 -0
- package/dist/component/payoutSnapshots/localState.js +186 -0
- package/dist/component/payoutSnapshots/localState.js.map +1 -0
- package/dist/component/payoutSnapshots/mutations.d.ts +108 -0
- package/dist/component/payoutSnapshots/mutations.d.ts.map +1 -0
- package/dist/component/payoutSnapshots/mutations.js +263 -0
- package/dist/component/payoutSnapshots/mutations.js.map +1 -0
- package/dist/component/payoutSnapshots/revisions.d.ts +12 -0
- package/dist/component/payoutSnapshots/revisions.d.ts.map +1 -0
- package/dist/component/payoutSnapshots/revisions.js +173 -0
- package/dist/component/payoutSnapshots/revisions.js.map +1 -0
- package/dist/component/payoutSnapshots/schema.d.ts +285 -0
- package/dist/component/payoutSnapshots/schema.d.ts.map +1 -0
- package/dist/component/payoutSnapshots/schema.js +108 -0
- package/dist/component/payoutSnapshots/schema.js.map +1 -0
- package/dist/component/payoutSnapshots/scope.d.ts +7 -0
- package/dist/component/payoutSnapshots/scope.d.ts.map +1 -0
- package/dist/component/payoutSnapshots/scope.js +8 -0
- package/dist/component/payoutSnapshots/scope.js.map +1 -0
- package/dist/component/payoutWorker/helpers.d.ts +30 -0
- package/dist/component/payoutWorker/helpers.d.ts.map +1 -0
- package/dist/component/payoutWorker/helpers.js +21 -0
- package/dist/component/payoutWorker/helpers.js.map +1 -0
- package/dist/component/payoutWorker/mutations.d.ts +68 -0
- package/dist/component/payoutWorker/mutations.d.ts.map +1 -0
- package/dist/component/payoutWorker/mutations.js +161 -0
- package/dist/component/payoutWorker/mutations.js.map +1 -0
- package/dist/component/payoutWorker/queries.d.ts +123 -0
- package/dist/component/payoutWorker/queries.d.ts.map +1 -0
- package/dist/component/payoutWorker/queries.js +61 -0
- package/dist/component/payoutWorker/queries.js.map +1 -0
- package/dist/component/payoutWorker/schema.d.ts +91 -0
- package/dist/component/payoutWorker/schema.d.ts.map +1 -0
- package/dist/component/payoutWorker/schema.js +27 -0
- package/dist/component/payoutWorker/schema.js.map +1 -0
- package/dist/component/schema.d.ts +479 -1
- package/dist/component/schema.js +19 -0
- package/dist/component/schema.js.map +1 -1
- package/dist/component/settlement/clawbackSchema.d.ts +161 -0
- package/dist/component/settlement/clawbackSchema.d.ts.map +1 -0
- package/dist/component/settlement/clawbackSchema.js +73 -0
- package/dist/component/settlement/clawbackSchema.js.map +1 -0
- package/dist/component/settlement/clawbacks.d.ts +55 -0
- package/dist/component/settlement/clawbacks.d.ts.map +1 -0
- package/dist/component/settlement/clawbacks.js +146 -0
- package/dist/component/settlement/clawbacks.js.map +1 -0
- package/dist/component/settlement/mutations.d.ts +16 -0
- package/dist/component/settlement/mutations.d.ts.map +1 -1
- package/dist/component/settlement/mutations.js +48 -0
- package/dist/component/settlement/mutations.js.map +1 -1
- package/dist/component/settlement/queries.d.ts +53 -0
- package/dist/component/settlement/queries.d.ts.map +1 -1
- package/dist/component/settlement/queries.js +26 -0
- package/dist/component/settlement/queries.js.map +1 -1
- package/dist/react/workflows/AffiliateRecovery.d.ts +46 -0
- package/dist/react/workflows/AffiliateRecovery.d.ts.map +1 -0
- package/dist/react/workflows/AffiliateRecovery.js +84 -0
- package/dist/react/workflows/AffiliateRecovery.js.map +1 -0
- package/dist/react/workflows/index.d.ts +2 -0
- package/dist/react/workflows/index.d.ts.map +1 -1
- package/dist/react/workflows/index.js +1 -0
- package/dist/react/workflows/index.js.map +1 -1
- package/dist/testing/affiliate-recovery.d.ts +10 -0
- package/dist/testing/affiliate-recovery.d.ts.map +1 -0
- package/dist/testing/affiliate-recovery.js +126 -0
- package/dist/testing/affiliate-recovery.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -1
- package/dist/testing/index.js +1 -0
- package/dist/testing/index.js.map +1 -1
- package/docs/affiliate-clawbacks.md +306 -0
- package/docs/read-contracts.md +48 -0
- package/docs/settlement.md +145 -1
- package/package.json +2 -1
- package/src/client/affiliateRecovery/disputes.ts +62 -0
- package/src/client/affiliateRecovery/engine.ts +196 -0
- package/src/client/affiliateRecovery/payoutGate.ts +65 -0
- package/src/client/affiliateRecovery/provider.ts +127 -0
- package/src/client/affiliateRecovery/review.ts +117 -0
- package/src/client/affiliateRecovery/validators.ts +38 -0
- package/src/client/affiliateRecovery.ts +173 -0
- package/src/client/billing/checkout.ts +11 -359
- package/src/client/billing/checkoutRequest.ts +362 -0
- package/src/client/billing/prepared-checkout.test.ts +430 -0
- package/src/client/billing/preparedCheckout.ts +143 -0
- package/src/client/checkoutRequests.ts +40 -0
- package/src/client/connect/commissionReceipts.test.ts +157 -0
- package/src/client/connect/commissionReceipts.ts +23 -0
- package/src/client/connect/payoutCollection.test.ts +74 -0
- package/src/client/connect/payoutCollection.ts +82 -0
- package/src/client/connect/payoutExecution.test.ts +1 -211
- package/src/client/connect/payoutExecutionTestHelpers.ts +213 -0
- package/src/client/connect/payoutWorker.test.ts +145 -0
- package/src/client/connect/payoutWorker.ts +144 -0
- package/src/client/connect/payouts.ts +75 -15
- package/src/client/connect/refundPrincipal.test.ts +46 -0
- package/src/client/connect/refundPrincipal.ts +26 -0
- package/src/client/connect/reversalExecution.ts +130 -0
- package/src/client/connect/transfers.test.ts +3 -3
- package/src/client/connect/transfers.ts +93 -92
- package/src/client/index.ts +16 -28
- package/src/client/payoutPolicy.ts +26 -1
- package/src/client/readContracts.ts +23 -0
- package/src/client/settlement/execution.test.ts +5 -0
- package/src/client/settlement/execution.ts +50 -3
- package/src/client/settlement/reconciliation.ts +20 -2
- package/src/client/webhooks/disputeRecovery.ts +74 -0
- package/src/client/webhooks/processors.test.ts +36 -53
- package/src/client/webhooks/processors.ts +18 -31
- package/src/component/_generated/api.ts +40 -0
- package/src/component/_generated/component.ts +975 -1
- package/src/component/affiliate-clawbacks.test.ts +370 -0
- package/src/component/affiliate-component-pagination.test.ts +83 -0
- package/src/component/affiliate-direct-payout.test.ts +160 -0
- package/src/component/affiliate-recovery-lifecycle.test.ts +587 -0
- package/src/component/affiliateEarnings/mutations.ts +196 -0
- package/src/component/affiliatePayouts/mutations.ts +121 -0
- package/src/component/affiliatePayouts/queries.ts +28 -0
- package/src/component/affiliatePayouts/recipientGuard.ts +42 -0
- package/src/component/affiliateRecovery/accounting.ts +111 -0
- package/src/component/affiliateRecovery/mutations.ts +275 -0
- package/src/component/affiliateRecovery/queries.ts +138 -0
- package/src/component/affiliateRecovery/schema.ts +86 -0
- package/src/component/connect/mutations.ts +9 -160
- package/src/component/connect/queries.ts +4 -47
- package/src/component/connect/reversalClaims.ts +232 -0
- package/src/component/connect/reversalDiagnostics.ts +61 -0
- package/src/component/connect/reversalReceipts.ts +147 -0
- package/src/component/connect/schema.ts +3 -3
- package/src/component/connect/validators.ts +2 -0
- package/src/component/core/mutations.ts +2 -0
- package/src/component/core/resetSafety.ts +67 -0
- package/src/component/earnings/triggers.ts +2 -0
- package/src/component/payout-recovery-integration.test.ts +172 -0
- package/src/component/payout-reset-safety.test.ts +148 -0
- package/src/component/payout-revisions.test.ts +125 -0
- package/src/component/payout-snapshots.test.ts +395 -0
- package/src/component/payout-worker.test.ts +165 -0
- package/src/component/payoutPolicy/schema.ts +3 -1
- package/src/component/payoutRelease/mutations.ts +10 -1
- package/src/component/payoutRelease/queries.ts +3 -1
- package/src/component/payoutRelease/schema.ts +1 -0
- package/src/component/payoutSnapshots/localState.ts +238 -0
- package/src/component/payoutSnapshots/mutations.ts +275 -0
- package/src/component/payoutSnapshots/revisions.ts +247 -0
- package/src/component/payoutSnapshots/schema.ts +125 -0
- package/src/component/payoutSnapshots/scope.ts +7 -0
- package/src/component/payoutWorker/helpers.ts +30 -0
- package/src/component/payoutWorker/mutations.ts +181 -0
- package/src/component/payoutWorker/queries.ts +64 -0
- package/src/component/payoutWorker/schema.ts +26 -0
- package/src/component/public.test.ts +2 -2
- package/src/component/schema.ts +36 -0
- package/src/component/settlement/clawbackSchema.ts +78 -0
- package/src/component/settlement/clawbacks.ts +233 -0
- package/src/component/settlement/mutations.ts +54 -0
- package/src/component/settlement/queries.ts +35 -0
- package/src/component/summary-arithmetic.test.ts +9 -4
- package/src/react/workflows/AffiliateRecovery.test.tsx +106 -0
- package/src/react/workflows/AffiliateRecovery.tsx +273 -0
- package/src/react/workflows/index.ts +9 -0
- package/src/testing/affiliate-recovery.ts +137 -0
- 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(
|
|
354
|
-
expect(ctx.runMutation.mock.calls[
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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({
|
|
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
|
-
{
|
|
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
|
|
393
|
-
*
|
|
394
|
-
*
|
|
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
|
-
/**
|
|
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
|
-
|
|
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: {
|
|
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
|
-
|
|
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.
|
package/src/client/index.ts
CHANGED
|
@@ -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");
|