@fantastic.dev/better-stripe 0.27.0 → 0.28.1
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/MIGRATION.md +13 -0
- package/README.md +1 -1
- package/dist/component/_generated/component.d.ts +8 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/affiliatePayouts/queries.d.ts.map +1 -1
- package/dist/component/affiliatePayouts/queries.js +3 -1
- package/dist/component/affiliatePayouts/queries.js.map +1 -1
- package/dist/component/costRecovery/queries.d.ts.map +1 -1
- package/dist/component/costRecovery/queries.js +3 -1
- package/dist/component/costRecovery/queries.js.map +1 -1
- package/dist/component/payoutPolicy/queries.d.ts.map +1 -1
- package/dist/component/payoutPolicy/queries.js +3 -1
- package/dist/component/payoutPolicy/queries.js.map +1 -1
- package/dist/component/payoutRelease/allocationTotals.d.ts +8 -0
- package/dist/component/payoutRelease/allocationTotals.d.ts.map +1 -0
- package/dist/component/payoutRelease/allocationTotals.js +43 -0
- package/dist/component/payoutRelease/allocationTotals.js.map +1 -0
- package/dist/component/payoutRelease/planning.d.ts.map +1 -1
- package/dist/component/payoutRelease/planning.js +2 -0
- package/dist/component/payoutRelease/planning.js.map +1 -1
- package/dist/component/payoutRelease/preview.d.ts +35 -2
- package/dist/component/payoutRelease/preview.d.ts.map +1 -1
- package/dist/component/payoutRelease/preview.js +6 -11
- package/dist/component/payoutRelease/preview.js.map +1 -1
- package/dist/component/payoutRelease/progress.d.ts +29 -0
- package/dist/component/payoutRelease/progress.d.ts.map +1 -0
- package/dist/component/payoutRelease/progress.js +40 -0
- package/dist/component/payoutRelease/progress.js.map +1 -0
- package/dist/component/payoutRelease/queries.d.ts +8 -0
- package/dist/component/payoutRelease/queries.d.ts.map +1 -1
- package/dist/component/payoutSnapshots/mutations.d.ts.map +1 -1
- package/dist/component/payoutSnapshots/mutations.js +6 -4
- package/dist/component/payoutSnapshots/mutations.js.map +1 -1
- package/dist/component/payoutWorker/queries.d.ts.map +1 -1
- package/dist/component/payoutWorker/queries.js +5 -3
- package/dist/component/payoutWorker/queries.js.map +1 -1
- package/dist/react/workflows/PayoutProgress.d.ts.map +1 -1
- package/dist/react/workflows/PayoutProgress.js +2 -2
- package/dist/react/workflows/PayoutProgress.js.map +1 -1
- package/dist/react/workflows/payout-progress-state.d.ts +8 -1
- package/dist/react/workflows/payout-progress-state.d.ts.map +1 -1
- package/dist/react/workflows/payout-progress-state.js +31 -0
- package/dist/react/workflows/payout-progress-state.js.map +1 -1
- package/dist/testing/component-db.d.ts +3 -0
- package/dist/testing/component-db.d.ts.map +1 -0
- package/dist/testing/component-db.js +26 -0
- package/dist/testing/component-db.js.map +1 -0
- package/docs/react-workflows.md +8 -1
- package/docs/settlement.md +33 -0
- package/package.json +1 -1
- package/src/client/connect/payoutPreview.test.ts +145 -0
- package/src/component/_generated/api.ts +4 -0
- package/src/component/_generated/component.ts +8 -0
- package/src/component/affiliate-component-pagination.test.ts +1 -25
- package/src/component/affiliatePayouts/queries.ts +3 -1
- package/src/component/costRecovery/queries.ts +3 -1
- package/src/component/payout-component-pagination.test.ts +212 -0
- package/src/component/payoutPolicy/queries.ts +3 -1
- package/src/component/payoutRelease/allocationTotals.ts +56 -0
- package/src/component/payoutRelease/planning.ts +2 -0
- package/src/component/payoutRelease/preview.ts +10 -20
- package/src/component/payoutRelease/progress.test.ts +63 -0
- package/src/component/payoutRelease/progress.ts +56 -0
- package/src/component/payoutSnapshots/mutations.ts +6 -4
- package/src/component/payoutWorker/queries.ts +5 -3
- package/src/react/workflows/PayoutProgress.test.tsx +39 -0
- package/src/react/workflows/PayoutProgress.tsx +14 -0
- package/src/react/workflows/payout-progress-state.ts +48 -1
- package/src/testing/component-db.ts +24 -0
|
@@ -14,10 +14,10 @@ export function PayoutProgress(props) {
|
|
|
14
14
|
if (children)
|
|
15
15
|
return _jsx(_Fragment, { children: children(state) });
|
|
16
16
|
const date = (value) => formatter.format(value);
|
|
17
|
-
return (_jsxs("section", { className: className, "data-better-stripe": "payout-progress", children: [_jsxs("h2", { children: ["Automatic payout progress (", currency.toUpperCase(), ")"] }), _jsx("p", { role: "status", children: state.message }), _jsx("p", { children: "Stripe enforces its payout floor; a numeric amount is unavailable." }), state.progress && (_jsx("progress", { "aria-label": "Combined payout minimum", value: state.progress.value, max: state.progress.max })), state.metrics.length > 0 && (_jsx("dl", { children: state.metrics.map((metric) => (_jsxs("div", { children: [_jsx("dt", { children: metric.label }), _jsx("dd", { children: metric.formattedValue })] }, metric.key))) })), state.sources.length > 0 && (_jsxs(_Fragment, { children: [_jsx("p", { children: "All categories contribute to one minimum. Source amounts are before shared costs and obligations. Pending funds do not qualify." }), _jsxs("table", { children: [_jsx("caption", { children: "Source contributions" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Source" }), _jsx("th", { scope: "col", children: "Mature unpaid" }), _jsx("th", { scope: "col", children: "Pending settlement" })] }) }), _jsx("tbody", { children: state.sources.map((source) => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: source.role === "store"
|
|
17
|
+
return (_jsxs("section", { className: className, "data-better-stripe": "payout-progress", children: [_jsxs("h2", { children: ["Automatic payout progress (", currency.toUpperCase(), ")"] }), _jsx("p", { role: "status", children: state.message }), _jsx("p", { children: "Stripe enforces its payout floor; a numeric amount is unavailable." }), state.progress && (_jsx("progress", { "aria-label": "Combined payout minimum", value: state.progress.value, max: state.progress.max })), state.metrics.length > 0 && (_jsx("dl", { children: state.metrics.map((metric) => (_jsxs("div", { children: [_jsx("dt", { children: metric.label }), _jsx("dd", { children: metric.formattedValue })] }, metric.key))) })), state.sources.length > 0 && (_jsxs(_Fragment, { children: [_jsx("p", { children: "All categories contribute to one minimum. Source amounts are before shared costs and obligations. Pending funds do not qualify." }), _jsxs("table", { children: [_jsx("caption", { children: "Source contributions" }), _jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { scope: "col", children: "Source" }), _jsx("th", { scope: "col", children: "Mature unpaid" }), _jsx("th", { scope: "col", children: "Pending settlement" }), state.accounting && _jsx("th", { scope: "col", children: "In flight" }), state.accounting && _jsx("th", { scope: "col", children: "Paid out" })] }) }), _jsx("tbody", { children: state.sources.map((source) => (_jsxs("tr", { children: [_jsx("th", { scope: "row", children: source.role === "store"
|
|
18
18
|
? "Store"
|
|
19
19
|
: source.role === "affiliate"
|
|
20
20
|
? "Affiliate"
|
|
21
|
-
: "Other" }), _jsx("td", { children: source.matureLabel }), _jsx("td", { children: source.pendingLabel })] }, source.role))) })] })] })), state.nextAttemptAt !== null && (_jsxs("p", { children: ["Next automatic attempt: ", date(state.nextAttemptAt), ". This is not a bank arrival date."] })), state.holdDeadline !== null && (_jsxs("p", { children: ["Custom holding deadline: ", date(state.holdDeadline)] })), state.observedAt !== null && _jsxs("p", { children: ["Assessed: ", date(state.observedAt)] })] }));
|
|
21
|
+
: "Other" }), _jsx("td", { children: source.matureLabel }), _jsx("td", { children: source.pendingLabel }), state.accounting && (_jsx("td", { children: source.reservedLabel ?? "Not assessed" })), state.accounting && (_jsx("td", { children: source.releasedLabel ?? "Not assessed" }))] }, source.role))) })] })] })), state.accounting && (_jsx("p", { children: "Carried-forward funds remain owed. In-flight payouts are separate from completed payouts. Paid-out amounts exclude returned payouts." })), state.nextAttemptAt !== null && (_jsxs("p", { children: ["Next automatic attempt: ", date(state.nextAttemptAt), ". This is not a bank arrival date."] })), state.holdDeadline !== null && (_jsxs("p", { children: ["Custom holding deadline: ", date(state.holdDeadline)] })), state.observedAt !== null && _jsxs("p", { children: ["Assessed: ", date(state.observedAt)] })] }));
|
|
22
22
|
}
|
|
23
23
|
//# sourceMappingURL=PayoutProgress.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PayoutProgress.js","sourceRoot":"","sources":["../../../src/react/workflows/PayoutProgress.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAChC,OAAO,EACL,mBAAmB,GAEpB,MAAM,4BAA4B,CAAC;AAMpC,qFAAqF;AACrF,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC5E,MAAM,KAAK,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,OAAO,CACvB,GAAG,EAAE,CACH,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE;QAC9B,SAAS,EAAE,QAAQ;QACnB,SAAS,EAAE,OAAO;QAClB,QAAQ;KACT,CAAC,EACJ,CAAC,MAAM,EAAE,QAAQ,CAAC,CACnB,CAAC;IACF,IAAI,QAAQ;QAAE,OAAO,4BAAG,QAAQ,CAAC,KAAK,CAAC,GAAI,CAAC;IAC5C,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACxD,OAAO,CACL,mBAAS,SAAS,EAAE,SAAS,wBAAqB,iBAAiB,aACjE,wDAAgC,QAAQ,CAAC,WAAW,EAAE,SAAO,EAC7D,YAAG,IAAI,EAAC,QAAQ,YAAE,KAAK,CAAC,OAAO,GAAK,EACpC,6FAAyE,EACxE,KAAK,CAAC,QAAQ,IAAI,CACjB,iCACa,yBAAyB,EACpC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,EAC3B,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,GACvB,CACH,EACA,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAC3B,uBACG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAC7B,0BACE,uBAAK,MAAM,CAAC,KAAK,GAAM,EACvB,uBAAK,MAAM,CAAC,cAAc,GAAM,KAFxB,MAAM,CAAC,GAAG,CAGd,CACP,CAAC,GACC,CACN,EACA,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAC3B,8BACE,0JAGI,EACJ,4BACE,qDAAuC,EACvC,0BACE,yBACE,aAAI,KAAK,EAAC,KAAK,uBAAY,EAC3B,aAAI,KAAK,EAAC,KAAK,8BAAmB,EAClC,aAAI,KAAK,EAAC,KAAK,mCAAwB,
|
|
1
|
+
{"version":3,"file":"PayoutProgress.js","sourceRoot":"","sources":["../../../src/react/workflows/PayoutProgress.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { PayoutPolicy, PayoutPreview } from "../../client/payoutPolicy.js";
|
|
3
3
|
export type PayoutProgressMetric = {
|
|
4
|
-
key: "qualifying" | "pending" | "minimum" | "eligible" | "fees" | "liabilities";
|
|
4
|
+
key: "qualifying" | "pending" | "minimum" | "eligible" | "fees" | "liabilities" | "carried" | "withheld" | "reserved" | "released";
|
|
5
5
|
label: string;
|
|
6
6
|
amount: number;
|
|
7
7
|
formattedValue: string;
|
|
@@ -12,12 +12,19 @@ export type PayoutProgressState = {
|
|
|
12
12
|
reason: string | null;
|
|
13
13
|
message: string;
|
|
14
14
|
metrics: PayoutProgressMetric[];
|
|
15
|
+
accounting?: NonNullable<Extract<PayoutPreview, {
|
|
16
|
+
currency: string;
|
|
17
|
+
}>["accounting"]>;
|
|
15
18
|
sources: {
|
|
16
19
|
role: "store" | "affiliate" | "other";
|
|
17
20
|
matureUnpaid: number;
|
|
18
21
|
pendingCredits: number;
|
|
19
22
|
matureLabel: string;
|
|
20
23
|
pendingLabel: string;
|
|
24
|
+
releasedAmount?: number;
|
|
25
|
+
reservedAmount?: number;
|
|
26
|
+
releasedLabel?: string;
|
|
27
|
+
reservedLabel?: string;
|
|
21
28
|
}[];
|
|
22
29
|
progress: {
|
|
23
30
|
value: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payout-progress-state.d.ts","sourceRoot":"","sources":["../../../src/react/workflows/payout-progress-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAEhF,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,
|
|
1
|
+
{"version":3,"file":"payout-progress-state.d.ts","sourceRoot":"","sources":["../../../src/react/workflows/payout-progress-state.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAEhF,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EACC,YAAY,GACZ,SAAS,GACT,SAAS,GACT,UAAU,GACV,MAAM,GACN,aAAa,GACb,SAAS,GACT,UAAU,GACV,UAAU,GACV,UAAU,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AACF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EACJ,SAAS,GAAG,gBAAgB,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;IACzE,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,WAAW,CACtB,OAAO,CAAC,aAAa,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,YAAY,CAAC,CAC3D,CAAC;IACF,OAAO,EAAE;QACP,IAAI,EAAE,OAAO,GAAG,WAAW,GAAG,OAAO,CAAC;QACtC,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,EAAE,CAAC;IACJ,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAChD,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AACF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EACF,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,QAAQ,GAAG,YAAY,GAAG,cAAc,CAAC,GACrE,IAAI,GACJ,SAAS,CAAC;IACd,OAAO,CAAC,EAAE,aAAa,GAAG,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,SAAS,CAAC;CACtD,CAAC;AAmBF,wBAAgB,mBAAmB,CAAC,EAClC,MAAM,EACN,OAAO,EACP,QAAQ,EACR,aAAa,EACb,MAAgB,GACjB,EAAE,mBAAmB,GAAG,mBAAmB,CAkH3C"}
|
|
@@ -58,6 +58,7 @@ export function payoutProgressState({ policy, preview, currency, nextAttemptAt,
|
|
|
58
58
|
: (reasons[preview.reason ?? ""] ??
|
|
59
59
|
"Automatic payout is on hold. Refresh or contact support.");
|
|
60
60
|
state.observedAt = preview.observedAt;
|
|
61
|
+
state.accounting = preview.accounting;
|
|
61
62
|
state.progress = {
|
|
62
63
|
value: Math.max(0, Math.min(preview.threshold, preview.matureUnpaid)),
|
|
63
64
|
max: preview.threshold,
|
|
@@ -67,6 +68,30 @@ export function payoutProgressState({ policy, preview, currency, nextAttemptAt,
|
|
|
67
68
|
["pending", "Pending settlement", preview.pendingCredits],
|
|
68
69
|
["minimum", "Combined payout minimum", preview.threshold],
|
|
69
70
|
["eligible", "Eligible at assessment", preview.amount],
|
|
71
|
+
...(preview.accounting
|
|
72
|
+
? [
|
|
73
|
+
[
|
|
74
|
+
"carried",
|
|
75
|
+
"Carried forward",
|
|
76
|
+
preview.accounting.carriedForwardAmount,
|
|
77
|
+
],
|
|
78
|
+
[
|
|
79
|
+
"withheld",
|
|
80
|
+
"Withheld for costs",
|
|
81
|
+
preview.accounting.withheldAmount,
|
|
82
|
+
],
|
|
83
|
+
[
|
|
84
|
+
"reserved",
|
|
85
|
+
"Payouts in progress",
|
|
86
|
+
preview.accounting.reservedAmount,
|
|
87
|
+
],
|
|
88
|
+
[
|
|
89
|
+
"released",
|
|
90
|
+
"Paid out, net of returns",
|
|
91
|
+
preview.accounting.releasedAmount,
|
|
92
|
+
],
|
|
93
|
+
]
|
|
94
|
+
: []),
|
|
70
95
|
["fees", "Confirmed payout costs", preview.confirmedFees],
|
|
71
96
|
[
|
|
72
97
|
"liabilities",
|
|
@@ -84,6 +109,12 @@ export function payoutProgressState({ policy, preview, currency, nextAttemptAt,
|
|
|
84
109
|
...source,
|
|
85
110
|
matureLabel: amount(source.matureUnpaid),
|
|
86
111
|
pendingLabel: amount(source.pendingCredits),
|
|
112
|
+
...(source.releasedAmount === undefined
|
|
113
|
+
? {}
|
|
114
|
+
: { releasedLabel: amount(source.releasedAmount) }),
|
|
115
|
+
...(source.reservedAmount === undefined
|
|
116
|
+
? {}
|
|
117
|
+
: { reservedLabel: amount(source.reservedAmount) }),
|
|
87
118
|
}));
|
|
88
119
|
}
|
|
89
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"payout-progress-state.js","sourceRoot":"","sources":["../../../src/react/workflows/payout-progress-state.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"payout-progress-state.js","sourceRoot":"","sources":["../../../src/react/workflows/payout-progress-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-db.d.ts","sourceRoot":"","sources":["../../src/testing/component-db.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAsBtD"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Model the deployed component boundary that convex-test does not enforce. */
|
|
2
|
+
export function componentDb(db) {
|
|
3
|
+
function wrap(value) {
|
|
4
|
+
return new Proxy(value, {
|
|
5
|
+
get(target, key) {
|
|
6
|
+
if (key === "paginate")
|
|
7
|
+
return () => {
|
|
8
|
+
throw new Error("paginate() is only supported in the app");
|
|
9
|
+
};
|
|
10
|
+
const member = Reflect.get(target, key);
|
|
11
|
+
if (typeof member !== "function")
|
|
12
|
+
return member;
|
|
13
|
+
return (...args) => {
|
|
14
|
+
const result = member.apply(target, args);
|
|
15
|
+
return result &&
|
|
16
|
+
typeof result === "object" &&
|
|
17
|
+
!(result instanceof Promise)
|
|
18
|
+
? wrap(result)
|
|
19
|
+
: result;
|
|
20
|
+
};
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
return wrap(db);
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=component-db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"component-db.js","sourceRoot":"","sources":["../../src/testing/component-db.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAAmB,EAAK;IACjD,SAAS,IAAI,CAAwB,KAAa;QAChD,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE;YACtB,GAAG,CAAC,MAAM,EAAE,GAAG;gBACb,IAAI,GAAG,KAAK,UAAU;oBACpB,OAAO,GAAG,EAAE;wBACV,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;oBAC7D,CAAC,CAAC;gBACJ,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBACxC,IAAI,OAAO,MAAM,KAAK,UAAU;oBAAE,OAAO,MAAM,CAAC;gBAChD,OAAO,CAAC,GAAG,IAAe,EAAE,EAAE;oBAC5B,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;oBAC1C,OAAO,MAAM;wBACX,OAAO,MAAM,KAAK,QAAQ;wBAC1B,CAAC,CAAC,MAAM,YAAY,OAAO,CAAC;wBAC5B,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;wBACd,CAAC,CAAC,MAAM,CAAC;gBACb,CAAC,CAAC;YACJ,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
|
package/docs/react-workflows.md
CHANGED
|
@@ -669,6 +669,12 @@ visible even though the visual progress indicator stops at zero. A qualified
|
|
|
669
669
|
assessment is informational; the automatic worker verifies it again before a
|
|
670
670
|
payout. The component has no withdrawal action.
|
|
671
671
|
|
|
672
|
+
When the assessment includes `accounting`, the component also shows carried
|
|
673
|
+
forward funds, funds withheld for costs, in-flight allocations and paid principal
|
|
674
|
+
net of verified payout returns. Its source table separates in-flight and paid
|
|
675
|
+
amounts. These metrics are omitted for older assessments without accounting
|
|
676
|
+
fields. They are never inferred from the current Stripe available balance.
|
|
677
|
+
|
|
672
678
|
`policy={undefined}` means loading. A null policy or `stripe_managed` mode shows
|
|
673
679
|
Stripe-managed defaults without inventing a numeric provider floor. Changing
|
|
674
680
|
policies suppress prior financial progress. For a ready custom policy, an
|
|
@@ -678,7 +684,8 @@ currency or configured minimum rejects the display.
|
|
|
678
684
|
|
|
679
685
|
Use the `children` render prop for translated labels and application cards. It
|
|
680
686
|
receives `status`, `reason`, `metrics`, `sources`, `progress`, `observedAt`,
|
|
681
|
-
`nextAttemptAt` and `
|
|
687
|
+
`nextAttemptAt`, `holdDeadline` and optional `accounting`. Accounting metric keys
|
|
688
|
+
are `carried`, `withheld`, `reserved` and `released`. Metrics include raw minor-unit
|
|
682
689
|
amounts as well as formatted values. Render props use the same state calculation
|
|
683
690
|
as the native markup; replace the English message with your own translated copy
|
|
684
691
|
selected by `status` and `reason`.
|
package/docs/settlement.md
CHANGED
|
@@ -643,6 +643,29 @@ pending credits never qualify. `amount` is the amount currently qualified for th
|
|
|
643
643
|
supported bank payout rail, or zero when held. `providerMinimum: null` means the
|
|
644
644
|
numeric Stripe floor is unknown, not zero.
|
|
645
645
|
|
|
646
|
+
Detailed assessments also include an optional `accounting` object, in the
|
|
647
|
+
selected currency's minor units:
|
|
648
|
+
|
|
649
|
+
| Field | Meaning |
|
|
650
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
|
651
|
+
| `carriedForwardAmount` | Positive combined mature unpaid entitlement minus the amount eligible now. Held funds remain owed. |
|
|
652
|
+
| `withheldAmount` | Mature unpaid funds earmarked for confirmed fees and independent liabilities, capped at the funds available to withhold. |
|
|
653
|
+
| `reservedAmount` | Source allocations reserved for in-flight payouts. These are separate from completed payouts. |
|
|
654
|
+
| `releasedAmount` | Verified paid principal, less verified payout returns. |
|
|
655
|
+
|
|
656
|
+
Each source category also includes `reservedAmount` and `releasedAmount`.
|
|
657
|
+
The component checks source allocation rollups against persisted payout claims
|
|
658
|
+
before reporting these amounts or reserving a new payout. Inconsistent or
|
|
659
|
+
incomplete claim history rejects the assessment. Shared costs are not assigned
|
|
660
|
+
to individual source categories. A refund after a completed bank payout reduces
|
|
661
|
+
future entitlement; it does not erase the paid principal unless Stripe verifies
|
|
662
|
+
that the bank payout itself returned. Full outstanding obligations remain in
|
|
663
|
+
`independentLiabilities` even when funds available to withhold are smaller.
|
|
664
|
+
|
|
665
|
+
Older detailed results can omit `accounting` and the source payout fields.
|
|
666
|
+
Treat omitted fields as unavailable, never as zero. Minimal held results do not
|
|
667
|
+
include accounting totals.
|
|
668
|
+
|
|
646
669
|
Below-threshold funds remain owed. `insufficient_available` distinguishes enough
|
|
647
670
|
qualifying earnings from insufficient provider funds on the supported rail. Some
|
|
648
671
|
holds return only `{ status: "held", reason, amount: 0 }`, including incomplete
|
|
@@ -666,6 +689,16 @@ provider-history continuation on larger accounts.
|
|
|
666
689
|
|
|
667
690
|
## Resumable local collections
|
|
668
691
|
|
|
692
|
+
Worker discovery, policy expiry, pending affiliate reconciliation, seller cost
|
|
693
|
+
history and local collection pages use the component-compatible paginator from
|
|
694
|
+
`convex-helpers`. Convex's native database `.paginate()` is unavailable inside
|
|
695
|
+
components. The public page shape remains `page`, `continueCursor` and `isDone`.
|
|
696
|
+
Treat cursors as opaque and restart cached pages at a null cursor when upgrading
|
|
697
|
+
these readers. Use the package's discard operation for an obsolete read-only
|
|
698
|
+
collection; never erase financially bound or unresolved payout state to restart
|
|
699
|
+
a scan. This change preserves the existing source/history limits and does not
|
|
700
|
+
make larger provider-history qualification complete.
|
|
701
|
+
|
|
669
702
|
An authorized host worker can collect the local recipient ledger in bounded
|
|
670
703
|
steps, retaining its cursor and step number across restarts:
|
|
671
704
|
|
package/package.json
CHANGED
|
@@ -26,6 +26,12 @@ it("previews combined eligibility and source categories without creating or rese
|
|
|
26
26
|
pendingCredits: 0,
|
|
27
27
|
threshold: 1000,
|
|
28
28
|
providerMinimum: null,
|
|
29
|
+
accounting: {
|
|
30
|
+
carriedForwardAmount: 0,
|
|
31
|
+
withheldAmount: 0,
|
|
32
|
+
reservedAmount: 0,
|
|
33
|
+
releasedAmount: 0,
|
|
34
|
+
},
|
|
29
35
|
sources: [
|
|
30
36
|
{ role: "store", matureUnpaid: 600, pendingCredits: 0 },
|
|
31
37
|
{ role: "affiliate", matureUnpaid: 400, pendingCredits: 0 },
|
|
@@ -48,6 +54,12 @@ it("shows below-threshold carry forward and independent liabilities", async () =
|
|
|
48
54
|
matureUnpaid: 899,
|
|
49
55
|
amount: 0,
|
|
50
56
|
independentLiabilities: 100,
|
|
57
|
+
accounting: {
|
|
58
|
+
carriedForwardAmount: 899,
|
|
59
|
+
withheldAmount: 100,
|
|
60
|
+
reservedAmount: 0,
|
|
61
|
+
releasedAmount: 0,
|
|
62
|
+
},
|
|
51
63
|
});
|
|
52
64
|
expect(s.provider.payouts.create).not.toHaveBeenCalled();
|
|
53
65
|
});
|
|
@@ -71,6 +83,17 @@ it("subtracts a previously paid claim while verifying its current provider recei
|
|
|
71
83
|
reason: "below_threshold",
|
|
72
84
|
matureUnpaid: 0,
|
|
73
85
|
amount: 0,
|
|
86
|
+
accounting: {
|
|
87
|
+
carriedForwardAmount: 0,
|
|
88
|
+
withheldAmount: 0,
|
|
89
|
+
reservedAmount: 0,
|
|
90
|
+
releasedAmount: 1000,
|
|
91
|
+
},
|
|
92
|
+
sources: [
|
|
93
|
+
{ role: "store", releasedAmount: 600, reservedAmount: 0 },
|
|
94
|
+
{ role: "affiliate", releasedAmount: 400, reservedAmount: 0 },
|
|
95
|
+
{ role: "other", releasedAmount: 0, reservedAmount: 0 },
|
|
96
|
+
],
|
|
74
97
|
});
|
|
75
98
|
expect(s.provider.payouts.create).toHaveBeenCalledTimes(1);
|
|
76
99
|
});
|
|
@@ -145,6 +168,12 @@ it("deducts confirmed payout costs without attributing shared costs to a source
|
|
|
145
168
|
reason: "below_threshold",
|
|
146
169
|
matureUnpaid: 950,
|
|
147
170
|
confirmedFees: 150,
|
|
171
|
+
accounting: {
|
|
172
|
+
carriedForwardAmount: 950,
|
|
173
|
+
withheldAmount: 150,
|
|
174
|
+
reservedAmount: 0,
|
|
175
|
+
releasedAmount: 0,
|
|
176
|
+
},
|
|
148
177
|
sources: [
|
|
149
178
|
{ role: "store", matureUnpaid: 700 },
|
|
150
179
|
{ role: "affiliate", matureUnpaid: 400 },
|
|
@@ -259,6 +288,12 @@ it("preserves negative affiliate entitlement when a paid commission is refunded"
|
|
|
259
288
|
reason: "below_threshold",
|
|
260
289
|
amount: 0,
|
|
261
290
|
matureUnpaid: -100,
|
|
291
|
+
accounting: {
|
|
292
|
+
carriedForwardAmount: 0,
|
|
293
|
+
withheldAmount: 0,
|
|
294
|
+
reservedAmount: 0,
|
|
295
|
+
releasedAmount: 1000,
|
|
296
|
+
},
|
|
262
297
|
sources: [
|
|
263
298
|
{ role: "store", matureUnpaid: 0 },
|
|
264
299
|
{ role: "affiliate", matureUnpaid: -100 },
|
|
@@ -267,3 +302,113 @@ it("preserves negative affiliate entitlement when a paid commission is refunded"
|
|
|
267
302
|
});
|
|
268
303
|
expect(s.provider.payouts.create).toHaveBeenCalledTimes(1);
|
|
269
304
|
});
|
|
305
|
+
it("caps actual withholding at mature unpaid funds when obligations exceed them", async () => {
|
|
306
|
+
const s = await preview([60, 40]);
|
|
307
|
+
expect(await s.preview({ independentLiabilities: 1000 })).toMatchObject({
|
|
308
|
+
matureUnpaid: -900,
|
|
309
|
+
accounting: {
|
|
310
|
+
carriedForwardAmount: 0,
|
|
311
|
+
withheldAmount: 100,
|
|
312
|
+
reservedAmount: 0,
|
|
313
|
+
releasedAmount: 0,
|
|
314
|
+
},
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
it("reports unpaid funds outside the supported-rail cap as carried forward", async () => {
|
|
318
|
+
const s = await preview([1000, 500]);
|
|
319
|
+
s.provider.balance.retrieve.mockResolvedValue({
|
|
320
|
+
available: [
|
|
321
|
+
{ currency: "usd", amount: 1500, source_types: { card: 1000 } },
|
|
322
|
+
],
|
|
323
|
+
pending: [],
|
|
324
|
+
});
|
|
325
|
+
expect(await s.preview()).toMatchObject({
|
|
326
|
+
status: "qualified",
|
|
327
|
+
amount: 1000,
|
|
328
|
+
matureUnpaid: 1500,
|
|
329
|
+
accounting: {
|
|
330
|
+
carriedForwardAmount: 500,
|
|
331
|
+
withheldAmount: 0,
|
|
332
|
+
reservedAmount: 0,
|
|
333
|
+
releasedAmount: 0,
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
it("refuses paid allocation totals without corresponding payout claims", async () => {
|
|
338
|
+
const s = await preview();
|
|
339
|
+
await s.t.run((ctx) =>
|
|
340
|
+
ctx.db.insert("payoutSourceAllocations", {
|
|
341
|
+
accountId: scope.accountId,
|
|
342
|
+
ownerKey: scope.ownerKey,
|
|
343
|
+
currency: "usd",
|
|
344
|
+
stripeTransferId: "tr_0",
|
|
345
|
+
paidAmount: 600,
|
|
346
|
+
reservedAmount: 0,
|
|
347
|
+
}),
|
|
348
|
+
);
|
|
349
|
+
await expect(s.preview()).rejects.toThrow(/allocation totals/i);
|
|
350
|
+
expect(s.provider.payouts.create).not.toHaveBeenCalled();
|
|
351
|
+
});
|
|
352
|
+
it("keeps a submitted payout reserved until Stripe verifies it as paid", async () => {
|
|
353
|
+
const s = await preview();
|
|
354
|
+
const create = s.provider.payouts.create.getMockImplementation()!;
|
|
355
|
+
s.provider.payouts.create.mockImplementation(async (args) => {
|
|
356
|
+
const payout = await create(args);
|
|
357
|
+
payout.status = "pending";
|
|
358
|
+
return payout;
|
|
359
|
+
});
|
|
360
|
+
expect(await s.run()).toMatchObject({
|
|
361
|
+
status: "updated",
|
|
362
|
+
claim: { status: "submitted" },
|
|
363
|
+
});
|
|
364
|
+
expect(await s.preview()).toMatchObject({
|
|
365
|
+
matureUnpaid: 0,
|
|
366
|
+
accounting: {
|
|
367
|
+
releasedAmount: 0,
|
|
368
|
+
reservedAmount: 1000,
|
|
369
|
+
carriedForwardAmount: 0,
|
|
370
|
+
withheldAmount: 0,
|
|
371
|
+
},
|
|
372
|
+
sources: [
|
|
373
|
+
{ role: "store", releasedAmount: 0, reservedAmount: 600 },
|
|
374
|
+
{ role: "affiliate", releasedAmount: 0, reservedAmount: 400 },
|
|
375
|
+
{ role: "other", releasedAmount: 0, reservedAmount: 0 },
|
|
376
|
+
],
|
|
377
|
+
});
|
|
378
|
+
(await s.provider.payouts.retrieve())!.status = "paid";
|
|
379
|
+
expect(await s.preview()).toMatchObject({
|
|
380
|
+
accounting: { releasedAmount: 1000, reservedAmount: 0 },
|
|
381
|
+
});
|
|
382
|
+
expect(s.provider.payouts.create).toHaveBeenCalledTimes(1);
|
|
383
|
+
});
|
|
384
|
+
it("removes a verified returned payout from released totals without forfeiting the funds", async () => {
|
|
385
|
+
const s = await preview();
|
|
386
|
+
await s.run();
|
|
387
|
+
Object.assign((await s.provider.payouts.retrieve())!, {
|
|
388
|
+
status: "failed",
|
|
389
|
+
failure_balance_transaction: "txn_return",
|
|
390
|
+
});
|
|
391
|
+
s.setTransactions([
|
|
392
|
+
{
|
|
393
|
+
...s.transactions()[0],
|
|
394
|
+
id: "txn_return",
|
|
395
|
+
source: "po_one",
|
|
396
|
+
amount: 1000,
|
|
397
|
+
net: 1000,
|
|
398
|
+
type: "payout_failure",
|
|
399
|
+
},
|
|
400
|
+
...s.transactions(),
|
|
401
|
+
]);
|
|
402
|
+
expect(await s.preview()).toMatchObject({
|
|
403
|
+
status: "qualified",
|
|
404
|
+
amount: 1000,
|
|
405
|
+
matureUnpaid: 1000,
|
|
406
|
+
accounting: {
|
|
407
|
+
releasedAmount: 0,
|
|
408
|
+
reservedAmount: 0,
|
|
409
|
+
carriedForwardAmount: 0,
|
|
410
|
+
withheldAmount: 0,
|
|
411
|
+
},
|
|
412
|
+
});
|
|
413
|
+
expect(s.provider.payouts.create).toHaveBeenCalledTimes(1);
|
|
414
|
+
});
|
|
@@ -52,12 +52,14 @@ import type * as payoutPolicy_mutations from "../payoutPolicy/mutations.js";
|
|
|
52
52
|
import type * as payoutPolicy_queries from "../payoutPolicy/queries.js";
|
|
53
53
|
import type * as payoutRelease_adoption from "../payoutRelease/adoption.js";
|
|
54
54
|
import type * as payoutRelease_allocation from "../payoutRelease/allocation.js";
|
|
55
|
+
import type * as payoutRelease_allocationTotals from "../payoutRelease/allocationTotals.js";
|
|
55
56
|
import type * as payoutRelease_fees from "../payoutRelease/fees.js";
|
|
56
57
|
import type * as payoutRelease_helpers from "../payoutRelease/helpers.js";
|
|
57
58
|
import type * as payoutRelease_mutations from "../payoutRelease/mutations.js";
|
|
58
59
|
import type * as payoutRelease_observation from "../payoutRelease/observation.js";
|
|
59
60
|
import type * as payoutRelease_planning from "../payoutRelease/planning.js";
|
|
60
61
|
import type * as payoutRelease_preview from "../payoutRelease/preview.js";
|
|
62
|
+
import type * as payoutRelease_progress from "../payoutRelease/progress.js";
|
|
61
63
|
import type * as payoutRelease_queries from "../payoutRelease/queries.js";
|
|
62
64
|
import type * as payoutSnapshots_localState from "../payoutSnapshots/localState.js";
|
|
63
65
|
import type * as payoutSnapshots_mutations from "../payoutSnapshots/mutations.js";
|
|
@@ -134,12 +136,14 @@ const fullApi: ApiFromModules<{
|
|
|
134
136
|
"payoutPolicy/queries": typeof payoutPolicy_queries;
|
|
135
137
|
"payoutRelease/adoption": typeof payoutRelease_adoption;
|
|
136
138
|
"payoutRelease/allocation": typeof payoutRelease_allocation;
|
|
139
|
+
"payoutRelease/allocationTotals": typeof payoutRelease_allocationTotals;
|
|
137
140
|
"payoutRelease/fees": typeof payoutRelease_fees;
|
|
138
141
|
"payoutRelease/helpers": typeof payoutRelease_helpers;
|
|
139
142
|
"payoutRelease/mutations": typeof payoutRelease_mutations;
|
|
140
143
|
"payoutRelease/observation": typeof payoutRelease_observation;
|
|
141
144
|
"payoutRelease/planning": typeof payoutRelease_planning;
|
|
142
145
|
"payoutRelease/preview": typeof payoutRelease_preview;
|
|
146
|
+
"payoutRelease/progress": typeof payoutRelease_progress;
|
|
143
147
|
"payoutRelease/queries": typeof payoutRelease_queries;
|
|
144
148
|
"payoutSnapshots/localState": typeof payoutSnapshots_localState;
|
|
145
149
|
"payoutSnapshots/mutations": typeof payoutSnapshots_mutations;
|
|
@@ -3630,6 +3630,12 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
|
|
|
3630
3630
|
},
|
|
3631
3631
|
| { amount: 0; reason: string; status: "held" }
|
|
3632
3632
|
| {
|
|
3633
|
+
accounting?: {
|
|
3634
|
+
carriedForwardAmount: number;
|
|
3635
|
+
releasedAmount: number;
|
|
3636
|
+
reservedAmount: number;
|
|
3637
|
+
withheldAmount: number;
|
|
3638
|
+
};
|
|
3633
3639
|
amount: number;
|
|
3634
3640
|
confirmedFees: number;
|
|
3635
3641
|
currency: string;
|
|
@@ -3643,6 +3649,8 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
|
|
|
3643
3649
|
sources: Array<{
|
|
3644
3650
|
matureUnpaid: number;
|
|
3645
3651
|
pendingCredits: number;
|
|
3652
|
+
releasedAmount?: number;
|
|
3653
|
+
reservedAmount?: number;
|
|
3646
3654
|
role: "store" | "affiliate" | "other";
|
|
3647
3655
|
}>;
|
|
3648
3656
|
status: "held" | "qualified";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @vitest-environment edge-runtime
|
|
2
2
|
import { convexTest } from "convex-test";
|
|
3
|
+
import { componentDb } from "../testing/component-db.js";
|
|
3
4
|
import { expect, it } from "vitest";
|
|
4
5
|
import type {
|
|
5
6
|
RegisteredQuery,
|
|
@@ -25,31 +26,6 @@ function handler<Args extends DefaultFunctionArgs, Result>(
|
|
|
25
26
|
)._handler;
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
// convex-test supports native pagination even though deployed components do not.
|
|
29
|
-
// Make that runtime restriction explicit while exercising real indexed reads.
|
|
30
|
-
function componentDb<T extends object>(db: T): T {
|
|
31
|
-
function wrap<TValue extends object>(value: TValue): TValue {
|
|
32
|
-
return new Proxy(value, {
|
|
33
|
-
get(target, key) {
|
|
34
|
-
if (key === "paginate")
|
|
35
|
-
return () => {
|
|
36
|
-
throw new Error("paginate() is only supported in the app");
|
|
37
|
-
};
|
|
38
|
-
const member = Reflect.get(target, key);
|
|
39
|
-
if (typeof member !== "function") return member;
|
|
40
|
-
return (...args: unknown[]) => {
|
|
41
|
-
const result = member.apply(target, args);
|
|
42
|
-
return result &&
|
|
43
|
-
typeof result === "object" &&
|
|
44
|
-
!(result instanceof Promise)
|
|
45
|
-
? wrap(result)
|
|
46
|
-
: result;
|
|
47
|
-
};
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
return wrap(db);
|
|
52
|
-
}
|
|
53
29
|
it("reads recovery pages and migrates inside the deployed component pagination boundary", async () => {
|
|
54
30
|
const t = convexTest(schema, import.meta.glob("./**/*.*s"));
|
|
55
31
|
await t.run(async (ctx) => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { paginator } from "convex-helpers/server/pagination";
|
|
2
|
+
import schema from "../schema.js";
|
|
1
3
|
import {
|
|
2
4
|
paginationOptsValidator,
|
|
3
5
|
paginationResultValidator,
|
|
@@ -18,7 +20,7 @@ export const pendingPayouts = query({
|
|
|
18
20
|
}),
|
|
19
21
|
),
|
|
20
22
|
handler: (ctx, args) =>
|
|
21
|
-
ctx.db
|
|
23
|
+
paginator(ctx.db, schema)
|
|
22
24
|
.query("affiliatePayoutReleases")
|
|
23
25
|
.withIndex("by_state", (q) => q.eq("state", args.state))
|
|
24
26
|
.paginate({
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { paginator } from "convex-helpers/server/pagination";
|
|
2
|
+
import schema from "../schema.js";
|
|
1
3
|
import { paginationOptsValidator } from "convex/server";
|
|
2
4
|
import { v } from "convex/values";
|
|
3
5
|
import { query } from "../_generated/server.js";
|
|
@@ -42,7 +44,7 @@ export const listClaims = query({
|
|
|
42
44
|
handler: async (ctx, args) => {
|
|
43
45
|
validateScope(args);
|
|
44
46
|
batchLimit(args.paginationOpts.numItems);
|
|
45
|
-
const result = await ctx.db
|
|
47
|
+
const result = await paginator(ctx.db, schema)
|
|
46
48
|
.query("recoveryClaims")
|
|
47
49
|
.withIndex("by_scope", (q) =>
|
|
48
50
|
q
|