@fantastic.dev/better-stripe 0.28.2 → 0.28.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +5 -1
  3. package/dist/client/connect/payoutAdoptionTestHelpers.d.ts +96 -2
  4. package/dist/client/connect/payoutAdoptionTestHelpers.d.ts.map +1 -1
  5. package/dist/client/connect/payoutExecutionTestHelpers.d.ts +48 -1
  6. package/dist/client/connect/payoutExecutionTestHelpers.d.ts.map +1 -1
  7. package/dist/client/connect/payoutExecutionTestHelpers.js +1 -1
  8. package/dist/client/connect/payoutExecutionTestHelpers.js.map +1 -1
  9. package/dist/client/connect/payoutExpiry.d.ts +42 -0
  10. package/dist/client/connect/payoutExpiry.d.ts.map +1 -0
  11. package/dist/client/connect/payoutExpiry.js +93 -0
  12. package/dist/client/connect/payoutExpiry.js.map +1 -0
  13. package/dist/client/connect/payoutSyncTestHelpers.d.ts +38 -1
  14. package/dist/client/connect/payoutSyncTestHelpers.d.ts.map +1 -1
  15. package/dist/client/payoutPolicy.d.ts +18 -2
  16. package/dist/client/payoutPolicy.d.ts.map +1 -1
  17. package/dist/client/payoutPolicy.js +3 -25
  18. package/dist/client/payoutPolicy.js.map +1 -1
  19. package/dist/component/_generated/component.d.ts +118 -0
  20. package/dist/component/_generated/component.d.ts.map +1 -1
  21. package/dist/component/core/resetSafety.d.ts.map +1 -1
  22. package/dist/component/core/resetSafety.js +7 -1
  23. package/dist/component/core/resetSafety.js.map +1 -1
  24. package/dist/component/earnings/triggers.d.ts +22 -2
  25. package/dist/component/earnings/triggers.d.ts.map +1 -1
  26. package/dist/component/payoutPolicy/expiry.d.ts +78 -0
  27. package/dist/component/payoutPolicy/expiry.d.ts.map +1 -0
  28. package/dist/component/payoutPolicy/expiry.js +57 -0
  29. package/dist/component/payoutPolicy/expiry.js.map +1 -0
  30. package/dist/component/payoutPolicy/helpers.d.ts +10 -0
  31. package/dist/component/payoutPolicy/helpers.d.ts.map +1 -1
  32. package/dist/component/payoutPolicy/mutations.d.ts +77 -0
  33. package/dist/component/payoutPolicy/mutations.d.ts.map +1 -1
  34. package/dist/component/payoutPolicy/mutations.js +36 -3
  35. package/dist/component/payoutPolicy/mutations.js.map +1 -1
  36. package/dist/component/payoutPolicy/queries.d.ts +20 -0
  37. package/dist/component/payoutPolicy/queries.d.ts.map +1 -1
  38. package/dist/component/payoutPolicy/schema.d.ts +139 -2
  39. package/dist/component/payoutPolicy/schema.d.ts.map +1 -1
  40. package/dist/component/payoutPolicy/schema.js +12 -0
  41. package/dist/component/payoutPolicy/schema.js.map +1 -1
  42. package/dist/component/payoutRelease/deadline.d.ts +10 -0
  43. package/dist/component/payoutRelease/deadline.d.ts.map +1 -0
  44. package/dist/component/payoutRelease/deadline.js +20 -0
  45. package/dist/component/payoutRelease/deadline.js.map +1 -0
  46. package/dist/component/payoutRelease/helpers.d.ts +10 -0
  47. package/dist/component/payoutRelease/helpers.d.ts.map +1 -1
  48. package/dist/component/payoutRelease/planning.d.ts +1 -0
  49. package/dist/component/payoutRelease/planning.d.ts.map +1 -1
  50. package/dist/component/payoutRelease/planning.js +5 -2
  51. package/dist/component/payoutRelease/planning.js.map +1 -1
  52. package/dist/component/payoutRelease/preview.d.ts +7 -1
  53. package/dist/component/payoutRelease/preview.d.ts.map +1 -1
  54. package/dist/component/payoutRelease/preview.js +5 -1
  55. package/dist/component/payoutRelease/preview.js.map +1 -1
  56. package/dist/component/payoutRelease/queries.d.ts +2 -0
  57. package/dist/component/payoutRelease/queries.d.ts.map +1 -1
  58. package/dist/component/payoutWorker/mutations.d.ts.map +1 -1
  59. package/dist/component/payoutWorker/mutations.js +12 -4
  60. package/dist/component/payoutWorker/mutations.js.map +1 -1
  61. package/dist/component/payoutWorker/queries.d.ts +20 -0
  62. package/dist/component/payoutWorker/queries.d.ts.map +1 -1
  63. package/dist/component/schema.d.ts +38 -1
  64. package/dist/react/workflows/PayoutProgress.d.ts.map +1 -1
  65. package/dist/react/workflows/PayoutProgress.js +2 -2
  66. package/dist/react/workflows/PayoutProgress.js.map +1 -1
  67. package/dist/react/workflows/PayoutSettings.d.ts.map +1 -1
  68. package/dist/react/workflows/PayoutSettings.js +1 -1
  69. package/dist/react/workflows/PayoutSettings.js.map +1 -1
  70. package/dist/react/workflows/payout-progress-state.d.ts +11 -1
  71. package/dist/react/workflows/payout-progress-state.d.ts.map +1 -1
  72. package/dist/react/workflows/payout-progress-state.js +42 -7
  73. package/dist/react/workflows/payout-progress-state.js.map +1 -1
  74. package/docs/react-workflows.md +14 -0
  75. package/docs/settlement.md +50 -0
  76. package/package.json +1 -1
  77. package/src/client/connect/payoutDeadline.test.ts +238 -0
  78. package/src/client/connect/payoutExecutionTestHelpers.ts +1 -1
  79. package/src/client/connect/payoutExpiry.ts +132 -0
  80. package/src/client/payoutPolicy.test.ts +196 -0
  81. package/src/client/payoutPolicy.ts +9 -23
  82. package/src/component/_generated/api.ts +4 -0
  83. package/src/component/_generated/component.ts +145 -0
  84. package/src/component/core/resetSafety.ts +49 -33
  85. package/src/component/payout-reset-safety.test.ts +28 -0
  86. package/src/component/payoutPolicy/expiry.ts +80 -0
  87. package/src/component/payoutPolicy/mutations.ts +47 -2
  88. package/src/component/payoutPolicy/schema.ts +17 -0
  89. package/src/component/payoutRelease/deadline.ts +24 -0
  90. package/src/component/payoutRelease/planning.ts +5 -2
  91. package/src/component/payoutRelease/preview.ts +5 -0
  92. package/src/component/payoutWorker/mutations.ts +20 -4
  93. package/src/react/workflows/PayoutProgress.test.tsx +65 -0
  94. package/src/react/workflows/PayoutProgress.tsx +25 -1
  95. package/src/react/workflows/PayoutSettings.tsx +4 -1
  96. package/src/react/workflows/payout-progress-state.ts +60 -8
