@better-auth/stripe 1.5.0-beta.7 → 1.5.0-beta.9
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/.turbo/turbo-build.log +5 -5
- package/dist/client.d.mts +1 -1
- package/dist/{index-CkImGy5x.d.mts → index-BqGWQFAv.d.mts} +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +6 -2
- package/package.json +7 -7
- package/src/routes.ts +26 -1
- package/test/stripe.test.ts +66 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @better-auth/stripe@1.5.0-beta.
|
|
2
|
+
> @better-auth/stripe@1.5.0-beta.9 build /home/runner/work/better-auth/better-auth/packages/stripe
|
|
3
3
|
> tsdown
|
|
4
4
|
|
|
5
5
|
[34mℹ[39m tsdown [2mv0.19.0[22m powered by rolldown [2mv1.0.0-beta.59[22m
|
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
[34mℹ[39m entry: [34msrc/index.ts, src/client.ts[39m
|
|
8
8
|
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
9
|
[34mℹ[39m Build start
|
|
10
|
-
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [
|
|
10
|
+
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m56.45 kB[22m [2m│ gzip: 10.16 kB[22m
|
|
11
11
|
[34mℹ[39m [2mdist/[22m[1mclient.mjs[22m [2m 0.39 kB[22m [2m│ gzip: 0.26 kB[22m
|
|
12
12
|
[34mℹ[39m [2mdist/[22merror-codes-Clj-xYDP.mjs [2m 1.62 kB[22m [2m│ gzip: 0.75 kB[22m
|
|
13
13
|
[34mℹ[39m [2mdist/[22m[32m[1mclient.d.mts[22m[39m [2m 6.71 kB[22m [2m│ gzip: 1.32 kB[22m
|
|
14
14
|
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m 0.21 kB[22m [2m│ gzip: 0.14 kB[22m
|
|
15
|
-
[34mℹ[39m [2mdist/[22m[32mindex-
|
|
16
|
-
[34mℹ[39m 6 files, total:
|
|
17
|
-
[32m✔[39m Build complete in [
|
|
15
|
+
[34mℹ[39m [2mdist/[22m[32mindex-BqGWQFAv.d.mts[39m [2m31.88 kB[22m [2m│ gzip: 5.35 kB[22m
|
|
16
|
+
[34mℹ[39m 6 files, total: 97.26 kB
|
|
17
|
+
[32m✔[39m Build complete in [32m25066ms[39m
|
package/dist/client.d.mts
CHANGED
|
@@ -483,6 +483,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
|
|
|
483
483
|
}>>;
|
|
484
484
|
metadata: zod0.ZodOptional<zod0.ZodRecord<zod0.ZodString, zod0.ZodAny>>;
|
|
485
485
|
seats: zod0.ZodOptional<zod0.ZodNumber>;
|
|
486
|
+
locale: zod0.ZodOptional<zod0.ZodCustom<Stripe.Checkout.Session.Locale, Stripe.Checkout.Session.Locale>>;
|
|
486
487
|
successUrl: zod0.ZodDefault<zod0.ZodString>;
|
|
487
488
|
cancelUrl: zod0.ZodDefault<zod0.ZodString>;
|
|
488
489
|
returnUrl: zod0.ZodOptional<zod0.ZodString>;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as SubscriptionOptions, i as Subscription, n as stripe, r as StripePlan, t as StripePlugin } from "./index-
|
|
1
|
+
import { a as SubscriptionOptions, i as Subscription, n as stripe, r as StripePlan, t as StripePlugin } from "./index-BqGWQFAv.mjs";
|
|
2
2
|
export { StripePlan, StripePlugin, Subscription, SubscriptionOptions, stripe };
|
package/dist/index.mjs
CHANGED
|
@@ -424,6 +424,9 @@ const upgradeSubscriptionBodySchema = z.object({
|
|
|
424
424
|
customerType: z.enum(["user", "organization"]).meta({ description: "Customer type for the subscription. Eg: \"user\" or \"organization\"" }).optional(),
|
|
425
425
|
metadata: z.record(z.string(), z.any()).optional(),
|
|
426
426
|
seats: z.number().meta({ description: "Number of seats to upgrade to (if applicable). Eg: 1" }).optional(),
|
|
427
|
+
locale: z.custom((localization) => {
|
|
428
|
+
return typeof localization === "string";
|
|
429
|
+
}).meta({ description: "The locale to display Checkout in. Eg: 'en', 'ko'. If not provided or set to `auto`, the browser's locale is used." }).optional(),
|
|
427
430
|
successUrl: z.string().meta({ description: "Callback URL to redirect back after successful subscription. Eg: \"https://example.com/success\"" }).default("/"),
|
|
428
431
|
cancelUrl: z.string().meta({ description: "If set, checkout shows a back button and customers will be directed here if they cancel payment. Eg: \"https://example.com/pricing\"" }).default("/"),
|
|
429
432
|
returnUrl: z.string().meta({ description: "URL to take customers to when they click on the billing portal’s link to return to your website. Eg: \"https://example.com/dashboard\"" }).optional(),
|
|
@@ -576,7 +579,7 @@ const upgradeSubscription = (options) => {
|
|
|
576
579
|
return false;
|
|
577
580
|
});
|
|
578
581
|
const incompleteSubscription = subscriptions$1.find((sub) => sub.status === "incomplete");
|
|
579
|
-
if (activeOrTrialingSubscription && activeOrTrialingSubscription.status === "active" && activeOrTrialingSubscription.plan === ctx.body.plan && activeOrTrialingSubscription.seats === (ctx.body.seats || 1)) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.ALREADY_SUBSCRIBED_PLAN);
|
|
582
|
+
if (activeOrTrialingSubscription && activeOrTrialingSubscription.status === "active" && activeOrTrialingSubscription.plan === ctx.body.plan && activeOrTrialingSubscription.seats === (ctx.body.seats || 1) && (!activeOrTrialingSubscription.periodEnd || activeOrTrialingSubscription.periodEnd > /* @__PURE__ */ new Date())) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.ALREADY_SUBSCRIBED_PLAN);
|
|
580
583
|
if (activeSubscription && customerId) {
|
|
581
584
|
let dbSubscription = await ctx.context.adapter.findOne({
|
|
582
585
|
model: "subscription",
|
|
@@ -695,6 +698,7 @@ const upgradeSubscription = (options) => {
|
|
|
695
698
|
address: "auto"
|
|
696
699
|
}
|
|
697
700
|
} : { customer_email: user$1.email },
|
|
701
|
+
locale: ctx.body.locale,
|
|
698
702
|
success_url: getUrl(ctx, `${ctx.context.baseURL}/subscription/success?callbackURL=${encodeURIComponent(ctx.body.successUrl)}&subscriptionId=${encodeURIComponent(subscription.id)}`),
|
|
699
703
|
cancel_url: getUrl(ctx, ctx.body.cancelUrl),
|
|
700
704
|
line_items: [{
|
|
@@ -1080,7 +1084,7 @@ const subscriptionSuccess = (options) => {
|
|
|
1080
1084
|
const createBillingPortalBodySchema = z.object({
|
|
1081
1085
|
locale: z.custom((localization) => {
|
|
1082
1086
|
return typeof localization === "string";
|
|
1083
|
-
}).optional(),
|
|
1087
|
+
}).meta({ description: "The IETF language tag of the locale Customer Portal is displayed in. Eg: 'en', 'ko'. If not provided or set to `auto`, the browser's locale is used." }).optional(),
|
|
1084
1088
|
referenceId: z.string().optional(),
|
|
1085
1089
|
customerType: z.enum(["user", "organization"]).meta({ description: "Customer type for the subscription. Eg: \"user\" or \"organization\"" }).optional(),
|
|
1086
1090
|
returnUrl: z.string().default("/"),
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/stripe",
|
|
3
3
|
"author": "Bereket Engida",
|
|
4
|
-
"version": "1.5.0-beta.
|
|
4
|
+
"version": "1.5.0-beta.9",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.mts",
|
|
@@ -46,19 +46,19 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"defu": "^6.1.4",
|
|
49
|
-
"zod": "^4.
|
|
49
|
+
"zod": "^4.3.5"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"stripe": "^18 || ^19 || ^20",
|
|
53
|
-
"@better-auth/core": "1.5.0-beta.
|
|
54
|
-
"better-auth": "1.5.0-beta.
|
|
53
|
+
"@better-auth/core": "1.5.0-beta.9",
|
|
54
|
+
"better-auth": "1.5.0-beta.9"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"better-call": "1.
|
|
57
|
+
"better-call": "1.2.0",
|
|
58
58
|
"stripe": "^20.0.0",
|
|
59
59
|
"tsdown": "^0.19.0",
|
|
60
|
-
"@better-auth/core": "1.5.0-beta.
|
|
61
|
-
"better-auth": "1.5.0-beta.
|
|
60
|
+
"@better-auth/core": "1.5.0-beta.9",
|
|
61
|
+
"better-auth": "1.5.0-beta.9"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"test": "vitest",
|
package/src/routes.ts
CHANGED
|
@@ -161,6 +161,19 @@ const upgradeSubscriptionBodySchema = z.object({
|
|
|
161
161
|
description: "Number of seats to upgrade to (if applicable). Eg: 1",
|
|
162
162
|
})
|
|
163
163
|
.optional(),
|
|
164
|
+
/**
|
|
165
|
+
* The IETF language tag of the locale Checkout is displayed in.
|
|
166
|
+
* If not provided or set to `auto`, the browser's locale is used.
|
|
167
|
+
*/
|
|
168
|
+
locale: z
|
|
169
|
+
.custom<StripeType.Checkout.Session.Locale>((localization) => {
|
|
170
|
+
return typeof localization === "string";
|
|
171
|
+
})
|
|
172
|
+
.meta({
|
|
173
|
+
description:
|
|
174
|
+
"The locale to display Checkout in. Eg: 'en', 'ko'. If not provided or set to `auto`, the browser's locale is used.",
|
|
175
|
+
})
|
|
176
|
+
.optional(),
|
|
164
177
|
/**
|
|
165
178
|
* The URL to which Stripe should send customers when payment or setup is complete.
|
|
166
179
|
*/
|
|
@@ -498,7 +511,10 @@ export const upgradeSubscription = (options: StripeOptions) => {
|
|
|
498
511
|
activeOrTrialingSubscription &&
|
|
499
512
|
activeOrTrialingSubscription.status === "active" &&
|
|
500
513
|
activeOrTrialingSubscription.plan === ctx.body.plan &&
|
|
501
|
-
activeOrTrialingSubscription.seats === (ctx.body.seats || 1)
|
|
514
|
+
activeOrTrialingSubscription.seats === (ctx.body.seats || 1) &&
|
|
515
|
+
// Skip if periodEnd has passed, in case status is stale
|
|
516
|
+
(!activeOrTrialingSubscription.periodEnd ||
|
|
517
|
+
activeOrTrialingSubscription.periodEnd > new Date())
|
|
502
518
|
) {
|
|
503
519
|
throw APIError.from(
|
|
504
520
|
"BAD_REQUEST",
|
|
@@ -702,6 +718,7 @@ export const upgradeSubscription = (options: StripeOptions) => {
|
|
|
702
718
|
: {
|
|
703
719
|
customer_email: user.email,
|
|
704
720
|
}),
|
|
721
|
+
locale: ctx.body.locale,
|
|
705
722
|
success_url: getUrl(
|
|
706
723
|
ctx,
|
|
707
724
|
`${
|
|
@@ -1429,10 +1446,18 @@ export const subscriptionSuccess = (options: StripeOptions) => {
|
|
|
1429
1446
|
};
|
|
1430
1447
|
|
|
1431
1448
|
const createBillingPortalBodySchema = z.object({
|
|
1449
|
+
/**
|
|
1450
|
+
* The IETF language tag of the locale Customer Portal is displayed in.
|
|
1451
|
+
* If not provided or set to `auto`, the browser's locale is used.
|
|
1452
|
+
*/
|
|
1432
1453
|
locale: z
|
|
1433
1454
|
.custom<StripeType.Checkout.Session.Locale>((localization) => {
|
|
1434
1455
|
return typeof localization === "string";
|
|
1435
1456
|
})
|
|
1457
|
+
.meta({
|
|
1458
|
+
description:
|
|
1459
|
+
"The IETF language tag of the locale Customer Portal is displayed in. Eg: 'en', 'ko'. If not provided or set to `auto`, the browser's locale is used.",
|
|
1460
|
+
})
|
|
1436
1461
|
.optional(),
|
|
1437
1462
|
referenceId: z.string().optional(),
|
|
1438
1463
|
/**
|
package/test/stripe.test.ts
CHANGED
|
@@ -1915,6 +1915,72 @@ describe("stripe", () => {
|
|
|
1915
1915
|
expect(upgradeRes.error?.message).toContain("already subscribed");
|
|
1916
1916
|
});
|
|
1917
1917
|
|
|
1918
|
+
it.each([
|
|
1919
|
+
{
|
|
1920
|
+
name: "past",
|
|
1921
|
+
periodEnd: new Date(Date.now() - 24 * 60 * 60 * 1000),
|
|
1922
|
+
shouldAllow: true,
|
|
1923
|
+
},
|
|
1924
|
+
{
|
|
1925
|
+
name: "future",
|
|
1926
|
+
periodEnd: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000),
|
|
1927
|
+
shouldAllow: false,
|
|
1928
|
+
},
|
|
1929
|
+
])("should handle re-subscribing when periodEnd is in the $name", async ({
|
|
1930
|
+
periodEnd,
|
|
1931
|
+
shouldAllow,
|
|
1932
|
+
}) => {
|
|
1933
|
+
const { client, auth, sessionSetter } = await getTestInstance(
|
|
1934
|
+
{
|
|
1935
|
+
database: memory,
|
|
1936
|
+
plugins: [stripe(stripeOptions)],
|
|
1937
|
+
},
|
|
1938
|
+
{
|
|
1939
|
+
disableTestUser: true,
|
|
1940
|
+
clientOptions: {
|
|
1941
|
+
plugins: [stripeClient({ subscription: true })],
|
|
1942
|
+
},
|
|
1943
|
+
},
|
|
1944
|
+
);
|
|
1945
|
+
const ctx = await auth.$context;
|
|
1946
|
+
|
|
1947
|
+
const userRes = await client.signUp.email(
|
|
1948
|
+
{ ...testUser, email: `periodend-${periodEnd.getTime()}@email.com` },
|
|
1949
|
+
{ throw: true },
|
|
1950
|
+
);
|
|
1951
|
+
|
|
1952
|
+
const headers = new Headers();
|
|
1953
|
+
await client.signIn.email(
|
|
1954
|
+
{ ...testUser, email: `periodend-${periodEnd.getTime()}@email.com` },
|
|
1955
|
+
{ throw: true, onSuccess: sessionSetter(headers) },
|
|
1956
|
+
);
|
|
1957
|
+
|
|
1958
|
+
await client.subscription.upgrade({
|
|
1959
|
+
plan: "starter",
|
|
1960
|
+
seats: 1,
|
|
1961
|
+
fetchOptions: { headers },
|
|
1962
|
+
});
|
|
1963
|
+
|
|
1964
|
+
await ctx.adapter.update({
|
|
1965
|
+
model: "subscription",
|
|
1966
|
+
update: { status: "active", seats: 1, periodEnd },
|
|
1967
|
+
where: [{ field: "referenceId", value: userRes.user.id }],
|
|
1968
|
+
});
|
|
1969
|
+
|
|
1970
|
+
const upgradeRes = await client.subscription.upgrade({
|
|
1971
|
+
plan: "starter",
|
|
1972
|
+
seats: 1,
|
|
1973
|
+
fetchOptions: { headers },
|
|
1974
|
+
});
|
|
1975
|
+
|
|
1976
|
+
if (shouldAllow) {
|
|
1977
|
+
expect(upgradeRes.error).toBeNull();
|
|
1978
|
+
expect(upgradeRes.data?.url).toBeDefined();
|
|
1979
|
+
} else {
|
|
1980
|
+
expect(upgradeRes.error?.message).toContain("already subscribed");
|
|
1981
|
+
}
|
|
1982
|
+
});
|
|
1983
|
+
|
|
1918
1984
|
it("should only call Stripe customers.create once for signup and upgrade", async () => {
|
|
1919
1985
|
const { client, sessionSetter } = await getTestInstance(
|
|
1920
1986
|
{
|