@fantastic.dev/better-stripe 0.9.0 → 0.10.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 +26 -0
- package/README.md +38 -1
- package/dist/client/apiVersion.d.ts +6 -0
- package/dist/client/apiVersion.d.ts.map +1 -0
- package/dist/client/apiVersion.js +13 -0
- package/dist/client/apiVersion.js.map +1 -0
- 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 +39 -37
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +47 -56
- package/dist/client/index.js.map +1 -1
- package/dist/client/previewRoutes.d.ts +9 -0
- package/dist/client/previewRoutes.d.ts.map +1 -0
- package/dist/client/previewRoutes.js +15 -0
- package/dist/client/previewRoutes.js.map +1 -0
- 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/types/options.d.ts +3 -0
- package/dist/client/types/options.d.ts.map +1 -1
- package/dist/client/utils/webhookEndpoints.d.ts +12 -8
- package/dist/client/utils/webhookEndpoints.d.ts.map +1 -1
- package/dist/client/utils/webhookEndpoints.js +41 -2
- package/dist/client/utils/webhookEndpoints.js.map +1 -1
- 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/client/webhooks/v2.d.ts.map +1 -1
- package/dist/client/webhooks/v2.js +10 -7
- package/dist/client/webhooks/v2.js.map +1 -1
- package/dist/component/_generated/component.d.ts +80 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/lib/stripeFactory.d.ts +3 -2
- package/dist/component/lib/stripeFactory.d.ts.map +1 -1
- package/dist/component/lib/stripeFactory.js +6 -5
- package/dist/component/lib/stripeFactory.js.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/accounts-v2-preview.md +132 -0
- package/docs/react-workflows.md +5 -2
- package/docs/settlement.md +158 -0
- package/package.json +3 -1
- package/src/client/apiVersion.ts +20 -0
- 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/customer-preview-thin.test.ts +41 -0
- package/src/client/customer-preview-webhooks.test.ts +150 -0
- package/src/client/customer-preview.test.ts +185 -0
- package/src/client/index.ts +115 -119
- package/src/client/previewRoutes.ts +26 -0
- 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/stripe-version.test.ts +10 -4
- package/src/client/types/options.ts +3 -0
- package/src/client/utils/webhookEndpoints.ts +70 -15
- package/src/client/webhooks/asyncHooks.ts +38 -0
- package/src/client/webhooks/processors.test.ts +9 -9
- package/src/client/webhooks/v2.ts +14 -10
- package/src/component/_generated/api.ts +4 -0
- package/src/component/_generated/component.ts +100 -0
- package/src/component/lib/stripeFactory.ts +13 -5
- 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
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import Stripe from "stripe";
|
|
2
|
+
import { componentsGeneric } from "convex/server";
|
|
3
|
+
import { expect, it, vi } from "vitest";
|
|
4
|
+
import { BetterStripe, type BetterStripeOptions } from "./index.js";
|
|
5
|
+
import { getStripeClient, type Component, type RunCtx } from "./helpers.js";
|
|
6
|
+
|
|
7
|
+
const preview = "2026-09-30.preview";
|
|
8
|
+
const component = componentsGeneric().betterStripe as unknown as Component;
|
|
9
|
+
const ctx = {
|
|
10
|
+
runQuery: vi.fn().mockImplementation(async (_ref, args) =>
|
|
11
|
+
args?.stripeAccountId
|
|
12
|
+
? {
|
|
13
|
+
_id: "row",
|
|
14
|
+
userId: "buyer",
|
|
15
|
+
stripeAccountId: "acct_buyer",
|
|
16
|
+
appliedConfigurations: [],
|
|
17
|
+
}
|
|
18
|
+
: null,
|
|
19
|
+
),
|
|
20
|
+
runMutation: vi.fn().mockResolvedValue("row"),
|
|
21
|
+
} as unknown as RunCtx;
|
|
22
|
+
function fixture(version: string | undefined) {
|
|
23
|
+
const key = `sk_test_preview_transport_${crypto.randomUUID()}`;
|
|
24
|
+
const bs = new BetterStripe(component, {
|
|
25
|
+
STRIPE_SECRET_KEY: key,
|
|
26
|
+
...(version === undefined ? {} : { stripeApiVersion: version }),
|
|
27
|
+
} as BetterStripeOptions);
|
|
28
|
+
const calls: {
|
|
29
|
+
path: string;
|
|
30
|
+
version: string;
|
|
31
|
+
idempotency: string | undefined;
|
|
32
|
+
body: string;
|
|
33
|
+
}[] = [];
|
|
34
|
+
for (const selected of new Set([version, "2026-09-30.endive"])) {
|
|
35
|
+
const sdk = getStripeClient(key, selected);
|
|
36
|
+
(
|
|
37
|
+
sdk as unknown as { _setApiField: (name: string, value: unknown) => void }
|
|
38
|
+
)._setApiField("httpClient", {
|
|
39
|
+
getClientName: () => "preview-contract-test",
|
|
40
|
+
makeRequest: async (
|
|
41
|
+
...[, , path, , headers, body]: Parameters<
|
|
42
|
+
ReturnType<typeof Stripe.createNodeHttpClient>["makeRequest"]
|
|
43
|
+
>
|
|
44
|
+
) => {
|
|
45
|
+
calls.push({
|
|
46
|
+
path,
|
|
47
|
+
version: String(headers["Stripe-Version"]),
|
|
48
|
+
idempotency: headers["Idempotency-Key"] as string | undefined,
|
|
49
|
+
body: String(body),
|
|
50
|
+
});
|
|
51
|
+
const data = path.includes("/checkout/sessions")
|
|
52
|
+
? {
|
|
53
|
+
id: "cs_preview",
|
|
54
|
+
object: "checkout.session",
|
|
55
|
+
client_secret: "test_secret",
|
|
56
|
+
status: "open",
|
|
57
|
+
}
|
|
58
|
+
: path.includes("/v2/core/accounts")
|
|
59
|
+
? {
|
|
60
|
+
id: "acct_buyer",
|
|
61
|
+
object: "v2.core.account",
|
|
62
|
+
applied_configurations: ["customer"],
|
|
63
|
+
configuration: { customer: {} },
|
|
64
|
+
metadata: { userId: "buyer" },
|
|
65
|
+
}
|
|
66
|
+
: path.includes("/prices/")
|
|
67
|
+
? {
|
|
68
|
+
id: "price_preview",
|
|
69
|
+
active: true,
|
|
70
|
+
unit_amount: 1000,
|
|
71
|
+
currency: "usd",
|
|
72
|
+
type: "one_time",
|
|
73
|
+
product: "prod_preview",
|
|
74
|
+
}
|
|
75
|
+
: path.includes("/products/")
|
|
76
|
+
? { id: "prod_preview", active: true }
|
|
77
|
+
: path.includes("/billing_portal/sessions")
|
|
78
|
+
? {
|
|
79
|
+
id: "bps_preview",
|
|
80
|
+
url: "https://billing.stripe.com/test",
|
|
81
|
+
}
|
|
82
|
+
: path.includes("/refunds")
|
|
83
|
+
? { id: "re_preview", status: "succeeded" }
|
|
84
|
+
: path.includes("/payment_intents/")
|
|
85
|
+
? {
|
|
86
|
+
id: "pi_preview",
|
|
87
|
+
latest_charge: {
|
|
88
|
+
id: "ch_preview",
|
|
89
|
+
amount: 1000,
|
|
90
|
+
currency: "usd",
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
: path.includes("/charges/")
|
|
94
|
+
? { id: "ch_preview", amount: 1000, currency: "usd" }
|
|
95
|
+
: path.includes("/coupons/")
|
|
96
|
+
? { id: "coupon_preview", valid: true }
|
|
97
|
+
: {
|
|
98
|
+
id: "sub_preview",
|
|
99
|
+
status: "active",
|
|
100
|
+
customer_account: "acct_buyer",
|
|
101
|
+
items: { data: [] },
|
|
102
|
+
metadata: {},
|
|
103
|
+
};
|
|
104
|
+
return {
|
|
105
|
+
getStatusCode: () => 200,
|
|
106
|
+
getHeaders: () => ({}),
|
|
107
|
+
getRawResponse: () => ({}),
|
|
108
|
+
toJSON: async () => data,
|
|
109
|
+
toStream: () => {
|
|
110
|
+
throw new Error("Unexpected stream");
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return { bs, calls };
|
|
117
|
+
}
|
|
118
|
+
it.each([undefined, preview])(
|
|
119
|
+
"uses one selected version for account, Checkout, billing, refunds and authoritative reads (%s)",
|
|
120
|
+
async (version) => {
|
|
121
|
+
const { bs, calls } = fixture(version);
|
|
122
|
+
await bs.ensureCustomerAccount(ctx, {
|
|
123
|
+
userId: "buyer",
|
|
124
|
+
email: "buyer@example.com",
|
|
125
|
+
idempotencyKey: "account:buyer",
|
|
126
|
+
});
|
|
127
|
+
await bs.createCheckoutSession(ctx, {
|
|
128
|
+
userId: "buyer",
|
|
129
|
+
accountId: "acct_buyer",
|
|
130
|
+
stripePriceId: "price_preview",
|
|
131
|
+
mode: "payment",
|
|
132
|
+
returnUrl: "https://example.com/receipt",
|
|
133
|
+
idempotencyKey: "order:one",
|
|
134
|
+
});
|
|
135
|
+
await bs.getCheckoutSessionFromStripe(ctx, {
|
|
136
|
+
stripeSessionId: "cs_preview",
|
|
137
|
+
});
|
|
138
|
+
await bs.getSubscriptionFromStripe(ctx, {
|
|
139
|
+
stripeSubscriptionId: "sub_preview",
|
|
140
|
+
});
|
|
141
|
+
await bs.getCouponFromStripe(ctx, { stripeCouponId: "coupon_preview" });
|
|
142
|
+
await bs.cancelSubscription(ctx, { stripeSubscriptionId: "sub_preview" });
|
|
143
|
+
await bs.reactivateSubscription(ctx, {
|
|
144
|
+
stripeSubscriptionId: "sub_preview",
|
|
145
|
+
});
|
|
146
|
+
await bs.createBillingPortalSession(ctx, {
|
|
147
|
+
stripeAccountId: "acct_buyer",
|
|
148
|
+
returnUrl: "https://example.com/billing",
|
|
149
|
+
});
|
|
150
|
+
await bs.createRefund(ctx, {
|
|
151
|
+
stripeChargeId: "ch_preview",
|
|
152
|
+
idempotencyKey: "refund:one",
|
|
153
|
+
});
|
|
154
|
+
expect(calls.length).toBeGreaterThanOrEqual(8);
|
|
155
|
+
expect(new Set(calls.map((c) => c.version))).toEqual(
|
|
156
|
+
new Set([version ?? "2026-09-30.endive"]),
|
|
157
|
+
);
|
|
158
|
+
expect(calls.find((c) => c.path === "/v2/core/accounts")?.idempotency).toBe(
|
|
159
|
+
"account:buyer",
|
|
160
|
+
);
|
|
161
|
+
expect(
|
|
162
|
+
calls.find((c) => c.path === "/v1/checkout/sessions" && c.idempotency)
|
|
163
|
+
?.idempotency,
|
|
164
|
+
).toBe("order:one");
|
|
165
|
+
expect(
|
|
166
|
+
calls.find((c) => c.path === "/v1/checkout/sessions" && c.idempotency)
|
|
167
|
+
?.body,
|
|
168
|
+
).toContain("customer_account=acct_buyer");
|
|
169
|
+
expect(
|
|
170
|
+
calls.find((c) => c.path === "/v2/core/accounts")?.body,
|
|
171
|
+
).not.toContain("merchant");
|
|
172
|
+
expect(bs.stripeApiVersion).toBe(version ?? "2026-09-30.endive");
|
|
173
|
+
},
|
|
174
|
+
);
|
|
175
|
+
it.each(["", "2020-08-27", "2026-09-30.preview; unsafe", "not-a-version"])(
|
|
176
|
+
"rejects unsupported client versions clearly (%s)",
|
|
177
|
+
(version) => {
|
|
178
|
+
expect(
|
|
179
|
+
() =>
|
|
180
|
+
new BetterStripe(component, {
|
|
181
|
+
stripeApiVersion: version,
|
|
182
|
+
} as unknown as BetterStripeOptions),
|
|
183
|
+
).toThrow("Unsupported Stripe API version");
|
|
184
|
+
},
|
|
185
|
+
);
|
package/src/client/index.ts
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
import type { HttpRouter } from "convex/server";
|
|
2
|
+
import { registerClientRoutes } from "./previewRoutes.js";
|
|
3
|
+
import {
|
|
4
|
+
resolveStripeApiVersion,
|
|
5
|
+
type SupportedStripeApiVersion,
|
|
6
|
+
} from "./apiVersion.js";
|
|
7
|
+
export {
|
|
8
|
+
STRIPE_CUSTOMER_PREVIEW_API_VERSION,
|
|
9
|
+
type SupportedStripeApiVersion,
|
|
10
|
+
} from "./apiVersion.js";
|
|
11
|
+
export type {
|
|
12
|
+
CheckoutSessionReadOptions,
|
|
13
|
+
SubscriptionReadOptions,
|
|
14
|
+
CouponReadOptions,
|
|
15
|
+
} from "./billing/providerReads.js";
|
|
16
|
+
import * as providerReads from "./billing/providerReads.js";
|
|
17
|
+
export type { CreateAccountOptions } from "./core/accounts.js";
|
|
18
|
+
import { buildAsyncHookRoutes } from "./webhooks/asyncHooks.js";
|
|
19
|
+
import * as saleContextImpl from "./settlement/verifiedSale.js";
|
|
20
|
+
import * as settlementImpl from "./settlement/settleSale.js";
|
|
21
|
+
import * as commissionImpl from "./settlement/commissions.js";
|
|
22
|
+
import * as payoutSnapshotImpl from "./connect/payoutSnapshot.js";
|
|
23
|
+
export { allocateSale } from "./settlement/allocation.js";
|
|
24
|
+
export type {
|
|
25
|
+
SaleAllocation,
|
|
26
|
+
SaleAllocationOptions,
|
|
27
|
+
} from "./settlement/allocation.js";
|
|
28
|
+
export type {
|
|
29
|
+
VerifiedSale,
|
|
30
|
+
VerifiedSaleOptions,
|
|
31
|
+
} from "./settlement/verifiedSale.js";
|
|
32
|
+
export type { SettleSaleOptions } from "./settlement/settleSale.js";
|
|
33
|
+
export type { SettlementResult } from "./settlement/execution.js";
|
|
34
|
+
export type {
|
|
35
|
+
CommissionTerm,
|
|
36
|
+
CommissionSelectionOptions,
|
|
37
|
+
CommissionSelection,
|
|
38
|
+
CommissionDecision,
|
|
39
|
+
} from "./settlement/commissions.js";
|
|
40
|
+
export type {
|
|
41
|
+
RecipientPayoutSnapshot,
|
|
42
|
+
RecipientPayoutRow,
|
|
43
|
+
PayoutSnapshotOptions,
|
|
44
|
+
} from "./connect/payoutSnapshot.js";
|
|
1
45
|
import { internalActionGeneric, internalMutationGeneric } from "convex/server";
|
|
2
46
|
import { v } from "convex/values";
|
|
3
47
|
import Stripe from "stripe";
|
|
@@ -146,12 +190,11 @@ function clonePlatformFee(config: PlatformFeeConfig): PlatformFeeConfig {
|
|
|
146
190
|
};
|
|
147
191
|
}
|
|
148
192
|
|
|
149
|
-
// =============================================================================
|
|
150
193
|
// BETTER STRIPE CLIENT
|
|
151
|
-
// =============================================================================
|
|
152
194
|
|
|
153
195
|
export class BetterStripe {
|
|
154
196
|
public component: Component;
|
|
197
|
+
readonly stripeApiVersion: SupportedStripeApiVersion;
|
|
155
198
|
private _apiKey?: string;
|
|
156
199
|
private _triggers?: SyncTriggers;
|
|
157
200
|
private _hooks?: AsyncHooks;
|
|
@@ -160,6 +203,7 @@ export class BetterStripe {
|
|
|
160
203
|
|
|
161
204
|
constructor(component: BetterStripeComponent, options?: BetterStripeOptions) {
|
|
162
205
|
this.component = component;
|
|
206
|
+
this.stripeApiVersion = resolveStripeApiVersion(options?.stripeApiVersion);
|
|
163
207
|
this._apiKey = options?.STRIPE_SECRET_KEY;
|
|
164
208
|
this._triggers = options?.triggers;
|
|
165
209
|
this._hooks = options?.hooks;
|
|
@@ -208,13 +252,18 @@ export class BetterStripe {
|
|
|
208
252
|
return key;
|
|
209
253
|
}
|
|
210
254
|
|
|
211
|
-
|
|
212
|
-
|
|
255
|
+
registerRoutes(
|
|
256
|
+
http: HttpRouter,
|
|
257
|
+
config?: Parameters<typeof registerClientRoutes>[2],
|
|
258
|
+
) {
|
|
259
|
+
return registerClientRoutes(this, http, config);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
private stripe(): Stripe {
|
|
263
|
+
return getStripeClient(this.apiKey, this.stripeApiVersion);
|
|
213
264
|
}
|
|
214
265
|
|
|
215
|
-
// ============================================================================
|
|
216
266
|
// Static defaults (preserved for backwards compatibility)
|
|
217
|
-
// ============================================================================
|
|
218
267
|
|
|
219
268
|
static DEFAULT_ACCOUNT_CONFIGURATION =
|
|
220
269
|
accountsImpl.DEFAULT_ACCOUNT_CONFIGURATION;
|
|
@@ -222,21 +271,9 @@ export class BetterStripe {
|
|
|
222
271
|
static DEFAULT_CUSTOMER_CONFIGURATION =
|
|
223
272
|
accountsImpl.DEFAULT_CUSTOMER_CONFIGURATION;
|
|
224
273
|
|
|
225
|
-
// ============================================================================
|
|
226
274
|
// ACCOUNT METHODS
|
|
227
|
-
// ============================================================================
|
|
228
275
|
|
|
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
|
-
) {
|
|
276
|
+
async createAccount(ctx: RunCtx, opts: accountsImpl.CreateAccountOptions) {
|
|
240
277
|
return accountsImpl.createAccount(this.stripe(), this.component, ctx, opts);
|
|
241
278
|
}
|
|
242
279
|
|
|
@@ -276,14 +313,7 @@ export class BetterStripe {
|
|
|
276
313
|
|
|
277
314
|
async getOrCreateAccount(
|
|
278
315
|
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
|
-
},
|
|
316
|
+
opts: accountsImpl.CreateAccountOptions,
|
|
287
317
|
) {
|
|
288
318
|
return accountsImpl.getOrCreateAccount(
|
|
289
319
|
this.stripe(),
|
|
@@ -453,14 +483,7 @@ export class BetterStripe {
|
|
|
453
483
|
*/
|
|
454
484
|
async ensureCustomerAccount(
|
|
455
485
|
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
|
-
},
|
|
486
|
+
opts: accountsImpl.CreateAccountOptions,
|
|
464
487
|
) {
|
|
465
488
|
return accountsImpl.ensureCustomerAccount(
|
|
466
489
|
this.stripe(),
|
|
@@ -470,9 +493,7 @@ export class BetterStripe {
|
|
|
470
493
|
);
|
|
471
494
|
}
|
|
472
495
|
|
|
473
|
-
// ============================================================================
|
|
474
496
|
// PRODUCT METHODS
|
|
475
|
-
// ============================================================================
|
|
476
497
|
|
|
477
498
|
async createProduct(
|
|
478
499
|
ctx: RunCtx,
|
|
@@ -559,9 +580,7 @@ export class BetterStripe {
|
|
|
559
580
|
return productsImpl.deleteProduct(this.stripe(), ctx, opts);
|
|
560
581
|
}
|
|
561
582
|
|
|
562
|
-
// ============================================================================
|
|
563
583
|
// PRICE METHODS
|
|
564
|
-
// ============================================================================
|
|
565
584
|
|
|
566
585
|
async createPrice(
|
|
567
586
|
ctx: RunCtx,
|
|
@@ -649,13 +668,12 @@ export class BetterStripe {
|
|
|
649
668
|
return pricesImpl.listStripePrices(this.stripe(), ctx, opts);
|
|
650
669
|
}
|
|
651
670
|
|
|
652
|
-
// ============================================================================
|
|
653
671
|
// CHECKOUT METHODS
|
|
654
|
-
// ============================================================================
|
|
655
672
|
|
|
656
673
|
async createCheckoutSession(
|
|
657
674
|
ctx: RunCtx,
|
|
658
675
|
opts: {
|
|
676
|
+
idempotencyKey?: string;
|
|
659
677
|
userId: string;
|
|
660
678
|
orgId?: string;
|
|
661
679
|
stripePriceId: string;
|
|
@@ -744,9 +762,7 @@ export class BetterStripe {
|
|
|
744
762
|
return checkoutImpl.updateCheckoutSession(this.stripe(), ctx, opts);
|
|
745
763
|
}
|
|
746
764
|
|
|
747
|
-
// ============================================================================
|
|
748
765
|
// SUBSCRIPTION METHODS
|
|
749
|
-
// ============================================================================
|
|
750
766
|
|
|
751
767
|
/**
|
|
752
768
|
* Create a subscription directly for a V2 buyer (`customer_account`), off the
|
|
@@ -943,14 +959,7 @@ export class BetterStripe {
|
|
|
943
959
|
accountId?: string;
|
|
944
960
|
userId: string;
|
|
945
961
|
orgId?: string;
|
|
946
|
-
status:
|
|
947
|
-
| "active"
|
|
948
|
-
| "trialing"
|
|
949
|
-
| "past_due"
|
|
950
|
-
| "canceled"
|
|
951
|
-
| "incomplete"
|
|
952
|
-
| "unpaid"
|
|
953
|
-
| "paused";
|
|
962
|
+
status: SubscriptionStatus;
|
|
954
963
|
priceId?: string;
|
|
955
964
|
quantity?: number;
|
|
956
965
|
currentPeriodStart?: string;
|
|
@@ -970,9 +979,7 @@ export class BetterStripe {
|
|
|
970
979
|
return subscriptionsImpl.getTrialStatus(this.component, ctx, opts);
|
|
971
980
|
}
|
|
972
981
|
|
|
973
|
-
// ============================================================================
|
|
974
982
|
// INVOICE METHODS
|
|
975
|
-
// ============================================================================
|
|
976
983
|
|
|
977
984
|
async listInvoices(
|
|
978
985
|
ctx: RunCtx,
|
|
@@ -1039,9 +1046,7 @@ export class BetterStripe {
|
|
|
1039
1046
|
return invoicesImpl.getInvoiceFromStripe(this.stripe(), ctx, opts);
|
|
1040
1047
|
}
|
|
1041
1048
|
|
|
1042
|
-
// ============================================================================
|
|
1043
1049
|
// PAYMENT METHOD METHODS
|
|
1044
|
-
// ============================================================================
|
|
1045
1050
|
|
|
1046
1051
|
async listPaymentMethods(
|
|
1047
1052
|
ctx: RunCtx,
|
|
@@ -1072,9 +1077,7 @@ export class BetterStripe {
|
|
|
1072
1077
|
return paymentMethodsImpl.setDefaultPaymentMethod(this.stripe(), ctx, opts);
|
|
1073
1078
|
}
|
|
1074
1079
|
|
|
1075
|
-
// ============================================================================
|
|
1076
1080
|
// ACCOUNT LINK METHODS
|
|
1077
|
-
// ============================================================================
|
|
1078
1081
|
|
|
1079
1082
|
async createAccountLink(
|
|
1080
1083
|
ctx: RunCtx,
|
|
@@ -1150,9 +1153,7 @@ export class BetterStripe {
|
|
|
1150
1153
|
return accountLinksImpl.getCountrySpecs(this.stripe(), ctx, opts);
|
|
1151
1154
|
}
|
|
1152
1155
|
|
|
1153
|
-
// ============================================================================
|
|
1154
1156
|
// PAYOUT METHODS
|
|
1155
|
-
// ============================================================================
|
|
1156
1157
|
|
|
1157
1158
|
async createPayout(
|
|
1158
1159
|
ctx: RunCtx,
|
|
@@ -1253,6 +1254,50 @@ export class BetterStripe {
|
|
|
1253
1254
|
* (`{ available, pending, currency }`, minor units) per currency — each entry
|
|
1254
1255
|
* feeds the headless `PayoutSchedule` component's `balance` prop directly.
|
|
1255
1256
|
*/
|
|
1257
|
+
async getCheckoutSessionFromStripe(
|
|
1258
|
+
_ctx: RunCtx,
|
|
1259
|
+
opts: providerReads.CheckoutSessionReadOptions,
|
|
1260
|
+
) {
|
|
1261
|
+
return providerReads.getCheckoutSessionFromStripe(this.stripe(), opts);
|
|
1262
|
+
}
|
|
1263
|
+
async getSubscriptionFromStripe(
|
|
1264
|
+
_ctx: RunCtx,
|
|
1265
|
+
opts: providerReads.SubscriptionReadOptions,
|
|
1266
|
+
) {
|
|
1267
|
+
return providerReads.getSubscriptionFromStripe(this.stripe(), opts);
|
|
1268
|
+
}
|
|
1269
|
+
async getCouponFromStripe(
|
|
1270
|
+
_ctx: RunCtx,
|
|
1271
|
+
opts: providerReads.CouponReadOptions,
|
|
1272
|
+
) {
|
|
1273
|
+
return providerReads.getCouponFromStripe(this.stripe(), opts);
|
|
1274
|
+
}
|
|
1275
|
+
async getVerifiedSale(
|
|
1276
|
+
_ctx: RunCtx,
|
|
1277
|
+
opts: saleContextImpl.VerifiedSaleOptions,
|
|
1278
|
+
) {
|
|
1279
|
+
return saleContextImpl.getVerifiedSale(this.stripe(), opts);
|
|
1280
|
+
}
|
|
1281
|
+
async settleSale(ctx: RunCtx, opts: settlementImpl.SettleSaleOptions) {
|
|
1282
|
+
return settlementImpl.settleSale(this.stripe(), this.component, ctx, opts);
|
|
1283
|
+
}
|
|
1284
|
+
async selectCommissionInvoice(
|
|
1285
|
+
ctx: RunCtx,
|
|
1286
|
+
opts: commissionImpl.CommissionSelectionOptions,
|
|
1287
|
+
) {
|
|
1288
|
+
return commissionImpl.selectCommissionInvoice(
|
|
1289
|
+
this.stripe(),
|
|
1290
|
+
this.component,
|
|
1291
|
+
ctx,
|
|
1292
|
+
opts,
|
|
1293
|
+
);
|
|
1294
|
+
}
|
|
1295
|
+
async getPayoutSnapshot(
|
|
1296
|
+
_ctx: RunCtx,
|
|
1297
|
+
opts: payoutSnapshotImpl.PayoutSnapshotOptions,
|
|
1298
|
+
) {
|
|
1299
|
+
return payoutSnapshotImpl.getPayoutSnapshot(this.stripe(), opts);
|
|
1300
|
+
}
|
|
1256
1301
|
async getAccountBalance(_ctx: RunCtx, opts: { stripeAccountId: string }) {
|
|
1257
1302
|
return payoutsImpl.getAccountBalance(this.stripe(), opts);
|
|
1258
1303
|
}
|
|
@@ -1268,9 +1313,7 @@ export class BetterStripe {
|
|
|
1268
1313
|
return payoutsImpl.listPayouts(this.component, ctx, opts);
|
|
1269
1314
|
}
|
|
1270
1315
|
|
|
1271
|
-
// ============================================================================
|
|
1272
1316
|
// REFUND METHODS
|
|
1273
|
-
// ============================================================================
|
|
1274
1317
|
|
|
1275
1318
|
/**
|
|
1276
1319
|
* Issue a refund (BTS-34). `refundApplicationFee` and `reverseTransfer`
|
|
@@ -1325,9 +1368,7 @@ export class BetterStripe {
|
|
|
1325
1368
|
return refundsImpl.listRefunds(this.component, ctx, opts);
|
|
1326
1369
|
}
|
|
1327
1370
|
|
|
1328
|
-
// ============================================================================
|
|
1329
1371
|
// DISPUTE METHODS
|
|
1330
|
-
// ============================================================================
|
|
1331
1372
|
|
|
1332
1373
|
async getDisputeByStripeId(
|
|
1333
1374
|
ctx: RunCtx,
|
|
@@ -1397,9 +1438,7 @@ export class BetterStripe {
|
|
|
1397
1438
|
return disputesImpl.closeDispute(this.stripe(), this.component, ctx, opts);
|
|
1398
1439
|
}
|
|
1399
1440
|
|
|
1400
|
-
// ============================================================================
|
|
1401
1441
|
// WEBHOOK ENDPOINT MANAGEMENT
|
|
1402
|
-
// ============================================================================
|
|
1403
1442
|
|
|
1404
1443
|
async listWebhookEndpoints(ctx: RunCtx, opts?: { limit?: number }) {
|
|
1405
1444
|
return webhookEndpointsImpl.listWebhookEndpoints(this.stripe(), ctx, opts);
|
|
@@ -1407,13 +1446,12 @@ export class BetterStripe {
|
|
|
1407
1446
|
|
|
1408
1447
|
async createWebhookEndpoint(
|
|
1409
1448
|
ctx: RunCtx,
|
|
1410
|
-
opts:
|
|
1411
|
-
url: string;
|
|
1412
|
-
description?: string;
|
|
1413
|
-
enabledEvents?: string[];
|
|
1414
|
-
},
|
|
1449
|
+
opts: webhookEndpointsImpl.WebhookEndpointOptions,
|
|
1415
1450
|
): Promise<{ id: string; secret: string; url: string }> {
|
|
1416
|
-
return webhookEndpointsImpl.createWebhookEndpoint(this.stripe(), ctx,
|
|
1451
|
+
return webhookEndpointsImpl.createWebhookEndpoint(this.stripe(), ctx, {
|
|
1452
|
+
...opts,
|
|
1453
|
+
apiVersion: this.stripeApiVersion,
|
|
1454
|
+
});
|
|
1417
1455
|
}
|
|
1418
1456
|
|
|
1419
1457
|
async listEventDestinations(ctx: RunCtx, opts?: { limit?: number }) {
|
|
@@ -1422,13 +1460,7 @@ export class BetterStripe {
|
|
|
1422
1460
|
|
|
1423
1461
|
async setupEventDestination(
|
|
1424
1462
|
ctx: RunCtx,
|
|
1425
|
-
opts:
|
|
1426
|
-
url: string;
|
|
1427
|
-
name?: string;
|
|
1428
|
-
description?: string;
|
|
1429
|
-
enabledEvents?: string[];
|
|
1430
|
-
eventPayload?: "snapshot" | "thin";
|
|
1431
|
-
},
|
|
1463
|
+
opts: webhookEndpointsImpl.EventDestinationOptions,
|
|
1432
1464
|
): Promise<{
|
|
1433
1465
|
id: string;
|
|
1434
1466
|
secret: string;
|
|
@@ -1436,12 +1468,13 @@ export class BetterStripe {
|
|
|
1436
1468
|
enabledEvents: string[];
|
|
1437
1469
|
created: boolean;
|
|
1438
1470
|
}> {
|
|
1439
|
-
return webhookEndpointsImpl.setupEventDestination(this.stripe(), ctx,
|
|
1471
|
+
return webhookEndpointsImpl.setupEventDestination(this.stripe(), ctx, {
|
|
1472
|
+
...opts,
|
|
1473
|
+
apiVersion: this.stripeApiVersion,
|
|
1474
|
+
});
|
|
1440
1475
|
}
|
|
1441
1476
|
|
|
1442
|
-
// ============================================================================
|
|
1443
1477
|
// WEBHOOK EVENT QUERIES
|
|
1444
|
-
// ============================================================================
|
|
1445
1478
|
|
|
1446
1479
|
async listWebhookEvents(
|
|
1447
1480
|
ctx: RunCtx,
|
|
@@ -1462,17 +1495,13 @@ export class BetterStripe {
|
|
|
1462
1495
|
}>;
|
|
1463
1496
|
}
|
|
1464
1497
|
|
|
1465
|
-
// ============================================================================
|
|
1466
1498
|
// DATA MANAGEMENT
|
|
1467
|
-
// ============================================================================
|
|
1468
1499
|
|
|
1469
1500
|
async clearAll(ctx: RunCtx): Promise<{ cleared: number; tables: string[] }> {
|
|
1470
1501
|
return dataImpl.clearAll(this.component, ctx);
|
|
1471
1502
|
}
|
|
1472
1503
|
|
|
1473
|
-
// ============================================================================
|
|
1474
1504
|
// SYNC METHODS
|
|
1475
|
-
// ============================================================================
|
|
1476
1505
|
|
|
1477
1506
|
async syncAllAccounts(ctx: RunCtx) {
|
|
1478
1507
|
return accountsImpl.syncAllAccounts(this.stripe(), this.component, ctx);
|
|
@@ -1490,9 +1519,7 @@ export class BetterStripe {
|
|
|
1490
1519
|
);
|
|
1491
1520
|
}
|
|
1492
1521
|
|
|
1493
|
-
// ============================================================================
|
|
1494
1522
|
// WEBHOOK HANDLER EXPORT (BetterAuth-style)
|
|
1495
|
-
// ============================================================================
|
|
1496
1523
|
|
|
1497
1524
|
/**
|
|
1498
1525
|
* Build the two webhook handler function definitions for the app to export
|
|
@@ -1811,38 +1838,7 @@ export class BetterStripe {
|
|
|
1811
1838
|
),
|
|
1812
1839
|
};
|
|
1813
1840
|
|
|
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
|
-
};
|
|
1841
|
+
const ASYNC = buildAsyncHookRoutes(hooks);
|
|
1846
1842
|
|
|
1847
1843
|
const syncWebhook = internalMutationGeneric({
|
|
1848
1844
|
args: { dispatcher: v.string(), data: v.any() },
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { HttpRouter } from "convex/server";
|
|
2
|
+
import type { Component } from "./helpers.js";
|
|
3
|
+
import type { RegisterRoutesConfig } from "./types.js";
|
|
4
|
+
import { registerRoutes } from "./webhooks/index.js";
|
|
5
|
+
import { throwStripeError } from "./errors.js";
|
|
6
|
+
export function registerClientRoutes(
|
|
7
|
+
client: { component: Component; apiKey: string; stripeApiVersion: string },
|
|
8
|
+
http: HttpRouter,
|
|
9
|
+
config?: RegisterRoutesConfig,
|
|
10
|
+
) {
|
|
11
|
+
if (
|
|
12
|
+
(config?.stripeApiVersion !== undefined &&
|
|
13
|
+
config.stripeApiVersion !== client.stripeApiVersion) ||
|
|
14
|
+
(config?.stripeSecretKey !== undefined &&
|
|
15
|
+
config.stripeSecretKey !== client.apiKey)
|
|
16
|
+
)
|
|
17
|
+
throwStripeError(
|
|
18
|
+
"INVALID_CONFIGURATION",
|
|
19
|
+
"Webhook API version and secret key must match the BetterStripe client.",
|
|
20
|
+
);
|
|
21
|
+
registerRoutes(http, client.component, {
|
|
22
|
+
...config,
|
|
23
|
+
stripeApiVersion: client.stripeApiVersion,
|
|
24
|
+
stripeSecretKey: client.apiKey,
|
|
25
|
+
});
|
|
26
|
+
}
|