@@ -0,0 +1,132 @@
1
+ import type Stripe from "stripe";
2
+ import type { Infer } from "convex/values";
3
+ import type { Component, RunCtx } from "../helpers.js";
4
+ import { runMutationOrThrow } from "../helpers.js";
5
+ import { componentRef } from "../webhooks/helpers.js";
6
+ import type { policyDoc } from "../../component/payoutPolicy/schema.js";
7
+ type Scope = { accountId: string; ownerKey: string };
8
+ type Policy = Infer<typeof policyDoc>;
9
+ function expiryBalances(balance: Stripe.Balance) {
10
+ const values = new Map<
11
+ string,
12
+ { currency: string; available: number; pending: number }
13
+ >();
14
+ for (const type of ["available", "pending"] as const) {
15
+ const seen = new Set<string>();
16
+ for (const row of balance[type]) {
17
+ if (
18
+ !/^[a-z]{3}$/.test(row.currency) ||
19
+ !Number.isSafeInteger(row.amount) ||
20
+ seen.has(row.currency)
21
+ )
22
+ throw new Error("Invalid expiry balance.");
23
+ seen.add(row.currency);
24
+ const value = values.get(row.currency) ?? {
25
+ currency: row.currency,
26
+ available: 0,
27
+ pending: 0,
28
+ };
29
+ value[type] = row.amount;
30
+ values.set(row.currency, value);
31
+ }
32
+ }
33
+ return [...values.values()].sort((a, b) =>
34
+ a.currency.localeCompare(b.currency),
35
+ );
36
+ }
37
+ /** Restore controls, then separately verify remaining balances and durable claims. Never creates a payout. */
38
+ export async function expirePayoutPolicy<
39
+ R extends { status: string },
40
+ P extends { status: string },
41
+ >(
42
+ stripe: Stripe,
43
+ component: Component,
44
+ ctx: RunCtx,
45
+ scope: Scope,
46
+ client: {
47
+ get(ctx: RunCtx, scope: Scope): Promise<Policy | null>;
48
+ apply(ctx: RunCtx, args: Scope & { operationKey: string }): Promise<R>;
49
+ prepare(
50
+ ctx: RunCtx,
51
+ args: Scope & {
52
+ operationKey: string;
53
+ expectedRevision: number;
54
+ mode: "stripe_managed";
55
+ thresholds: [];
56
+ },
57
+ ): Promise<P>;
58
+ },
59
+ ) {
60
+ scope = { accountId: scope.accountId, ownerKey: scope.ownerKey };
61
+ let policy = await client.get(ctx, scope);
62
+ if (!policy?.holdDeadline || policy.holdDeadline > Date.now())
63
+ return { status: "not_due" as const };
64
+ if (policy.mode === "custom")
65
+ policy = (await runMutationOrThrow(
66
+ ctx,
67
+ componentRef(component, "payoutPolicy/mutations/beginHoldingExpiry"),
68
+ scope,
69
+ )) as Policy;
70
+ if (policy.status === "changing") {
71
+ const result = await client.apply(ctx, {
72
+ ...scope,
73
+ operationKey: policy.operationKey,
74
+ });
75
+ if (result.status !== "ready") return result;
76
+ policy = await client.get(ctx, scope);
77
+ }
78
+ if (!policy) return { status: "not_due" as const };
79
+ if (policy.mode === "custom") {
80
+ const operationKey = `bs:payout-expiry:${scope.accountId}:${policy.revision}`;
81
+ const prepared = await client.prepare(ctx, {
82
+ ...scope,
83
+ operationKey,
84
+ expectedRevision: policy.revision,
85
+ mode: "stripe_managed",
86
+ thresholds: [],
87
+ });
88
+ if (prepared.status !== "prepared") return prepared;
89
+ const applied = await client.apply(ctx, { ...scope, operationKey });
90
+ if (applied.status !== "ready") return applied;
91
+ policy = await client.get(ctx, scope);
92
+ }
93
+ if (
94
+ !policy?.holdingExpiry ||
95
+ policy.mode !== "stripe_managed" ||
96
+ policy.status !== "ready"
97
+ )
98
+ return { status: "not_due" as const };
99
+ const unresolved = {
100
+ status: "expiry_unresolved" as const,
101
+ holdingExpiry: policy.holdingExpiry,
102
+ };
103
+ let balances;
104
+ const observedAt = Date.now();
105
+ try {
106
+ balances = expiryBalances(
107
+ await stripe.balance.retrieve(undefined, {
108
+ stripeAccount: scope.accountId,
109
+ }),
110
+ );
111
+ } catch {
112
+ return unresolved;
113
+ }
114
+ if (Date.now() - observedAt > 30000) return unresolved;
115
+ const observed = (await runMutationOrThrow(
116
+ ctx,
117
+ componentRef(component, "payoutPolicy/mutations/observeHoldingExpiry"),
118
+ {
119
+ ...scope,
120
+ expectedRevision: policy.revision,
121
+ deadline: policy.holdingExpiry.deadline,
122
+ observedAt,
123
+ balances,
124
+ },
125
+ )) as Policy;
126
+ if (observed.holdingExpiry!.status !== "no_held_balance")
127
+ return {
128
+ status: "expiry_unresolved" as const,
129
+ holdingExpiry: observed.holdingExpiry!,
130
+ };
131
+ return client.apply(ctx, { ...scope, operationKey: policy.operationKey });
132
+ }
@@ -381,3 +381,199 @@ it("requires adoption for historical payouts even when today's balance is zero",
381
381
  expect(provider.balanceSettings.update).not.toHaveBeenCalled();
382
382
  expect(await client.get(ctx, scope)).toBeNull();
383
383
  });
