@fantastic.dev/better-stripe 0.9.0 → 0.10.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 +6 -0
- package/MIGRATION.md +12 -0
- package/README.md +29 -1
- package/dist/client/billing/checkout.d.ts +1 -0
- package/dist/client/billing/checkout.d.ts.map +1 -1
- package/dist/client/billing/checkout.js +5 -1
- package/dist/client/billing/checkout.js.map +1 -1
- package/dist/client/billing/providerReads.d.ts +18 -0
- package/dist/client/billing/providerReads.d.ts.map +1 -0
- package/dist/client/billing/providerReads.js +15 -0
- package/dist/client/billing/providerReads.js.map +1 -0
- package/dist/client/billing/subscriptions.d.ts +1 -1
- package/dist/client/billing/subscriptions.d.ts.map +1 -1
- package/dist/client/billing/subscriptions.js.map +1 -1
- package/dist/client/connect/payoutSnapshot.d.ts +28 -0
- package/dist/client/connect/payoutSnapshot.d.ts.map +1 -0
- package/dist/client/connect/payoutSnapshot.js +81 -0
- package/dist/client/connect/payoutSnapshot.js.map +1 -0
- package/dist/client/connect/transfers.d.ts.map +1 -1
- package/dist/client/connect/transfers.js +13 -32
- package/dist/client/connect/transfers.js.map +1 -1
- package/dist/client/core/accounts.d.ts +12 -23
- package/dist/client/core/accounts.d.ts.map +1 -1
- package/dist/client/core/accounts.js +5 -1
- package/dist/client/core/accounts.js.map +1 -1
- package/dist/client/core/idempotency.d.ts +5 -0
- package/dist/client/core/idempotency.d.ts.map +1 -0
- package/dist/client/core/idempotency.js +10 -0
- package/dist/client/core/idempotency.js.map +1 -0
- package/dist/client/index.d.ts +31 -25
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +29 -52
- package/dist/client/index.js.map +1 -1
- package/dist/client/settlement/allocation.d.ts +30 -0
- package/dist/client/settlement/allocation.d.ts.map +1 -0
- package/dist/client/settlement/allocation.js +71 -0
- package/dist/client/settlement/allocation.js.map +1 -0
- package/dist/client/settlement/commissions.d.ts +27 -0
- package/dist/client/settlement/commissions.d.ts.map +1 -0
- package/dist/client/settlement/commissions.js +69 -0
- package/dist/client/settlement/commissions.js.map +1 -0
- package/dist/client/settlement/execution.d.ts +27 -0
- package/dist/client/settlement/execution.d.ts.map +1 -0
- package/dist/client/settlement/execution.js +70 -0
- package/dist/client/settlement/execution.js.map +1 -0
- package/dist/client/settlement/reconciliation.d.ts +10 -0
- package/dist/client/settlement/reconciliation.d.ts.map +1 -0
- package/dist/client/settlement/reconciliation.js +73 -0
- package/dist/client/settlement/reconciliation.js.map +1 -0
- package/dist/client/settlement/settleSale.d.ts +21 -0
- package/dist/client/settlement/settleSale.d.ts.map +1 -0
- package/dist/client/settlement/settleSale.js +27 -0
- package/dist/client/settlement/settleSale.js.map +1 -0
- package/dist/client/settlement/verifiedSale.d.ts +25 -0
- package/dist/client/settlement/verifiedSale.d.ts.map +1 -0
- package/dist/client/settlement/verifiedSale.js +100 -0
- package/dist/client/settlement/verifiedSale.js.map +1 -0
- package/dist/client/webhooks/asyncHooks.d.ts +5 -0
- package/dist/client/webhooks/asyncHooks.d.ts.map +1 -0
- package/dist/client/webhooks/asyncHooks.js +20 -0
- package/dist/client/webhooks/asyncHooks.js.map +1 -0
- package/dist/component/_generated/component.d.ts +80 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/schema.d.ts +67 -0
- package/dist/component/schema.js +4 -0
- package/dist/component/schema.js.map +1 -1
- package/dist/component/settlement/mutations.d.ts +47 -0
- package/dist/component/settlement/mutations.d.ts.map +1 -0
- package/dist/component/settlement/mutations.js +104 -0
- package/dist/component/settlement/mutations.js.map +1 -0
- package/dist/component/settlement/queries.d.ts +29 -0
- package/dist/component/settlement/queries.d.ts.map +1 -0
- package/dist/component/settlement/queries.js +35 -0
- package/dist/component/settlement/queries.js.map +1 -0
- package/dist/component/settlement/schema.d.ts +99 -0
- package/dist/component/settlement/schema.d.ts.map +1 -0
- package/dist/component/settlement/schema.js +35 -0
- package/dist/component/settlement/schema.js.map +1 -0
- package/dist/react/workflows/Checkout.d.ts +3 -1
- package/dist/react/workflows/Checkout.d.ts.map +1 -1
- package/dist/react/workflows/Checkout.js +3 -2
- package/dist/react/workflows/Checkout.js.map +1 -1
- package/dist/react/workflows/Payouts.d.ts +3 -18
- package/dist/react/workflows/Payouts.d.ts.map +1 -1
- package/dist/react/workflows/Payouts.js +2 -2
- package/dist/react/workflows/Payouts.js.map +1 -1
- package/docs/react-workflows.md +5 -2
- package/docs/settlement.md +158 -0
- package/package.json +2 -1
- package/src/client/billing/checkout-idempotency.test.ts +82 -0
- package/src/client/billing/checkout.ts +6 -1
- package/src/client/billing/providerReads.test.ts +60 -0
- package/src/client/billing/providerReads.ts +30 -0
- package/src/client/billing/subscriptions.ts +1 -8
- package/src/client/connect/payoutSnapshot.test.ts +91 -0
- package/src/client/connect/payoutSnapshot.ts +130 -0
- package/src/client/connect/transfers.test.ts +15 -4
- package/src/client/connect/transfers.ts +13 -42
- package/src/client/core/account-idempotency.test.ts +78 -0
- package/src/client/core/accounts.ts +18 -25
- package/src/client/core/idempotency.test.ts +10 -0
- package/src/client/core/idempotency.ts +11 -0
- package/src/client/index.ts +84 -103
- package/src/client/settlement/allocation.test.ts +98 -0
- package/src/client/settlement/allocation.ts +110 -0
- package/src/client/settlement/commissions.test.ts +103 -0
- package/src/client/settlement/commissions.ts +125 -0
- package/src/client/settlement/execution.test.ts +186 -0
- package/src/client/settlement/execution.ts +134 -0
- package/src/client/settlement/reconciliation.ts +119 -0
- package/src/client/settlement/settleSale.ts +59 -0
- package/src/client/settlement/verifiedSale.test.ts +139 -0
- package/src/client/settlement/verifiedSale.ts +159 -0
- package/src/client/webhooks/asyncHooks.ts +38 -0
- package/src/client/webhooks/processors.test.ts +9 -9
- package/src/component/_generated/api.ts +4 -0
- package/src/component/_generated/component.ts +100 -0
- package/src/component/schema.ts +8 -0
- package/src/component/settlement/mutations.ts +119 -0
- package/src/component/settlement/queries.ts +38 -0
- package/src/component/settlement/schema.ts +45 -0
- package/src/component/settlement-claims.test.ts +77 -0
- package/src/react/components/EmbeddedDisputes.render.test.tsx +2 -2
- package/src/react/index.payment-element.test.ts +22 -37
- package/src/react/workflows/Checkout.test.tsx +30 -0
- package/src/react/workflows/Checkout.tsx +10 -3
- package/src/react/workflows/Payouts.test.tsx +33 -0
- package/src/react/workflows/Payouts.tsx +21 -15
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { recoverSettlementTransfers } from "../settlement/reconciliation.js";
|
|
2
|
+
import { executeResolvedTransfers } from "../settlement/execution.js";
|
|
1
3
|
import type Stripe from "stripe";
|
|
2
4
|
|
|
3
5
|
import type { SplitRecipient } from "../../component/lib/fees.js";
|
|
@@ -303,6 +305,7 @@ export async function reverseTransfers(
|
|
|
303
305
|
throw new Error("reverseTransfers: amount must be a non-negative integer");
|
|
304
306
|
}
|
|
305
307
|
|
|
308
|
+
await recoverSettlementTransfers(stripe, component, ctx, opts.sourceChargeId);
|
|
306
309
|
if (opts.operationId) {
|
|
307
310
|
const claim = (await runMutationOrThrow(
|
|
308
311
|
ctx,
|
|
@@ -421,6 +424,7 @@ export async function reverseTransfersForRefund(
|
|
|
421
424
|
return { reversals: [] };
|
|
422
425
|
}
|
|
423
426
|
|
|
427
|
+
await recoverSettlementTransfers(stripe, component, ctx, opts.sourceChargeId);
|
|
424
428
|
const claim = (await runMutationOrThrow(
|
|
425
429
|
ctx,
|
|
426
430
|
componentRef(component, "connect/mutations/claimReversalSlices"),
|
|
@@ -460,48 +464,15 @@ export async function createSplitTransfers(
|
|
|
460
464
|
): Promise<SplitResult> {
|
|
461
465
|
const result = computeSplit(opts.amount, opts.feeConfig, opts.split);
|
|
462
466
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
);
|
|
473
|
-
|
|
474
|
-
for (const t of result.transfers) {
|
|
475
|
-
if (t.amount <= 0) continue;
|
|
476
|
-
if (done.has(`${t.destinationAccountId}:${t.role}`)) continue;
|
|
477
|
-
const transfer = await stripe.transfers.create(
|
|
478
|
-
{
|
|
479
|
-
amount: t.amount,
|
|
480
|
-
currency: opts.currency,
|
|
481
|
-
destination: t.destinationAccountId,
|
|
482
|
-
source_transaction: opts.sourceChargeId,
|
|
483
|
-
metadata: { bsRole: t.role, bsSourceCharge: opts.sourceChargeId },
|
|
484
|
-
},
|
|
485
|
-
// Deterministic key so a webhook retry can't double-transfer (BTS-24).
|
|
486
|
-
{
|
|
487
|
-
idempotencyKey: `bs_split_${opts.sourceChargeId}_${t.destinationAccountId}_${t.role}`,
|
|
488
|
-
},
|
|
489
|
-
);
|
|
490
|
-
await runMutationOrThrow(
|
|
491
|
-
ctx,
|
|
492
|
-
componentRef(component, "connect/mutations/upsertTransfer"),
|
|
493
|
-
{
|
|
494
|
-
stripeTransferId: transfer.id,
|
|
495
|
-
sourceChargeId: opts.sourceChargeId,
|
|
496
|
-
destinationAccountId: t.destinationAccountId,
|
|
497
|
-
amount: t.amount,
|
|
498
|
-
currency: opts.currency,
|
|
499
|
-
role: t.role,
|
|
500
|
-
status: "paid" as const,
|
|
501
|
-
paymentId: opts.paymentId,
|
|
502
|
-
},
|
|
503
|
-
);
|
|
504
|
-
}
|
|
467
|
+
await executeResolvedTransfers(stripe, component, ctx, {
|
|
468
|
+
sourceChargeId: opts.sourceChargeId,
|
|
469
|
+
gross: opts.amount,
|
|
470
|
+
currency: opts.currency,
|
|
471
|
+
processingFee: 0,
|
|
472
|
+
platformNet: result.platformRetained,
|
|
473
|
+
transfers: result.transfers,
|
|
474
|
+
paymentId: opts.paymentId,
|
|
475
|
+
});
|
|
505
476
|
|
|
506
477
|
return result;
|
|
507
478
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// @vitest-environment edge-runtime
|
|
2
|
+
import type Stripe from "stripe";
|
|
3
|
+
import { convexTest } from "convex-test";
|
|
4
|
+
import { componentsGeneric, defineSchema } from "convex/server";
|
|
5
|
+
import { expect, it, vi } from "vitest";
|
|
6
|
+
import componentSchema from "../../component/schema.js";
|
|
7
|
+
import type { Component, RunCtx } from "../helpers.js";
|
|
8
|
+
import { createAccount, getOrCreateAccount } from "./accounts.js";
|
|
9
|
+
const modules = import.meta.glob("../../component/**/*.*s");
|
|
10
|
+
it("reuses one provider account for concurrent calls and recovers a persistence failure", async () => {
|
|
11
|
+
const t = convexTest(defineSchema({}), modules);
|
|
12
|
+
t.registerComponent("betterStripe", componentSchema, modules);
|
|
13
|
+
const component = componentsGeneric().betterStripe as unknown as Component;
|
|
14
|
+
const provider = new Map<string, { params: string; id: string }>();
|
|
15
|
+
let created = 0;
|
|
16
|
+
const sdk = {
|
|
17
|
+
v2: {
|
|
18
|
+
core: {
|
|
19
|
+
accounts: {
|
|
20
|
+
create: vi.fn(
|
|
21
|
+
async (params: unknown, options?: { idempotencyKey?: string }) => {
|
|
22
|
+
const key = options?.idempotencyKey ?? `unkeyed-${++created}`,
|
|
23
|
+
existing = provider.get(key),
|
|
24
|
+
fingerprint = JSON.stringify(params);
|
|
25
|
+
if (existing && existing.params !== fingerprint)
|
|
26
|
+
throw new Error("idempotency_error");
|
|
27
|
+
if (existing) return { id: existing.id };
|
|
28
|
+
const value = { params: fingerprint, id: `acct_${++created}` };
|
|
29
|
+
provider.set(key, value);
|
|
30
|
+
return { id: value.id };
|
|
31
|
+
},
|
|
32
|
+
),
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
let fail = true;
|
|
38
|
+
const ctx: RunCtx = {
|
|
39
|
+
runQuery: t.query as RunCtx["runQuery"],
|
|
40
|
+
runMutation: (async (
|
|
41
|
+
ref: Parameters<typeof t.mutation>[0],
|
|
42
|
+
args: Record<string, unknown>,
|
|
43
|
+
) => {
|
|
44
|
+
if (fail) {
|
|
45
|
+
fail = false;
|
|
46
|
+
throw new Error("persistence unavailable");
|
|
47
|
+
}
|
|
48
|
+
return t.mutation(ref, args);
|
|
49
|
+
}) as RunCtx["runMutation"],
|
|
50
|
+
};
|
|
51
|
+
const opts = {
|
|
52
|
+
userId: "buyer",
|
|
53
|
+
email: "buyer@example.com",
|
|
54
|
+
idempotencyKey: "account:buyer:v1",
|
|
55
|
+
};
|
|
56
|
+
await expect(
|
|
57
|
+
createAccount(sdk as unknown as Stripe, component, ctx, opts),
|
|
58
|
+
).rejects.toThrow("persistence unavailable");
|
|
59
|
+
const [a, b] = await Promise.all([
|
|
60
|
+
getOrCreateAccount(sdk as unknown as Stripe, component, ctx, opts),
|
|
61
|
+
getOrCreateAccount(sdk as unknown as Stripe, component, ctx, opts),
|
|
62
|
+
]);
|
|
63
|
+
expect(a.stripeAccountId).toBe(b.stripeAccountId);
|
|
64
|
+
expect(provider.size).toBe(1);
|
|
65
|
+
expect(sdk.v2.core.accounts.create).toHaveBeenCalledWith(expect.anything(), {
|
|
66
|
+
idempotencyKey: opts.idempotencyKey,
|
|
67
|
+
});
|
|
68
|
+
await expect(
|
|
69
|
+
createAccount(sdk as unknown as Stripe, component, ctx, {
|
|
70
|
+
...opts,
|
|
71
|
+
email: "changed@example.com",
|
|
72
|
+
}),
|
|
73
|
+
).rejects.toThrow("idempotency_error");
|
|
74
|
+
const row = await t.query(component.core.queries.getAccountByUserId, {
|
|
75
|
+
userId: "buyer",
|
|
76
|
+
});
|
|
77
|
+
expect(row?.stripeAccountId).toBe(a.stripeAccountId);
|
|
78
|
+
});
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
import { idempotencyOptions } from "./idempotency.js";
|
|
2
|
+
export type CreateAccountOptions = {
|
|
3
|
+
userId: string;
|
|
4
|
+
email?: string;
|
|
5
|
+
name?: string;
|
|
6
|
+
country?: string;
|
|
7
|
+
orgId?: string;
|
|
8
|
+
metadata?: Record<string, string>;
|
|
9
|
+
/** Stable account-provisioning key; use a different key for a different account. */
|
|
10
|
+
idempotencyKey?: string;
|
|
11
|
+
};
|
|
1
12
|
import type Stripe from "stripe";
|
|
2
13
|
|
|
3
14
|
import type { Component, RunCtx } from "../helpers.js";
|
|
@@ -31,14 +42,7 @@ export async function createAccount(
|
|
|
31
42
|
stripe: Stripe,
|
|
32
43
|
component: Component,
|
|
33
44
|
ctx: RunCtx,
|
|
34
|
-
opts:
|
|
35
|
-
userId: string;
|
|
36
|
-
email?: string;
|
|
37
|
-
name?: string;
|
|
38
|
-
country?: string;
|
|
39
|
-
orgId?: string;
|
|
40
|
-
metadata?: Record<string, string>;
|
|
41
|
-
},
|
|
45
|
+
opts: CreateAccountOptions,
|
|
42
46
|
) {
|
|
43
47
|
const metadata = {
|
|
44
48
|
...(opts.metadata ?? {}),
|
|
@@ -56,7 +60,10 @@ export async function createAccount(
|
|
|
56
60
|
};
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
const
|
|
63
|
+
const requestOptions = idempotencyOptions(opts.idempotencyKey);
|
|
64
|
+
const account = requestOptions
|
|
65
|
+
? await stripe.v2.core.accounts.create(createParams, requestOptions)
|
|
66
|
+
: await stripe.v2.core.accounts.create(createParams);
|
|
60
67
|
|
|
61
68
|
await runMutationOrThrow(
|
|
62
69
|
ctx,
|
|
@@ -191,14 +198,7 @@ export async function getOrCreateAccount(
|
|
|
191
198
|
stripe: Stripe,
|
|
192
199
|
component: Component,
|
|
193
200
|
ctx: RunCtx,
|
|
194
|
-
opts:
|
|
195
|
-
userId: string;
|
|
196
|
-
email?: string;
|
|
197
|
-
name?: string;
|
|
198
|
-
country?: string;
|
|
199
|
-
orgId?: string;
|
|
200
|
-
metadata?: Record<string, string>;
|
|
201
|
-
},
|
|
201
|
+
opts: CreateAccountOptions,
|
|
202
202
|
) {
|
|
203
203
|
const existing = opts.orgId
|
|
204
204
|
? await ctx.runQuery(
|
|
@@ -238,14 +238,7 @@ export async function ensureCustomerAccount(
|
|
|
238
238
|
stripe: Stripe,
|
|
239
239
|
component: Component,
|
|
240
240
|
ctx: RunCtx,
|
|
241
|
-
opts:
|
|
242
|
-
userId: string;
|
|
243
|
-
email?: string;
|
|
244
|
-
name?: string;
|
|
245
|
-
country?: string;
|
|
246
|
-
orgId?: string;
|
|
247
|
-
metadata?: Record<string, string>;
|
|
248
|
-
},
|
|
241
|
+
opts: CreateAccountOptions,
|
|
249
242
|
): Promise<{
|
|
250
243
|
stripeAccountId: string;
|
|
251
244
|
accountId: string | null;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { expect, it } from "vitest";
|
|
2
|
+
import { idempotencyOptions } from "./idempotency.js";
|
|
3
|
+
it("preserves omitted options and validates explicit request identities", () => {
|
|
4
|
+
expect(idempotencyOptions(undefined)).toBeUndefined();
|
|
5
|
+
expect(idempotencyOptions("logical-order:123")).toEqual({
|
|
6
|
+
idempotencyKey: "logical-order:123",
|
|
7
|
+
});
|
|
8
|
+
for (const key of ["", " ", "bad\nkey", "x".repeat(256)])
|
|
9
|
+
expect(() => idempotencyOptions(key)).toThrow();
|
|
10
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { throwStripeError } from "../errors.js";
|
|
2
|
+
/** Explicit request identity. Omission preserves the SDK's existing behavior. */
|
|
3
|
+
export function idempotencyOptions(key: string | undefined) {
|
|
4
|
+
if (key === undefined) return undefined;
|
|
5
|
+
if (!key.trim() || key.length > 255 || /[\r\n]/.test(key))
|
|
6
|
+
throwStripeError(
|
|
7
|
+
"INVALID_CONFIGURATION",
|
|
8
|
+
"Idempotency keys must be nonempty, at most 255 characters, and contain no line breaks.",
|
|
9
|
+
);
|
|
10
|
+
return { idempotencyKey: key };
|
|
11
|
+
}
|
package/src/client/index.ts
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
+
export type {
|
|
2
|
+
CheckoutSessionReadOptions,
|
|
3
|
+
SubscriptionReadOptions,
|
|
4
|
+
CouponReadOptions,
|
|
5
|
+
} from "./billing/providerReads.js";
|
|
6
|
+
import * as providerReads from "./billing/providerReads.js";
|
|
7
|
+
export type { CreateAccountOptions } from "./core/accounts.js";
|
|
8
|
+
import { buildAsyncHookRoutes } from "./webhooks/asyncHooks.js";
|
|
9
|
+
import * as saleContextImpl from "./settlement/verifiedSale.js";
|
|
10
|
+
import * as settlementImpl from "./settlement/settleSale.js";
|
|
11
|
+
import * as commissionImpl from "./settlement/commissions.js";
|
|
12
|
+
import * as payoutSnapshotImpl from "./connect/payoutSnapshot.js";
|
|
13
|
+
export { allocateSale } from "./settlement/allocation.js";
|
|
14
|
+
export type {
|
|
15
|
+
SaleAllocation,
|
|
16
|
+
SaleAllocationOptions,
|
|
17
|
+
} from "./settlement/allocation.js";
|
|
18
|
+
export type {
|
|
19
|
+
VerifiedSale,
|
|
20
|
+
VerifiedSaleOptions,
|
|
21
|
+
} from "./settlement/verifiedSale.js";
|
|
22
|
+
export type { SettleSaleOptions } from "./settlement/settleSale.js";
|
|
23
|
+
export type { SettlementResult } from "./settlement/execution.js";
|
|
24
|
+
export type {
|
|
25
|
+
CommissionTerm,
|
|
26
|
+
CommissionSelectionOptions,
|
|
27
|
+
CommissionSelection,
|
|
28
|
+
CommissionDecision,
|
|
29
|
+
} from "./settlement/commissions.js";
|
|
30
|
+
export type {
|
|
31
|
+
RecipientPayoutSnapshot,
|
|
32
|
+
RecipientPayoutRow,
|
|
33
|
+
PayoutSnapshotOptions,
|
|
34
|
+
} from "./connect/payoutSnapshot.js";
|
|
1
35
|
import { internalActionGeneric, internalMutationGeneric } from "convex/server";
|
|
2
36
|
import { v } from "convex/values";
|
|
3
37
|
import Stripe from "stripe";
|
|
@@ -146,9 +180,7 @@ function clonePlatformFee(config: PlatformFeeConfig): PlatformFeeConfig {
|
|
|
146
180
|
};
|
|
147
181
|
}
|
|
148
182
|
|
|
149
|
-
// =============================================================================
|
|
150
183
|
// BETTER STRIPE CLIENT
|
|
151
|
-
// =============================================================================
|
|
152
184
|
|
|
153
185
|
export class BetterStripe {
|
|
154
186
|
public component: Component;
|
|
@@ -212,9 +244,7 @@ export class BetterStripe {
|
|
|
212
244
|
return getStripeClient(this.apiKey, apiVersion);
|
|
213
245
|
}
|
|
214
246
|
|
|
215
|
-
// ============================================================================
|
|
216
247
|
// Static defaults (preserved for backwards compatibility)
|
|
217
|
-
// ============================================================================
|
|
218
248
|
|
|
219
249
|
static DEFAULT_ACCOUNT_CONFIGURATION =
|
|
220
250
|
accountsImpl.DEFAULT_ACCOUNT_CONFIGURATION;
|
|
@@ -222,21 +252,9 @@ export class BetterStripe {
|
|
|
222
252
|
static DEFAULT_CUSTOMER_CONFIGURATION =
|
|
223
253
|
accountsImpl.DEFAULT_CUSTOMER_CONFIGURATION;
|
|
224
254
|
|
|
225
|
-
// ============================================================================
|
|
226
255
|
// ACCOUNT METHODS
|
|
227
|
-
// ============================================================================
|
|
228
256
|
|
|
229
|
-
async createAccount(
|
|
230
|
-
ctx: RunCtx,
|
|
231
|
-
opts: {
|
|
232
|
-
userId: string;
|
|
233
|
-
email?: string;
|
|
234
|
-
name?: string;
|
|
235
|
-
country?: string;
|
|
236
|
-
orgId?: string;
|
|
237
|
-
metadata?: Record<string, string>;
|
|
238
|
-
},
|
|
239
|
-
) {
|
|
257
|
+
async createAccount(ctx: RunCtx, opts: accountsImpl.CreateAccountOptions) {
|
|
240
258
|
return accountsImpl.createAccount(this.stripe(), this.component, ctx, opts);
|
|
241
259
|
}
|
|
242
260
|
|
|
@@ -276,14 +294,7 @@ export class BetterStripe {
|
|
|
276
294
|
|
|
277
295
|
async getOrCreateAccount(
|
|
278
296
|
ctx: RunCtx,
|
|
279
|
-
opts:
|
|
280
|
-
userId: string;
|
|
281
|
-
email?: string;
|
|
282
|
-
name?: string;
|
|
283
|
-
country?: string;
|
|
284
|
-
orgId?: string;
|
|
285
|
-
metadata?: Record<string, string>;
|
|
286
|
-
},
|
|
297
|
+
opts: accountsImpl.CreateAccountOptions,
|
|
287
298
|
) {
|
|
288
299
|
return accountsImpl.getOrCreateAccount(
|
|
289
300
|
this.stripe(),
|
|
@@ -453,14 +464,7 @@ export class BetterStripe {
|
|
|
453
464
|
*/
|
|
454
465
|
async ensureCustomerAccount(
|
|
455
466
|
ctx: RunCtx,
|
|
456
|
-
opts:
|
|
457
|
-
userId: string;
|
|
458
|
-
email?: string;
|
|
459
|
-
name?: string;
|
|
460
|
-
country?: string;
|
|
461
|
-
orgId?: string;
|
|
462
|
-
metadata?: Record<string, string>;
|
|
463
|
-
},
|
|
467
|
+
opts: accountsImpl.CreateAccountOptions,
|
|
464
468
|
) {
|
|
465
469
|
return accountsImpl.ensureCustomerAccount(
|
|
466
470
|
this.stripe(),
|
|
@@ -470,9 +474,7 @@ export class BetterStripe {
|
|
|
470
474
|
);
|
|
471
475
|
}
|
|
472
476
|
|
|
473
|
-
// ============================================================================
|
|
474
477
|
// PRODUCT METHODS
|
|
475
|
-
// ============================================================================
|
|
476
478
|
|
|
477
479
|
async createProduct(
|
|
478
480
|
ctx: RunCtx,
|
|
@@ -559,9 +561,7 @@ export class BetterStripe {
|
|
|
559
561
|
return productsImpl.deleteProduct(this.stripe(), ctx, opts);
|
|
560
562
|
}
|
|
561
563
|
|
|
562
|
-
// ============================================================================
|
|
563
564
|
// PRICE METHODS
|
|
564
|
-
// ============================================================================
|
|
565
565
|
|
|
566
566
|
async createPrice(
|
|
567
567
|
ctx: RunCtx,
|
|
@@ -649,13 +649,12 @@ export class BetterStripe {
|
|
|
649
649
|
return pricesImpl.listStripePrices(this.stripe(), ctx, opts);
|
|
650
650
|
}
|
|
651
651
|
|
|
652
|
-
// ============================================================================
|
|
653
652
|
// CHECKOUT METHODS
|
|
654
|
-
// ============================================================================
|
|
655
653
|
|
|
656
654
|
async createCheckoutSession(
|
|
657
655
|
ctx: RunCtx,
|
|
658
656
|
opts: {
|
|
657
|
+
idempotencyKey?: string;
|
|
659
658
|
userId: string;
|
|
660
659
|
orgId?: string;
|
|
661
660
|
stripePriceId: string;
|
|
@@ -744,9 +743,7 @@ export class BetterStripe {
|
|
|
744
743
|
return checkoutImpl.updateCheckoutSession(this.stripe(), ctx, opts);
|
|
745
744
|
}
|
|
746
745
|
|
|
747
|
-
// ============================================================================
|
|
748
746
|
// SUBSCRIPTION METHODS
|
|
749
|
-
// ============================================================================
|
|
750
747
|
|
|
751
748
|
/**
|
|
752
749
|
* Create a subscription directly for a V2 buyer (`customer_account`), off the
|
|
@@ -943,14 +940,7 @@ export class BetterStripe {
|
|
|
943
940
|
accountId?: string;
|
|
944
941
|
userId: string;
|
|
945
942
|
orgId?: string;
|
|
946
|
-
status:
|
|
947
|
-
| "active"
|
|
948
|
-
| "trialing"
|
|
949
|
-
| "past_due"
|
|
950
|
-
| "canceled"
|
|
951
|
-
| "incomplete"
|
|
952
|
-
| "unpaid"
|
|
953
|
-
| "paused";
|
|
943
|
+
status: SubscriptionStatus;
|
|
954
944
|
priceId?: string;
|
|
955
945
|
quantity?: number;
|
|
956
946
|
currentPeriodStart?: string;
|
|
@@ -970,9 +960,7 @@ export class BetterStripe {
|
|
|
970
960
|
return subscriptionsImpl.getTrialStatus(this.component, ctx, opts);
|
|
971
961
|
}
|
|
972
962
|
|
|
973
|
-
// ============================================================================
|
|
974
963
|
// INVOICE METHODS
|
|
975
|
-
// ============================================================================
|
|
976
964
|
|
|
977
965
|
async listInvoices(
|
|
978
966
|
ctx: RunCtx,
|
|
@@ -1039,9 +1027,7 @@ export class BetterStripe {
|
|
|
1039
1027
|
return invoicesImpl.getInvoiceFromStripe(this.stripe(), ctx, opts);
|
|
1040
1028
|
}
|
|
1041
1029
|
|
|
1042
|
-
// ============================================================================
|
|
1043
1030
|
// PAYMENT METHOD METHODS
|
|
1044
|
-
// ============================================================================
|
|
1045
1031
|
|
|
1046
1032
|
async listPaymentMethods(
|
|
1047
1033
|
ctx: RunCtx,
|
|
@@ -1072,9 +1058,7 @@ export class BetterStripe {
|
|
|
1072
1058
|
return paymentMethodsImpl.setDefaultPaymentMethod(this.stripe(), ctx, opts);
|
|
1073
1059
|
}
|
|
1074
1060
|
|
|
1075
|
-
// ============================================================================
|
|
1076
1061
|
// ACCOUNT LINK METHODS
|
|
1077
|
-
// ============================================================================
|
|
1078
1062
|
|
|
1079
1063
|
async createAccountLink(
|
|
1080
1064
|
ctx: RunCtx,
|
|
@@ -1150,9 +1134,7 @@ export class BetterStripe {
|
|
|
1150
1134
|
return accountLinksImpl.getCountrySpecs(this.stripe(), ctx, opts);
|
|
1151
1135
|
}
|
|
1152
1136
|
|
|
1153
|
-
// ============================================================================
|
|
1154
1137
|
// PAYOUT METHODS
|
|
1155
|
-
// ============================================================================
|
|
1156
1138
|
|
|
1157
1139
|
async createPayout(
|
|
1158
1140
|
ctx: RunCtx,
|
|
@@ -1253,6 +1235,50 @@ export class BetterStripe {
|
|
|
1253
1235
|
* (`{ available, pending, currency }`, minor units) per currency — each entry
|
|
1254
1236
|
* feeds the headless `PayoutSchedule` component's `balance` prop directly.
|
|
1255
1237
|
*/
|
|
1238
|
+
async getCheckoutSessionFromStripe(
|
|
1239
|
+
_ctx: RunCtx,
|
|
1240
|
+
opts: providerReads.CheckoutSessionReadOptions,
|
|
1241
|
+
) {
|
|
1242
|
+
return providerReads.getCheckoutSessionFromStripe(this.stripe(), opts);
|
|
1243
|
+
}
|
|
1244
|
+
async getSubscriptionFromStripe(
|
|
1245
|
+
_ctx: RunCtx,
|
|
1246
|
+
opts: providerReads.SubscriptionReadOptions,
|
|
1247
|
+
) {
|
|
1248
|
+
return providerReads.getSubscriptionFromStripe(this.stripe(), opts);
|
|
1249
|
+
}
|
|
1250
|
+
async getCouponFromStripe(
|
|
1251
|
+
_ctx: RunCtx,
|
|
1252
|
+
opts: providerReads.CouponReadOptions,
|
|
1253
|
+
) {
|
|
1254
|
+
return providerReads.getCouponFromStripe(this.stripe(), opts);
|
|
1255
|
+
}
|
|
1256
|
+
async getVerifiedSale(
|
|
1257
|
+
_ctx: RunCtx,
|
|
1258
|
+
opts: saleContextImpl.VerifiedSaleOptions,
|
|
1259
|
+
) {
|
|
1260
|
+
return saleContextImpl.getVerifiedSale(this.stripe(), opts);
|
|
1261
|
+
}
|
|
1262
|
+
async settleSale(ctx: RunCtx, opts: settlementImpl.SettleSaleOptions) {
|
|
1263
|
+
return settlementImpl.settleSale(this.stripe(), this.component, ctx, opts);
|
|
1264
|
+
}
|
|
1265
|
+
async selectCommissionInvoice(
|
|
1266
|
+
ctx: RunCtx,
|
|
1267
|
+
opts: commissionImpl.CommissionSelectionOptions,
|
|
1268
|
+
) {
|
|
1269
|
+
return commissionImpl.selectCommissionInvoice(
|
|
1270
|
+
this.stripe(),
|
|
1271
|
+
this.component,
|
|
1272
|
+
ctx,
|
|
1273
|
+
opts,
|
|
1274
|
+
);
|
|
1275
|
+
}
|
|
1276
|
+
async getPayoutSnapshot(
|
|
1277
|
+
_ctx: RunCtx,
|
|
1278
|
+
opts: payoutSnapshotImpl.PayoutSnapshotOptions,
|
|
1279
|
+
) {
|
|
1280
|
+
return payoutSnapshotImpl.getPayoutSnapshot(this.stripe(), opts);
|
|
1281
|
+
}
|
|
1256
1282
|
async getAccountBalance(_ctx: RunCtx, opts: { stripeAccountId: string }) {
|
|
1257
1283
|
return payoutsImpl.getAccountBalance(this.stripe(), opts);
|
|
1258
1284
|
}
|
|
@@ -1268,9 +1294,7 @@ export class BetterStripe {
|
|
|
1268
1294
|
return payoutsImpl.listPayouts(this.component, ctx, opts);
|
|
1269
1295
|
}
|
|
1270
1296
|
|
|
1271
|
-
// ============================================================================
|
|
1272
1297
|
// REFUND METHODS
|
|
1273
|
-
// ============================================================================
|
|
1274
1298
|
|
|
1275
1299
|
/**
|
|
1276
1300
|
* Issue a refund (BTS-34). `refundApplicationFee` and `reverseTransfer`
|
|
@@ -1325,9 +1349,7 @@ export class BetterStripe {
|
|
|
1325
1349
|
return refundsImpl.listRefunds(this.component, ctx, opts);
|
|
1326
1350
|
}
|
|
1327
1351
|
|
|
1328
|
-
// ============================================================================
|
|
1329
1352
|
// DISPUTE METHODS
|
|
1330
|
-
// ============================================================================
|
|
1331
1353
|
|
|
1332
1354
|
async getDisputeByStripeId(
|
|
1333
1355
|
ctx: RunCtx,
|
|
@@ -1397,9 +1419,7 @@ export class BetterStripe {
|
|
|
1397
1419
|
return disputesImpl.closeDispute(this.stripe(), this.component, ctx, opts);
|
|
1398
1420
|
}
|
|
1399
1421
|
|
|
1400
|
-
// ============================================================================
|
|
1401
1422
|
// WEBHOOK ENDPOINT MANAGEMENT
|
|
1402
|
-
// ============================================================================
|
|
1403
1423
|
|
|
1404
1424
|
async listWebhookEndpoints(ctx: RunCtx, opts?: { limit?: number }) {
|
|
1405
1425
|
return webhookEndpointsImpl.listWebhookEndpoints(this.stripe(), ctx, opts);
|
|
@@ -1439,9 +1459,7 @@ export class BetterStripe {
|
|
|
1439
1459
|
return webhookEndpointsImpl.setupEventDestination(this.stripe(), ctx, opts);
|
|
1440
1460
|
}
|
|
1441
1461
|
|
|
1442
|
-
// ============================================================================
|
|
1443
1462
|
// WEBHOOK EVENT QUERIES
|
|
1444
|
-
// ============================================================================
|
|
1445
1463
|
|
|
1446
1464
|
async listWebhookEvents(
|
|
1447
1465
|
ctx: RunCtx,
|
|
@@ -1462,17 +1480,13 @@ export class BetterStripe {
|
|
|
1462
1480
|
}>;
|
|
1463
1481
|
}
|
|
1464
1482
|
|
|
1465
|
-
// ============================================================================
|
|
1466
1483
|
// DATA MANAGEMENT
|
|
1467
|
-
// ============================================================================
|
|
1468
1484
|
|
|
1469
1485
|
async clearAll(ctx: RunCtx): Promise<{ cleared: number; tables: string[] }> {
|
|
1470
1486
|
return dataImpl.clearAll(this.component, ctx);
|
|
1471
1487
|
}
|
|
1472
1488
|
|
|
1473
|
-
// ============================================================================
|
|
1474
1489
|
// SYNC METHODS
|
|
1475
|
-
// ============================================================================
|
|
1476
1490
|
|
|
1477
1491
|
async syncAllAccounts(ctx: RunCtx) {
|
|
1478
1492
|
return accountsImpl.syncAllAccounts(this.stripe(), this.component, ctx);
|
|
@@ -1490,9 +1504,7 @@ export class BetterStripe {
|
|
|
1490
1504
|
);
|
|
1491
1505
|
}
|
|
1492
1506
|
|
|
1493
|
-
// ============================================================================
|
|
1494
1507
|
// WEBHOOK HANDLER EXPORT (BetterAuth-style)
|
|
1495
|
-
// ============================================================================
|
|
1496
1508
|
|
|
1497
1509
|
/**
|
|
1498
1510
|
* Build the two webhook handler function definitions for the app to export
|
|
@@ -1811,38 +1823,7 @@ export class BetterStripe {
|
|
|
1811
1823
|
),
|
|
1812
1824
|
};
|
|
1813
1825
|
|
|
1814
|
-
|
|
1815
|
-
const ASYNC: Record<
|
|
1816
|
-
AsyncHookName,
|
|
1817
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined
|
|
1818
|
-
> = {
|
|
1819
|
-
afterAccountUpdated: hooks?.onAccountUpdated as
|
|
1820
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1821
|
-
afterCheckoutCompleted: hooks?.onCheckoutCompleted as
|
|
1822
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1823
|
-
afterSubscriptionUpdated: hooks?.onSubscriptionUpdated as
|
|
1824
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1825
|
-
afterSubscriptionCanceled: hooks?.onSubscriptionCanceled as
|
|
1826
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1827
|
-
afterTrialEnding: hooks?.onTrialEnding as
|
|
1828
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1829
|
-
afterInvoicePaid: hooks?.onInvoicePaid as
|
|
1830
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1831
|
-
afterInvoicePaymentFailed: hooks?.onInvoicePaymentFailed as
|
|
1832
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1833
|
-
afterPaymentSucceeded: hooks?.onPaymentSucceeded as
|
|
1834
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1835
|
-
afterPaymentFailed: hooks?.onPaymentFailed as
|
|
1836
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1837
|
-
afterPayoutCompleted: hooks?.onPayoutCompleted as
|
|
1838
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1839
|
-
afterRefundCreated: hooks?.onRefundCreated as
|
|
1840
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1841
|
-
afterDisputeCreated: hooks?.onDisputeCreated as
|
|
1842
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1843
|
-
afterDisputeClosed: hooks?.onDisputeClosed as
|
|
1844
|
-
((ctx: AsyncHookCtx, doc: unknown) => Promise<void>) | undefined,
|
|
1845
|
-
};
|
|
1826
|
+
const ASYNC = buildAsyncHookRoutes(hooks);
|
|
1846
1827
|
|
|
1847
1828
|
const syncWebhook = internalMutationGeneric({
|
|
1848
1829
|
args: { dispatcher: v.string(), data: v.any() },
|