@fantastic.dev/better-stripe 0.20.1 → 0.22.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 +12 -0
- package/README.md +16 -5
- package/dist/client/connect/payoutExecution.d.ts +34 -0
- package/dist/client/connect/payoutExecution.d.ts.map +1 -0
- package/dist/client/connect/payoutExecution.js +189 -0
- package/dist/client/connect/payoutExecution.js.map +1 -0
- package/dist/client/connect/payoutHistory.d.ts +22 -0
- package/dist/client/connect/payoutHistory.d.ts.map +1 -0
- package/dist/client/connect/payoutHistory.js +122 -0
- package/dist/client/connect/payoutHistory.js.map +1 -0
- package/dist/client/connect/payoutReceipt.d.ts +53 -0
- package/dist/client/connect/payoutReceipt.d.ts.map +1 -0
- package/dist/client/connect/payoutReceipt.js +185 -0
- package/dist/client/connect/payoutReceipt.js.map +1 -0
- package/dist/client/connect/payoutReconciliation.d.ts +38 -0
- package/dist/client/connect/payoutReconciliation.d.ts.map +1 -0
- package/dist/client/connect/payoutReconciliation.js +112 -0
- package/dist/client/connect/payoutReconciliation.js.map +1 -0
- package/dist/client/payoutPolicy.d.ts +9 -0
- package/dist/client/payoutPolicy.d.ts.map +1 -1
- package/dist/client/payoutPolicy.js +12 -0
- package/dist/client/payoutPolicy.js.map +1 -1
- package/dist/component/_generated/component.d.ts +112 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/earnings/triggers.d.ts +52 -2
- package/dist/component/earnings/triggers.d.ts.map +1 -1
- package/dist/component/payoutRelease/allocation.d.ts +1 -0
- package/dist/component/payoutRelease/allocation.d.ts.map +1 -1
- package/dist/component/payoutRelease/allocation.js +3 -0
- package/dist/component/payoutRelease/allocation.js.map +1 -1
- package/dist/component/payoutRelease/fees.d.ts +22 -0
- package/dist/component/payoutRelease/fees.d.ts.map +1 -0
- package/dist/component/payoutRelease/fees.js +73 -0
- package/dist/component/payoutRelease/fees.js.map +1 -0
- package/dist/component/payoutRelease/helpers.d.ts +5 -0
- package/dist/component/payoutRelease/helpers.d.ts.map +1 -1
- package/dist/component/payoutRelease/mutations.d.ts +29 -0
- package/dist/component/payoutRelease/mutations.d.ts.map +1 -1
- package/dist/component/payoutRelease/mutations.js +24 -1
- package/dist/component/payoutRelease/mutations.js.map +1 -1
- package/dist/component/payoutRelease/queries.d.ts +87 -0
- package/dist/component/payoutRelease/queries.d.ts.map +1 -1
- package/dist/component/payoutRelease/queries.js +39 -0
- package/dist/component/payoutRelease/queries.js.map +1 -1
- package/dist/component/payoutRelease/schema.d.ts +43 -2
- package/dist/component/payoutRelease/schema.d.ts.map +1 -1
- package/dist/component/payoutRelease/schema.js +12 -0
- package/dist/component/payoutRelease/schema.js.map +1 -1
- package/dist/component/schema.d.ts +27 -1
- package/dist/component/schema.js +2 -1
- package/dist/component/schema.js.map +1 -1
- package/docs/settlement.md +134 -3
- package/package.json +1 -1
- package/src/client/connect/payoutAllocation.test.ts +36 -3
- package/src/client/connect/payoutExecution.test.ts +504 -0
- package/src/client/connect/payoutExecution.ts +265 -0
- package/src/client/connect/payoutHistory.test.ts +145 -0
- package/src/client/connect/payoutHistory.ts +149 -0
- package/src/client/connect/payoutReceipt.test.ts +312 -0
- package/src/client/connect/payoutReceipt.ts +287 -0
- package/src/client/connect/payoutReconciliation.test.ts +398 -0
- package/src/client/connect/payoutReconciliation.ts +178 -0
- package/src/client/payoutPolicy.ts +30 -0
- package/src/component/_generated/api.ts +2 -0
- package/src/component/_generated/component.ts +118 -0
- package/src/component/payout-fees.test.ts +224 -0
- package/src/component/payout-release-snapshot.test.ts +57 -0
- package/src/component/payoutRelease/allocation.ts +6 -0
- package/src/component/payoutRelease/fees.ts +93 -0
- package/src/component/payoutRelease/mutations.ts +26 -1
- package/src/component/payoutRelease/queries.ts +46 -0
- package/src/component/payoutRelease/schema.ts +13 -0
- package/src/component/schema.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,18 @@
|
|
|
14
14
|
- Remove internal tracker references from public documentation and add a
|
|
15
15
|
regression check that prevents their reintroduction.
|
|
16
16
|
|
|
17
|
+
## [0.22.0](https://github.com/FantasticDevHQ/better-stripe/compare/v0.21.0...v0.22.0) (2026-10-15)
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
- **payouts:** qualify and execute combined recipient releases ([#189](https://github.com/FantasticDevHQ/better-stripe/issues/189)) ([08f4cec](https://github.com/FantasticDevHQ/better-stripe/commit/08f4cecf004635caa42255d4171206e35bda181c))
|
|
22
|
+
|
|
23
|
+
## [0.21.0](https://github.com/FantasticDevHQ/better-stripe/compare/v0.20.1...v0.21.0) (2026-10-15)
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
- **payouts:** reconcile verified payout outcomes and fees ([#187](https://github.com/FantasticDevHQ/better-stripe/issues/187)) ([7f14edb](https://github.com/FantasticDevHQ/better-stripe/commit/7f14edb93dcc2c7808f1e3e3f3a8dbe2ff84ad3d))
|
|
28
|
+
|
|
17
29
|
## [0.20.1](https://github.com/FantasticDevHQ/better-stripe/compare/v0.20.0...v0.20.1) (2026-10-15)
|
|
18
30
|
|
|
19
31
|
### Documentation
|
package/README.md
CHANGED
|
@@ -42,14 +42,18 @@ deadline-expiry API. See [policy setup and limits](docs/settlement.md#recipient-
|
|
|
42
42
|
A [recipient funding reader](docs/settlement.md#verified-recipient-funding-receipts)
|
|
43
43
|
verifies original and reversal receipts, maturity, and exact settlement amounts;
|
|
44
44
|
received credit is kept distinct from still-unpaid entitlement.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
A [payout receipt and reconciliation API](docs/settlement.md#verified-payout-receipts-and-reconciliation)
|
|
46
|
+
verifies actual bank-payout debits and returns, adopts an attempted claim's
|
|
47
|
+
provider outcome, and books its net payout fees once.
|
|
48
|
+
The [combined release API](docs/settlement.md#combined-recipient-release) verifies
|
|
49
|
+
complete source and payout history, reserves mature unpaid funds, and creates an
|
|
50
|
+
idempotent bank payout. Install a host job to invoke it and expire due policies.
|
|
51
|
+
Existing unallocated balances, larger histories and other debit allocations still
|
|
52
|
+
require migration; schedule controls alone do not enforce a minimum.
|
|
49
53
|
|
|
50
54
|
## Status
|
|
51
55
|
|
|
52
|
-
**Version**: `0.
|
|
56
|
+
**Version**: `0.22.0` <!-- x-release-please-version --> (pre-1.0). API may change between minor versions until 1.0.
|
|
53
57
|
|
|
54
58
|
Used in production by its authors. Webhook pipeline is covered by unit tests and a live E2E harness (`npm run e2e:webhooks`) that fires real Stripe-signed events and asserts the ledger.
|
|
55
59
|
|
|
@@ -131,6 +135,13 @@ existing integration to this API version.
|
|
|
131
135
|
|
|
132
136
|
The component ships committed Convex codegen output at `src/component/_generated/{api,component,dataModel,server}.ts` — consumers reach the bindings via the `./_generated/component` subpath export. The example app also commits its own codegen at `example/convex/_generated/`. Running `pnpm dev` (which wraps `convex dev`) regenerates these automatically when the schema or function definitions change, but only against the live dev deployment and only while the dev server is watching.
|
|
133
137
|
|
|
138
|
+
The example resolves the workspace package through `dist/`. After changing
|
|
139
|
+
component source, regenerate library bindings with `pnpm codegen:lib`, run
|
|
140
|
+
`pnpm build`, then deploy the rebuilt component from the example directory with
|
|
141
|
+
`pnpm exec convex dev --once`. Run `pnpm codegen:example` afterward. Code generation
|
|
142
|
+
alone does not prove that a newly added function is mounted; invoke a representative
|
|
143
|
+
query or action against the development deployment before running financial tests.
|
|
144
|
+
|
|
134
145
|
If you add, remove, or rename a query/mutation/action on a branch without the dev server watching — or after a rebase — regenerate explicitly before committing:
|
|
135
146
|
|
|
136
147
|
```bash
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
import type { Infer } from "convex/values";
|
|
3
|
+
import type { Component, RunCtx } from "../helpers.js";
|
|
4
|
+
import type { policyDoc } from "../../component/payoutPolicy/schema.js";
|
|
5
|
+
import { type PayoutReconciliation } from "./payoutReconciliation.js";
|
|
6
|
+
type Policy = Infer<typeof policyDoc>;
|
|
7
|
+
export type PayoutReleaseOptions = {
|
|
8
|
+
accountId: string;
|
|
9
|
+
ownerKey: string;
|
|
10
|
+
operationKey: string;
|
|
11
|
+
currency: string;
|
|
12
|
+
/** Host supplies all authorized off-provider debts/reserves, without double counting provider receipt debits. */
|
|
13
|
+
independentLiabilities: number;
|
|
14
|
+
maxPages?: number;
|
|
15
|
+
};
|
|
16
|
+
type Held = {
|
|
17
|
+
status: "held";
|
|
18
|
+
reason: string;
|
|
19
|
+
};
|
|
20
|
+
export type PayoutReleaseResult = PayoutReconciliation | Held;
|
|
21
|
+
/**
|
|
22
|
+
* Complete receipt qualification followed by an atomic claim and one immutable
|
|
23
|
+
* provider request. Host authorizes the recipient, policy, operation and known
|
|
24
|
+
* off-provider liabilities. Attempted operations only reconcile on subsequent
|
|
25
|
+
* calls; they are never blindly recreated after an unknown provider outcome.
|
|
26
|
+
*/
|
|
27
|
+
export declare function releaseRecipientPayout(stripe: Stripe, component: Component, ctx: RunCtx, opts: PayoutReleaseOptions, verify: () => Promise<{
|
|
28
|
+
status: "verified";
|
|
29
|
+
policy: Policy;
|
|
30
|
+
} | {
|
|
31
|
+
status: string;
|
|
32
|
+
}>): Promise<PayoutReleaseResult>;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=payoutExecution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payoutExecution.d.ts","sourceRoot":"","sources":["../../../src/client/connect/payoutExecution.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAKvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wCAAwC,CAAC;AAUxE,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,2BAA2B,CAAC;AAEnC,KAAK,MAAM,GAAG,KAAK,CAAC,OAAO,SAAS,CAAC,CAAC;AACtC,MAAM,MAAM,oBAAoB,GAAG;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,iHAAiH;IACjH,sBAAsB,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AACF,KAAK,IAAI,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAC/C,MAAM,MAAM,mBAAmB,GAAG,oBAAoB,GAAG,IAAI,CAAC;AAQ9D;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,oBAAoB,EAC1B,MAAM,EAAE,MAAM,OAAO,CACnB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAC5D,GACA,OAAO,CAAC,mBAAmB,CAAC,CAiN9B"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { runMutationOrThrow } from "../helpers.js";
|
|
2
|
+
import { componentRef } from "../webhooks/helpers.js";
|
|
3
|
+
import { transferFingerprint, validateIdentity, } from "../../component/payoutRelease/helpers.js";
|
|
4
|
+
import { getTransferFundingReceipt, } from "./transferReceipt.js";
|
|
5
|
+
import { verifyPayoutHistory } from "./payoutHistory.js";
|
|
6
|
+
import { reconcileRecipientPayout, } from "./payoutReconciliation.js";
|
|
7
|
+
/**
|
|
8
|
+
* Complete receipt qualification followed by an atomic claim and one immutable
|
|
9
|
+
* provider request. Host authorizes the recipient, policy, operation and known
|
|
10
|
+
* off-provider liabilities. Attempted operations only reconcile on subsequent
|
|
11
|
+
* calls; they are never blindly recreated after an unknown provider outcome.
|
|
12
|
+
*/
|
|
13
|
+
export async function releaseRecipientPayout(stripe, component, ctx, opts, verify) {
|
|
14
|
+
validateIdentity(opts);
|
|
15
|
+
if (!/^[a-z]{3}$/.test(opts.currency) ||
|
|
16
|
+
!Number.isSafeInteger(opts.independentLiabilities) ||
|
|
17
|
+
opts.independentLiabilities < 0)
|
|
18
|
+
throw new Error("Invalid payout currency or independent liabilities.");
|
|
19
|
+
const maxPages = opts.maxPages ?? 10;
|
|
20
|
+
if (!Number.isInteger(maxPages) || maxPages < 1 || maxPages > 100)
|
|
21
|
+
throw new Error("Payout page budget must be between 1 and 100.");
|
|
22
|
+
if (!ctx.runMutation)
|
|
23
|
+
throw new Error("Payout release requires runMutation.");
|
|
24
|
+
const identity = {
|
|
25
|
+
accountId: opts.accountId,
|
|
26
|
+
ownerKey: opts.ownerKey,
|
|
27
|
+
operationKey: opts.operationKey,
|
|
28
|
+
};
|
|
29
|
+
const existing = (await ctx.runQuery(componentRef(component, "payoutRelease/queries/get"), identity));
|
|
30
|
+
if (existing) {
|
|
31
|
+
if (existing.currency !== opts.currency)
|
|
32
|
+
throw new Error("Payout claim currency cannot be changed.");
|
|
33
|
+
if (existing.attemptedAt !== undefined || existing.status !== "reserved")
|
|
34
|
+
return reconcileRecipientPayout(stripe, component, ctx, {
|
|
35
|
+
...identity,
|
|
36
|
+
maxPages,
|
|
37
|
+
});
|
|
38
|
+
// A crash before the attempt has no provider side effect. Release its exact
|
|
39
|
+
// reservations; the next scheduled operation must collect fresh receipts.
|
|
40
|
+
const claim = (await runMutationOrThrow(ctx, componentRef(component, "payoutRelease/mutations/cancelUnattempted"), identity));
|
|
41
|
+
return { status: "terminal", claim };
|
|
42
|
+
}
|
|
43
|
+
const controls = await verify();
|
|
44
|
+
if (controls.status !== "verified" || !("policy" in controls))
|
|
45
|
+
return { status: "held", reason: controls.status };
|
|
46
|
+
const snapshot = (await ctx.runQuery(componentRef(component, "payoutRelease/queries/snapshot"), { accountId: opts.accountId, ownerKey: opts.ownerKey }));
|
|
47
|
+
if (snapshot.status !== "ready")
|
|
48
|
+
return snapshot;
|
|
49
|
+
const banks = [];
|
|
50
|
+
let bankCursor;
|
|
51
|
+
for (let page = 0;; page++) {
|
|
52
|
+
if (page >= maxPages)
|
|
53
|
+
return { status: "held", reason: "bank_history_incomplete" };
|
|
54
|
+
const batch = await stripe.accounts.listExternalAccounts(opts.accountId, {
|
|
55
|
+
object: "bank_account",
|
|
56
|
+
limit: 100,
|
|
57
|
+
...(bankCursor ? { starting_after: bankCursor } : {}),
|
|
58
|
+
});
|
|
59
|
+
for (const bank of batch.data)
|
|
60
|
+
if (bank.object === "bank_account" &&
|
|
61
|
+
bank.currency === opts.currency &&
|
|
62
|
+
bank.default_for_currency &&
|
|
63
|
+
bank.status !== "errored")
|
|
64
|
+
banks.push(bank.id);
|
|
65
|
+
if (!batch.has_more)
|
|
66
|
+
break;
|
|
67
|
+
const next = batch.data[batch.data.length - 1]?.id;
|
|
68
|
+
if (!next || next === bankCursor)
|
|
69
|
+
return { status: "held", reason: "bank_history_incomplete" };
|
|
70
|
+
bankCursor = next;
|
|
71
|
+
}
|
|
72
|
+
if (banks.length !== 1 || !/^ba_\w+$/.test(banks[0]))
|
|
73
|
+
return { status: "held", reason: "bank_destination_unavailable" };
|
|
74
|
+
const destinationId = banks[0];
|
|
75
|
+
const transactions = [];
|
|
76
|
+
for (const claim of snapshot.claims) {
|
|
77
|
+
if (claim.currency !== opts.currency ||
|
|
78
|
+
claim.status === "canceled" ||
|
|
79
|
+
claim.status === "rejected")
|
|
80
|
+
continue;
|
|
81
|
+
if (claim.attemptedAt === undefined)
|
|
82
|
+
return { status: "held", reason: "pending_claim" };
|
|
83
|
+
const result = await reconcileRecipientPayout(stripe, component, ctx, {
|
|
84
|
+
accountId: opts.accountId,
|
|
85
|
+
ownerKey: opts.ownerKey,
|
|
86
|
+
operationKey: claim.operationKey,
|
|
87
|
+
maxPages,
|
|
88
|
+
});
|
|
89
|
+
if (result.status !== "updated")
|
|
90
|
+
return result;
|
|
91
|
+
for (const t of [result.receipt.debit, result.receipt.credit])
|
|
92
|
+
if (t)
|
|
93
|
+
transactions.push({ ...t, sourceId: result.receipt.stripePayoutId });
|
|
94
|
+
}
|
|
95
|
+
const observations = [];
|
|
96
|
+
for (const row of snapshot.transfers) {
|
|
97
|
+
const receipt = await getTransferFundingReceipt(stripe, component, ctx, {
|
|
98
|
+
accountId: opts.accountId,
|
|
99
|
+
stripeTransferId: row.stripeTransferId,
|
|
100
|
+
});
|
|
101
|
+
if (receipt.status !== "ready")
|
|
102
|
+
return { status: "held", reason: receipt.reason };
|
|
103
|
+
observations.push({
|
|
104
|
+
stripeTransferId: row.stripeTransferId,
|
|
105
|
+
currency: receipt.settlementCurrency,
|
|
106
|
+
matureNet: receipt.matureNet,
|
|
107
|
+
pendingCredits: receipt.pendingCredits,
|
|
108
|
+
ledgerFingerprint: transferFingerprint(row),
|
|
109
|
+
observedAt: receipt.observedAt,
|
|
110
|
+
transactionIds: receipt.transactions.map((t) => t.id),
|
|
111
|
+
});
|
|
112
|
+
if (receipt.settlementCurrency === opts.currency)
|
|
113
|
+
transactions.push(...receipt.transactions);
|
|
114
|
+
}
|
|
115
|
+
const history = await verifyPayoutHistory(stripe, {
|
|
116
|
+
accountId: opts.accountId,
|
|
117
|
+
currency: opts.currency,
|
|
118
|
+
transactions,
|
|
119
|
+
maxPages,
|
|
120
|
+
});
|
|
121
|
+
if (history.status !== "verified")
|
|
122
|
+
return history;
|
|
123
|
+
const claim = (await runMutationOrThrow(ctx, componentRef(component, "payoutRelease/mutations/claim"), {
|
|
124
|
+
...identity,
|
|
125
|
+
expectedRevision: controls.policy.revision,
|
|
126
|
+
currency: opts.currency,
|
|
127
|
+
destinationId,
|
|
128
|
+
providerAvailable: history.providerAvailable,
|
|
129
|
+
independentLiabilities: opts.independentLiabilities,
|
|
130
|
+
observations,
|
|
131
|
+
}));
|
|
132
|
+
if (claim.status === "held")
|
|
133
|
+
return claim;
|
|
134
|
+
// Another caller can win this operation while receipts were being collected.
|
|
135
|
+
if (claim.attemptedAt !== undefined || claim.status !== "reserved")
|
|
136
|
+
return reconcileRecipientPayout(stripe, component, ctx, {
|
|
137
|
+
...identity,
|
|
138
|
+
maxPages,
|
|
139
|
+
});
|
|
140
|
+
const latest = await verify();
|
|
141
|
+
if (latest.status !== "verified" ||
|
|
142
|
+
!("policy" in latest) ||
|
|
143
|
+
latest.policy.revision !== controls.policy.revision) {
|
|
144
|
+
await runMutationOrThrow(ctx, componentRef(component, "payoutRelease/mutations/cancelUnattempted"), identity);
|
|
145
|
+
return {
|
|
146
|
+
status: "held",
|
|
147
|
+
reason: latest.status === "verified" ? "policy_changed" : latest.status,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
await runMutationOrThrow(ctx, componentRef(component, "payoutRelease/mutations/beginAttempt"), identity);
|
|
151
|
+
let payout;
|
|
152
|
+
try {
|
|
153
|
+
payout = await stripe.payouts.create({
|
|
154
|
+
amount: claim.amount,
|
|
155
|
+
currency: claim.currency,
|
|
156
|
+
destination: claim.destinationId,
|
|
157
|
+
method: "standard",
|
|
158
|
+
source_type: "card",
|
|
159
|
+
metadata: { bsPayoutClaim: claim.operationKey },
|
|
160
|
+
}, {
|
|
161
|
+
stripeAccount: claim.accountId,
|
|
162
|
+
idempotencyKey: `bs:payout-release:${claim.operationKey}`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (error instanceof Error &&
|
|
167
|
+
"type" in error &&
|
|
168
|
+
error.type === "StripeInvalidRequestError" &&
|
|
169
|
+
"code" in error &&
|
|
170
|
+
["balance_insufficient", "amount_too_small"].includes(String(error.code)) &&
|
|
171
|
+
"requestId" in error &&
|
|
172
|
+
typeof error.requestId === "string" &&
|
|
173
|
+
/^req_\w+$/.test(error.requestId)) {
|
|
174
|
+
const saved = (await runMutationOrThrow(ctx, componentRef(component, "payoutRelease/mutations/recordRejection"), {
|
|
175
|
+
...identity,
|
|
176
|
+
requestId: error.requestId,
|
|
177
|
+
code: error.code,
|
|
178
|
+
}));
|
|
179
|
+
return { status: "terminal", claim: saved };
|
|
180
|
+
}
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
return reconcileRecipientPayout(stripe, component, ctx, {
|
|
184
|
+
...identity,
|
|
185
|
+
stripePayoutId: payout.id,
|
|
186
|
+
maxPages,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=payoutExecution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payoutExecution.js","sourceRoot":"","sources":["../../../src/client/connect/payoutExecution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
import type { TransferReceiptTransaction } from "./transferReceipt.js";
|
|
3
|
+
export type PayoutHistoryVerification = {
|
|
4
|
+
status: "verified";
|
|
5
|
+
providerAvailable: number;
|
|
6
|
+
observedAt: number;
|
|
7
|
+
} | {
|
|
8
|
+
status: "held";
|
|
9
|
+
reason: "unallocated_history" | "history_changed" | "history_incomplete" | "balance_changed";
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Verify a complete currency history against independently verified transfer and
|
|
13
|
+
* payout receipts. Unknown debits AND credits require explicit allocation. A
|
|
14
|
+
* current balance alone never establishes still-unpaid source ownership.
|
|
15
|
+
*/
|
|
16
|
+
export declare function verifyPayoutHistory(stripe: Stripe, opts: {
|
|
17
|
+
accountId: string;
|
|
18
|
+
currency: string;
|
|
19
|
+
transactions: TransferReceiptTransaction[];
|
|
20
|
+
maxPages?: number;
|
|
21
|
+
}): Promise<PayoutHistoryVerification>;
|
|
22
|
+
//# sourceMappingURL=payoutHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payoutHistory.d.ts","sourceRoot":"","sources":["../../../src/client/connect/payoutHistory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEvE,MAAM,MAAM,yBAAyB,GACjC;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACrE;IACE,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EACF,qBAAqB,GACrB,iBAAiB,GACjB,oBAAoB,GACpB,iBAAiB,CAAC;CACvB,CAAC;AA+BN;;;;GAIG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IACJ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,0BAA0B,EAAE,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,OAAO,CAAC,yBAAyB,CAAC,CA4FpC"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { addSummaryAmounts as add } from "../../component/earnings/arithmetic.js";
|
|
2
|
+
function fingerprint(t) {
|
|
3
|
+
return JSON.stringify([
|
|
4
|
+
t.id,
|
|
5
|
+
t.sourceId,
|
|
6
|
+
t.amount,
|
|
7
|
+
t.fee,
|
|
8
|
+
t.net,
|
|
9
|
+
t.currency,
|
|
10
|
+
t.created,
|
|
11
|
+
t.availableOn,
|
|
12
|
+
t.status,
|
|
13
|
+
t.type,
|
|
14
|
+
]);
|
|
15
|
+
}
|
|
16
|
+
function normalize(t) {
|
|
17
|
+
if (t.status !== "available" && t.status !== "pending")
|
|
18
|
+
throw new Error("Invalid provider receipt status.");
|
|
19
|
+
return {
|
|
20
|
+
id: t.id,
|
|
21
|
+
sourceId: typeof t.source === "string" ? t.source : (t.source?.id ?? ""),
|
|
22
|
+
amount: t.amount,
|
|
23
|
+
fee: t.fee,
|
|
24
|
+
net: t.net,
|
|
25
|
+
currency: t.currency,
|
|
26
|
+
created: t.created,
|
|
27
|
+
availableOn: t.available_on,
|
|
28
|
+
status: t.status,
|
|
29
|
+
type: t.type,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Verify a complete currency history against independently verified transfer and
|
|
34
|
+
* payout receipts. Unknown debits AND credits require explicit allocation. A
|
|
35
|
+
* current balance alone never establishes still-unpaid source ownership.
|
|
36
|
+
*/
|
|
37
|
+
export async function verifyPayoutHistory(stripe, opts) {
|
|
38
|
+
const maxPages = opts.maxPages ?? 10;
|
|
39
|
+
if (!Number.isInteger(maxPages) || maxPages < 1 || maxPages > 100)
|
|
40
|
+
throw new Error("History page budget must be between 1 and 100.");
|
|
41
|
+
if (!/^acct_\w+$/.test(opts.accountId) || !/^[a-z]{3}$/.test(opts.currency))
|
|
42
|
+
throw new Error("Invalid payout history scope.");
|
|
43
|
+
const expected = new Map();
|
|
44
|
+
for (const t of opts.transactions) {
|
|
45
|
+
if (expected.has(t.id))
|
|
46
|
+
throw new Error("Duplicate payout history receipt.");
|
|
47
|
+
if (t.currency !== opts.currency ||
|
|
48
|
+
!/^txn_\w+$/.test(t.id) ||
|
|
49
|
+
!t.sourceId ||
|
|
50
|
+
[t.amount, t.fee, t.net, t.created, t.availableOn].some((n) => !Number.isSafeInteger(n)) ||
|
|
51
|
+
t.net !== add(t.amount, -t.fee))
|
|
52
|
+
throw new Error("Invalid payout history receipt.");
|
|
53
|
+
expected.set(t.id, fingerprint(t));
|
|
54
|
+
}
|
|
55
|
+
const scope = { stripeAccount: opts.accountId };
|
|
56
|
+
const seen = new Set();
|
|
57
|
+
let cursor, head;
|
|
58
|
+
let available = 0, pending = 0, complete = false;
|
|
59
|
+
const held = (reason) => ({ status: "held", reason });
|
|
60
|
+
for (let page = 0; page < maxPages; page++) {
|
|
61
|
+
const batch = await stripe.balanceTransactions.list({
|
|
62
|
+
currency: opts.currency,
|
|
63
|
+
limit: 100,
|
|
64
|
+
...(cursor ? { starting_after: cursor } : {}),
|
|
65
|
+
}, scope);
|
|
66
|
+
if (page === 0 && batch.data[0])
|
|
67
|
+
head = fingerprint(normalize(batch.data[0]));
|
|
68
|
+
for (const raw of batch.data) {
|
|
69
|
+
const t = normalize(raw);
|
|
70
|
+
if (seen.has(t.id))
|
|
71
|
+
return held("history_incomplete");
|
|
72
|
+
seen.add(t.id);
|
|
73
|
+
if (!expected.has(t.id))
|
|
74
|
+
return held("unallocated_history");
|
|
75
|
+
if (fingerprint(t) !== expected.get(t.id))
|
|
76
|
+
return held("history_changed");
|
|
77
|
+
if (t.status === "available")
|
|
78
|
+
available = add(available, t.net);
|
|
79
|
+
else if (t.status === "pending")
|
|
80
|
+
pending = add(pending, t.net);
|
|
81
|
+
else
|
|
82
|
+
return held("history_changed");
|
|
83
|
+
}
|
|
84
|
+
if (!batch.has_more) {
|
|
85
|
+
complete = true;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
const next = batch.data[batch.data.length - 1]?.id;
|
|
89
|
+
if (!next || next === cursor)
|
|
90
|
+
return held("history_incomplete");
|
|
91
|
+
cursor = next;
|
|
92
|
+
}
|
|
93
|
+
if (!complete)
|
|
94
|
+
return held("history_incomplete");
|
|
95
|
+
if (seen.size !== expected.size)
|
|
96
|
+
return held("history_changed");
|
|
97
|
+
const balance = await stripe.balance.retrieve(undefined, scope);
|
|
98
|
+
const latest = await stripe.balanceTransactions.list({ currency: opts.currency, limit: 1 }, scope);
|
|
99
|
+
const latestHead = latest.data[0]
|
|
100
|
+
? fingerprint(normalize(latest.data[0]))
|
|
101
|
+
: undefined;
|
|
102
|
+
if (latestHead !== head)
|
|
103
|
+
return held("history_changed");
|
|
104
|
+
const entries = (rows) => rows.filter((t) => t.currency === opts.currency);
|
|
105
|
+
const a = entries(balance.available), p = entries(balance.pending);
|
|
106
|
+
if (a.length > 1 ||
|
|
107
|
+
p.length > 1 ||
|
|
108
|
+
(a[0]?.amount ?? 0) !== available ||
|
|
109
|
+
(p[0]?.amount ?? 0) !== pending)
|
|
110
|
+
return held("balance_changed");
|
|
111
|
+
// The durable payout request explicitly draws from card balance. Other rails
|
|
112
|
+
// cannot increase this cap even if they contribute to aggregate availability.
|
|
113
|
+
const card = a[0]?.source_types?.card ?? 0;
|
|
114
|
+
if (!Number.isSafeInteger(card))
|
|
115
|
+
throw new Error("Invalid provider card balance.");
|
|
116
|
+
return {
|
|
117
|
+
status: "verified",
|
|
118
|
+
providerAvailable: Math.min(available, card),
|
|
119
|
+
observedAt: Date.now(),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=payoutHistory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payoutHistory.js","sourceRoot":"","sources":["../../../src/client/connect/payoutHistory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type Stripe from "stripe";
|
|
2
|
+
import type { PayoutStatus } from "../../component/connect/validators.js";
|
|
3
|
+
export type RecipientPayoutReceiptOptions = {
|
|
4
|
+
accountId: string;
|
|
5
|
+
stripePayoutId: string;
|
|
6
|
+
/** Required when adopting a provider payout into a previously attempted claim. */
|
|
7
|
+
operationKey?: string;
|
|
8
|
+
};
|
|
9
|
+
export type PayoutReceiptTransaction = {
|
|
10
|
+
id: string;
|
|
11
|
+
amount: number;
|
|
12
|
+
fee: number;
|
|
13
|
+
net: number;
|
|
14
|
+
currency: string;
|
|
15
|
+
status: "available" | "pending";
|
|
16
|
+
created: number;
|
|
17
|
+
availableOn: number;
|
|
18
|
+
type: string;
|
|
19
|
+
};
|
|
20
|
+
export type RecipientPayoutReceipt = {
|
|
21
|
+
status: "not_ready";
|
|
22
|
+
accountId: string;
|
|
23
|
+
stripePayoutId: string;
|
|
24
|
+
reason: "debit_unavailable" | "debit_pending" | "return_unavailable" | "return_pending" | "provider_changed" | "reversal_allocation_required" | "currency_allocation_required";
|
|
25
|
+
} | {
|
|
26
|
+
status: "ready";
|
|
27
|
+
accountId: string;
|
|
28
|
+
stripePayoutId: string;
|
|
29
|
+
operationKey?: string;
|
|
30
|
+
amount: number;
|
|
31
|
+
currency: string;
|
|
32
|
+
providerStatus: PayoutStatus;
|
|
33
|
+
automatic: boolean;
|
|
34
|
+
method: string;
|
|
35
|
+
type: string;
|
|
36
|
+
sourceType: string;
|
|
37
|
+
destinationId: string;
|
|
38
|
+
created: number;
|
|
39
|
+
arrivalDate: number;
|
|
40
|
+
debit: PayoutReceiptTransaction;
|
|
41
|
+
credit?: PayoutReceiptTransaction;
|
|
42
|
+
returnedPrincipal: number;
|
|
43
|
+
returnedNet: number;
|
|
44
|
+
observedAt: number;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Read-only provider receipts, not unpaid entitlement or authorization to release
|
|
48
|
+
* a reservation. Fees remain separate from principal and must be accounted for
|
|
49
|
+
* by the payout/recovery ledger. Manual payout receipts do not identify the
|
|
50
|
+
* original transfers that funded them. Host authorizes access to this account.
|
|
51
|
+
*/
|
|
52
|
+
export declare function getRecipientPayoutReceipt(stripe: Stripe, options: RecipientPayoutReceiptOptions): Promise<RecipientPayoutReceipt>;
|
|
53
|
+
//# sourceMappingURL=payoutReceipt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payoutReceipt.d.ts","sourceRoot":"","sources":["../../../src/client/connect/payoutReceipt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uCAAuC,CAAC;AAC1E,MAAM,MAAM,6BAA6B,GAAG;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,kFAAkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AACF,MAAM,MAAM,wBAAwB,GAAG;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AACF,MAAM,MAAM,sBAAsB,GAC9B;IACE,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EACF,mBAAmB,GACnB,eAAe,GACf,oBAAoB,GACpB,gBAAgB,GAChB,kBAAkB,GAClB,8BAA8B,GAC9B,8BAA8B,CAAC;CACpC,GACD;IACE,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,YAAY,CAAC;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,wBAAwB,CAAC;IAChC,MAAM,CAAC,EAAE,wBAAwB,CAAC;IAClC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAqFN;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,sBAAsB,CAAC,CA2IjC"}
|