384
+
385
+ async function expiredRecipient() {
386
+ const s = await setup();
387
+ await s.client.prepare(s.ctx, options);
388
+ await s.client.apply(s.ctx, { ...scope, operationKey: "enable" });
389
+ const deadline = Date.now() - 1;
390
+ await s.t.run(async (ctx) => {
391
+ const p = (await ctx.db.query("payoutPolicies").first())!;
392
+ await ctx.db.patch(p._id, { holdDeadline: deadline });
393
+ });
394
+ return { ...s, deadline };
395
+ }
396
+ it("keeps funded expiry discoverable after restoring weekly controls until fresh balances clear", async () => {
397
+ const s = await expiredRecipient();
398
+ s.provider.balance.retrieve.mockResolvedValue({
399
+ available: [{ currency: "usd", amount: 999 }],
400
+ pending: [],
401
+ });
402
+ expect(await s.client.expire(s.ctx, scope)).toMatchObject({
403
+ status: "expiry_unresolved",
404
+ });
405
+ expect(await s.client.get(s.ctx, scope)).toMatchObject({
406
+ mode: "stripe_managed",
407
+ status: "ready",
408
+ holdDeadline: s.deadline,
409
+ holdingExpiry: {
410
+ deadline: s.deadline,
411
+ status: "balance_remaining",
412
+ balances: [{ currency: "usd", available: 999, pending: 0 }],
413
+ },
414
+ });
415
+ expect(
416
+ (await s.client.due(s.ctx, { cursor: null, numItems: 10 })).page,
417
+ ).toHaveLength(1);
418
+ await s.client.expire(s.ctx, scope);
419
+ expect(s.provider.balanceSettings.update).toHaveBeenCalledTimes(2);
420
+ s.provider.balance.retrieve.mockResolvedValue({
421
+ available: [{ currency: "usd", amount: 0 }],
422
+ pending: [],
423
+ });
424
+ expect(await s.client.expire(s.ctx, scope)).toMatchObject({
425
+ status: "ready",
426
+ });
427
+ expect((await s.client.get(s.ctx, scope))!.holdDeadline).toBeUndefined();
428
+ expect((await s.client.get(s.ctx, scope))!.holdingExpiry).toMatchObject({
429
+ status: "no_held_balance",
430
+ deadline: s.deadline,
431
+ });
432
+ expect(
433
+ (await s.client.due(s.ctx, { cursor: null, numItems: 10 })).page,
434
+ ).toHaveLength(0);
435
+ });
436
+ it("restores controls even if expiry balance verification is unavailable, without fabricating zero", async () => {
437
+ const s = await expiredRecipient();
438
+ s.provider.balance.retrieve.mockRejectedValue(
439
+ new Error("provider unavailable"),
440
+ );
441
+ expect(await s.client.expire(s.ctx, scope)).toMatchObject({
442
+ status: "expiry_unresolved",
443
+ });
444
+ const p = await s.client.get(s.ctx, scope);
445
+ expect(p).toMatchObject({
446
+ mode: "stripe_managed",
447
+ holdDeadline: s.deadline,
448
+ holdingExpiry: { status: "unverified" },
449
+ });
450
+ expect(p!.holdingExpiry!.balances).toBeUndefined();
451
+ expect(
452
+ (await s.provider.balanceSettings.retrieve()).payments.payouts.schedule
453
+ .interval,
454
+ ).toBe("weekly");
455
+ });
456
+ it("does not clear an unknown payout claim at expiry even when Stripe balance is zero", async () => {
457
+ const s = await expiredRecipient();
458
+ const id = await s.t.run((ctx) =>
459
+ ctx.db.insert("payoutReleaseClaims", {
460
+ ...scope,
461
+ operationKey: "unknown-payout",
462
+ expectedRevision: 0,
463
+ amount: 999,
464
+ currency: "usd",
465
+ allocations: [],
466
+ observations: [],
467
+ status: "reserved",
468
+ attemptedAt: Date.now(),
469
+ }),
470
+ );
471
+ expect(await s.client.expire(s.ctx, scope)).toMatchObject({
472
+ status: "expiry_unresolved",
473
+ });
474
+ expect((await s.client.get(s.ctx, scope))!.holdingExpiry).toMatchObject({
475
+ status: "claims_unresolved",
476
+ });
477
+ expect(await s.t.run((ctx) => ctx.db.get(id))).toMatchObject({
478
+ status: "reserved",
479
+ amount: 999,
480
+ });
481
+ await expect(
482
+ s.client.prepare(s.ctx, {
483
+ ...options,
484
+ expectedRevision: 1,
485
+ operationKey: "reactivate",
486
+ }),
487
+ ).rejects.toThrow(/expiry.*recovery/i);
488
+ });
489
+ it("does not net currencies or pending funds when checking expiry recovery", async () => {
490
+ const s = await expiredRecipient();
491
+ s.provider.balance.retrieve.mockResolvedValue({
492
+ available: [
493
+ { currency: "usd", amount: 100 },
494
+ { currency: "eur", amount: -100 },
495
+ ],
496
+ pending: [{ currency: "usd", amount: 25 }],
497
+ });
498
+ expect(await s.client.expire(s.ctx, scope)).toMatchObject({
499
+ status: "expiry_unresolved",
500
+ });
501
+ expect((await s.client.get(s.ctx, scope))!.holdingExpiry!.balances).toEqual([
502
+ { currency: "eur", available: -100, pending: 0 },
503
+ { currency: "usd", available: 100, pending: 25 },
504
+ ]);
505
+ });
506
+
507
+ it("does not label a delayed expiry balance response as a fresh observation", async () => {
508
+ vi.useFakeTimers();
509
+ try {
510
+ const s = await expiredRecipient();
511
+ s.provider.balance.retrieve.mockImplementation(async () => {
512
+ vi.advanceTimersByTime(31000);
513
+ return { available: [{ currency: "usd", amount: 0 }], pending: [] };
514
+ });
515
+ expect(await s.client.expire(s.ctx, scope)).toMatchObject({
516
+ status: "expiry_unresolved",
517
+ });
518
+ expect((await s.client.get(s.ctx, scope))!.holdingExpiry).toMatchObject({
519
+ status: "unverified",
520
+ });
521
+ } finally {
522
+ vi.useRealTimers();
523
+ }
524
+ });
525
+
526
+ it("retries a lost recovery write without losing its original deadline or restoring twice", async () => {
527
+ const s = await expiredRecipient();
528
+ const write = s.ctx.runMutation!;
529
+ s.ctx.runMutation = (async (ref: Record<symbol, string>, args: never) => {
530
+ if (ref[symbol].endsWith("/observeHoldingExpiry"))
531
+ throw new Error("recovery write failed");
532
+ return write(ref as never, args);
533
+ }) as never;
534
+ await expect(s.client.expire(s.ctx, scope)).rejects.toThrow(
535
+ /recovery write failed/,
536
+ );
537
+ expect(await s.client.get(s.ctx, scope)).toMatchObject({
538
+ mode: "stripe_managed",
539
+ holdDeadline: s.deadline,
540
+ holdingExpiry: { status: "unverified" },
541
+ });
542
+ s.ctx.runMutation = write;
543
+ expect(await s.client.expire(s.ctx, scope)).toMatchObject({
544
+ status: "ready",
545
+ });
546
+ expect(s.provider.balanceSettings.update).toHaveBeenCalledTimes(2);
547
+ });
548
+ it("concurrent expiry retries preserve one restoration identity and unresolved funds", async () => {
549
+ const s = await expiredRecipient();
550
+ s.provider.balance.retrieve.mockResolvedValue({
551
+ available: [{ currency: "usd", amount: 999 }],
552
+ pending: [],
553
+ });
554
+ const results = await Promise.allSettled([
555
+ s.client.expire(s.ctx, scope),
556
+ s.client.expire(s.ctx, scope),
557
+ ]);
558
+ expect(results.some((r) => r.status === "fulfilled")).toBe(true);
559
+ expect(await s.client.expire(s.ctx, scope)).toMatchObject({
560
+ status: "expiry_unresolved",
561
+ });
562
+ expect(await s.client.get(s.ctx, scope)).toMatchObject({
563
+ mode: "stripe_managed",
564
+ holdDeadline: s.deadline,
565
+ holdingExpiry: { status: "balance_remaining" },
566
+ });
567
+ const restoreKeys = s.provider.balanceSettings.update.mock.calls
568
+ .slice(1)
569
+ .map((c) => (c[1] as { idempotencyKey: string }).idempotencyKey);
570
+ expect(new Set(restoreKeys).size).toBe(1);
571
+ });
572
+
573
+ it("accepts a due policy document as scope without forwarding its extra fields to mutations", async () => {
574
+ const s = await expiredRecipient();
575
+ const policy = (await s.client.get(s.ctx, scope))!;
576
+ expect(await s.client.expire(s.ctx, policy)).toMatchObject({
577
+ status: "ready",
578
+ });
579
+ });
@@ -1,3 +1,5 @@
1
+ export { holdingExpiry as payoutHoldingExpiryValidator } from "../component/payoutPolicy/schema.js";
2
+ import { expirePayoutPolicy } from "./connect/payoutExpiry.js";
1
3
  import {
2
4
  previewRecipientPayout,
3
5
  type PayoutPreviewOptions,
@@ -570,28 +572,12 @@ export class PayoutPolicyClient {
570
572
  }
571
573
  /** A host cron must page due() and call expire(); payout execution is a separate boundary. */
572
574
  async expire(ctx: RunCtx, scope: PayoutPolicyScope) {
573
- let policy = await this.get(ctx, scope);
574
- if (!policy?.holdDeadline || policy.holdDeadline > Date.now())
575
- return { status: "not_due" as const };
576
- if (policy.status === "changing") {
577
- const result = await this.apply(ctx, {
578
- ...scope,
579
- operationKey: policy.operationKey,
580
- });
581
- if (result.status !== "ready") return result;
582
- policy = await this.get(ctx, scope);
583
- }
584
- if (!policy || policy.mode !== "custom")
585
- return { status: "not_due" as const };
586
- const operationKey = `bs:payout-expiry:${scope.accountId}:${policy.revision}`;
587
- const prepared = await this.prepare(ctx, {
588
- ...scope,
589
- operationKey,
590
- expectedRevision: policy.revision,
591
- mode: "stripe_managed",
592
- thresholds: [],
593
- });
594
- if (prepared.status !== "prepared") return prepared;
595
- return this.apply(ctx, { ...scope, operationKey });
575
+ return expirePayoutPolicy(
576
+ this.provider(),
577
+ this.component,
578
+ ctx,
579
+ scope,
580
+ this,
581
+ );
596
582
  }
597
583
  }
