@better-auth/stripe 1.4.9 → 1.5.0-beta.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/.turbo/turbo-build.log +9 -8
- package/dist/client.d.mts +72 -3
- package/dist/client.mjs +5 -5
- package/dist/error-codes-qqooUh6R.mjs +16 -0
- package/dist/{index-DQa3pHPd.d.mts → index-DpiQGYLJ.d.mts} +33 -9
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +19 -27
- package/package.json +5 -5
- package/src/client.ts +3 -1
- package/src/error-codes.ts +14 -0
- package/src/routes.ts +54 -55
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @better-auth/stripe@1.
|
|
2
|
+
> @better-auth/stripe@1.5.0-beta.1 build /home/runner/work/better-auth/better-auth/packages/stripe
|
|
3
3
|
> tsdown
|
|
4
4
|
|
|
5
5
|
[34mℹ[39m tsdown [2mv0.17.2[22m powered by rolldown [2mv1.0.0-beta.53[22m
|
|
@@ -7,10 +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
|
|
11
|
-
[34mℹ[39m [2mdist/[22m[1mclient.mjs[22m
|
|
12
|
-
[34mℹ[39m [2mdist/[
|
|
13
|
-
[34mℹ[39m [2mdist/[22m[32m[
|
|
14
|
-
[34mℹ[39m [2mdist/[22m[
|
|
15
|
-
[34mℹ[39m
|
|
16
|
-
[
|
|
10
|
+
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m40.12 kB[22m [2m│ gzip: 7.63 kB[22m
|
|
11
|
+
[34mℹ[39m [2mdist/[22m[1mclient.mjs[22m [2m 0.35 kB[22m [2m│ gzip: 0.25 kB[22m
|
|
12
|
+
[34mℹ[39m [2mdist/[22merror-codes-qqooUh6R.mjs [2m 0.72 kB[22m [2m│ gzip: 0.42 kB[22m
|
|
13
|
+
[34mℹ[39m [2mdist/[22m[32m[1mclient.d.mts[22m[39m [2m 2.97 kB[22m [2m│ gzip: 0.79 kB[22m
|
|
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-DpiQGYLJ.d.mts[39m [2m25.42 kB[22m [2m│ gzip: 4.88 kB[22m
|
|
16
|
+
[34mℹ[39m 6 files, total: 69.80 kB
|
|
17
|
+
[32m✔[39m Build complete in [32m16274ms[39m
|
package/dist/client.d.mts
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
|
-
import { n as stripe } from "./index-
|
|
1
|
+
import { n as stripe } from "./index-DpiQGYLJ.mjs";
|
|
2
2
|
|
|
3
|
+
//#region src/error-codes.d.ts
|
|
4
|
+
declare const STRIPE_ERROR_CODES: {
|
|
5
|
+
readonly SUBSCRIPTION_NOT_FOUND: {
|
|
6
|
+
code: "SUBSCRIPTION_NOT_FOUND";
|
|
7
|
+
message: "Subscription not found";
|
|
8
|
+
};
|
|
9
|
+
readonly SUBSCRIPTION_PLAN_NOT_FOUND: {
|
|
10
|
+
code: "SUBSCRIPTION_PLAN_NOT_FOUND";
|
|
11
|
+
message: "Subscription plan not found";
|
|
12
|
+
};
|
|
13
|
+
readonly ALREADY_SUBSCRIBED_PLAN: {
|
|
14
|
+
code: "ALREADY_SUBSCRIBED_PLAN";
|
|
15
|
+
message: "You're already subscribed to this plan";
|
|
16
|
+
};
|
|
17
|
+
readonly UNABLE_TO_CREATE_CUSTOMER: {
|
|
18
|
+
code: "UNABLE_TO_CREATE_CUSTOMER";
|
|
19
|
+
message: "Unable to create customer";
|
|
20
|
+
};
|
|
21
|
+
readonly FAILED_TO_FETCH_PLANS: {
|
|
22
|
+
code: "FAILED_TO_FETCH_PLANS";
|
|
23
|
+
message: "Failed to fetch plans";
|
|
24
|
+
};
|
|
25
|
+
readonly EMAIL_VERIFICATION_REQUIRED: {
|
|
26
|
+
code: "EMAIL_VERIFICATION_REQUIRED";
|
|
27
|
+
message: "Email verification is required before you can subscribe to a plan";
|
|
28
|
+
};
|
|
29
|
+
readonly SUBSCRIPTION_NOT_ACTIVE: {
|
|
30
|
+
code: "SUBSCRIPTION_NOT_ACTIVE";
|
|
31
|
+
message: "Subscription is not active";
|
|
32
|
+
};
|
|
33
|
+
readonly SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: {
|
|
34
|
+
code: "SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION";
|
|
35
|
+
message: "Subscription is not scheduled for cancellation";
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
3
39
|
//#region src/client.d.ts
|
|
4
40
|
declare const stripeClient: <O extends {
|
|
5
41
|
subscription: boolean;
|
|
@@ -17,9 +53,42 @@ declare const stripeClient: <O extends {
|
|
|
17
53
|
stripeWebhookSecret: string;
|
|
18
54
|
}>>;
|
|
19
55
|
pathMethods: {
|
|
20
|
-
"/subscription/restore": "POST";
|
|
21
56
|
"/subscription/billing-portal": "POST";
|
|
22
57
|
};
|
|
58
|
+
$ERROR_CODES: {
|
|
59
|
+
readonly SUBSCRIPTION_NOT_FOUND: {
|
|
60
|
+
code: "SUBSCRIPTION_NOT_FOUND";
|
|
61
|
+
message: "Subscription not found";
|
|
62
|
+
};
|
|
63
|
+
readonly SUBSCRIPTION_PLAN_NOT_FOUND: {
|
|
64
|
+
code: "SUBSCRIPTION_PLAN_NOT_FOUND";
|
|
65
|
+
message: "Subscription plan not found";
|
|
66
|
+
};
|
|
67
|
+
readonly ALREADY_SUBSCRIBED_PLAN: {
|
|
68
|
+
code: "ALREADY_SUBSCRIBED_PLAN";
|
|
69
|
+
message: "You're already subscribed to this plan";
|
|
70
|
+
};
|
|
71
|
+
readonly UNABLE_TO_CREATE_CUSTOMER: {
|
|
72
|
+
code: "UNABLE_TO_CREATE_CUSTOMER";
|
|
73
|
+
message: "Unable to create customer";
|
|
74
|
+
};
|
|
75
|
+
readonly FAILED_TO_FETCH_PLANS: {
|
|
76
|
+
code: "FAILED_TO_FETCH_PLANS";
|
|
77
|
+
message: "Failed to fetch plans";
|
|
78
|
+
};
|
|
79
|
+
readonly EMAIL_VERIFICATION_REQUIRED: {
|
|
80
|
+
code: "EMAIL_VERIFICATION_REQUIRED";
|
|
81
|
+
message: "Email verification is required before you can subscribe to a plan";
|
|
82
|
+
};
|
|
83
|
+
readonly SUBSCRIPTION_NOT_ACTIVE: {
|
|
84
|
+
code: "SUBSCRIPTION_NOT_ACTIVE";
|
|
85
|
+
message: "Subscription is not active";
|
|
86
|
+
};
|
|
87
|
+
readonly SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: {
|
|
88
|
+
code: "SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION";
|
|
89
|
+
message: "Subscription is not scheduled for cancellation";
|
|
90
|
+
};
|
|
91
|
+
};
|
|
23
92
|
};
|
|
24
93
|
//#endregion
|
|
25
|
-
export { stripeClient };
|
|
94
|
+
export { STRIPE_ERROR_CODES, stripeClient };
|
package/dist/client.mjs
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
+
import { t as STRIPE_ERROR_CODES } from "./error-codes-qqooUh6R.mjs";
|
|
2
|
+
|
|
1
3
|
//#region src/client.ts
|
|
2
4
|
const stripeClient = (options) => {
|
|
3
5
|
return {
|
|
4
6
|
id: "stripe-client",
|
|
5
7
|
$InferServerPlugin: {},
|
|
6
|
-
pathMethods: {
|
|
7
|
-
|
|
8
|
-
"/subscription/billing-portal": "POST"
|
|
9
|
-
}
|
|
8
|
+
pathMethods: { "/subscription/billing-portal": "POST" },
|
|
9
|
+
$ERROR_CODES: STRIPE_ERROR_CODES
|
|
10
10
|
};
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
//#endregion
|
|
14
|
-
export { stripeClient };
|
|
14
|
+
export { STRIPE_ERROR_CODES, stripeClient };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { defineErrorCodes } from "@better-auth/core/utils";
|
|
2
|
+
|
|
3
|
+
//#region src/error-codes.ts
|
|
4
|
+
const STRIPE_ERROR_CODES = defineErrorCodes({
|
|
5
|
+
SUBSCRIPTION_NOT_FOUND: "Subscription not found",
|
|
6
|
+
SUBSCRIPTION_PLAN_NOT_FOUND: "Subscription plan not found",
|
|
7
|
+
ALREADY_SUBSCRIBED_PLAN: "You're already subscribed to this plan",
|
|
8
|
+
UNABLE_TO_CREATE_CUSTOMER: "Unable to create customer",
|
|
9
|
+
FAILED_TO_FETCH_PLANS: "Failed to fetch plans",
|
|
10
|
+
EMAIL_VERIFICATION_REQUIRED: "Email verification is required before you can subscribe to a plan",
|
|
11
|
+
SUBSCRIPTION_NOT_ACTIVE: "Subscription is not active",
|
|
12
|
+
SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: "Subscription is not scheduled for cancellation"
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
//#endregion
|
|
16
|
+
export { STRIPE_ERROR_CODES as t };
|
|
@@ -646,7 +646,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
|
|
|
646
646
|
};
|
|
647
647
|
use: ((inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<void>)[];
|
|
648
648
|
}, {
|
|
649
|
-
status: ("OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "
|
|
649
|
+
status: ("NOT_FOUND" | "FOUND" | "OK" | "CREATED" | "ACCEPTED" | "NO_CONTENT" | "MULTIPLE_CHOICES" | "MOVED_PERMANENTLY" | "SEE_OTHER" | "NOT_MODIFIED" | "TEMPORARY_REDIRECT" | "BAD_REQUEST" | "UNAUTHORIZED" | "PAYMENT_REQUIRED" | "FORBIDDEN" | "METHOD_NOT_ALLOWED" | "NOT_ACCEPTABLE" | "PROXY_AUTHENTICATION_REQUIRED" | "REQUEST_TIMEOUT" | "CONFLICT" | "GONE" | "LENGTH_REQUIRED" | "PRECONDITION_FAILED" | "PAYLOAD_TOO_LARGE" | "URI_TOO_LONG" | "UNSUPPORTED_MEDIA_TYPE" | "RANGE_NOT_SATISFIABLE" | "EXPECTATION_FAILED" | "I'M_A_TEAPOT" | "MISDIRECTED_REQUEST" | "UNPROCESSABLE_ENTITY" | "LOCKED" | "FAILED_DEPENDENCY" | "TOO_EARLY" | "UPGRADE_REQUIRED" | "PRECONDITION_REQUIRED" | "TOO_MANY_REQUESTS" | "REQUEST_HEADER_FIELDS_TOO_LARGE" | "UNAVAILABLE_FOR_LEGAL_REASONS" | "INTERNAL_SERVER_ERROR" | "NOT_IMPLEMENTED" | "BAD_GATEWAY" | "SERVICE_UNAVAILABLE" | "GATEWAY_TIMEOUT" | "HTTP_VERSION_NOT_SUPPORTED" | "VARIANT_ALSO_NEGOTIATES" | "INSUFFICIENT_STORAGE" | "LOOP_DETECTED" | "NOT_EXTENDED" | "NETWORK_AUTHENTICATION_REQUIRED") | better_call0.Status;
|
|
650
650
|
body: ({
|
|
651
651
|
message?: string;
|
|
652
652
|
code?: string;
|
|
@@ -732,14 +732,38 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
|
|
|
732
732
|
schema: {};
|
|
733
733
|
options: NoInfer<O>;
|
|
734
734
|
$ERROR_CODES: {
|
|
735
|
-
readonly SUBSCRIPTION_NOT_FOUND:
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
readonly
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
735
|
+
readonly SUBSCRIPTION_NOT_FOUND: {
|
|
736
|
+
code: "SUBSCRIPTION_NOT_FOUND";
|
|
737
|
+
message: "Subscription not found";
|
|
738
|
+
};
|
|
739
|
+
readonly SUBSCRIPTION_PLAN_NOT_FOUND: {
|
|
740
|
+
code: "SUBSCRIPTION_PLAN_NOT_FOUND";
|
|
741
|
+
message: "Subscription plan not found";
|
|
742
|
+
};
|
|
743
|
+
readonly ALREADY_SUBSCRIBED_PLAN: {
|
|
744
|
+
code: "ALREADY_SUBSCRIBED_PLAN";
|
|
745
|
+
message: "You're already subscribed to this plan";
|
|
746
|
+
};
|
|
747
|
+
readonly UNABLE_TO_CREATE_CUSTOMER: {
|
|
748
|
+
code: "UNABLE_TO_CREATE_CUSTOMER";
|
|
749
|
+
message: "Unable to create customer";
|
|
750
|
+
};
|
|
751
|
+
readonly FAILED_TO_FETCH_PLANS: {
|
|
752
|
+
code: "FAILED_TO_FETCH_PLANS";
|
|
753
|
+
message: "Failed to fetch plans";
|
|
754
|
+
};
|
|
755
|
+
readonly EMAIL_VERIFICATION_REQUIRED: {
|
|
756
|
+
code: "EMAIL_VERIFICATION_REQUIRED";
|
|
757
|
+
message: "Email verification is required before you can subscribe to a plan";
|
|
758
|
+
};
|
|
759
|
+
readonly SUBSCRIPTION_NOT_ACTIVE: {
|
|
760
|
+
code: "SUBSCRIPTION_NOT_ACTIVE";
|
|
761
|
+
message: "Subscription is not active";
|
|
762
|
+
};
|
|
763
|
+
readonly SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: {
|
|
764
|
+
code: "SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION";
|
|
765
|
+
message: "Subscription is not scheduled for cancellation";
|
|
766
|
+
};
|
|
743
767
|
};
|
|
744
768
|
};
|
|
745
769
|
type StripePlugin<O extends StripeOptions> = ReturnType<typeof stripe<O>>;
|
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-DpiQGYLJ.mjs";
|
|
2
2
|
export { StripePlan, StripePlugin, Subscription, SubscriptionOptions, stripe };
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { t as STRIPE_ERROR_CODES$1 } from "./error-codes-qqooUh6R.mjs";
|
|
1
2
|
import { defineErrorCodes } from "@better-auth/core/utils";
|
|
2
3
|
import { defu } from "defu";
|
|
3
4
|
import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api";
|
|
5
|
+
import { APIError } from "@better-auth/core/error";
|
|
4
6
|
import { HIDE_METADATA, logger } from "better-auth";
|
|
5
|
-
import { APIError, getSessionFromCtx, originCheck, sessionMiddleware } from "better-auth/api";
|
|
7
|
+
import { APIError as APIError$1, getSessionFromCtx, originCheck, sessionMiddleware } from "better-auth/api";
|
|
6
8
|
import * as z from "zod/v4";
|
|
7
9
|
import { mergeSchema } from "better-auth/db";
|
|
8
10
|
|
|
@@ -188,11 +190,11 @@ async function onSubscriptionDeleted(ctx, options, event) {
|
|
|
188
190
|
//#region src/middleware.ts
|
|
189
191
|
const referenceMiddleware = (subscriptionOptions, action) => createAuthMiddleware(async (ctx) => {
|
|
190
192
|
const session = ctx.context.session;
|
|
191
|
-
if (!session) throw new APIError("UNAUTHORIZED");
|
|
193
|
+
if (!session) throw new APIError$1("UNAUTHORIZED");
|
|
192
194
|
const referenceId = ctx.body?.referenceId || ctx.query?.referenceId || session.user.id;
|
|
193
195
|
if (referenceId !== session.user.id && !subscriptionOptions.authorizeReference) {
|
|
194
196
|
logger.error(`Passing referenceId into a subscription action isn't allowed if subscription.authorizeReference isn't defined in your stripe plugin config.`);
|
|
195
|
-
throw new APIError("BAD_REQUEST", { message: "Reference id is not allowed. Read server logs for more details." });
|
|
197
|
+
throw new APIError$1("BAD_REQUEST", { message: "Reference id is not allowed. Read server logs for more details." });
|
|
196
198
|
}
|
|
197
199
|
/**
|
|
198
200
|
* if referenceId is the same as the active session user's id
|
|
@@ -203,21 +205,11 @@ const referenceMiddleware = (subscriptionOptions, action) => createAuthMiddlewar
|
|
|
203
205
|
session: session.session,
|
|
204
206
|
referenceId,
|
|
205
207
|
action
|
|
206
|
-
}, ctx) || sameReference : true)) throw new APIError("UNAUTHORIZED", { message: "Unauthorized" });
|
|
208
|
+
}, ctx) || sameReference : true)) throw new APIError$1("UNAUTHORIZED", { message: "Unauthorized" });
|
|
207
209
|
});
|
|
208
210
|
|
|
209
211
|
//#endregion
|
|
210
212
|
//#region src/routes.ts
|
|
211
|
-
const STRIPE_ERROR_CODES$1 = defineErrorCodes({
|
|
212
|
-
SUBSCRIPTION_NOT_FOUND: "Subscription not found",
|
|
213
|
-
SUBSCRIPTION_PLAN_NOT_FOUND: "Subscription plan not found",
|
|
214
|
-
ALREADY_SUBSCRIBED_PLAN: "You're already subscribed to this plan",
|
|
215
|
-
UNABLE_TO_CREATE_CUSTOMER: "Unable to create customer",
|
|
216
|
-
FAILED_TO_FETCH_PLANS: "Failed to fetch plans",
|
|
217
|
-
EMAIL_VERIFICATION_REQUIRED: "Email verification is required before you can subscribe to a plan",
|
|
218
|
-
SUBSCRIPTION_NOT_ACTIVE: "Subscription is not active",
|
|
219
|
-
SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: "Subscription is not scheduled for cancellation"
|
|
220
|
-
});
|
|
221
213
|
const upgradeSubscriptionBodySchema = z.object({
|
|
222
214
|
plan: z.string().meta({ description: "The name of the plan to upgrade to. Eg: \"pro\"" }),
|
|
223
215
|
annual: z.boolean().meta({ description: "Whether to upgrade to an annual plan. Eg: true" }).optional(),
|
|
@@ -261,10 +253,10 @@ const upgradeSubscription = (options) => {
|
|
|
261
253
|
]
|
|
262
254
|
}, async (ctx) => {
|
|
263
255
|
const { user: user$1, session } = ctx.context.session;
|
|
264
|
-
if (!user$1.emailVerified && subscriptionOptions.requireEmailVerification) throw
|
|
256
|
+
if (!user$1.emailVerified && subscriptionOptions.requireEmailVerification) throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.EMAIL_VERIFICATION_REQUIRED);
|
|
265
257
|
const referenceId = ctx.body.referenceId || user$1.id;
|
|
266
258
|
const plan = await getPlanByName(options, ctx.body.plan);
|
|
267
|
-
if (!plan) throw
|
|
259
|
+
if (!plan) throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.SUBSCRIPTION_PLAN_NOT_FOUND);
|
|
268
260
|
let subscriptionToUpdate = ctx.body.subscriptionId ? await ctx.context.adapter.findOne({
|
|
269
261
|
model: "subscription",
|
|
270
262
|
where: [{
|
|
@@ -279,7 +271,7 @@ const upgradeSubscription = (options) => {
|
|
|
279
271
|
}]
|
|
280
272
|
}) : null;
|
|
281
273
|
if (ctx.body.subscriptionId && subscriptionToUpdate && subscriptionToUpdate.referenceId !== referenceId) subscriptionToUpdate = null;
|
|
282
|
-
if (ctx.body.subscriptionId && !subscriptionToUpdate) throw
|
|
274
|
+
if (ctx.body.subscriptionId && !subscriptionToUpdate) throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.SUBSCRIPTION_NOT_FOUND);
|
|
283
275
|
let customerId = subscriptionToUpdate?.stripeCustomerId || user$1.stripeCustomerId;
|
|
284
276
|
if (!customerId) try {
|
|
285
277
|
let stripeCustomer = (await client.customers.list({
|
|
@@ -305,7 +297,7 @@ const upgradeSubscription = (options) => {
|
|
|
305
297
|
customerId = stripeCustomer.id;
|
|
306
298
|
} catch (e) {
|
|
307
299
|
ctx.context.logger.error(e);
|
|
308
|
-
throw
|
|
300
|
+
throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.UNABLE_TO_CREATE_CUSTOMER);
|
|
309
301
|
}
|
|
310
302
|
const subscriptions$1 = subscriptionToUpdate ? [subscriptionToUpdate] : await ctx.context.adapter.findMany({
|
|
311
303
|
model: "subscription",
|
|
@@ -321,7 +313,7 @@ const upgradeSubscription = (options) => {
|
|
|
321
313
|
return false;
|
|
322
314
|
});
|
|
323
315
|
const incompleteSubscription = subscriptions$1.find((sub) => sub.status === "incomplete");
|
|
324
|
-
if (activeOrTrialingSubscription && activeOrTrialingSubscription.status === "active" && activeOrTrialingSubscription.plan === ctx.body.plan && activeOrTrialingSubscription.seats === (ctx.body.seats || 1)) throw
|
|
316
|
+
if (activeOrTrialingSubscription && activeOrTrialingSubscription.status === "active" && activeOrTrialingSubscription.plan === ctx.body.plan && activeOrTrialingSubscription.seats === (ctx.body.seats || 1)) throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.ALREADY_SUBSCRIBED_PLAN);
|
|
325
317
|
if (activeSubscription && customerId) {
|
|
326
318
|
let dbSubscription = await ctx.context.adapter.findOne({
|
|
327
319
|
model: "subscription",
|
|
@@ -563,7 +555,7 @@ const cancelSubscription = (options) => {
|
|
|
563
555
|
}]
|
|
564
556
|
}).then((subs) => subs.find((sub) => sub.status === "active" || sub.status === "trialing"));
|
|
565
557
|
if (ctx.body.subscriptionId && subscription && subscription.referenceId !== referenceId) subscription = void 0;
|
|
566
|
-
if (!subscription || !subscription.stripeCustomerId) throw
|
|
558
|
+
if (!subscription || !subscription.stripeCustomerId) throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.SUBSCRIPTION_NOT_FOUND);
|
|
567
559
|
const activeSubscriptions = await client.subscriptions.list({ customer: subscription.stripeCustomerId }).then((res) => res.data.filter((sub) => sub.status === "active" || sub.status === "trialing"));
|
|
568
560
|
if (!activeSubscriptions.length) {
|
|
569
561
|
/**
|
|
@@ -577,10 +569,10 @@ const cancelSubscription = (options) => {
|
|
|
577
569
|
value: referenceId
|
|
578
570
|
}]
|
|
579
571
|
});
|
|
580
|
-
throw
|
|
572
|
+
throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.SUBSCRIPTION_NOT_FOUND);
|
|
581
573
|
}
|
|
582
574
|
const activeSubscription = activeSubscriptions.find((sub) => sub.id === subscription.stripeSubscriptionId);
|
|
583
|
-
if (!activeSubscription) throw
|
|
575
|
+
if (!activeSubscription) throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.SUBSCRIPTION_NOT_FOUND);
|
|
584
576
|
const { url } = await client.billingPortal.sessions.create({
|
|
585
577
|
customer: subscription.stripeCustomerId,
|
|
586
578
|
return_url: getUrl(ctx, `${ctx.context.baseURL}/subscription/cancel/callback?callbackURL=${encodeURIComponent(ctx.body?.returnUrl || "/")}&subscriptionId=${encodeURIComponent(subscription.id)}`),
|
|
@@ -642,11 +634,11 @@ const restoreSubscription = (options) => {
|
|
|
642
634
|
}]
|
|
643
635
|
}).then((subs) => subs.find((sub) => sub.status === "active" || sub.status === "trialing"));
|
|
644
636
|
if (ctx.body.subscriptionId && subscription && subscription.referenceId !== referenceId) subscription = void 0;
|
|
645
|
-
if (!subscription || !subscription.stripeCustomerId) throw
|
|
646
|
-
if (subscription.status != "active" && subscription.status != "trialing") throw
|
|
647
|
-
if (!subscription.cancelAtPeriodEnd) throw
|
|
637
|
+
if (!subscription || !subscription.stripeCustomerId) throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.SUBSCRIPTION_NOT_FOUND);
|
|
638
|
+
if (subscription.status != "active" && subscription.status != "trialing") throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.SUBSCRIPTION_NOT_ACTIVE);
|
|
639
|
+
if (!subscription.cancelAtPeriodEnd) throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION);
|
|
648
640
|
const activeSubscription = await client.subscriptions.list({ customer: subscription.stripeCustomerId }).then((res) => res.data.filter((sub) => sub.status === "active" || sub.status === "trialing")[0]);
|
|
649
|
-
if (!activeSubscription) throw
|
|
641
|
+
if (!activeSubscription) throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.SUBSCRIPTION_NOT_FOUND);
|
|
650
642
|
try {
|
|
651
643
|
const newSub = await client.subscriptions.update(activeSubscription.id, { cancel_at_period_end: false });
|
|
652
644
|
await ctx.context.adapter.update({
|
|
@@ -663,7 +655,7 @@ const restoreSubscription = (options) => {
|
|
|
663
655
|
return ctx.json(newSub);
|
|
664
656
|
} catch (error) {
|
|
665
657
|
ctx.context.logger.error("Error restoring subscription", error);
|
|
666
|
-
throw
|
|
658
|
+
throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES$1.UNABLE_TO_CREATE_CUSTOMER);
|
|
667
659
|
}
|
|
668
660
|
});
|
|
669
661
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/stripe",
|
|
3
3
|
"author": "Bereket Engida",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.5.0-beta.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.mts",
|
|
@@ -50,15 +50,15 @@
|
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"stripe": "^18 || ^19 || ^20",
|
|
53
|
-
"@better-auth/core": "1.
|
|
54
|
-
"better-auth": "1.
|
|
53
|
+
"@better-auth/core": "1.5.0-beta.1",
|
|
54
|
+
"better-auth": "1.5.0-beta.1"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"better-call": "1.1.7",
|
|
58
58
|
"stripe": "^20.0.0",
|
|
59
59
|
"tsdown": "^0.17.2",
|
|
60
|
-
"@better-auth/core": "1.
|
|
61
|
-
"better-auth": "1.
|
|
60
|
+
"@better-auth/core": "1.5.0-beta.1",
|
|
61
|
+
"better-auth": "1.5.0-beta.1"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"test": "vitest",
|
package/src/client.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BetterAuthClientPlugin } from "better-auth";
|
|
2
|
+
import { STRIPE_ERROR_CODES } from "./error-codes";
|
|
2
3
|
import type { stripe } from "./index";
|
|
3
4
|
|
|
4
5
|
export const stripeClient = <
|
|
@@ -28,8 +29,9 @@ export const stripeClient = <
|
|
|
28
29
|
>
|
|
29
30
|
>,
|
|
30
31
|
pathMethods: {
|
|
31
|
-
"/subscription/restore": "POST",
|
|
32
32
|
"/subscription/billing-portal": "POST",
|
|
33
33
|
},
|
|
34
|
+
$ERROR_CODES: STRIPE_ERROR_CODES,
|
|
34
35
|
} satisfies BetterAuthClientPlugin;
|
|
35
36
|
};
|
|
37
|
+
export * from "./error-codes";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineErrorCodes } from "@better-auth/core/utils";
|
|
2
|
+
|
|
3
|
+
export const STRIPE_ERROR_CODES = defineErrorCodes({
|
|
4
|
+
SUBSCRIPTION_NOT_FOUND: "Subscription not found",
|
|
5
|
+
SUBSCRIPTION_PLAN_NOT_FOUND: "Subscription plan not found",
|
|
6
|
+
ALREADY_SUBSCRIBED_PLAN: "You're already subscribed to this plan",
|
|
7
|
+
UNABLE_TO_CREATE_CUSTOMER: "Unable to create customer",
|
|
8
|
+
FAILED_TO_FETCH_PLANS: "Failed to fetch plans",
|
|
9
|
+
EMAIL_VERIFICATION_REQUIRED:
|
|
10
|
+
"Email verification is required before you can subscribe to a plan",
|
|
11
|
+
SUBSCRIPTION_NOT_ACTIVE: "Subscription is not active",
|
|
12
|
+
SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION:
|
|
13
|
+
"Subscription is not scheduled for cancellation",
|
|
14
|
+
});
|
package/src/routes.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { createAuthEndpoint } from "@better-auth/core/api";
|
|
2
|
-
import {
|
|
2
|
+
import { APIError } from "@better-auth/core/error";
|
|
3
3
|
import type { GenericEndpointContext } from "better-auth";
|
|
4
4
|
import { HIDE_METADATA } from "better-auth";
|
|
5
5
|
import {
|
|
6
|
-
APIError,
|
|
7
6
|
getSessionFromCtx,
|
|
8
7
|
originCheck,
|
|
9
8
|
sessionMiddleware,
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
import type Stripe from "stripe";
|
|
12
11
|
import type { Stripe as StripeType } from "stripe";
|
|
13
12
|
import * as z from "zod/v4";
|
|
13
|
+
import { STRIPE_ERROR_CODES } from "./error-codes";
|
|
14
14
|
import {
|
|
15
15
|
onCheckoutSessionCompleted,
|
|
16
16
|
onSubscriptionDeleted,
|
|
@@ -25,19 +25,6 @@ import type {
|
|
|
25
25
|
} from "./types";
|
|
26
26
|
import { getPlanByName, getPlanByPriceInfo, getPlans } from "./utils";
|
|
27
27
|
|
|
28
|
-
const STRIPE_ERROR_CODES = defineErrorCodes({
|
|
29
|
-
SUBSCRIPTION_NOT_FOUND: "Subscription not found",
|
|
30
|
-
SUBSCRIPTION_PLAN_NOT_FOUND: "Subscription plan not found",
|
|
31
|
-
ALREADY_SUBSCRIBED_PLAN: "You're already subscribed to this plan",
|
|
32
|
-
UNABLE_TO_CREATE_CUSTOMER: "Unable to create customer",
|
|
33
|
-
FAILED_TO_FETCH_PLANS: "Failed to fetch plans",
|
|
34
|
-
EMAIL_VERIFICATION_REQUIRED:
|
|
35
|
-
"Email verification is required before you can subscribe to a plan",
|
|
36
|
-
SUBSCRIPTION_NOT_ACTIVE: "Subscription is not active",
|
|
37
|
-
SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION:
|
|
38
|
-
"Subscription is not scheduled for cancellation",
|
|
39
|
-
});
|
|
40
|
-
|
|
41
28
|
const upgradeSubscriptionBodySchema = z.object({
|
|
42
29
|
/**
|
|
43
30
|
* The name of the plan to subscribe
|
|
@@ -171,16 +158,18 @@ export const upgradeSubscription = (options: StripeOptions) => {
|
|
|
171
158
|
async (ctx) => {
|
|
172
159
|
const { user, session } = ctx.context.session;
|
|
173
160
|
if (!user.emailVerified && subscriptionOptions.requireEmailVerification) {
|
|
174
|
-
throw
|
|
175
|
-
|
|
176
|
-
|
|
161
|
+
throw APIError.from(
|
|
162
|
+
"BAD_REQUEST",
|
|
163
|
+
STRIPE_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED,
|
|
164
|
+
);
|
|
177
165
|
}
|
|
178
166
|
const referenceId = ctx.body.referenceId || user.id;
|
|
179
167
|
const plan = await getPlanByName(options, ctx.body.plan);
|
|
180
168
|
if (!plan) {
|
|
181
|
-
throw
|
|
182
|
-
|
|
183
|
-
|
|
169
|
+
throw APIError.from(
|
|
170
|
+
"BAD_REQUEST",
|
|
171
|
+
STRIPE_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND,
|
|
172
|
+
);
|
|
184
173
|
}
|
|
185
174
|
let subscriptionToUpdate = ctx.body.subscriptionId
|
|
186
175
|
? await ctx.context.adapter.findOne<Subscription>({
|
|
@@ -208,9 +197,10 @@ export const upgradeSubscription = (options: StripeOptions) => {
|
|
|
208
197
|
}
|
|
209
198
|
|
|
210
199
|
if (ctx.body.subscriptionId && !subscriptionToUpdate) {
|
|
211
|
-
throw
|
|
212
|
-
|
|
213
|
-
|
|
200
|
+
throw APIError.from(
|
|
201
|
+
"BAD_REQUEST",
|
|
202
|
+
STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
203
|
+
);
|
|
214
204
|
}
|
|
215
205
|
|
|
216
206
|
let customerId =
|
|
@@ -254,9 +244,10 @@ export const upgradeSubscription = (options: StripeOptions) => {
|
|
|
254
244
|
customerId = stripeCustomer.id;
|
|
255
245
|
} catch (e: any) {
|
|
256
246
|
ctx.context.logger.error(e);
|
|
257
|
-
throw
|
|
258
|
-
|
|
259
|
-
|
|
247
|
+
throw APIError.from(
|
|
248
|
+
"BAD_REQUEST",
|
|
249
|
+
STRIPE_ERROR_CODES.UNABLE_TO_CREATE_CUSTOMER,
|
|
250
|
+
);
|
|
260
251
|
}
|
|
261
252
|
}
|
|
262
253
|
|
|
@@ -315,9 +306,10 @@ export const upgradeSubscription = (options: StripeOptions) => {
|
|
|
315
306
|
activeOrTrialingSubscription.plan === ctx.body.plan &&
|
|
316
307
|
activeOrTrialingSubscription.seats === (ctx.body.seats || 1)
|
|
317
308
|
) {
|
|
318
|
-
throw
|
|
319
|
-
|
|
320
|
-
|
|
309
|
+
throw APIError.from(
|
|
310
|
+
"BAD_REQUEST",
|
|
311
|
+
STRIPE_ERROR_CODES.ALREADY_SUBSCRIBED_PLAN,
|
|
312
|
+
);
|
|
321
313
|
}
|
|
322
314
|
|
|
323
315
|
if (activeSubscription && customerId) {
|
|
@@ -732,9 +724,10 @@ export const cancelSubscription = (options: StripeOptions) => {
|
|
|
732
724
|
}
|
|
733
725
|
|
|
734
726
|
if (!subscription || !subscription.stripeCustomerId) {
|
|
735
|
-
throw
|
|
736
|
-
|
|
737
|
-
|
|
727
|
+
throw APIError.from(
|
|
728
|
+
"BAD_REQUEST",
|
|
729
|
+
STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
730
|
+
);
|
|
738
731
|
}
|
|
739
732
|
const activeSubscriptions = await client.subscriptions
|
|
740
733
|
.list({
|
|
@@ -759,17 +752,19 @@ export const cancelSubscription = (options: StripeOptions) => {
|
|
|
759
752
|
},
|
|
760
753
|
],
|
|
761
754
|
});
|
|
762
|
-
throw
|
|
763
|
-
|
|
764
|
-
|
|
755
|
+
throw APIError.from(
|
|
756
|
+
"BAD_REQUEST",
|
|
757
|
+
STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
758
|
+
);
|
|
765
759
|
}
|
|
766
760
|
const activeSubscription = activeSubscriptions.find(
|
|
767
761
|
(sub) => sub.id === subscription.stripeSubscriptionId,
|
|
768
762
|
);
|
|
769
763
|
if (!activeSubscription) {
|
|
770
|
-
throw
|
|
771
|
-
|
|
772
|
-
|
|
764
|
+
throw APIError.from(
|
|
765
|
+
"BAD_REQUEST",
|
|
766
|
+
STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
767
|
+
);
|
|
773
768
|
}
|
|
774
769
|
const { url } = await client.billingPortal.sessions
|
|
775
770
|
.create({
|
|
@@ -893,23 +888,25 @@ export const restoreSubscription = (options: StripeOptions) => {
|
|
|
893
888
|
subscription = undefined;
|
|
894
889
|
}
|
|
895
890
|
if (!subscription || !subscription.stripeCustomerId) {
|
|
896
|
-
throw
|
|
897
|
-
|
|
898
|
-
|
|
891
|
+
throw APIError.from(
|
|
892
|
+
"BAD_REQUEST",
|
|
893
|
+
STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
894
|
+
);
|
|
899
895
|
}
|
|
900
896
|
if (
|
|
901
897
|
subscription.status != "active" &&
|
|
902
898
|
subscription.status != "trialing"
|
|
903
899
|
) {
|
|
904
|
-
throw
|
|
905
|
-
|
|
906
|
-
|
|
900
|
+
throw APIError.from(
|
|
901
|
+
"BAD_REQUEST",
|
|
902
|
+
STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_ACTIVE,
|
|
903
|
+
);
|
|
907
904
|
}
|
|
908
905
|
if (!subscription.cancelAtPeriodEnd) {
|
|
909
|
-
throw
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
906
|
+
throw APIError.from(
|
|
907
|
+
"BAD_REQUEST",
|
|
908
|
+
STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION,
|
|
909
|
+
);
|
|
913
910
|
}
|
|
914
911
|
|
|
915
912
|
const activeSubscription = await client.subscriptions
|
|
@@ -923,9 +920,10 @@ export const restoreSubscription = (options: StripeOptions) => {
|
|
|
923
920
|
)[0],
|
|
924
921
|
);
|
|
925
922
|
if (!activeSubscription) {
|
|
926
|
-
throw
|
|
927
|
-
|
|
928
|
-
|
|
923
|
+
throw APIError.from(
|
|
924
|
+
"BAD_REQUEST",
|
|
925
|
+
STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
926
|
+
);
|
|
929
927
|
}
|
|
930
928
|
|
|
931
929
|
try {
|
|
@@ -953,9 +951,10 @@ export const restoreSubscription = (options: StripeOptions) => {
|
|
|
953
951
|
return ctx.json(newSub);
|
|
954
952
|
} catch (error) {
|
|
955
953
|
ctx.context.logger.error("Error restoring subscription", error);
|
|
956
|
-
throw
|
|
957
|
-
|
|
958
|
-
|
|
954
|
+
throw APIError.from(
|
|
955
|
+
"BAD_REQUEST",
|
|
956
|
+
STRIPE_ERROR_CODES.UNABLE_TO_CREATE_CUSTOMER,
|
|
957
|
+
);
|
|
959
958
|
}
|
|
960
959
|
},
|
|
961
960
|
);
|