@@ -47,12 +47,14 @@ import type * as lib_paymentSeller from "../lib/paymentSeller.js";
47
47
  import type * as lib_reversals from "../lib/reversals.js";
48
48
  import type * as lib_stripeFactory from "../lib/stripeFactory.js";
49
49
  import type * as payoutPolicy_adoption from "../payoutPolicy/adoption.js";
50
+ import type * as payoutPolicy_expiry from "../payoutPolicy/expiry.js";
50
51
  import type * as payoutPolicy_helpers from "../payoutPolicy/helpers.js";
51
52
  import type * as payoutPolicy_mutations from "../payoutPolicy/mutations.js";
52
53
  import type * as payoutPolicy_queries from "../payoutPolicy/queries.js";
53
54
  import type * as payoutRelease_adoption from "../payoutRelease/adoption.js";
54
55
  import type * as payoutRelease_allocation from "../payoutRelease/allocation.js";
55
56
  import type * as payoutRelease_allocationTotals from "../payoutRelease/allocationTotals.js";
57
+ import type * as payoutRelease_deadline from "../payoutRelease/deadline.js";
56
58
  import type * as payoutRelease_fees from "../payoutRelease/fees.js";
57
59
  import type * as payoutRelease_helpers from "../payoutRelease/helpers.js";
58
60
  import type * as payoutRelease_mutations from "../payoutRelease/mutations.js";
@@ -131,12 +133,14 @@ const fullApi: ApiFromModules<{
131
133
  "lib/reversals": typeof lib_reversals;
132
134
  "lib/stripeFactory": typeof lib_stripeFactory;
133
135
  "payoutPolicy/adoption": typeof payoutPolicy_adoption;
136
+ "payoutPolicy/expiry": typeof payoutPolicy_expiry;
134
137
  "payoutPolicy/helpers": typeof payoutPolicy_helpers;
135
138
  "payoutPolicy/mutations": typeof payoutPolicy_mutations;
136
139
  "payoutPolicy/queries": typeof payoutPolicy_queries;
137
140
  "payoutRelease/adoption": typeof payoutRelease_adoption;
138
141
  "payoutRelease/allocation": typeof payoutRelease_allocation;
139
142
  "payoutRelease/allocationTotals": typeof payoutRelease_allocationTotals;
143
+ "payoutRelease/deadline": typeof payoutRelease_deadline;
140
144
  "payoutRelease/fees": typeof payoutRelease_fees;
141
145
  "payoutRelease/helpers": typeof payoutRelease_helpers;
142
146
  "payoutRelease/mutations": typeof payoutRelease_mutations;
@@ -2790,6 +2790,44 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
2790
2790
  },
2791
2791
  Name
2792
2792
  >;
2793
+ beginHoldingExpiry: FunctionReference<
2794
+ "mutation",
2795
+ "internal",
2796
+ { accountId: string; ownerKey: string },
2797
+ {
2798
+ _creationTime: number;
2799
+ _id: string;
2800
+ accountId: string;
2801
+ country: string;
2802
+ holdDeadline?: number;
2803
+ holdingExpiry?: {
2804
+ balances?: Array<{
2805
+ available: number;
2806
+ currency: string;
2807
+ pending: number;
2808
+ }>;
2809
+ deadline: number;
2810
+ observedAt?: number;
2811
+ status:
2812
+ | "unverified"
2813
+ | "balance_remaining"
2814
+ | "claims_unresolved"
2815
+ | "no_held_balance";
2816
+ };
2817
+ mode: "stripe_managed" | "custom";
2818
+ operationKey: string;
2819
+ ownerKey: string;
2820
+ previousSchedule?: {
2821
+ interval: "daily" | "weekly" | "monthly" | "manual";
2822
+ monthlyDays?: Array<number>;
2823
+ weeklyDays?: Array<string>;
2824
+ };
2825
+ revision: number;
2826
+ status: "changing" | "ready";
2827
+ thresholds: Array<{ amount: number; currency: string }>;
2828
+ },
2829
+ Name
2830
+ >;
2793
2831
  cancelUnattempted: FunctionReference<
2794
2832
  "mutation",
2795
2833
  "internal",
@@ -2906,6 +2944,55 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
2906
2944
  },
2907
2945
  Name
2908
2946
  >;
2947
+ observeHoldingExpiry: FunctionReference<
2948
+ "mutation",
2949
+ "internal",
2950
+ {
2951
+ accountId: string;
2952
+ balances: Array<{
2953
+ available: number;
2954
+ currency: string;
2955
+ pending: number;
2956
+ }>;
2957
+ deadline: number;
2958
+ expectedRevision: number;
2959
+ observedAt: number;
2960
+ ownerKey: string;
2961
+ },
2962
+ {
2963
+ _creationTime: number;
2964
+ _id: string;
2965
+ accountId: string;
2966
+ country: string;
2967
+ holdDeadline?: number;
2968
+ holdingExpiry?: {
2969
+ balances?: Array<{
2970
+ available: number;
2971
+ currency: string;
2972
+ pending: number;
2973
+ }>;
2974
+ deadline: number;
2975
+ observedAt?: number;
2976
+ status:
2977
+ | "unverified"
2978
+ | "balance_remaining"
2979
+ | "claims_unresolved"
2980
+ | "no_held_balance";
2981
+ };
2982
+ mode: "stripe_managed" | "custom";
2983
+ operationKey: string;
2984
+ ownerKey: string;
2985
+ previousSchedule?: {
2986
+ interval: "daily" | "weekly" | "monthly" | "manual";
2987
+ monthlyDays?: Array<number>;
2988
+ weeklyDays?: Array<string>;
2989
+ };
2990
+ revision: number;
2991
+ status: "changing" | "ready";
2992
+ thresholds: Array<{ amount: number; currency: string }>;
2993
+ },
2994
+ Name
2995
+ >;
2909
2996
  prepare: FunctionReference<
2910
2997
  "mutation",
2911
2998
  "internal",
@@ -3007,6 +3094,20 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
3007
3094
  accountId: string;
3008
3095
  country: string;
3009
3096
  holdDeadline?: number;
3097
+ holdingExpiry?: {
3098
+ balances?: Array<{
3099
+ available: number;
3100
+ currency: string;
3101
+ pending: number;
3102
+ }>;
3103
+ deadline: number;
3104
+ observedAt?: number;
3105
+ status:
3106
+ | "unverified"
3107
+ | "balance_remaining"
3108
+ | "claims_unresolved"
3109
+ | "no_held_balance";
3110
+ };
3010
3111
  mode: "stripe_managed" | "custom";
3011
3112
  operationKey: string;
3012
3113
  ownerKey: string;
@@ -3032,6 +3133,20 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
3032
3133
  accountId: string;
3033
3134
  country: string;
3034
3135
  holdDeadline?: number;
3136
+ holdingExpiry?: {
3137
+ balances?: Array<{
3138
+ available: number;
3139
+ currency: string;
3140
+ pending: number;
3141
+ }>;
3142
+ deadline: number;
3143
+ observedAt?: number;
3144
+ status:
3145
+ | "unverified"
3146
+ | "balance_remaining"
3147
+ | "claims_unresolved"
3148
+ | "no_held_balance";
3149
+ };
3035
3150
  mode: "stripe_managed" | "custom";
3036
3151
  operationKey: string;
3037
3152
  ownerKey: string;
@@ -3639,8 +3754,10 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
3639
3754
  amount: number;
3640
3755
  confirmedFees: number;
3641
3756
  currency: string;
3757
+ holdDeadline?: number;
3642
3758
  independentLiabilities: number;
3643
3759
  matureUnpaid: number;
3760
+ minimumWaived?: boolean;
3644
3761
  observedAt: number;
3645
3762
  pendingCredits: number;
3646
3763
  providerAvailable: number;
@@ -4061,6 +4178,20 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
4061
4178
  accountId: string;
4062
4179
  country: string;
4063
4180
  holdDeadline?: number;
4181
+ holdingExpiry?: {
4182
+ balances?: Array<{
4183
+ available: number;
4184
+ currency: string;
4185
+ pending: number;
4186
+ }>;
4187
+ deadline: number;
4188
+ observedAt?: number;
4189
+ status:
4190
+ | "unverified"
4191
+ | "balance_remaining"
4192
+ | "claims_unresolved"
4193
+ | "no_held_balance";
4194
+ };
4064
4195
  mode: "stripe_managed" | "custom";
4065
4196
  operationKey: string;
4066
4197
  ownerKey: string;
@@ -4122,6 +4253,20 @@ export type ComponentApi<Name extends string | undefined = string | undefined> =
4122
4253
  accountId: string;
4123
4254
  country: string;
4124
4255
  holdDeadline?: number;
4256
+ holdingExpiry?: {
4257
+ balances?: Array<{
4258
+ available: number;
4259
+ currency: string;
4260
+ pending: number;
4261
+ }>;
4262
+ deadline: number;
4263
+ observedAt?: number;
4264
+ status:
4265
+ | "unverified"
4266
+ | "balance_remaining"
4267
+ | "claims_unresolved"
4268
+ | "no_held_balance";
4269
+ };
4125
4270
  mode: "stripe_managed" | "custom";
4126
4271
  operationKey: string;
4127
4272
  ownerKey: string;