@better-auth/stripe 1.5.0-beta.11 → 1.5.0-beta.13

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @better-auth/stripe@1.5.0-beta.11 build /home/runner/work/better-auth/better-auth/packages/stripe
2
+ > @better-auth/stripe@1.5.0-beta.13 build /home/runner/work/better-auth/better-auth/packages/stripe
3
3
  > tsdown
4
4
 
5
5
  ℹ tsdown v0.20.1 powered by rolldown v1.0.0-rc.1
@@ -7,16 +7,16 @@
7
7
  ℹ entry: src/index.ts, src/client.ts
8
8
  ℹ tsconfig: tsconfig.json
9
9
  ℹ Build start
10
- ℹ dist/index.mjs  57.16 kB │ gzip: 10.38 kB
11
- [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugin `rolldown-plugin-dts:generate`. See https://rolldown.rs/options/checks#plugintimings for more details.
10
+ ℹ dist/index.mjs  57.13 kB │ gzip: 10.39 kB
12
11
  ℹ dist/client.mjs  0.43 kB │ gzip: 0.29 kB
13
-
14
- ℹ dist/index.mjs.map 122.22 kB │ gzip: 22.94 kB
15
- ℹ dist/error-codes-CMowBCzF.mjs.map  2.09 kB │ gzip: 0.96 kB
16
- ℹ dist/error-codes-CMowBCzF.mjs  1.67 kB │ gzip: 0.78 kB
12
+ ℹ dist/index.mjs.map 122.17 kB │ gzip: 22.93 kB
13
+ ℹ dist/error-codes-CHMyMR5v.mjs.map  2.23 kB │ gzip: 1.01 kB
14
+ ℹ dist/error-codes-CHMyMR5v.mjs  1.78 kB │ gzip: 0.82 kB
17
15
  ℹ dist/client.mjs.map  1.25 kB │ gzip: 0.59 kB
18
- ℹ dist/client.d.mts  4.43 kB │ gzip: 0.88 kB
16
+ ℹ dist/client.d.mts  4.61 kB │ gzip: 0.90 kB
19
17
  ℹ dist/index.d.mts  0.21 kB │ gzip: 0.14 kB
20
- ℹ dist/index-DRCIVNqh.d.mts  30.80 kB │ gzip: 5.11 kB
21
- ℹ 9 files, total: 220.26 kB
22
- ✔ Build complete in 31403ms
18
+ ℹ dist/index-BELqjMd2.d.mts  30.82 kB │ gzip: 5.13 kB
19
+ ℹ 9 files, total: 220.63 kB
20
+ [PLUGIN_TIMINGS] Warning: Your build spent significant time in plugin `rolldown-plugin-dts:generate`. See https://rolldown.rs/options/checks#plugintimings for more details.
21
+
22
+ ✔ Build complete in 35719ms
package/dist/client.d.mts CHANGED
@@ -1,29 +1,30 @@
1
- import { n as stripe } from "./index-DRCIVNqh.mjs";
2
- import * as better_auth49 from "better-auth";
1
+ import { n as stripe } from "./index-BELqjMd2.mjs";
2
+ import * as better_auth51 from "better-auth";
3
3
 
4
4
  //#region src/error-codes.d.ts
5
5
  declare const STRIPE_ERROR_CODES: {
6
- UNAUTHORIZED: better_auth49.RawError<"UNAUTHORIZED">;
7
- INVALID_REQUEST_BODY: better_auth49.RawError<"INVALID_REQUEST_BODY">;
8
- SUBSCRIPTION_NOT_FOUND: better_auth49.RawError<"SUBSCRIPTION_NOT_FOUND">;
9
- SUBSCRIPTION_PLAN_NOT_FOUND: better_auth49.RawError<"SUBSCRIPTION_PLAN_NOT_FOUND">;
10
- ALREADY_SUBSCRIBED_PLAN: better_auth49.RawError<"ALREADY_SUBSCRIBED_PLAN">;
11
- REFERENCE_ID_NOT_ALLOWED: better_auth49.RawError<"REFERENCE_ID_NOT_ALLOWED">;
12
- CUSTOMER_NOT_FOUND: better_auth49.RawError<"CUSTOMER_NOT_FOUND">;
13
- UNABLE_TO_CREATE_CUSTOMER: better_auth49.RawError<"UNABLE_TO_CREATE_CUSTOMER">;
14
- UNABLE_TO_CREATE_BILLING_PORTAL: better_auth49.RawError<"UNABLE_TO_CREATE_BILLING_PORTAL">;
15
- STRIPE_SIGNATURE_NOT_FOUND: better_auth49.RawError<"STRIPE_SIGNATURE_NOT_FOUND">;
16
- STRIPE_WEBHOOK_SECRET_NOT_FOUND: better_auth49.RawError<"STRIPE_WEBHOOK_SECRET_NOT_FOUND">;
17
- STRIPE_WEBHOOK_ERROR: better_auth49.RawError<"STRIPE_WEBHOOK_ERROR">;
18
- FAILED_TO_CONSTRUCT_STRIPE_EVENT: better_auth49.RawError<"FAILED_TO_CONSTRUCT_STRIPE_EVENT">;
19
- FAILED_TO_FETCH_PLANS: better_auth49.RawError<"FAILED_TO_FETCH_PLANS">;
20
- EMAIL_VERIFICATION_REQUIRED: better_auth49.RawError<"EMAIL_VERIFICATION_REQUIRED">;
21
- SUBSCRIPTION_NOT_ACTIVE: better_auth49.RawError<"SUBSCRIPTION_NOT_ACTIVE">;
22
- SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: better_auth49.RawError<"SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION">;
23
- ORGANIZATION_NOT_FOUND: better_auth49.RawError<"ORGANIZATION_NOT_FOUND">;
24
- ORGANIZATION_SUBSCRIPTION_NOT_ENABLED: better_auth49.RawError<"ORGANIZATION_SUBSCRIPTION_NOT_ENABLED">;
25
- ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION: better_auth49.RawError<"ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION">;
26
- ORGANIZATION_REFERENCE_ID_REQUIRED: better_auth49.RawError<"ORGANIZATION_REFERENCE_ID_REQUIRED">;
6
+ UNAUTHORIZED: better_auth51.RawError<"UNAUTHORIZED">;
7
+ INVALID_REQUEST_BODY: better_auth51.RawError<"INVALID_REQUEST_BODY">;
8
+ SUBSCRIPTION_NOT_FOUND: better_auth51.RawError<"SUBSCRIPTION_NOT_FOUND">;
9
+ SUBSCRIPTION_PLAN_NOT_FOUND: better_auth51.RawError<"SUBSCRIPTION_PLAN_NOT_FOUND">;
10
+ ALREADY_SUBSCRIBED_PLAN: better_auth51.RawError<"ALREADY_SUBSCRIBED_PLAN">;
11
+ REFERENCE_ID_NOT_ALLOWED: better_auth51.RawError<"REFERENCE_ID_NOT_ALLOWED">;
12
+ CUSTOMER_NOT_FOUND: better_auth51.RawError<"CUSTOMER_NOT_FOUND">;
13
+ UNABLE_TO_CREATE_CUSTOMER: better_auth51.RawError<"UNABLE_TO_CREATE_CUSTOMER">;
14
+ UNABLE_TO_CREATE_BILLING_PORTAL: better_auth51.RawError<"UNABLE_TO_CREATE_BILLING_PORTAL">;
15
+ STRIPE_SIGNATURE_NOT_FOUND: better_auth51.RawError<"STRIPE_SIGNATURE_NOT_FOUND">;
16
+ STRIPE_WEBHOOK_SECRET_NOT_FOUND: better_auth51.RawError<"STRIPE_WEBHOOK_SECRET_NOT_FOUND">;
17
+ STRIPE_WEBHOOK_ERROR: better_auth51.RawError<"STRIPE_WEBHOOK_ERROR">;
18
+ FAILED_TO_CONSTRUCT_STRIPE_EVENT: better_auth51.RawError<"FAILED_TO_CONSTRUCT_STRIPE_EVENT">;
19
+ FAILED_TO_FETCH_PLANS: better_auth51.RawError<"FAILED_TO_FETCH_PLANS">;
20
+ EMAIL_VERIFICATION_REQUIRED: better_auth51.RawError<"EMAIL_VERIFICATION_REQUIRED">;
21
+ SUBSCRIPTION_NOT_ACTIVE: better_auth51.RawError<"SUBSCRIPTION_NOT_ACTIVE">;
22
+ SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: better_auth51.RawError<"SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION">;
23
+ ORGANIZATION_NOT_FOUND: better_auth51.RawError<"ORGANIZATION_NOT_FOUND">;
24
+ ORGANIZATION_SUBSCRIPTION_NOT_ENABLED: better_auth51.RawError<"ORGANIZATION_SUBSCRIPTION_NOT_ENABLED">;
25
+ AUTHORIZE_REFERENCE_REQUIRED: better_auth51.RawError<"AUTHORIZE_REFERENCE_REQUIRED">;
26
+ ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION: better_auth51.RawError<"ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION">;
27
+ ORGANIZATION_REFERENCE_ID_REQUIRED: better_auth51.RawError<"ORGANIZATION_REFERENCE_ID_REQUIRED">;
27
28
  };
28
29
  //#endregion
29
30
  //#region src/client.d.ts
@@ -47,27 +48,28 @@ declare const stripeClient: <O extends {
47
48
  "/subscription/restore": "POST";
48
49
  };
49
50
  $ERROR_CODES: {
50
- UNAUTHORIZED: better_auth49.RawError<"UNAUTHORIZED">;
51
- INVALID_REQUEST_BODY: better_auth49.RawError<"INVALID_REQUEST_BODY">;
52
- SUBSCRIPTION_NOT_FOUND: better_auth49.RawError<"SUBSCRIPTION_NOT_FOUND">;
53
- SUBSCRIPTION_PLAN_NOT_FOUND: better_auth49.RawError<"SUBSCRIPTION_PLAN_NOT_FOUND">;
54
- ALREADY_SUBSCRIBED_PLAN: better_auth49.RawError<"ALREADY_SUBSCRIBED_PLAN">;
55
- REFERENCE_ID_NOT_ALLOWED: better_auth49.RawError<"REFERENCE_ID_NOT_ALLOWED">;
56
- CUSTOMER_NOT_FOUND: better_auth49.RawError<"CUSTOMER_NOT_FOUND">;
57
- UNABLE_TO_CREATE_CUSTOMER: better_auth49.RawError<"UNABLE_TO_CREATE_CUSTOMER">;
58
- UNABLE_TO_CREATE_BILLING_PORTAL: better_auth49.RawError<"UNABLE_TO_CREATE_BILLING_PORTAL">;
59
- STRIPE_SIGNATURE_NOT_FOUND: better_auth49.RawError<"STRIPE_SIGNATURE_NOT_FOUND">;
60
- STRIPE_WEBHOOK_SECRET_NOT_FOUND: better_auth49.RawError<"STRIPE_WEBHOOK_SECRET_NOT_FOUND">;
61
- STRIPE_WEBHOOK_ERROR: better_auth49.RawError<"STRIPE_WEBHOOK_ERROR">;
62
- FAILED_TO_CONSTRUCT_STRIPE_EVENT: better_auth49.RawError<"FAILED_TO_CONSTRUCT_STRIPE_EVENT">;
63
- FAILED_TO_FETCH_PLANS: better_auth49.RawError<"FAILED_TO_FETCH_PLANS">;
64
- EMAIL_VERIFICATION_REQUIRED: better_auth49.RawError<"EMAIL_VERIFICATION_REQUIRED">;
65
- SUBSCRIPTION_NOT_ACTIVE: better_auth49.RawError<"SUBSCRIPTION_NOT_ACTIVE">;
66
- SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: better_auth49.RawError<"SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION">;
67
- ORGANIZATION_NOT_FOUND: better_auth49.RawError<"ORGANIZATION_NOT_FOUND">;
68
- ORGANIZATION_SUBSCRIPTION_NOT_ENABLED: better_auth49.RawError<"ORGANIZATION_SUBSCRIPTION_NOT_ENABLED">;
69
- ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION: better_auth49.RawError<"ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION">;
70
- ORGANIZATION_REFERENCE_ID_REQUIRED: better_auth49.RawError<"ORGANIZATION_REFERENCE_ID_REQUIRED">;
51
+ UNAUTHORIZED: better_auth51.RawError<"UNAUTHORIZED">;
52
+ INVALID_REQUEST_BODY: better_auth51.RawError<"INVALID_REQUEST_BODY">;
53
+ SUBSCRIPTION_NOT_FOUND: better_auth51.RawError<"SUBSCRIPTION_NOT_FOUND">;
54
+ SUBSCRIPTION_PLAN_NOT_FOUND: better_auth51.RawError<"SUBSCRIPTION_PLAN_NOT_FOUND">;
55
+ ALREADY_SUBSCRIBED_PLAN: better_auth51.RawError<"ALREADY_SUBSCRIBED_PLAN">;
56
+ REFERENCE_ID_NOT_ALLOWED: better_auth51.RawError<"REFERENCE_ID_NOT_ALLOWED">;
57
+ CUSTOMER_NOT_FOUND: better_auth51.RawError<"CUSTOMER_NOT_FOUND">;
58
+ UNABLE_TO_CREATE_CUSTOMER: better_auth51.RawError<"UNABLE_TO_CREATE_CUSTOMER">;
59
+ UNABLE_TO_CREATE_BILLING_PORTAL: better_auth51.RawError<"UNABLE_TO_CREATE_BILLING_PORTAL">;
60
+ STRIPE_SIGNATURE_NOT_FOUND: better_auth51.RawError<"STRIPE_SIGNATURE_NOT_FOUND">;
61
+ STRIPE_WEBHOOK_SECRET_NOT_FOUND: better_auth51.RawError<"STRIPE_WEBHOOK_SECRET_NOT_FOUND">;
62
+ STRIPE_WEBHOOK_ERROR: better_auth51.RawError<"STRIPE_WEBHOOK_ERROR">;
63
+ FAILED_TO_CONSTRUCT_STRIPE_EVENT: better_auth51.RawError<"FAILED_TO_CONSTRUCT_STRIPE_EVENT">;
64
+ FAILED_TO_FETCH_PLANS: better_auth51.RawError<"FAILED_TO_FETCH_PLANS">;
65
+ EMAIL_VERIFICATION_REQUIRED: better_auth51.RawError<"EMAIL_VERIFICATION_REQUIRED">;
66
+ SUBSCRIPTION_NOT_ACTIVE: better_auth51.RawError<"SUBSCRIPTION_NOT_ACTIVE">;
67
+ SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: better_auth51.RawError<"SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION">;
68
+ ORGANIZATION_NOT_FOUND: better_auth51.RawError<"ORGANIZATION_NOT_FOUND">;
69
+ ORGANIZATION_SUBSCRIPTION_NOT_ENABLED: better_auth51.RawError<"ORGANIZATION_SUBSCRIPTION_NOT_ENABLED">;
70
+ AUTHORIZE_REFERENCE_REQUIRED: better_auth51.RawError<"AUTHORIZE_REFERENCE_REQUIRED">;
71
+ ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION: better_auth51.RawError<"ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION">;
72
+ ORGANIZATION_REFERENCE_ID_REQUIRED: better_auth51.RawError<"ORGANIZATION_REFERENCE_ID_REQUIRED">;
71
73
  };
72
74
  };
73
75
  //#endregion
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as STRIPE_ERROR_CODES } from "./error-codes-CMowBCzF.mjs";
1
+ import { t as STRIPE_ERROR_CODES } from "./error-codes-CHMyMR5v.mjs";
2
2
 
3
3
  //#region src/client.ts
4
4
  const stripeClient = (options) => {
@@ -21,10 +21,11 @@ const STRIPE_ERROR_CODES = defineErrorCodes({
21
21
  SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: "Subscription is not scheduled for cancellation",
22
22
  ORGANIZATION_NOT_FOUND: "Organization not found",
23
23
  ORGANIZATION_SUBSCRIPTION_NOT_ENABLED: "Organization subscription is not enabled",
24
+ AUTHORIZE_REFERENCE_REQUIRED: "Organization subscriptions require authorizeReference callback to be configured",
24
25
  ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION: "Cannot delete organization with active subscription",
25
26
  ORGANIZATION_REFERENCE_ID_REQUIRED: "Reference ID is required. Provide referenceId or set activeOrganizationId in session"
26
27
  });
27
28
 
28
29
  //#endregion
29
30
  export { STRIPE_ERROR_CODES as t };
30
- //# sourceMappingURL=error-codes-CMowBCzF.mjs.map
31
+ //# sourceMappingURL=error-codes-CHMyMR5v.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"error-codes-CMowBCzF.mjs","names":[],"sources":["../src/error-codes.ts"],"sourcesContent":["import { defineErrorCodes } from \"@better-auth/core/utils/error-codes\";\n\nexport const STRIPE_ERROR_CODES = defineErrorCodes({\n\tUNAUTHORIZED: \"Unauthorized access\",\n\tINVALID_REQUEST_BODY: \"Invalid request body\",\n\tSUBSCRIPTION_NOT_FOUND: \"Subscription not found\",\n\tSUBSCRIPTION_PLAN_NOT_FOUND: \"Subscription plan not found\",\n\tALREADY_SUBSCRIBED_PLAN: \"You're already subscribed to this plan\",\n\tREFERENCE_ID_NOT_ALLOWED: \"Reference id is not allowed\",\n\tCUSTOMER_NOT_FOUND: \"Stripe customer not found for this user\",\n\tUNABLE_TO_CREATE_CUSTOMER: \"Unable to create customer\",\n\tUNABLE_TO_CREATE_BILLING_PORTAL: \"Unable to create billing portal session\",\n\tSTRIPE_SIGNATURE_NOT_FOUND: \"Stripe signature not found\",\n\tSTRIPE_WEBHOOK_SECRET_NOT_FOUND: \"Stripe webhook secret not found\",\n\tSTRIPE_WEBHOOK_ERROR: \"Stripe webhook error\",\n\tFAILED_TO_CONSTRUCT_STRIPE_EVENT: \"Failed to construct Stripe event\",\n\tFAILED_TO_FETCH_PLANS: \"Failed to fetch plans\",\n\tEMAIL_VERIFICATION_REQUIRED:\n\t\t\"Email verification is required before you can subscribe to a plan\",\n\tSUBSCRIPTION_NOT_ACTIVE: \"Subscription is not active\",\n\tSUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION:\n\t\t\"Subscription is not scheduled for cancellation\",\n\tORGANIZATION_NOT_FOUND: \"Organization not found\",\n\tORGANIZATION_SUBSCRIPTION_NOT_ENABLED:\n\t\t\"Organization subscription is not enabled\",\n\tORGANIZATION_HAS_ACTIVE_SUBSCRIPTION:\n\t\t\"Cannot delete organization with active subscription\",\n\tORGANIZATION_REFERENCE_ID_REQUIRED:\n\t\t\"Reference ID is required. Provide referenceId or set activeOrganizationId in session\",\n});\n"],"mappings":";;;AAEA,MAAa,qBAAqB,iBAAiB;CAClD,cAAc;CACd,sBAAsB;CACtB,wBAAwB;CACxB,6BAA6B;CAC7B,yBAAyB;CACzB,0BAA0B;CAC1B,oBAAoB;CACpB,2BAA2B;CAC3B,iCAAiC;CACjC,4BAA4B;CAC5B,iCAAiC;CACjC,sBAAsB;CACtB,kCAAkC;CAClC,uBAAuB;CACvB,6BACC;CACD,yBAAyB;CACzB,6CACC;CACD,wBAAwB;CACxB,uCACC;CACD,sCACC;CACD,oCACC;CACD,CAAC"}
1
+ {"version":3,"file":"error-codes-CHMyMR5v.mjs","names":[],"sources":["../src/error-codes.ts"],"sourcesContent":["import { defineErrorCodes } from \"@better-auth/core/utils/error-codes\";\n\nexport const STRIPE_ERROR_CODES = defineErrorCodes({\n\tUNAUTHORIZED: \"Unauthorized access\",\n\tINVALID_REQUEST_BODY: \"Invalid request body\",\n\tSUBSCRIPTION_NOT_FOUND: \"Subscription not found\",\n\tSUBSCRIPTION_PLAN_NOT_FOUND: \"Subscription plan not found\",\n\tALREADY_SUBSCRIBED_PLAN: \"You're already subscribed to this plan\",\n\tREFERENCE_ID_NOT_ALLOWED: \"Reference id is not allowed\",\n\tCUSTOMER_NOT_FOUND: \"Stripe customer not found for this user\",\n\tUNABLE_TO_CREATE_CUSTOMER: \"Unable to create customer\",\n\tUNABLE_TO_CREATE_BILLING_PORTAL: \"Unable to create billing portal session\",\n\tSTRIPE_SIGNATURE_NOT_FOUND: \"Stripe signature not found\",\n\tSTRIPE_WEBHOOK_SECRET_NOT_FOUND: \"Stripe webhook secret not found\",\n\tSTRIPE_WEBHOOK_ERROR: \"Stripe webhook error\",\n\tFAILED_TO_CONSTRUCT_STRIPE_EVENT: \"Failed to construct Stripe event\",\n\tFAILED_TO_FETCH_PLANS: \"Failed to fetch plans\",\n\tEMAIL_VERIFICATION_REQUIRED:\n\t\t\"Email verification is required before you can subscribe to a plan\",\n\tSUBSCRIPTION_NOT_ACTIVE: \"Subscription is not active\",\n\tSUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION:\n\t\t\"Subscription is not scheduled for cancellation\",\n\tORGANIZATION_NOT_FOUND: \"Organization not found\",\n\tORGANIZATION_SUBSCRIPTION_NOT_ENABLED:\n\t\t\"Organization subscription is not enabled\",\n\tAUTHORIZE_REFERENCE_REQUIRED:\n\t\t\"Organization subscriptions require authorizeReference callback to be configured\",\n\tORGANIZATION_HAS_ACTIVE_SUBSCRIPTION:\n\t\t\"Cannot delete organization with active subscription\",\n\tORGANIZATION_REFERENCE_ID_REQUIRED:\n\t\t\"Reference ID is required. Provide referenceId or set activeOrganizationId in session\",\n});\n"],"mappings":";;;AAEA,MAAa,qBAAqB,iBAAiB;CAClD,cAAc;CACd,sBAAsB;CACtB,wBAAwB;CACxB,6BAA6B;CAC7B,yBAAyB;CACzB,0BAA0B;CAC1B,oBAAoB;CACpB,2BAA2B;CAC3B,iCAAiC;CACjC,4BAA4B;CAC5B,iCAAiC;CACjC,sBAAsB;CACtB,kCAAkC;CAClC,uBAAuB;CACvB,6BACC;CACD,yBAAyB;CACzB,6CACC;CACD,wBAAwB;CACxB,uCACC;CACD,8BACC;CACD,sCACC;CACD,oCACC;CACD,CAAC"}
@@ -1,4 +1,4 @@
1
- import * as better_auth0 from "better-auth";
1
+ import * as better_auth21 from "better-auth";
2
2
  import { GenericEndpointContext, InferOptionSchema, Session, User } from "better-auth";
3
3
  import * as better_call0 from "better-call";
4
4
  import * as zod0 from "zod";
@@ -488,7 +488,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
488
488
  cancelUrl: zod0.ZodDefault<zod0.ZodString>;
489
489
  returnUrl: zod0.ZodOptional<zod0.ZodString>;
490
490
  disableRedirect: zod0.ZodDefault<zod0.ZodBoolean>;
491
- }, better_auth0.$strip>;
491
+ }, better_auth21.$strip>;
492
492
  metadata: {
493
493
  openapi: {
494
494
  operationId: string;
@@ -513,7 +513,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
513
513
  updatedAt: Date;
514
514
  email: string;
515
515
  emailVerified: boolean;
516
- name?: string | null | undefined;
516
+ name: string;
517
517
  image?: string | null | undefined;
518
518
  };
519
519
  };
@@ -624,7 +624,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
624
624
  }>>;
625
625
  returnUrl: zod0.ZodString;
626
626
  disableRedirect: zod0.ZodDefault<zod0.ZodBoolean>;
627
- }, better_auth0.$strip>;
627
+ }, better_auth21.$strip>;
628
628
  metadata: {
629
629
  openapi: {
630
630
  operationId: string;
@@ -649,7 +649,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
649
649
  updatedAt: Date;
650
650
  email: string;
651
651
  emailVerified: boolean;
652
- name?: string | null | undefined;
652
+ name: string;
653
653
  image?: string | null | undefined;
654
654
  };
655
655
  };
@@ -670,7 +670,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
670
670
  user: "user";
671
671
  organization: "organization";
672
672
  }>>;
673
- }, better_auth0.$strip>;
673
+ }, better_auth21.$strip>;
674
674
  metadata: {
675
675
  openapi: {
676
676
  operationId: string;
@@ -695,7 +695,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
695
695
  updatedAt: Date;
696
696
  email: string;
697
697
  emailVerified: boolean;
698
- name?: string | null | undefined;
698
+ name: string;
699
699
  image?: string | null | undefined;
700
700
  };
701
701
  };
@@ -712,7 +712,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
712
712
  user: "user";
713
713
  organization: "organization";
714
714
  }>>;
715
- }, better_auth0.$strip>>;
715
+ }, better_auth21.$strip>>;
716
716
  metadata: {
717
717
  openapi: {
718
718
  operationId: string;
@@ -737,7 +737,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
737
737
  updatedAt: Date;
738
738
  email: string;
739
739
  emailVerified: boolean;
740
- name?: string | null | undefined;
740
+ name: string;
741
741
  image?: string | null | undefined;
742
742
  };
743
743
  };
@@ -786,7 +786,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
786
786
  }>>;
787
787
  returnUrl: zod0.ZodDefault<zod0.ZodString>;
788
788
  disableRedirect: zod0.ZodDefault<zod0.ZodBoolean>;
789
- }, better_auth0.$strip>;
789
+ }, better_auth21.$strip>;
790
790
  metadata: {
791
791
  openapi: {
792
792
  operationId: string;
@@ -811,7 +811,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
811
811
  updatedAt: Date;
812
812
  email: string;
813
813
  emailVerified: boolean;
814
- name?: string | null | undefined;
814
+ name: string;
815
815
  image?: string | null | undefined;
816
816
  };
817
817
  };
@@ -824,15 +824,15 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
824
824
  redirect: boolean;
825
825
  }>;
826
826
  } : {});
827
- init(ctx: better_auth0.AuthContext): {
827
+ init(ctx: better_auth21.AuthContext): {
828
828
  options: {
829
829
  databaseHooks: {
830
830
  user: {
831
831
  create: {
832
- after(user: User & WithStripeCustomerId, ctx: better_auth0.GenericEndpointContext | null): Promise<void>;
832
+ after(user: User & WithStripeCustomerId, ctx: better_auth21.GenericEndpointContext | null): Promise<void>;
833
833
  };
834
834
  update: {
835
- after(user: User & WithStripeCustomerId, ctx: better_auth0.GenericEndpointContext | null): Promise<void>;
835
+ after(user: User & WithStripeCustomerId, ctx: better_auth21.GenericEndpointContext | null): Promise<void>;
836
836
  };
837
837
  };
838
838
  };
@@ -925,30 +925,31 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
925
925
  } : {});
926
926
  options: NoInfer<O>;
927
927
  $ERROR_CODES: {
928
- UNAUTHORIZED: better_auth0.RawError<"UNAUTHORIZED">;
929
- INVALID_REQUEST_BODY: better_auth0.RawError<"INVALID_REQUEST_BODY">;
930
- SUBSCRIPTION_NOT_FOUND: better_auth0.RawError<"SUBSCRIPTION_NOT_FOUND">;
931
- SUBSCRIPTION_PLAN_NOT_FOUND: better_auth0.RawError<"SUBSCRIPTION_PLAN_NOT_FOUND">;
932
- ALREADY_SUBSCRIBED_PLAN: better_auth0.RawError<"ALREADY_SUBSCRIBED_PLAN">;
933
- REFERENCE_ID_NOT_ALLOWED: better_auth0.RawError<"REFERENCE_ID_NOT_ALLOWED">;
934
- CUSTOMER_NOT_FOUND: better_auth0.RawError<"CUSTOMER_NOT_FOUND">;
935
- UNABLE_TO_CREATE_CUSTOMER: better_auth0.RawError<"UNABLE_TO_CREATE_CUSTOMER">;
936
- UNABLE_TO_CREATE_BILLING_PORTAL: better_auth0.RawError<"UNABLE_TO_CREATE_BILLING_PORTAL">;
937
- STRIPE_SIGNATURE_NOT_FOUND: better_auth0.RawError<"STRIPE_SIGNATURE_NOT_FOUND">;
938
- STRIPE_WEBHOOK_SECRET_NOT_FOUND: better_auth0.RawError<"STRIPE_WEBHOOK_SECRET_NOT_FOUND">;
939
- STRIPE_WEBHOOK_ERROR: better_auth0.RawError<"STRIPE_WEBHOOK_ERROR">;
940
- FAILED_TO_CONSTRUCT_STRIPE_EVENT: better_auth0.RawError<"FAILED_TO_CONSTRUCT_STRIPE_EVENT">;
941
- FAILED_TO_FETCH_PLANS: better_auth0.RawError<"FAILED_TO_FETCH_PLANS">;
942
- EMAIL_VERIFICATION_REQUIRED: better_auth0.RawError<"EMAIL_VERIFICATION_REQUIRED">;
943
- SUBSCRIPTION_NOT_ACTIVE: better_auth0.RawError<"SUBSCRIPTION_NOT_ACTIVE">;
944
- SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: better_auth0.RawError<"SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION">;
945
- ORGANIZATION_NOT_FOUND: better_auth0.RawError<"ORGANIZATION_NOT_FOUND">;
946
- ORGANIZATION_SUBSCRIPTION_NOT_ENABLED: better_auth0.RawError<"ORGANIZATION_SUBSCRIPTION_NOT_ENABLED">;
947
- ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION: better_auth0.RawError<"ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION">;
948
- ORGANIZATION_REFERENCE_ID_REQUIRED: better_auth0.RawError<"ORGANIZATION_REFERENCE_ID_REQUIRED">;
928
+ UNAUTHORIZED: better_auth21.RawError<"UNAUTHORIZED">;
929
+ INVALID_REQUEST_BODY: better_auth21.RawError<"INVALID_REQUEST_BODY">;
930
+ SUBSCRIPTION_NOT_FOUND: better_auth21.RawError<"SUBSCRIPTION_NOT_FOUND">;
931
+ SUBSCRIPTION_PLAN_NOT_FOUND: better_auth21.RawError<"SUBSCRIPTION_PLAN_NOT_FOUND">;
932
+ ALREADY_SUBSCRIBED_PLAN: better_auth21.RawError<"ALREADY_SUBSCRIBED_PLAN">;
933
+ REFERENCE_ID_NOT_ALLOWED: better_auth21.RawError<"REFERENCE_ID_NOT_ALLOWED">;
934
+ CUSTOMER_NOT_FOUND: better_auth21.RawError<"CUSTOMER_NOT_FOUND">;
935
+ UNABLE_TO_CREATE_CUSTOMER: better_auth21.RawError<"UNABLE_TO_CREATE_CUSTOMER">;
936
+ UNABLE_TO_CREATE_BILLING_PORTAL: better_auth21.RawError<"UNABLE_TO_CREATE_BILLING_PORTAL">;
937
+ STRIPE_SIGNATURE_NOT_FOUND: better_auth21.RawError<"STRIPE_SIGNATURE_NOT_FOUND">;
938
+ STRIPE_WEBHOOK_SECRET_NOT_FOUND: better_auth21.RawError<"STRIPE_WEBHOOK_SECRET_NOT_FOUND">;
939
+ STRIPE_WEBHOOK_ERROR: better_auth21.RawError<"STRIPE_WEBHOOK_ERROR">;
940
+ FAILED_TO_CONSTRUCT_STRIPE_EVENT: better_auth21.RawError<"FAILED_TO_CONSTRUCT_STRIPE_EVENT">;
941
+ FAILED_TO_FETCH_PLANS: better_auth21.RawError<"FAILED_TO_FETCH_PLANS">;
942
+ EMAIL_VERIFICATION_REQUIRED: better_auth21.RawError<"EMAIL_VERIFICATION_REQUIRED">;
943
+ SUBSCRIPTION_NOT_ACTIVE: better_auth21.RawError<"SUBSCRIPTION_NOT_ACTIVE">;
944
+ SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION: better_auth21.RawError<"SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION">;
945
+ ORGANIZATION_NOT_FOUND: better_auth21.RawError<"ORGANIZATION_NOT_FOUND">;
946
+ ORGANIZATION_SUBSCRIPTION_NOT_ENABLED: better_auth21.RawError<"ORGANIZATION_SUBSCRIPTION_NOT_ENABLED">;
947
+ AUTHORIZE_REFERENCE_REQUIRED: better_auth21.RawError<"AUTHORIZE_REFERENCE_REQUIRED">;
948
+ ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION: better_auth21.RawError<"ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION">;
949
+ ORGANIZATION_REFERENCE_ID_REQUIRED: better_auth21.RawError<"ORGANIZATION_REFERENCE_ID_REQUIRED">;
949
950
  };
950
951
  };
951
952
  type StripePlugin<O extends StripeOptions> = ReturnType<typeof stripe<O>>;
952
953
  //#endregion
953
954
  export { SubscriptionOptions as a, Subscription as i, stripe as n, StripePlan as r, StripePlugin as t };
954
- //# sourceMappingURL=index-DRCIVNqh.d.mts.map
955
+ //# sourceMappingURL=index-BELqjMd2.d.mts.map
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-DRCIVNqh.mjs";
1
+ import { a as SubscriptionOptions, i as Subscription, n as stripe, r as StripePlan, t as StripePlugin } from "./index-BELqjMd2.mjs";
2
2
  export { StripePlan, StripePlugin, Subscription, SubscriptionOptions, stripe };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as STRIPE_ERROR_CODES } from "./error-codes-CMowBCzF.mjs";
1
+ import { t as STRIPE_ERROR_CODES } from "./error-codes-CHMyMR5v.mjs";
2
2
  import { APIError, HIDE_METADATA } from "better-auth";
3
3
  import { defu } from "defu";
4
4
  import { createAuthEndpoint, createAuthMiddleware } from "@better-auth/core/api";
@@ -397,7 +397,7 @@ const referenceMiddleware = (subscriptionOptions, action) => createAuthMiddlewar
397
397
  if (customerType === "organization") {
398
398
  if (!subscriptionOptions.authorizeReference) {
399
399
  ctx.context.logger.error(`Organization subscriptions require authorizeReference to be defined in your stripe plugin config.`);
400
- throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.ORGANIZATION_SUBSCRIPTION_NOT_ENABLED);
400
+ throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.AUTHORIZE_REFERENCE_REQUIRED);
401
401
  }
402
402
  const referenceId = explicitReferenceId || ctxSession.session.activeOrganizationId;
403
403
  if (!referenceId) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.ORGANIZATION_REFERENCE_ID_REQUIRED);
@@ -581,7 +581,7 @@ const upgradeSubscription = (options) => {
581
581
  })).data[0];
582
582
  if (!stripeCustomer) stripeCustomer = await client.customers.create({
583
583
  email: user.email,
584
- name: user.name ?? void 0,
584
+ name: user.name,
585
585
  metadata: customerMetadata.set({
586
586
  userId: user.id,
587
587
  customerType: "user"
@@ -1419,7 +1419,7 @@ const stripe = (options) => {
1419
1419
  if (options.getCustomerCreateParams) extraCreateParams = await options.getCustomerCreateParams(user, ctx);
1420
1420
  const params = defu({
1421
1421
  email: user.email,
1422
- name: user.name ?? void 0,
1422
+ name: user.name,
1423
1423
  metadata: customerMetadata.set({
1424
1424
  userId: user.id,
1425
1425
  customerType: "user"
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["APIError","APIError"],"sources":["../src/metadata.ts","../src/utils.ts","../src/hooks.ts","../src/middleware.ts","../src/routes.ts","../src/schema.ts","../src/index.ts"],"sourcesContent":["import { defu } from \"defu\";\nimport type Stripe from \"stripe\";\n\n/**\n * Internal metadata fields for Stripe Customer.\n */\ntype CustomerInternalMetadata =\n\t| { customerType: \"user\"; userId: string }\n\t| { customerType: \"organization\"; organizationId: string };\n\n/**\n * Internal metadata fields for Stripe Subscription/Checkout.\n */\ntype SubscriptionInternalMetadata = {\n\tuserId: string;\n\tsubscriptionId: string;\n\treferenceId: string;\n};\n\n/**\n * Customer metadata - set internal fields and extract typed fields.\n */\nexport const customerMetadata = {\n\t/**\n\t * Internal metadata keys for type-safe access.\n\t */\n\tkeys: {\n\t\tuserId: \"userId\",\n\t\torganizationId: \"organizationId\",\n\t\tcustomerType: \"customerType\",\n\t} as const,\n\n\t/**\n\t * Create metadata with internal fields that cannot be overridden by user metadata.\n\t * Uses `defu` which prioritizes the first argument.\n\t */\n\tset(\n\t\tinternalFields: CustomerInternalMetadata,\n\t\t...userMetadata: (Stripe.Emptyable<Stripe.MetadataParam> | undefined)[]\n\t): Stripe.MetadataParam {\n\t\treturn defu(internalFields, ...userMetadata.filter(Boolean));\n\t},\n\n\t/**\n\t * Extract internal fields from Stripe metadata.\n\t * Provides type-safe access to internal metadata keys.\n\t */\n\tget(metadata: Stripe.Metadata | null | undefined) {\n\t\treturn {\n\t\t\tuserId: metadata?.userId,\n\t\t\torganizationId: metadata?.organizationId,\n\t\t\tcustomerType: metadata?.customerType as\n\t\t\t\t| CustomerInternalMetadata[\"customerType\"]\n\t\t\t\t| undefined,\n\t\t};\n\t},\n};\n\n/**\n * Subscription/Checkout metadata - set internal fields and extract typed fields.\n */\nexport const subscriptionMetadata = {\n\t/**\n\t * Internal metadata keys for type-safe access.\n\t */\n\tkeys: {\n\t\tuserId: \"userId\",\n\t\tsubscriptionId: \"subscriptionId\",\n\t\treferenceId: \"referenceId\",\n\t} as const,\n\n\t/**\n\t * Create metadata with internal fields that cannot be overridden by user metadata.\n\t * Uses `defu` which prioritizes the first argument.\n\t */\n\tset(\n\t\tinternalFields: SubscriptionInternalMetadata,\n\t\t...userMetadata: (Stripe.Emptyable<Stripe.MetadataParam> | undefined)[]\n\t): Stripe.MetadataParam {\n\t\treturn defu(internalFields, ...userMetadata.filter(Boolean));\n\t},\n\n\t/**\n\t * Extract internal fields from Stripe metadata.\n\t * Provides type-safe access to internal metadata keys.\n\t */\n\tget(metadata: Stripe.Metadata | null | undefined) {\n\t\treturn {\n\t\t\tuserId: metadata?.userId,\n\t\t\tsubscriptionId: metadata?.subscriptionId,\n\t\t\treferenceId: metadata?.referenceId,\n\t\t};\n\t},\n};\n","import type Stripe from \"stripe\";\nimport type { StripeOptions, Subscription } from \"./types\";\n\nexport async function getPlans(\n\tsubscriptionOptions: StripeOptions[\"subscription\"],\n) {\n\tif (subscriptionOptions?.enabled) {\n\t\treturn typeof subscriptionOptions.plans === \"function\"\n\t\t\t? await subscriptionOptions.plans()\n\t\t\t: subscriptionOptions.plans;\n\t}\n\tthrow new Error(\"Subscriptions are not enabled in the Stripe options.\");\n}\n\nexport async function getPlanByPriceInfo(\n\toptions: StripeOptions,\n\tpriceId: string,\n\tpriceLookupKey: string | null,\n) {\n\treturn await getPlans(options.subscription).then((res) =>\n\t\tres?.find(\n\t\t\t(plan) =>\n\t\t\t\tplan.priceId === priceId ||\n\t\t\t\tplan.annualDiscountPriceId === priceId ||\n\t\t\t\t(priceLookupKey &&\n\t\t\t\t\t(plan.lookupKey === priceLookupKey ||\n\t\t\t\t\t\tplan.annualDiscountLookupKey === priceLookupKey)),\n\t\t),\n\t);\n}\n\nexport async function getPlanByName(options: StripeOptions, name: string) {\n\treturn await getPlans(options.subscription).then((res) =>\n\t\tres?.find((plan) => plan.name.toLowerCase() === name.toLowerCase()),\n\t);\n}\n\n/**\n * Checks if a subscription is in an available state (active or trialing)\n */\nexport function isActiveOrTrialing(\n\tsub: Subscription | Stripe.Subscription,\n): boolean {\n\treturn sub.status === \"active\" || sub.status === \"trialing\";\n}\n\n/**\n * Check if a subscription is scheduled to be canceled (DB subscription object)\n */\nexport function isPendingCancel(sub: Subscription): boolean {\n\treturn !!(sub.cancelAtPeriodEnd || sub.cancelAt);\n}\n\n/**\n * Check if a Stripe subscription is scheduled to be canceled (Stripe API response)\n */\nexport function isStripePendingCancel(stripeSub: Stripe.Subscription): boolean {\n\treturn !!(stripeSub.cancel_at_period_end || stripeSub.cancel_at);\n}\n\n/**\n * Escapes a value for use in Stripe search queries.\n * Stripe search query uses double quotes for string values,\n * and double quotes within the value need to be escaped with backslash.\n *\n * @see https://docs.stripe.com/search#search-query-language\n */\nexport function escapeStripeSearchValue(value: string): string {\n\treturn value.replace(/\"/g, '\\\\\"');\n}\n","import type { GenericEndpointContext } from \"@better-auth/core\";\nimport type { User } from \"@better-auth/core/db\";\nimport type { Organization } from \"better-auth/plugins/organization\";\nimport type Stripe from \"stripe\";\nimport { subscriptionMetadata } from \"./metadata\";\nimport type { CustomerType, StripeOptions, Subscription } from \"./types\";\nimport {\n\tgetPlanByPriceInfo,\n\tisActiveOrTrialing,\n\tisPendingCancel,\n\tisStripePendingCancel,\n} from \"./utils\";\n\n/**\n * Find organization or user by stripeCustomerId.\n * @internal\n */\nasync function findReferenceByStripeCustomerId(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tstripeCustomerId: string,\n): Promise<{ customerType: CustomerType; referenceId: string } | null> {\n\tif (options.organization?.enabled) {\n\t\tconst org = await ctx.context.adapter.findOne<Organization>({\n\t\t\tmodel: \"organization\",\n\t\t\twhere: [{ field: \"stripeCustomerId\", value: stripeCustomerId }],\n\t\t});\n\t\tif (org) return { customerType: \"organization\", referenceId: org.id };\n\t}\n\n\tconst user = await ctx.context.adapter.findOne<User>({\n\t\tmodel: \"user\",\n\t\twhere: [{ field: \"stripeCustomerId\", value: stripeCustomerId }],\n\t});\n\tif (user) return { customerType: \"user\", referenceId: user.id };\n\n\treturn null;\n}\n\nexport async function onCheckoutSessionCompleted(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tevent: Stripe.Event,\n) {\n\ttry {\n\t\tconst client = options.stripeClient;\n\t\tconst checkoutSession = event.data.object as Stripe.Checkout.Session;\n\t\tif (checkoutSession.mode === \"setup\" || !options.subscription?.enabled) {\n\t\t\treturn;\n\t\t}\n\t\tconst subscription = await client.subscriptions.retrieve(\n\t\t\tcheckoutSession.subscription as string,\n\t\t);\n\t\tconst subscriptionItem = subscription.items.data[0];\n\t\tif (!subscriptionItem) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: Subscription ${subscription.id} has no items`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst priceId = subscriptionItem.price.id;\n\t\tconst priceLookupKey = subscriptionItem.price.lookup_key;\n\t\tconst plan = await getPlanByPriceInfo(\n\t\t\toptions,\n\t\t\tpriceId as string,\n\t\t\tpriceLookupKey,\n\t\t);\n\t\tif (plan) {\n\t\t\tconst checkoutMeta = subscriptionMetadata.get(checkoutSession?.metadata);\n\t\t\tconst referenceId =\n\t\t\t\tcheckoutSession?.client_reference_id || checkoutMeta.referenceId;\n\t\t\tconst { subscriptionId } = checkoutMeta;\n\t\t\tconst seats = subscriptionItem.quantity;\n\t\t\tif (referenceId && subscriptionId) {\n\t\t\t\tconst trial =\n\t\t\t\t\tsubscription.trial_start && subscription.trial_end\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\ttrialStart: new Date(subscription.trial_start * 1000),\n\t\t\t\t\t\t\t\ttrialEnd: new Date(subscription.trial_end * 1000),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {};\n\n\t\t\t\tlet dbSubscription = await ctx.context.adapter.update<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\t\tstatus: subscription.status,\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\tperiodStart: new Date(subscriptionItem.current_period_start * 1000),\n\t\t\t\t\t\tperiodEnd: new Date(subscriptionItem.current_period_end * 1000),\n\t\t\t\t\t\tstripeSubscriptionId: checkoutSession.subscription as string,\n\t\t\t\t\t\tcancelAtPeriodEnd: subscription.cancel_at_period_end,\n\t\t\t\t\t\tcancelAt: subscription.cancel_at\n\t\t\t\t\t\t\t? new Date(subscription.cancel_at * 1000)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tcanceledAt: subscription.canceled_at\n\t\t\t\t\t\t\t? new Date(subscription.canceled_at * 1000)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tendedAt: subscription.ended_at\n\t\t\t\t\t\t\t? new Date(subscription.ended_at * 1000)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tseats: seats,\n\t\t\t\t\t\t...trial,\n\t\t\t\t\t},\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tif (trial.trialStart && plan.freeTrial?.onTrialStart) {\n\t\t\t\t\tawait plan.freeTrial.onTrialStart(dbSubscription as Subscription);\n\t\t\t\t}\n\n\t\t\t\tif (!dbSubscription) {\n\t\t\t\t\tdbSubscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tawait options.subscription?.onSubscriptionComplete?.(\n\t\t\t\t\t{\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\tsubscription: dbSubscription as Subscription,\n\t\t\t\t\t\tstripeSubscription: subscription,\n\t\t\t\t\t\tplan,\n\t\t\t\t\t},\n\t\t\t\t\tctx,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} catch (e: any) {\n\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${e.message}`);\n\t}\n}\n\nexport async function onSubscriptionCreated(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tevent: Stripe.Event,\n) {\n\ttry {\n\t\tif (!options.subscription?.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst subscriptionCreated = event.data.object as Stripe.Subscription;\n\t\tconst stripeCustomerId = subscriptionCreated.customer?.toString();\n\t\tif (!stripeCustomerId) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: customer.subscription.created event received without customer ID`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if subscription already exists in database\n\t\tconst { subscriptionId } = subscriptionMetadata.get(\n\t\t\tsubscriptionCreated.metadata,\n\t\t);\n\t\tconst existingSubscription =\n\t\t\tawait ctx.context.adapter.findOne<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: subscriptionId\n\t\t\t\t\t? [{ field: \"id\", value: subscriptionId }]\n\t\t\t\t\t: [{ field: \"stripeSubscriptionId\", value: subscriptionCreated.id }], // Probably won't match since it's not set yet\n\t\t\t});\n\t\tif (existingSubscription) {\n\t\t\tctx.context.logger.info(\n\t\t\t\t`Stripe webhook: Subscription already exists in database (id: ${existingSubscription.id}), skipping creation`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Find reference\n\t\tconst reference = await findReferenceByStripeCustomerId(\n\t\t\tctx,\n\t\t\toptions,\n\t\t\tstripeCustomerId,\n\t\t);\n\t\tif (!reference) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: No user or organization found with stripeCustomerId: ${stripeCustomerId}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tconst { referenceId, customerType } = reference;\n\n\t\tconst subscriptionItem = subscriptionCreated.items.data[0];\n\t\tif (!subscriptionItem) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: Subscription ${subscriptionCreated.id} has no items`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst priceId = subscriptionItem.price.id;\n\t\tconst priceLookupKey = subscriptionItem.price.lookup_key || null;\n\t\tconst plan = await getPlanByPriceInfo(options, priceId, priceLookupKey);\n\t\tif (!plan) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: No matching plan found for priceId: ${priceId}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst seats = subscriptionItem.quantity;\n\t\tconst periodStart = new Date(subscriptionItem.current_period_start * 1000);\n\t\tconst periodEnd = new Date(subscriptionItem.current_period_end * 1000);\n\n\t\tconst trial =\n\t\t\tsubscriptionCreated.trial_start && subscriptionCreated.trial_end\n\t\t\t\t? {\n\t\t\t\t\t\ttrialStart: new Date(subscriptionCreated.trial_start * 1000),\n\t\t\t\t\t\ttrialEnd: new Date(subscriptionCreated.trial_end * 1000),\n\t\t\t\t\t}\n\t\t\t\t: {};\n\n\t\t// Create the subscription in the database\n\t\tconst newSubscription = await ctx.context.adapter.create<Subscription>({\n\t\t\tmodel: \"subscription\",\n\t\t\tdata: {\n\t\t\t\treferenceId,\n\t\t\t\tstripeCustomerId,\n\t\t\t\tstripeSubscriptionId: subscriptionCreated.id,\n\t\t\t\tstatus: subscriptionCreated.status,\n\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\tperiodStart,\n\t\t\t\tperiodEnd,\n\t\t\t\tseats,\n\t\t\t\t...(plan.limits ? { limits: plan.limits } : {}),\n\t\t\t\t...trial,\n\t\t\t},\n\t\t});\n\n\t\tctx.context.logger.info(\n\t\t\t`Stripe webhook: Created subscription ${subscriptionCreated.id} for ${customerType} ${referenceId} from dashboard`,\n\t\t);\n\n\t\tawait options.subscription.onSubscriptionCreated?.({\n\t\t\tevent,\n\t\t\tsubscription: newSubscription,\n\t\t\tstripeSubscription: subscriptionCreated,\n\t\t\tplan,\n\t\t});\n\t} catch (error: any) {\n\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${error}`);\n\t}\n}\n\nexport async function onSubscriptionUpdated(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tevent: Stripe.Event,\n) {\n\ttry {\n\t\tif (!options.subscription?.enabled) {\n\t\t\treturn;\n\t\t}\n\t\tconst subscriptionUpdated = event.data.object as Stripe.Subscription;\n\t\tconst subscriptionItem = subscriptionUpdated.items.data[0];\n\t\tif (!subscriptionItem) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: Subscription ${subscriptionUpdated.id} has no items`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst priceId = subscriptionItem.price.id;\n\t\tconst priceLookupKey = subscriptionItem.price.lookup_key;\n\t\tconst plan = await getPlanByPriceInfo(options, priceId, priceLookupKey);\n\n\t\tconst { subscriptionId } = subscriptionMetadata.get(\n\t\t\tsubscriptionUpdated.metadata,\n\t\t);\n\t\tconst customerId = subscriptionUpdated.customer?.toString();\n\t\tlet subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\tmodel: \"subscription\",\n\t\t\twhere: subscriptionId\n\t\t\t\t? [{ field: \"id\", value: subscriptionId }]\n\t\t\t\t: [{ field: \"stripeSubscriptionId\", value: subscriptionUpdated.id }],\n\t\t});\n\t\tif (!subscription) {\n\t\t\tconst subs = await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [{ field: \"stripeCustomerId\", value: customerId }],\n\t\t\t});\n\t\t\tif (subs.length > 1) {\n\t\t\t\tconst activeSub = subs.find((sub: Subscription) =>\n\t\t\t\t\tisActiveOrTrialing(sub),\n\t\t\t\t);\n\t\t\t\tif (!activeSub) {\n\t\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t\t`Stripe webhook error: Multiple subscriptions found for customerId: ${customerId} and no active subscription is found`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsubscription = activeSub;\n\t\t\t} else {\n\t\t\t\tsubscription = subs[0]!;\n\t\t\t}\n\t\t}\n\n\t\tconst updatedSubscription = await ctx.context.adapter.update<Subscription>({\n\t\t\tmodel: \"subscription\",\n\t\t\tupdate: {\n\t\t\t\t...(plan\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\t\t\tlimits: plan.limits,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t\tstatus: subscriptionUpdated.status,\n\t\t\t\tperiodStart: new Date(subscriptionItem.current_period_start * 1000),\n\t\t\t\tperiodEnd: new Date(subscriptionItem.current_period_end * 1000),\n\t\t\t\tcancelAtPeriodEnd: subscriptionUpdated.cancel_at_period_end,\n\t\t\t\tcancelAt: subscriptionUpdated.cancel_at\n\t\t\t\t\t? new Date(subscriptionUpdated.cancel_at * 1000)\n\t\t\t\t\t: null,\n\t\t\t\tcanceledAt: subscriptionUpdated.canceled_at\n\t\t\t\t\t? new Date(subscriptionUpdated.canceled_at * 1000)\n\t\t\t\t\t: null,\n\t\t\t\tendedAt: subscriptionUpdated.ended_at\n\t\t\t\t\t? new Date(subscriptionUpdated.ended_at * 1000)\n\t\t\t\t\t: null,\n\t\t\t\tseats: subscriptionItem.quantity,\n\t\t\t\tstripeSubscriptionId: subscriptionUpdated.id,\n\t\t\t},\n\t\t\twhere: [\n\t\t\t\t{\n\t\t\t\t\tfield: \"id\",\n\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t\tconst isNewCancellation =\n\t\t\tsubscriptionUpdated.status === \"active\" &&\n\t\t\tisStripePendingCancel(subscriptionUpdated) &&\n\t\t\t!isPendingCancel(subscription);\n\t\tif (isNewCancellation) {\n\t\t\tawait options.subscription.onSubscriptionCancel?.({\n\t\t\t\tsubscription,\n\t\t\t\tcancellationDetails:\n\t\t\t\t\tsubscriptionUpdated.cancellation_details || undefined,\n\t\t\t\tstripeSubscription: subscriptionUpdated,\n\t\t\t\tevent,\n\t\t\t});\n\t\t}\n\t\tawait options.subscription.onSubscriptionUpdate?.({\n\t\t\tevent,\n\t\t\tsubscription: updatedSubscription || subscription,\n\t\t});\n\t\tif (plan) {\n\t\t\tif (\n\t\t\t\tsubscriptionUpdated.status === \"active\" &&\n\t\t\t\tsubscription.status === \"trialing\" &&\n\t\t\t\tplan.freeTrial?.onTrialEnd\n\t\t\t) {\n\t\t\t\tawait plan.freeTrial.onTrialEnd({ subscription }, ctx);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tsubscriptionUpdated.status === \"incomplete_expired\" &&\n\t\t\t\tsubscription.status === \"trialing\" &&\n\t\t\t\tplan.freeTrial?.onTrialExpired\n\t\t\t) {\n\t\t\t\tawait plan.freeTrial.onTrialExpired(subscription, ctx);\n\t\t\t}\n\t\t}\n\t} catch (error: any) {\n\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${error}`);\n\t}\n}\n\nexport async function onSubscriptionDeleted(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tevent: Stripe.Event,\n) {\n\tif (!options.subscription?.enabled) {\n\t\treturn;\n\t}\n\ttry {\n\t\tconst subscriptionDeleted = event.data.object as Stripe.Subscription;\n\t\tconst subscriptionId = subscriptionDeleted.id;\n\t\tconst subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\tmodel: \"subscription\",\n\t\t\twhere: [\n\t\t\t\t{\n\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t\tif (subscription) {\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tupdate: {\n\t\t\t\t\tstatus: \"canceled\",\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\tcancelAtPeriodEnd: subscriptionDeleted.cancel_at_period_end,\n\t\t\t\t\tcancelAt: subscriptionDeleted.cancel_at\n\t\t\t\t\t\t? new Date(subscriptionDeleted.cancel_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tcanceledAt: subscriptionDeleted.canceled_at\n\t\t\t\t\t\t? new Date(subscriptionDeleted.canceled_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tendedAt: subscriptionDeleted.ended_at\n\t\t\t\t\t\t? new Date(subscriptionDeleted.ended_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait options.subscription.onSubscriptionDeleted?.({\n\t\t\t\tevent,\n\t\t\t\tstripeSubscription: subscriptionDeleted,\n\t\t\t\tsubscription,\n\t\t\t});\n\t\t} else {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook error: Subscription not found for subscriptionId: ${subscriptionId}`,\n\t\t\t);\n\t\t}\n\t} catch (error: any) {\n\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${error}`);\n\t}\n}\n","import { createAuthMiddleware } from \"@better-auth/core/api\";\nimport { APIError } from \"@better-auth/core/error\";\nimport { sessionMiddleware } from \"better-auth/api\";\nimport { STRIPE_ERROR_CODES } from \"./error-codes\";\nimport type {\n\tAuthorizeReferenceAction,\n\tCustomerType,\n\tStripeCtxSession,\n\tSubscriptionOptions,\n} from \"./types\";\n\nexport const stripeSessionMiddleware = createAuthMiddleware(\n\t{\n\t\tuse: [sessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session as StripeCtxSession;\n\t\treturn {\n\t\t\tsession,\n\t\t};\n\t},\n);\n\nexport const referenceMiddleware = (\n\tsubscriptionOptions: SubscriptionOptions,\n\taction: AuthorizeReferenceAction,\n) =>\n\tcreateAuthMiddleware(async (ctx) => {\n\t\tconst ctxSession = ctx.context.session as StripeCtxSession;\n\t\tif (!ctxSession) {\n\t\t\tthrow APIError.from(\"UNAUTHORIZED\", STRIPE_ERROR_CODES.UNAUTHORIZED);\n\t\t}\n\n\t\tconst customerType: CustomerType =\n\t\t\tctx.body?.customerType || ctx.query?.customerType;\n\t\tconst explicitReferenceId = ctx.body?.referenceId || ctx.query?.referenceId;\n\n\t\tif (customerType === \"organization\") {\n\t\t\t// Organization subscriptions always require authorizeReference\n\t\t\tif (!subscriptionOptions.authorizeReference) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t`Organization subscriptions require authorizeReference to be defined in your stripe plugin config.`,\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_SUBSCRIPTION_NOT_ENABLED,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst referenceId =\n\t\t\t\texplicitReferenceId || ctxSession.session.activeOrganizationId;\n\t\t\tif (!referenceId) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_REFERENCE_ID_REQUIRED,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst isAuthorized = await subscriptionOptions.authorizeReference(\n\t\t\t\t{\n\t\t\t\t\tuser: ctxSession.user,\n\t\t\t\t\tsession: ctxSession.session,\n\t\t\t\t\treferenceId,\n\t\t\t\t\taction,\n\t\t\t\t},\n\t\t\t\tctx,\n\t\t\t);\n\t\t\tif (!isAuthorized) {\n\t\t\t\tthrow APIError.from(\"UNAUTHORIZED\", STRIPE_ERROR_CODES.UNAUTHORIZED);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// User subscriptions - pass if no explicit referenceId\n\t\tif (!explicitReferenceId) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass if referenceId is user id\n\t\tif (explicitReferenceId === ctxSession.user.id) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!subscriptionOptions.authorizeReference) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t`Passing referenceId into a subscription action isn't allowed if subscription.authorizeReference isn't defined in your stripe plugin config.`,\n\t\t\t);\n\t\t\tthrow APIError.from(\n\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\tSTRIPE_ERROR_CODES.REFERENCE_ID_NOT_ALLOWED,\n\t\t\t);\n\t\t}\n\t\tconst isAuthorized = await subscriptionOptions.authorizeReference(\n\t\t\t{\n\t\t\t\tuser: ctxSession.user,\n\t\t\t\tsession: ctxSession.session,\n\t\t\t\treferenceId: explicitReferenceId,\n\t\t\t\taction,\n\t\t\t},\n\t\t\tctx,\n\t\t);\n\t\tif (!isAuthorized) {\n\t\t\tthrow APIError.from(\"UNAUTHORIZED\", STRIPE_ERROR_CODES.UNAUTHORIZED);\n\t\t}\n\t});\n","import { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { APIError } from \"@better-auth/core/error\";\nimport type { GenericEndpointContext, User } from \"better-auth\";\nimport { HIDE_METADATA } from \"better-auth\";\nimport { getSessionFromCtx, originCheck } from \"better-auth/api\";\nimport type { Organization } from \"better-auth/plugins/organization\";\nimport { defu } from \"defu\";\nimport type Stripe from \"stripe\";\nimport type { Stripe as StripeType } from \"stripe\";\nimport * as z from \"zod/v4\";\nimport { STRIPE_ERROR_CODES } from \"./error-codes\";\nimport {\n\tonCheckoutSessionCompleted,\n\tonSubscriptionCreated,\n\tonSubscriptionDeleted,\n\tonSubscriptionUpdated,\n} from \"./hooks\";\nimport { customerMetadata, subscriptionMetadata } from \"./metadata\";\nimport { referenceMiddleware, stripeSessionMiddleware } from \"./middleware\";\nimport type {\n\tCustomerType,\n\tStripeCtxSession,\n\tStripeOptions,\n\tSubscription,\n\tSubscriptionOptions,\n\tWithStripeCustomerId,\n} from \"./types\";\nimport {\n\tescapeStripeSearchValue,\n\tgetPlanByName,\n\tgetPlanByPriceInfo,\n\tgetPlans,\n\tisActiveOrTrialing,\n\tisPendingCancel,\n\tisStripePendingCancel,\n} from \"./utils\";\n\n/**\n * Converts a relative URL to an absolute URL using baseURL.\n * @internal\n */\nfunction getUrl(ctx: GenericEndpointContext, url: string) {\n\tif (/^[a-zA-Z][a-zA-Z0-9+\\-.]*:/.test(url)) {\n\t\treturn url;\n\t}\n\treturn `${ctx.context.options.baseURL}${\n\t\turl.startsWith(\"/\") ? url : `/${url}`\n\t}`;\n}\n\n/**\n * Resolves a Stripe price ID from a lookup key.\n * @internal\n */\nasync function resolvePriceIdFromLookupKey(\n\tstripeClient: Stripe,\n\tlookupKey: string,\n): Promise<string | undefined> {\n\tif (!lookupKey) return undefined;\n\tconst prices = await stripeClient.prices.list({\n\t\tlookup_keys: [lookupKey],\n\t\tactive: true,\n\t\tlimit: 1,\n\t});\n\treturn prices.data[0]?.id;\n}\n\n/**\n * Determines the reference ID based on customer type.\n * - `user` (default): uses userId\n * - `organization`: uses activeOrganizationId from session\n * @internal\n */\nfunction getReferenceId(\n\tctxSession: StripeCtxSession,\n\tcustomerType: CustomerType | undefined,\n\toptions: StripeOptions,\n): string {\n\tconst { user, session } = ctxSession;\n\tconst type = customerType || \"user\";\n\n\tif (type === \"organization\") {\n\t\tif (!options.organization?.enabled) {\n\t\t\tthrow APIError.from(\n\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_SUBSCRIPTION_NOT_ENABLED,\n\t\t\t);\n\t\t}\n\n\t\tif (!session.activeOrganizationId) {\n\t\t\tthrow APIError.from(\n\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_NOT_FOUND,\n\t\t\t);\n\t\t}\n\t\treturn session.activeOrganizationId;\n\t}\n\n\treturn user.id;\n}\n\nconst upgradeSubscriptionBodySchema = z.object({\n\t/**\n\t * The name of the plan to subscribe\n\t */\n\tplan: z.string().meta({\n\t\tdescription: 'The name of the plan to upgrade to. Eg: \"pro\"',\n\t}),\n\t/**\n\t * If annual plan should be applied.\n\t */\n\tannual: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription: \"Whether to upgrade to an annual plan. Eg: true\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Reference ID for the subscription based on customerType:\n\t * - `user`: defaults to `user.id`\n\t * - `organization`: defaults to `session.activeOrganizationId`\n\t */\n\treferenceId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: 'Reference ID for the subscription. Eg: \"org_123\"',\n\t\t})\n\t\t.optional(),\n\t/**\n\t * The Stripe subscription ID to upgrade.\n\t * If provided and not found, it'll throw an error.\n\t */\n\tsubscriptionId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'The Stripe subscription ID to upgrade. Eg: \"sub_1ABC2DEF3GHI4JKL\"',\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Customer type for the subscription.\n\t * - `user`: User owns the subscription (default)\n\t * - `organization`: Organization owns the subscription (requires referenceId)\n\t */\n\tcustomerType: z\n\t\t.enum([\"user\", \"organization\"])\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Additional metadata to store with the subscription.\n\t */\n\tmetadata: z.record(z.string(), z.any()).optional(),\n\t/**\n\t * Number of seats for subscriptions.\n\t */\n\tseats: z\n\t\t.number()\n\t\t.meta({\n\t\t\tdescription: \"Number of seats to upgrade to (if applicable). Eg: 1\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * The IETF language tag of the locale Checkout is displayed in.\n\t * If not provided or set to `auto`, the browser's locale is used.\n\t */\n\tlocale: z\n\t\t.custom<StripeType.Checkout.Session.Locale>((localization) => {\n\t\t\treturn typeof localization === \"string\";\n\t\t})\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"The locale to display Checkout in. Eg: 'en', 'ko'. If not provided or set to `auto`, the browser's locale is used.\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * The URL to which Stripe should send customers when payment or setup is complete.\n\t */\n\tsuccessUrl: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Callback URL to redirect back after successful subscription. Eg: \"https://example.com/success\"',\n\t\t})\n\t\t.default(\"/\"),\n\t/**\n\t * If set, checkout shows a back button and customers will be directed here if they cancel payment.\n\t */\n\tcancelUrl: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'If set, checkout shows a back button and customers will be directed here if they cancel payment. Eg: \"https://example.com/pricing\"',\n\t\t})\n\t\t.default(\"/\"),\n\t/**\n\t * The URL to return to from the Billing Portal (used when upgrading existing subscriptions)\n\t */\n\treturnUrl: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'URL to take customers to when they click on the billing portal’s link to return to your website. Eg: \"https://example.com/dashboard\"',\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Disable Redirect\n\t */\n\tdisableRedirect: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription: \"Disable redirect after successful subscription. Eg: true\",\n\t\t})\n\t\t.default(false),\n});\n\n/**\n * ### Endpoint\n *\n * POST `/subscription/upgrade`\n *\n * ### API Methods\n *\n * **server:**\n * `auth.api.upgradeSubscription`\n *\n * **client:**\n * `authClient.subscription.upgrade`\n *\n * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/stripe#api-method-subscription-upgrade)\n */\nexport const upgradeSubscription = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\n\treturn createAuthEndpoint(\n\t\t\"/subscription/upgrade\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: upgradeSubscriptionBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"upgradeSubscription\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"upgrade-subscription\"),\n\t\t\t\toriginCheck((c) => {\n\t\t\t\t\treturn [c.body.successUrl as string, c.body.cancelUrl as string];\n\t\t\t\t}),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { user, session } = ctx.context.session;\n\t\t\tconst customerType = ctx.body.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.body.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tif (!user.emailVerified && subscriptionOptions.requireEmailVerification) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst plan = await getPlanByName(options, ctx.body.plan);\n\t\t\tif (!plan) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// If subscriptionId is provided, find that specific subscription.\n\t\t\t// Otherwise, active subscription will be resolved by referenceId later.\n\t\t\tconst subscriptionToUpdate = ctx.body.subscriptionId\n\t\t\t\t? await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\t\t\t\tvalue: ctx.body.subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t})\n\t\t\t\t: null;\n\t\t\tif (ctx.body.subscriptionId && !subscriptionToUpdate) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tctx.body.subscriptionId &&\n\t\t\t\tsubscriptionToUpdate &&\n\t\t\t\tsubscriptionToUpdate.referenceId !== referenceId\n\t\t\t) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Determine customer id\n\t\t\tlet customerId: string | undefined;\n\t\t\tif (customerType === \"organization\") {\n\t\t\t\t// Organization subscription - get customer ID from organization\n\t\t\t\tcustomerId = subscriptionToUpdate?.stripeCustomerId;\n\t\t\t\tif (!customerId) {\n\t\t\t\t\tconst org = await ctx.context.adapter.findOne<\n\t\t\t\t\t\tOrganization & WithStripeCustomerId\n\t\t\t\t\t>({\n\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\tif (!org) {\n\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_NOT_FOUND,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tcustomerId = org.stripeCustomerId;\n\n\t\t\t\t\t// If org doesn't have a customer ID, create one\n\t\t\t\t\tif (!customerId) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// First, search for existing organization customer by organizationId\n\t\t\t\t\t\t\tconst existingOrgCustomers = await client.customers.search({\n\t\t\t\t\t\t\t\tquery: `metadata[\"${customerMetadata.keys.organizationId}\"]:\"${org.id}\"`,\n\t\t\t\t\t\t\t\tlimit: 1,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tlet stripeCustomer = existingOrgCustomers.data[0];\n\n\t\t\t\t\t\t\tif (!stripeCustomer) {\n\t\t\t\t\t\t\t\t// Get custom params if provided\n\t\t\t\t\t\t\t\tlet extraCreateParams: Partial<StripeType.CustomerCreateParams> =\n\t\t\t\t\t\t\t\t\t{};\n\t\t\t\t\t\t\t\tif (options.organization?.getCustomerCreateParams) {\n\t\t\t\t\t\t\t\t\textraCreateParams =\n\t\t\t\t\t\t\t\t\t\tawait options.organization.getCustomerCreateParams(\n\t\t\t\t\t\t\t\t\t\t\torg,\n\t\t\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Create Stripe customer for organization\n\t\t\t\t\t\t\t\t// Email can be set via getCustomerCreateParams or updated in billing portal\n\t\t\t\t\t\t\t\t// Use defu to merge params (first argument takes priority)\n\t\t\t\t\t\t\t\tconst customerParams = defu(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: org.name,\n\t\t\t\t\t\t\t\t\t\tmetadata: customerMetadata.set(\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\torganizationId: org.id,\n\t\t\t\t\t\t\t\t\t\t\t\tcustomerType: \"organization\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tctx.body.metadata,\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\textraCreateParams,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tstripeCustomer = await client.customers.create(customerParams);\n\n\t\t\t\t\t\t\t\t// Call onCustomerCreate callback only for newly created customers\n\t\t\t\t\t\t\t\tawait options.organization?.onCustomerCreate?.(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tstripeCustomer,\n\t\t\t\t\t\t\t\t\t\torganization: {\n\t\t\t\t\t\t\t\t\t\t\t...org,\n\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\t\tvalue: org.id,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tcustomerId = stripeCustomer.id;\n\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\tctx.context.logger.error(e);\n\t\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\t\tSTRIPE_ERROR_CODES.UNABLE_TO_CREATE_CUSTOMER,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// User subscription - get customer ID from user\n\t\t\t\tcustomerId =\n\t\t\t\t\tsubscriptionToUpdate?.stripeCustomerId || user.stripeCustomerId;\n\t\t\t\tif (!customerId) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Try to find existing user Stripe customer by email\n\t\t\t\t\t\tconst existingCustomers = await client.customers.search({\n\t\t\t\t\t\t\tquery: `email:\"${escapeStripeSearchValue(user.email)}\" AND -metadata[\"${customerMetadata.keys.customerType}\"]:\"organization\"`,\n\t\t\t\t\t\t\tlimit: 1,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tlet stripeCustomer = existingCustomers.data[0];\n\n\t\t\t\t\t\tif (!stripeCustomer) {\n\t\t\t\t\t\t\tstripeCustomer = await client.customers.create({\n\t\t\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\t\t\tname: user.name ?? undefined,\n\t\t\t\t\t\t\t\tmetadata: customerMetadata.set(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t\t\t\t\tcustomerType: \"user\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tctx.body.metadata,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Update local DB with Stripe customer ID\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tcustomerId = stripeCustomer.id;\n\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\tctx.context.logger.error(e);\n\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\tSTRIPE_ERROR_CODES.UNABLE_TO_CREATE_CUSTOMER,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst subscriptions = subscriptionToUpdate\n\t\t\t\t? [subscriptionToUpdate]\n\t\t\t\t: await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\n\t\t\tconst activeOrTrialingSubscription = subscriptions.find((sub) =>\n\t\t\t\tisActiveOrTrialing(sub),\n\t\t\t);\n\n\t\t\tconst activeSubscriptions = await client.subscriptions\n\t\t\t\t.list({\n\t\t\t\t\tcustomer: customerId,\n\t\t\t\t})\n\t\t\t\t.then((res) => res.data.filter((sub) => isActiveOrTrialing(sub)));\n\n\t\t\tconst activeSubscription = activeSubscriptions.find((sub) => {\n\t\t\t\t// If we have a specific subscription to update, match by ID\n\t\t\t\tif (\n\t\t\t\t\tsubscriptionToUpdate?.stripeSubscriptionId ||\n\t\t\t\t\tctx.body.subscriptionId\n\t\t\t\t) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tsub.id === subscriptionToUpdate?.stripeSubscriptionId ||\n\t\t\t\t\t\tsub.id === ctx.body.subscriptionId\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// Only find subscription for the same referenceId to avoid mixing personal and org subscriptions\n\t\t\t\tif (activeOrTrialingSubscription?.stripeSubscriptionId) {\n\t\t\t\t\treturn sub.id === activeOrTrialingSubscription.stripeSubscriptionId;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t});\n\n\t\t\t// Get the current price ID from the active Stripe subscription\n\t\t\tconst stripeSubscriptionPriceId =\n\t\t\t\tactiveSubscription?.items.data[0]?.price.id;\n\n\t\t\t// Also find any incomplete subscription that we can reuse\n\t\t\tconst incompleteSubscription = subscriptions.find(\n\t\t\t\t(sub) => sub.status === \"incomplete\",\n\t\t\t);\n\n\t\t\tconst priceId = ctx.body.annual\n\t\t\t\t? plan.annualDiscountPriceId\n\t\t\t\t: plan.priceId;\n\t\t\tconst lookupKey = ctx.body.annual\n\t\t\t\t? plan.annualDiscountLookupKey\n\t\t\t\t: plan.lookupKey;\n\t\t\tconst resolvedPriceId = lookupKey\n\t\t\t\t? await resolvePriceIdFromLookupKey(client, lookupKey)\n\t\t\t\t: undefined;\n\n\t\t\tconst priceIdToUse = priceId || resolvedPriceId;\n\t\t\tif (!priceIdToUse) {\n\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Price ID not found for the selected plan\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst isSamePlan = activeOrTrialingSubscription?.plan === ctx.body.plan;\n\t\t\tconst isSameSeats =\n\t\t\t\tactiveOrTrialingSubscription?.seats === (ctx.body.seats || 1);\n\t\t\tconst isSamePriceId = stripeSubscriptionPriceId === priceIdToUse;\n\t\t\tconst isSubscriptionStillValid =\n\t\t\t\t!activeOrTrialingSubscription?.periodEnd ||\n\t\t\t\tactiveOrTrialingSubscription.periodEnd > new Date();\n\n\t\t\tconst isAlreadySubscribed =\n\t\t\t\tactiveOrTrialingSubscription?.status === \"active\" &&\n\t\t\t\tisSamePlan &&\n\t\t\t\tisSameSeats &&\n\t\t\t\tisSamePriceId &&\n\t\t\t\tisSubscriptionStillValid;\n\t\t\tif (isAlreadySubscribed) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.ALREADY_SUBSCRIBED_PLAN,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (activeSubscription && customerId) {\n\t\t\t\t// Find the corresponding database subscription for this Stripe subscription\n\t\t\t\tlet dbSubscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\t\t\tvalue: activeSubscription.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\t// If no database record exists for this Stripe subscription, update the existing one\n\t\t\t\tif (!dbSubscription && activeOrTrialingSubscription) {\n\t\t\t\t\tawait ctx.context.adapter.update<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tstripeSubscriptionId: activeSubscription.id,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: activeOrTrialingSubscription.id,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\tdbSubscription = activeOrTrialingSubscription;\n\t\t\t\t}\n\n\t\t\t\tconst { url } = await client.billingPortal.sessions\n\t\t\t\t\t.create({\n\t\t\t\t\t\tcustomer: customerId,\n\t\t\t\t\t\treturn_url: getUrl(ctx, ctx.body.returnUrl || \"/\"),\n\t\t\t\t\t\tflow_data: {\n\t\t\t\t\t\t\ttype: \"subscription_update_confirm\",\n\t\t\t\t\t\t\tafter_completion: {\n\t\t\t\t\t\t\t\ttype: \"redirect\",\n\t\t\t\t\t\t\t\tredirect: {\n\t\t\t\t\t\t\t\t\treturn_url: getUrl(ctx, ctx.body.returnUrl || \"/\"),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tsubscription_update_confirm: {\n\t\t\t\t\t\t\t\tsubscription: activeSubscription.id,\n\t\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tid: activeSubscription.items.data[0]?.id as string,\n\t\t\t\t\t\t\t\t\t\tquantity: ctx.body.seats || 1,\n\t\t\t\t\t\t\t\t\t\tprice: priceIdToUse,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\t.catch(async (e) => {\n\t\t\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\treturn ctx.json({\n\t\t\t\t\turl,\n\t\t\t\t\tredirect: !ctx.body.disableRedirect,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet subscription: Subscription | undefined =\n\t\t\t\tactiveOrTrialingSubscription || incompleteSubscription;\n\n\t\t\tif (incompleteSubscription && !activeOrTrialingSubscription) {\n\t\t\t\tconst updated = await ctx.context.adapter.update<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\t\tseats: ctx.body.seats || 1,\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t},\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\tvalue: incompleteSubscription.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tsubscription = (updated as Subscription) || incompleteSubscription;\n\t\t\t}\n\n\t\t\tif (!subscription) {\n\t\t\t\tsubscription = await ctx.context.adapter.create<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\t\tstripeCustomerId: customerId,\n\t\t\t\t\t\tstatus: \"incomplete\",\n\t\t\t\t\t\treferenceId,\n\t\t\t\t\t\tseats: ctx.body.seats || 1,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (!subscription) {\n\t\t\t\tctx.context.logger.error(\"Subscription ID not found\");\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"NOT_FOUND\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst params = await subscriptionOptions.getCheckoutSessionParams?.(\n\t\t\t\t{\n\t\t\t\t\tuser,\n\t\t\t\t\tsession,\n\t\t\t\t\tplan,\n\t\t\t\t\tsubscription,\n\t\t\t\t},\n\t\t\t\tctx.request,\n\t\t\t\tctx,\n\t\t\t);\n\n\t\t\tconst allSubscriptions = await ctx.context.adapter.findMany<Subscription>(\n\t\t\t\t{\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\twhere: [{ field: \"referenceId\", value: referenceId }],\n\t\t\t\t},\n\t\t\t);\n\t\t\tconst hasEverTrialed = allSubscriptions.some((s) => {\n\t\t\t\t// Check if user has ever had a trial for any plan (not just the same plan)\n\t\t\t\t// This prevents users from getting multiple trials by switching plans\n\t\t\t\tconst hadTrial =\n\t\t\t\t\t!!(s.trialStart || s.trialEnd) || s.status === \"trialing\";\n\t\t\t\treturn hadTrial;\n\t\t\t});\n\n\t\t\tconst freeTrial =\n\t\t\t\t!hasEverTrialed && plan.freeTrial\n\t\t\t\t\t? { trial_period_days: plan.freeTrial.days }\n\t\t\t\t\t: undefined;\n\n\t\t\tconst checkoutSession = await client.checkout.sessions\n\t\t\t\t.create(\n\t\t\t\t\t{\n\t\t\t\t\t\t...(customerId\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tcustomer: customerId,\n\t\t\t\t\t\t\t\t\tcustomer_update:\n\t\t\t\t\t\t\t\t\t\tcustomerType !== \"user\"\n\t\t\t\t\t\t\t\t\t\t\t? ({ address: \"auto\" } as const)\n\t\t\t\t\t\t\t\t\t\t\t: ({ name: \"auto\", address: \"auto\" } as const), // The customer name is automatically set only for users\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\tcustomer_email: user.email,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\tlocale: ctx.body.locale,\n\t\t\t\t\t\tsuccess_url: getUrl(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t`${\n\t\t\t\t\t\t\t\tctx.context.baseURL\n\t\t\t\t\t\t\t}/subscription/success?callbackURL=${encodeURIComponent(\n\t\t\t\t\t\t\t\tctx.body.successUrl,\n\t\t\t\t\t\t\t)}&subscriptionId=${encodeURIComponent(subscription.id)}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcancel_url: getUrl(ctx, ctx.body.cancelUrl),\n\t\t\t\t\t\tline_items: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tprice: priceIdToUse,\n\t\t\t\t\t\t\t\tquantity: ctx.body.seats || 1,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tsubscription_data: {\n\t\t\t\t\t\t\t...freeTrial,\n\t\t\t\t\t\t\tmetadata: subscriptionMetadata.set(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\t\t\t\t\treferenceId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tctx.body.metadata,\n\t\t\t\t\t\t\t\tparams?.params?.subscription_data?.metadata,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmode: \"subscription\",\n\t\t\t\t\t\tclient_reference_id: referenceId,\n\t\t\t\t\t\t...params?.params,\n\t\t\t\t\t\t// metadata should come after spread to protect internal fields\n\t\t\t\t\t\tmetadata: subscriptionMetadata.set(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\t\t\t\treferenceId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tctx.body.metadata,\n\t\t\t\t\t\t\tparams?.params?.metadata,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t\tparams?.options,\n\t\t\t\t)\n\t\t\t\t.catch(async (e) => {\n\t\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\t...checkoutSession,\n\t\t\t\tredirect: !ctx.body.disableRedirect,\n\t\t\t});\n\t\t},\n\t);\n};\n\nconst cancelSubscriptionCallbackQuerySchema = z\n\t.record(z.string(), z.any())\n\t.optional();\n\nexport const cancelSubscriptionCallback = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/cancel/callback\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: cancelSubscriptionCallbackQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"cancelSubscriptionCallback\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || \"/\"));\n\t\t\t}\n\t\t\tconst session = await getSessionFromCtx<User & WithStripeCustomerId>(ctx);\n\t\t\tif (!session) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || \"/\"));\n\t\t\t}\n\t\t\tconst { user } = session;\n\t\t\tconst { callbackURL, subscriptionId } = ctx.query;\n\n\t\t\tif (user?.stripeCustomerId) {\n\t\t\t\ttry {\n\t\t\t\t\tconst subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\tif (\n\t\t\t\t\t\t!subscription ||\n\t\t\t\t\t\tsubscription.status === \"canceled\" ||\n\t\t\t\t\t\tisPendingCancel(subscription)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t\t\t}\n\n\t\t\t\t\tconst stripeSubscription = await client.subscriptions.list({\n\t\t\t\t\t\tcustomer: user.stripeCustomerId,\n\t\t\t\t\t\tstatus: \"active\",\n\t\t\t\t\t});\n\t\t\t\t\tconst currentSubscription = stripeSubscription.data.find(\n\t\t\t\t\t\t(sub) => sub.id === subscription.stripeSubscriptionId,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst isNewCancellation =\n\t\t\t\t\t\tcurrentSubscription &&\n\t\t\t\t\t\tisStripePendingCancel(currentSubscription) &&\n\t\t\t\t\t\t!isPendingCancel(subscription);\n\t\t\t\t\tif (isNewCancellation) {\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tstatus: currentSubscription?.status,\n\t\t\t\t\t\t\t\tcancelAtPeriodEnd:\n\t\t\t\t\t\t\t\t\tcurrentSubscription?.cancel_at_period_end || false,\n\t\t\t\t\t\t\t\tcancelAt: currentSubscription?.cancel_at\n\t\t\t\t\t\t\t\t\t? new Date(currentSubscription.cancel_at * 1000)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\tcanceledAt: currentSubscription?.canceled_at\n\t\t\t\t\t\t\t\t\t? new Date(currentSubscription.canceled_at * 1000)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tawait subscriptionOptions.onSubscriptionCancel?.({\n\t\t\t\t\t\t\tsubscription,\n\t\t\t\t\t\t\tcancellationDetails: currentSubscription.cancellation_details,\n\t\t\t\t\t\t\tstripeSubscription: currentSubscription,\n\t\t\t\t\t\t\tevent: undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\t\"Error checking subscription status from Stripe\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t},\n\t);\n};\n\nconst cancelSubscriptionBodySchema = z.object({\n\treferenceId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"Reference id of the subscription to cancel. Eg: '123'\",\n\t\t})\n\t\t.optional(),\n\tsubscriptionId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"The Stripe subscription ID to cancel. Eg: 'sub_1ABC2DEF3GHI4JKL'\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Customer type for the subscription.\n\t * - `user`: User owns the subscription (default)\n\t * - `organization`: Organization owns the subscription\n\t */\n\tcustomerType: z\n\t\t.enum([\"user\", \"organization\"])\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t})\n\t\t.optional(),\n\treturnUrl: z.string().meta({\n\t\tdescription:\n\t\t\t'URL to take customers to when they click on the billing portal\\'s link to return to your website. Eg: \"/account\"',\n\t}),\n\t/**\n\t * Disable Redirect\n\t */\n\tdisableRedirect: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Disable redirect after successful subscription cancellation. Eg: true\",\n\t\t})\n\t\t.default(false),\n});\n\n/**\n * ### Endpoint\n *\n * POST `/subscription/cancel`\n *\n * ### API Methods\n *\n * **server:**\n * `auth.api.cancelSubscription`\n *\n * **client:**\n * `authClient.subscription.cancel`\n *\n * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/stripe#api-method-subscription-cancel)\n */\nexport const cancelSubscription = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/cancel\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: cancelSubscriptionBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"cancelSubscription\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"cancel-subscription\"),\n\t\t\t\toriginCheck((ctx) => ctx.body.returnUrl),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst customerType = ctx.body.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.body.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tlet subscription = ctx.body.subscriptionId\n\t\t\t\t? await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\t\t\t\tvalue: ctx.body.subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t})\n\t\t\t\t: await ctx.context.adapter\n\t\t\t\t\t\t.findMany<Subscription>({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\twhere: [{ field: \"referenceId\", value: referenceId }],\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then((subs) => subs.find((sub) => isActiveOrTrialing(sub)));\n\t\t\tif (\n\t\t\t\tctx.body.subscriptionId &&\n\t\t\t\tsubscription &&\n\t\t\t\tsubscription.referenceId !== referenceId\n\t\t\t) {\n\t\t\t\tsubscription = undefined;\n\t\t\t}\n\n\t\t\tif (!subscription || !subscription.stripeCustomerId) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst activeSubscriptions = await client.subscriptions\n\t\t\t\t.list({\n\t\t\t\t\tcustomer: subscription.stripeCustomerId,\n\t\t\t\t})\n\t\t\t\t.then((res) => res.data.filter((sub) => isActiveOrTrialing(sub)));\n\t\t\tif (!activeSubscriptions.length) {\n\t\t\t\t/**\n\t\t\t\t * If the subscription is not found, we need to delete the subscription\n\t\t\t\t * from the database. This is a rare case and should not happen.\n\t\t\t\t */\n\t\t\t\tawait ctx.context.adapter.deleteMany({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst activeSubscription = activeSubscriptions.find(\n\t\t\t\t(sub) => sub.id === subscription.stripeSubscriptionId,\n\t\t\t);\n\t\t\tif (!activeSubscription) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst { url } = await client.billingPortal.sessions\n\t\t\t\t.create({\n\t\t\t\t\tcustomer: subscription.stripeCustomerId,\n\t\t\t\t\treturn_url: getUrl(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t`${\n\t\t\t\t\t\t\tctx.context.baseURL\n\t\t\t\t\t\t}/subscription/cancel/callback?callbackURL=${encodeURIComponent(\n\t\t\t\t\t\t\tctx.body?.returnUrl || \"/\",\n\t\t\t\t\t\t)}&subscriptionId=${encodeURIComponent(subscription.id)}`,\n\t\t\t\t\t),\n\t\t\t\t\tflow_data: {\n\t\t\t\t\t\ttype: \"subscription_cancel\",\n\t\t\t\t\t\tsubscription_cancel: {\n\t\t\t\t\t\t\tsubscription: activeSubscription.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t.catch(async (e) => {\n\t\t\t\t\tif (e.message?.includes(\"already set to be canceled\")) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * in-case we missed the event from stripe, we sync the actual state\n\t\t\t\t\t\t * this is a rare case and should not happen\n\t\t\t\t\t\t */\n\t\t\t\t\t\tif (!isPendingCancel(subscription)) {\n\t\t\t\t\t\t\tconst stripeSub = await client.subscriptions.retrieve(\n\t\t\t\t\t\t\t\tactiveSubscription.id,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\tcancelAtPeriodEnd: stripeSub.cancel_at_period_end,\n\t\t\t\t\t\t\t\t\tcancelAt: stripeSub.cancel_at\n\t\t\t\t\t\t\t\t\t\t? new Date(stripeSub.cancel_at * 1000)\n\t\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t\tcanceledAt: stripeSub.canceled_at\n\t\t\t\t\t\t\t\t\t\t? new Date(stripeSub.canceled_at * 1000)\n\t\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\turl,\n\t\t\t\tredirect: !ctx.body.disableRedirect,\n\t\t\t});\n\t\t},\n\t);\n};\n\nconst restoreSubscriptionBodySchema = z.object({\n\treferenceId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"Reference id of the subscription to restore. Eg: '123'\",\n\t\t})\n\t\t.optional(),\n\tsubscriptionId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"The Stripe subscription ID to restore. Eg: 'sub_1ABC2DEF3GHI4JKL'\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Customer type for the subscription.\n\t * - `user`: User owns the subscription (default)\n\t * - `organization`: Organization owns the subscription\n\t */\n\tcustomerType: z\n\t\t.enum([\"user\", \"organization\"])\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t})\n\t\t.optional(),\n});\n\nexport const restoreSubscription = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/restore\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: restoreSubscriptionBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"restoreSubscription\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"restore-subscription\"),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst customerType = ctx.body.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.body.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tlet subscription = ctx.body.subscriptionId\n\t\t\t\t? await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\t\t\t\tvalue: ctx.body.subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t})\n\t\t\t\t: await ctx.context.adapter\n\t\t\t\t\t\t.findMany<Subscription>({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then((subs) => subs.find((sub) => isActiveOrTrialing(sub)));\n\t\t\tif (\n\t\t\t\tctx.body.subscriptionId &&\n\t\t\t\tsubscription &&\n\t\t\t\tsubscription.referenceId !== referenceId\n\t\t\t) {\n\t\t\t\tsubscription = undefined;\n\t\t\t}\n\t\t\tif (!subscription || !subscription.stripeCustomerId) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!isActiveOrTrialing(subscription)) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_ACTIVE,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!isPendingCancel(subscription)) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst activeSubscription = await client.subscriptions\n\t\t\t\t.list({\n\t\t\t\t\tcustomer: subscription.stripeCustomerId,\n\t\t\t\t})\n\t\t\t\t.then((res) => res.data.filter((sub) => isActiveOrTrialing(sub))[0]);\n\t\t\tif (!activeSubscription) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Clear scheduled cancellation based on Stripe subscription state\n\t\t\t// Note: Stripe doesn't accept both `cancel_at` and `cancel_at_period_end` simultaneously\n\t\t\tconst updateParams: Stripe.SubscriptionUpdateParams = {};\n\t\t\tif (activeSubscription.cancel_at) {\n\t\t\t\tupdateParams.cancel_at = \"\";\n\t\t\t} else if (activeSubscription.cancel_at_period_end) {\n\t\t\t\tupdateParams.cancel_at_period_end = false;\n\t\t\t}\n\n\t\t\tconst newSub = await client.subscriptions\n\t\t\t\t.update(activeSubscription.id, updateParams)\n\t\t\t\t.catch((e) => {\n\t\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\tupdate: {\n\t\t\t\t\tcancelAtPeriodEnd: false,\n\t\t\t\t\tcancelAt: null,\n\t\t\t\t\tcanceledAt: null,\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t},\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\treturn ctx.json(newSub);\n\t\t},\n\t);\n};\n\nconst listActiveSubscriptionsQuerySchema = z.optional(\n\tz.object({\n\t\treferenceId: z\n\t\t\t.string()\n\t\t\t.meta({\n\t\t\t\tdescription: \"Reference id of the subscription to list. Eg: '123'\",\n\t\t\t})\n\t\t\t.optional(),\n\t\t/**\n\t\t * Customer type for the subscription.\n\t\t * - `user`: User owns the subscription (default)\n\t\t * - `organization`: Organization owns the subscription\n\t\t */\n\t\tcustomerType: z\n\t\t\t.enum([\"user\", \"organization\"])\n\t\t\t.meta({\n\t\t\t\tdescription:\n\t\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t\t})\n\t\t\t.optional(),\n\t}),\n);\n/**\n * ### Endpoint\n *\n * GET `/subscription/list`\n *\n * ### API Methods\n *\n * **server:**\n * `auth.api.listActiveSubscriptions`\n *\n * **client:**\n * `authClient.subscription.list`\n *\n * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/stripe#api-method-subscription-list)\n */\nexport const listActiveSubscriptions = (options: StripeOptions) => {\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/list\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: listActiveSubscriptionsQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"listActiveSubscriptions\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"list-subscription\"),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst customerType = ctx.query?.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.query?.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tconst subscriptions = await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!subscriptions.length) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tconst plans = await getPlans(options.subscription);\n\t\t\tif (!plans) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tconst subs = subscriptions\n\t\t\t\t.map((sub) => {\n\t\t\t\t\tconst plan = plans.find(\n\t\t\t\t\t\t(p) => p.name.toLowerCase() === sub.plan.toLowerCase(),\n\t\t\t\t\t);\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...sub,\n\t\t\t\t\t\tlimits: plan?.limits,\n\t\t\t\t\t\tpriceId: plan?.priceId,\n\t\t\t\t\t};\n\t\t\t\t})\n\t\t\t\t.filter((sub) => isActiveOrTrialing(sub));\n\t\t\treturn ctx.json(subs);\n\t\t},\n\t);\n};\n\nconst subscriptionSuccessQuerySchema = z.record(z.string(), z.any()).optional();\n\nexport const subscriptionSuccess = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/success\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: subscriptionSuccessQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"handleSubscriptionSuccess\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || \"/\"));\n\t\t\t}\n\t\t\tconst { callbackURL, subscriptionId } = ctx.query;\n\n\t\t\tconst session = await getSessionFromCtx<User & WithStripeCustomerId>(ctx);\n\t\t\tif (!session) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || \"/\"));\n\t\t\t}\n\n\t\t\tconst subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!subscription) {\n\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t`Subscription record not found for subscriptionId: ${subscriptionId}`,\n\t\t\t\t);\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\t// Already active or trialing, no need to update\n\t\t\tif (isActiveOrTrialing(subscription)) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tconst customerId =\n\t\t\t\tsubscription.stripeCustomerId || session.user.stripeCustomerId;\n\t\t\tif (!customerId) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tconst stripeSubscription = await client.subscriptions\n\t\t\t\t.list({ customer: customerId, status: \"active\" })\n\t\t\t\t.then((res) => res.data[0])\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\t\"Error fetching subscription from Stripe\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t\t});\n\t\t\tif (!stripeSubscription) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tconst subscriptionItem = stripeSubscription.items.data[0];\n\t\t\tif (!subscriptionItem) {\n\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t`No subscription items found for Stripe subscription ${stripeSubscription.id}`,\n\t\t\t\t);\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tconst plan = await getPlanByPriceInfo(\n\t\t\t\toptions,\n\t\t\t\tsubscriptionItem.price.id,\n\t\t\t\tsubscriptionItem.price.lookup_key,\n\t\t\t);\n\t\t\tif (!plan) {\n\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t`Plan not found for price ${subscriptionItem.price.id}`,\n\t\t\t\t);\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\tupdate: {\n\t\t\t\t\tstatus: stripeSubscription.status,\n\t\t\t\t\tseats: subscriptionItem.quantity || 1,\n\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\tperiodEnd: new Date(subscriptionItem.current_period_end * 1000),\n\t\t\t\t\tperiodStart: new Date(subscriptionItem.current_period_start * 1000),\n\t\t\t\t\tstripeSubscriptionId: stripeSubscription.id,\n\t\t\t\t\tcancelAtPeriodEnd: stripeSubscription.cancel_at_period_end,\n\t\t\t\t\tcancelAt: stripeSubscription.cancel_at\n\t\t\t\t\t\t? new Date(stripeSubscription.cancel_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tcanceledAt: stripeSubscription.canceled_at\n\t\t\t\t\t\t? new Date(stripeSubscription.canceled_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t\t...(stripeSubscription.trial_start && stripeSubscription.trial_end\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\ttrialStart: new Date(stripeSubscription.trial_start * 1000),\n\t\t\t\t\t\t\t\ttrialEnd: new Date(stripeSubscription.trial_end * 1000),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t},\n\t);\n};\n\nconst createBillingPortalBodySchema = z.object({\n\t/**\n\t * The IETF language tag of the locale Customer Portal is displayed in.\n\t * If not provided or set to `auto`, the browser's locale is used.\n\t */\n\tlocale: z\n\t\t.custom<StripeType.Checkout.Session.Locale>((localization) => {\n\t\t\treturn typeof localization === \"string\";\n\t\t})\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"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.\",\n\t\t})\n\t\t.optional(),\n\treferenceId: z.string().optional(),\n\t/**\n\t * Customer type for the subscription.\n\t * - `user`: User owns the subscription (default)\n\t * - `organization`: Organization owns the subscription\n\t */\n\tcustomerType: z\n\t\t.enum([\"user\", \"organization\"])\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t})\n\t\t.optional(),\n\treturnUrl: z.string().default(\"/\"),\n\t/**\n\t * Disable Redirect\n\t */\n\tdisableRedirect: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Disable redirect after creating billing portal session. Eg: true\",\n\t\t})\n\t\t.default(false),\n});\n\nexport const createBillingPortal = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/billing-portal\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: createBillingPortalBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"createBillingPortal\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"billing-portal\"),\n\t\t\t\toriginCheck((ctx) => ctx.body.returnUrl),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { user } = ctx.context.session;\n\t\t\tconst customerType = ctx.body.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.body.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tlet customerId: string | undefined;\n\n\t\t\tif (customerType === \"organization\") {\n\t\t\t\t// Organization billing portal - get customer ID from organization\n\t\t\t\tconst org = await ctx.context.adapter.findOne<\n\t\t\t\t\tOrganization & WithStripeCustomerId\n\t\t\t\t>({\n\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\twhere: [{ field: \"id\", value: referenceId }],\n\t\t\t\t});\n\t\t\t\tcustomerId = org?.stripeCustomerId;\n\n\t\t\t\tif (!customerId) {\n\t\t\t\t\t// Fallback to subscription's stripeCustomerId\n\t\t\t\t\tconst subscription = await ctx.context.adapter\n\t\t\t\t\t\t.findMany<Subscription>({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\twhere: [{ field: \"referenceId\", value: referenceId }],\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then((subs) => subs.find((sub) => isActiveOrTrialing(sub)));\n\t\t\t\t\tcustomerId = subscription?.stripeCustomerId;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// User billing portal\n\t\t\t\tcustomerId = user.stripeCustomerId;\n\t\t\t\tif (!customerId) {\n\t\t\t\t\tconst subscription = await ctx.context.adapter\n\t\t\t\t\t\t.findMany<Subscription>({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then((subs) => subs.find((sub) => isActiveOrTrialing(sub)));\n\n\t\t\t\t\tcustomerId = subscription?.stripeCustomerId;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!customerId) {\n\t\t\t\tthrow APIError.from(\"NOT_FOUND\", STRIPE_ERROR_CODES.CUSTOMER_NOT_FOUND);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst { url } = await client.billingPortal.sessions.create({\n\t\t\t\t\tlocale: ctx.body.locale,\n\t\t\t\t\tcustomer: customerId,\n\t\t\t\t\treturn_url: getUrl(ctx, ctx.body.returnUrl),\n\t\t\t\t});\n\n\t\t\t\treturn ctx.json({\n\t\t\t\t\turl,\n\t\t\t\t\tredirect: !ctx.body.disableRedirect,\n\t\t\t\t});\n\t\t\t} catch (error: any) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\"Error creating billing portal session\",\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"INTERNAL_SERVER_ERROR\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.UNABLE_TO_CREATE_BILLING_PORTAL,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t);\n};\n\nexport const stripeWebhook = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\treturn createAuthEndpoint(\n\t\t\"/stripe/webhook\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"handleStripeWebhook\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tcloneRequest: true,\n\t\t\tdisableBody: true, // Don't parse the body\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!ctx.request?.body) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.INVALID_REQUEST_BODY,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst sig = ctx.request.headers.get(\"stripe-signature\");\n\t\t\tif (!sig) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.STRIPE_SIGNATURE_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst webhookSecret = options.stripeWebhookSecret;\n\t\t\tif (!webhookSecret) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"INTERNAL_SERVER_ERROR\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.STRIPE_WEBHOOK_SECRET_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst payload = await ctx.request.text();\n\n\t\t\tlet event: Stripe.Event;\n\t\t\ttry {\n\t\t\t\t// Support both Stripe v18 (constructEvent) and v19+ (constructEventAsync)\n\t\t\t\tif (typeof client.webhooks.constructEventAsync === \"function\") {\n\t\t\t\t\t// Stripe v19+ - use async method\n\t\t\t\t\tevent = await client.webhooks.constructEventAsync(\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t\tsig,\n\t\t\t\t\t\twebhookSecret,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Stripe v18 - use sync method\n\t\t\t\t\tevent = client.webhooks.constructEvent(payload, sig, webhookSecret);\n\t\t\t\t}\n\t\t\t} catch (err: any) {\n\t\t\t\tctx.context.logger.error(`${err.message}`);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.FAILED_TO_CONSTRUCT_STRIPE_EVENT,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!event) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.FAILED_TO_CONSTRUCT_STRIPE_EVENT,\n\t\t\t\t);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tswitch (event.type) {\n\t\t\t\t\tcase \"checkout.session.completed\":\n\t\t\t\t\t\tawait onCheckoutSessionCompleted(ctx, options, event);\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"customer.subscription.created\":\n\t\t\t\t\t\tawait onSubscriptionCreated(ctx, options, event);\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"customer.subscription.updated\":\n\t\t\t\t\t\tawait onSubscriptionUpdated(ctx, options, event);\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"customer.subscription.deleted\":\n\t\t\t\t\t\tawait onSubscriptionDeleted(ctx, options, event);\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} catch (e: any) {\n\t\t\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${e.message}`);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.STRIPE_WEBHOOK_ERROR,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn ctx.json({ success: true });\n\t\t},\n\t);\n};\n","import type { BetterAuthPluginDBSchema } from \"@better-auth/core/db\";\nimport { mergeSchema } from \"better-auth/db\";\nimport type { StripeOptions } from \"./types\";\n\nexport const subscriptions = {\n\tsubscription: {\n\t\tfields: {\n\t\t\tplan: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\treferenceId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tstripeCustomerId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tstripeSubscriptionId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tstatus: {\n\t\t\t\ttype: \"string\",\n\t\t\t\tdefaultValue: \"incomplete\",\n\t\t\t},\n\t\t\tperiodStart: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tperiodEnd: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\ttrialStart: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\ttrialEnd: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tcancelAtPeriodEnd: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trequired: false,\n\t\t\t\tdefaultValue: false,\n\t\t\t},\n\t\t\tcancelAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tcanceledAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tendedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tseats: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\nexport const user = {\n\tuser: {\n\t\tfields: {\n\t\t\tstripeCustomerId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\nexport const organization = {\n\torganization: {\n\t\tfields: {\n\t\t\tstripeCustomerId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\ntype GetSchemaResult<O extends StripeOptions> = typeof user &\n\t(O[\"subscription\"] extends { enabled: true } ? typeof subscriptions : {}) &\n\t(O[\"organization\"] extends { enabled: true } ? typeof organization : {});\n\nexport const getSchema = <O extends StripeOptions>(\n\toptions: O,\n): GetSchemaResult<O> => {\n\tlet baseSchema: BetterAuthPluginDBSchema = {};\n\n\tif (options.subscription?.enabled) {\n\t\tbaseSchema = {\n\t\t\t...subscriptions,\n\t\t\t...user,\n\t\t};\n\t} else {\n\t\tbaseSchema = {\n\t\t\t...user,\n\t\t};\n\t}\n\n\tif (options.organization?.enabled) {\n\t\tbaseSchema = {\n\t\t\t...baseSchema,\n\t\t\t...organization,\n\t\t};\n\t}\n\n\tif (\n\t\toptions.schema &&\n\t\t!options.subscription?.enabled &&\n\t\t\"subscription\" in options.schema\n\t) {\n\t\tconst { subscription: _subscription, ...restSchema } = options.schema;\n\t\treturn mergeSchema(baseSchema, restSchema) as GetSchemaResult<O>;\n\t}\n\n\treturn mergeSchema(baseSchema, options.schema) as GetSchemaResult<O>;\n};\n","import type { BetterAuthPlugin, User } from \"better-auth\";\nimport { APIError } from \"better-auth\";\nimport type { Organization } from \"better-auth/plugins/organization\";\nimport { defu } from \"defu\";\nimport type Stripe from \"stripe\";\nimport { STRIPE_ERROR_CODES } from \"./error-codes\";\nimport { customerMetadata } from \"./metadata\";\nimport {\n\tcancelSubscription,\n\tcancelSubscriptionCallback,\n\tcreateBillingPortal,\n\tlistActiveSubscriptions,\n\trestoreSubscription,\n\tstripeWebhook,\n\tsubscriptionSuccess,\n\tupgradeSubscription,\n} from \"./routes\";\nimport { getSchema } from \"./schema\";\nimport type {\n\tStripeOptions,\n\tStripePlan,\n\tSubscription,\n\tSubscriptionOptions,\n\tWithStripeCustomerId,\n} from \"./types\";\nimport { escapeStripeSearchValue } from \"./utils\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\tstripe: {\n\t\t\tcreator: typeof stripe;\n\t\t};\n\t}\n}\n\nexport const stripe = <O extends StripeOptions>(options: O) => {\n\tconst client = options.stripeClient;\n\n\tconst subscriptionEndpoints = {\n\t\tupgradeSubscription: upgradeSubscription(options),\n\t\tcancelSubscriptionCallback: cancelSubscriptionCallback(options),\n\t\tcancelSubscription: cancelSubscription(options),\n\t\trestoreSubscription: restoreSubscription(options),\n\t\tlistActiveSubscriptions: listActiveSubscriptions(options),\n\t\tsubscriptionSuccess: subscriptionSuccess(options),\n\t\tcreateBillingPortal: createBillingPortal(options),\n\t};\n\n\treturn {\n\t\tid: \"stripe\",\n\t\tendpoints: {\n\t\t\tstripeWebhook: stripeWebhook(options),\n\t\t\t...((options.subscription?.enabled\n\t\t\t\t? subscriptionEndpoints\n\t\t\t\t: {}) as O[\"subscription\"] extends {\n\t\t\t\tenabled: true;\n\t\t\t}\n\t\t\t\t? typeof subscriptionEndpoints\n\t\t\t\t: {}),\n\t\t},\n\t\tinit(ctx) {\n\t\t\tif (options.organization?.enabled) {\n\t\t\t\tconst orgPlugin = ctx.getPlugin(\"organization\");\n\t\t\t\tif (!orgPlugin) {\n\t\t\t\t\tctx.logger.error(`Organization plugin not found`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst existingHooks = orgPlugin.options.organizationHooks ?? {};\n\n\t\t\t\t/**\n\t\t\t\t * Sync organization name to Stripe customer\n\t\t\t\t */\n\t\t\t\tconst afterUpdateStripeOrg = async (data: {\n\t\t\t\t\torganization: (Organization & WithStripeCustomerId) | null;\n\t\t\t\t\tuser: User;\n\t\t\t\t}) => {\n\t\t\t\t\tconst { organization } = data;\n\t\t\t\t\tif (!organization?.stripeCustomerId) return;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst stripeCustomer = await client.customers.retrieve(\n\t\t\t\t\t\t\torganization.stripeCustomerId,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (stripeCustomer.deleted) {\n\t\t\t\t\t\t\tctx.logger.warn(\n\t\t\t\t\t\t\t\t`Stripe customer ${organization.stripeCustomerId} was deleted`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Update Stripe customer if name changed\n\t\t\t\t\t\tif (organization.name !== stripeCustomer.name) {\n\t\t\t\t\t\t\tawait client.customers.update(organization.stripeCustomerId, {\n\t\t\t\t\t\t\t\tname: organization.name,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tctx.logger.info(\n\t\t\t\t\t\t\t\t`Synced organization name to Stripe: \"${stripeCustomer.name}\" → \"${organization.name}\"`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\tctx.logger.error(\n\t\t\t\t\t\t\t`Failed to sync organization to Stripe: ${e.message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t/**\n\t\t\t\t * Block deletion if organization has active subscriptions\n\t\t\t\t */\n\t\t\t\tconst beforeDeleteStripeOrg = async (data: {\n\t\t\t\t\torganization: Organization & WithStripeCustomerId;\n\t\t\t\t\tuser: User;\n\t\t\t\t}) => {\n\t\t\t\t\tconst { organization } = data;\n\t\t\t\t\tif (!organization.stripeCustomerId) return;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Check if organization has any active subscriptions\n\t\t\t\t\t\tconst subscriptions = await client.subscriptions.list({\n\t\t\t\t\t\t\tcustomer: organization.stripeCustomerId,\n\t\t\t\t\t\t\tstatus: \"all\",\n\t\t\t\t\t\t\tlimit: 100, // 1 ~ 100\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfor (const sub of subscriptions.data) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tsub.status !== \"canceled\" &&\n\t\t\t\t\t\t\t\tsub.status !== \"incomplete\" &&\n\t\t\t\t\t\t\t\tsub.status !== \"incomplete_expired\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\tif (error instanceof APIError) {\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tctx.logger.error(\n\t\t\t\t\t\t\t`Failed to check organization subscriptions: ${error.message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\torgPlugin.options.organizationHooks = {\n\t\t\t\t\t...existingHooks,\n\t\t\t\t\tafterUpdateOrganization: existingHooks.afterUpdateOrganization\n\t\t\t\t\t\t? async (data) => {\n\t\t\t\t\t\t\t\tawait existingHooks.afterUpdateOrganization!(data);\n\t\t\t\t\t\t\t\tawait afterUpdateStripeOrg(data);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: afterUpdateStripeOrg,\n\t\t\t\t\tbeforeDeleteOrganization: existingHooks.beforeDeleteOrganization\n\t\t\t\t\t\t? async (data) => {\n\t\t\t\t\t\t\t\tawait existingHooks.beforeDeleteOrganization!(data);\n\t\t\t\t\t\t\t\tawait beforeDeleteStripeOrg(data);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: beforeDeleteStripeOrg,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\toptions: {\n\t\t\t\t\tdatabaseHooks: {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync after(user: User & WithStripeCustomerId, ctx) {\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t!ctx ||\n\t\t\t\t\t\t\t\t\t\t!options.createCustomerOnSignUp ||\n\t\t\t\t\t\t\t\t\t\tuser.stripeCustomerId // Skip if user already has a Stripe customer ID\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t// Check if user customer already exists in Stripe by email\n\t\t\t\t\t\t\t\t\t\tconst existingCustomers = await client.customers.search({\n\t\t\t\t\t\t\t\t\t\t\tquery: `email:\"${escapeStripeSearchValue(user.email)}\" AND -metadata[\"${customerMetadata.keys.customerType}\"]:\"organization\"`,\n\t\t\t\t\t\t\t\t\t\t\tlimit: 1,\n\t\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t\t\tlet stripeCustomer = existingCustomers.data[0];\n\n\t\t\t\t\t\t\t\t\t\t// If user customer exists, link it to prevent duplicate creation\n\t\t\t\t\t\t\t\t\t\tif (stripeCustomer) {\n\t\t\t\t\t\t\t\t\t\t\tawait ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\tawait options.onCustomerCreate?.(\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomer,\n\t\t\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t...user,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t\t\t\t\t\t\t\t`Linked existing Stripe customer ${stripeCustomer.id} to user ${user.id}`,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Create new Stripe customer\n\t\t\t\t\t\t\t\t\t\tlet extraCreateParams: Partial<Stripe.CustomerCreateParams> =\n\t\t\t\t\t\t\t\t\t\t\t{};\n\t\t\t\t\t\t\t\t\t\tif (options.getCustomerCreateParams) {\n\t\t\t\t\t\t\t\t\t\t\textraCreateParams = await options.getCustomerCreateParams(\n\t\t\t\t\t\t\t\t\t\t\t\tuser,\n\t\t\t\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tconst params = defu(\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\t\t\t\t\t\t\tname: user.name ?? undefined,\n\t\t\t\t\t\t\t\t\t\t\t\tmetadata: customerMetadata.set(\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcustomerType: \"user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\textraCreateParams?.metadata,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\textraCreateParams,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\tstripeCustomer = await client.customers.create(params);\n\t\t\t\t\t\t\t\t\t\tawait ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\tawait options.onCustomerCreate?.(\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomer,\n\t\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t...user,\n\t\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t\t\t\t\t\t\t`Created new Stripe customer ${stripeCustomer.id} for user ${user.id}`,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\t\t\t\t\t\t`Failed to create or link Stripe customer: ${e.message}`,\n\t\t\t\t\t\t\t\t\t\t\te,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tasync after(user: User & WithStripeCustomerId, ctx) {\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t!ctx ||\n\t\t\t\t\t\t\t\t\t\t!user.stripeCustomerId // Only proceed if user has a Stripe customer ID\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t// Get the user from the database to check if email actually changed\n\t\t\t\t\t\t\t\t\t\t// The 'user' parameter here is the freshly updated user\n\t\t\t\t\t\t\t\t\t\t// We need to check if the Stripe customer's email matches\n\t\t\t\t\t\t\t\t\t\tconst stripeCustomer = await client.customers.retrieve(\n\t\t\t\t\t\t\t\t\t\t\tuser.stripeCustomerId,\n\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Check if customer was deleted\n\t\t\t\t\t\t\t\t\t\tif (stripeCustomer.deleted) {\n\t\t\t\t\t\t\t\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t\t\t\t\t\t\t\t`Stripe customer ${user.stripeCustomerId} was deleted, cannot update email`,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// If Stripe customer email doesn't match the user's current email, update it\n\t\t\t\t\t\t\t\t\t\tif (stripeCustomer.email !== user.email) {\n\t\t\t\t\t\t\t\t\t\t\tawait client.customers.update(user.stripeCustomerId, {\n\t\t\t\t\t\t\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t\t\t\t\t\t\t\t`Updated Stripe customer email from ${stripeCustomer.email} to ${user.email}`,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\t\t\t\t// Ignore errors - this is a best-effort sync\n\t\t\t\t\t\t\t\t\t\t// Email might have been deleted or Stripe customer might not exist\n\t\t\t\t\t\t\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\t\t\t\t\t\t`Failed to sync email to Stripe customer: ${e.message}`,\n\t\t\t\t\t\t\t\t\t\t\te,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tschema: getSchema(options),\n\t\toptions: options as NoInfer<O>,\n\t\t$ERROR_CODES: STRIPE_ERROR_CODES,\n\t} satisfies BetterAuthPlugin;\n};\n\nexport type StripePlugin<O extends StripeOptions> = ReturnType<\n\ttypeof stripe<O>\n>;\n\nexport type { Subscription, SubscriptionOptions, StripePlan };\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["APIError","APIError"],"sources":["../src/metadata.ts","../src/utils.ts","../src/hooks.ts","../src/middleware.ts","../src/routes.ts","../src/schema.ts","../src/index.ts"],"sourcesContent":["import { defu } from \"defu\";\nimport type Stripe from \"stripe\";\n\n/**\n * Internal metadata fields for Stripe Customer.\n */\ntype CustomerInternalMetadata =\n\t| { customerType: \"user\"; userId: string }\n\t| { customerType: \"organization\"; organizationId: string };\n\n/**\n * Internal metadata fields for Stripe Subscription/Checkout.\n */\ntype SubscriptionInternalMetadata = {\n\tuserId: string;\n\tsubscriptionId: string;\n\treferenceId: string;\n};\n\n/**\n * Customer metadata - set internal fields and extract typed fields.\n */\nexport const customerMetadata = {\n\t/**\n\t * Internal metadata keys for type-safe access.\n\t */\n\tkeys: {\n\t\tuserId: \"userId\",\n\t\torganizationId: \"organizationId\",\n\t\tcustomerType: \"customerType\",\n\t} as const,\n\n\t/**\n\t * Create metadata with internal fields that cannot be overridden by user metadata.\n\t * Uses `defu` which prioritizes the first argument.\n\t */\n\tset(\n\t\tinternalFields: CustomerInternalMetadata,\n\t\t...userMetadata: (Stripe.Emptyable<Stripe.MetadataParam> | undefined)[]\n\t): Stripe.MetadataParam {\n\t\treturn defu(internalFields, ...userMetadata.filter(Boolean));\n\t},\n\n\t/**\n\t * Extract internal fields from Stripe metadata.\n\t * Provides type-safe access to internal metadata keys.\n\t */\n\tget(metadata: Stripe.Metadata | null | undefined) {\n\t\treturn {\n\t\t\tuserId: metadata?.userId,\n\t\t\torganizationId: metadata?.organizationId,\n\t\t\tcustomerType: metadata?.customerType as\n\t\t\t\t| CustomerInternalMetadata[\"customerType\"]\n\t\t\t\t| undefined,\n\t\t};\n\t},\n};\n\n/**\n * Subscription/Checkout metadata - set internal fields and extract typed fields.\n */\nexport const subscriptionMetadata = {\n\t/**\n\t * Internal metadata keys for type-safe access.\n\t */\n\tkeys: {\n\t\tuserId: \"userId\",\n\t\tsubscriptionId: \"subscriptionId\",\n\t\treferenceId: \"referenceId\",\n\t} as const,\n\n\t/**\n\t * Create metadata with internal fields that cannot be overridden by user metadata.\n\t * Uses `defu` which prioritizes the first argument.\n\t */\n\tset(\n\t\tinternalFields: SubscriptionInternalMetadata,\n\t\t...userMetadata: (Stripe.Emptyable<Stripe.MetadataParam> | undefined)[]\n\t): Stripe.MetadataParam {\n\t\treturn defu(internalFields, ...userMetadata.filter(Boolean));\n\t},\n\n\t/**\n\t * Extract internal fields from Stripe metadata.\n\t * Provides type-safe access to internal metadata keys.\n\t */\n\tget(metadata: Stripe.Metadata | null | undefined) {\n\t\treturn {\n\t\t\tuserId: metadata?.userId,\n\t\t\tsubscriptionId: metadata?.subscriptionId,\n\t\t\treferenceId: metadata?.referenceId,\n\t\t};\n\t},\n};\n","import type Stripe from \"stripe\";\nimport type { StripeOptions, Subscription } from \"./types\";\n\nexport async function getPlans(\n\tsubscriptionOptions: StripeOptions[\"subscription\"],\n) {\n\tif (subscriptionOptions?.enabled) {\n\t\treturn typeof subscriptionOptions.plans === \"function\"\n\t\t\t? await subscriptionOptions.plans()\n\t\t\t: subscriptionOptions.plans;\n\t}\n\tthrow new Error(\"Subscriptions are not enabled in the Stripe options.\");\n}\n\nexport async function getPlanByPriceInfo(\n\toptions: StripeOptions,\n\tpriceId: string,\n\tpriceLookupKey: string | null,\n) {\n\treturn await getPlans(options.subscription).then((res) =>\n\t\tres?.find(\n\t\t\t(plan) =>\n\t\t\t\tplan.priceId === priceId ||\n\t\t\t\tplan.annualDiscountPriceId === priceId ||\n\t\t\t\t(priceLookupKey &&\n\t\t\t\t\t(plan.lookupKey === priceLookupKey ||\n\t\t\t\t\t\tplan.annualDiscountLookupKey === priceLookupKey)),\n\t\t),\n\t);\n}\n\nexport async function getPlanByName(options: StripeOptions, name: string) {\n\treturn await getPlans(options.subscription).then((res) =>\n\t\tres?.find((plan) => plan.name.toLowerCase() === name.toLowerCase()),\n\t);\n}\n\n/**\n * Checks if a subscription is in an available state (active or trialing)\n */\nexport function isActiveOrTrialing(\n\tsub: Subscription | Stripe.Subscription,\n): boolean {\n\treturn sub.status === \"active\" || sub.status === \"trialing\";\n}\n\n/**\n * Check if a subscription is scheduled to be canceled (DB subscription object)\n */\nexport function isPendingCancel(sub: Subscription): boolean {\n\treturn !!(sub.cancelAtPeriodEnd || sub.cancelAt);\n}\n\n/**\n * Check if a Stripe subscription is scheduled to be canceled (Stripe API response)\n */\nexport function isStripePendingCancel(stripeSub: Stripe.Subscription): boolean {\n\treturn !!(stripeSub.cancel_at_period_end || stripeSub.cancel_at);\n}\n\n/**\n * Escapes a value for use in Stripe search queries.\n * Stripe search query uses double quotes for string values,\n * and double quotes within the value need to be escaped with backslash.\n *\n * @see https://docs.stripe.com/search#search-query-language\n */\nexport function escapeStripeSearchValue(value: string): string {\n\treturn value.replace(/\"/g, '\\\\\"');\n}\n","import type { GenericEndpointContext } from \"@better-auth/core\";\nimport type { User } from \"@better-auth/core/db\";\nimport type { Organization } from \"better-auth/plugins/organization\";\nimport type Stripe from \"stripe\";\nimport { subscriptionMetadata } from \"./metadata\";\nimport type { CustomerType, StripeOptions, Subscription } from \"./types\";\nimport {\n\tgetPlanByPriceInfo,\n\tisActiveOrTrialing,\n\tisPendingCancel,\n\tisStripePendingCancel,\n} from \"./utils\";\n\n/**\n * Find organization or user by stripeCustomerId.\n * @internal\n */\nasync function findReferenceByStripeCustomerId(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tstripeCustomerId: string,\n): Promise<{ customerType: CustomerType; referenceId: string } | null> {\n\tif (options.organization?.enabled) {\n\t\tconst org = await ctx.context.adapter.findOne<Organization>({\n\t\t\tmodel: \"organization\",\n\t\t\twhere: [{ field: \"stripeCustomerId\", value: stripeCustomerId }],\n\t\t});\n\t\tif (org) return { customerType: \"organization\", referenceId: org.id };\n\t}\n\n\tconst user = await ctx.context.adapter.findOne<User>({\n\t\tmodel: \"user\",\n\t\twhere: [{ field: \"stripeCustomerId\", value: stripeCustomerId }],\n\t});\n\tif (user) return { customerType: \"user\", referenceId: user.id };\n\n\treturn null;\n}\n\nexport async function onCheckoutSessionCompleted(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tevent: Stripe.Event,\n) {\n\ttry {\n\t\tconst client = options.stripeClient;\n\t\tconst checkoutSession = event.data.object as Stripe.Checkout.Session;\n\t\tif (checkoutSession.mode === \"setup\" || !options.subscription?.enabled) {\n\t\t\treturn;\n\t\t}\n\t\tconst subscription = await client.subscriptions.retrieve(\n\t\t\tcheckoutSession.subscription as string,\n\t\t);\n\t\tconst subscriptionItem = subscription.items.data[0];\n\t\tif (!subscriptionItem) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: Subscription ${subscription.id} has no items`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst priceId = subscriptionItem.price.id;\n\t\tconst priceLookupKey = subscriptionItem.price.lookup_key;\n\t\tconst plan = await getPlanByPriceInfo(\n\t\t\toptions,\n\t\t\tpriceId as string,\n\t\t\tpriceLookupKey,\n\t\t);\n\t\tif (plan) {\n\t\t\tconst checkoutMeta = subscriptionMetadata.get(checkoutSession?.metadata);\n\t\t\tconst referenceId =\n\t\t\t\tcheckoutSession?.client_reference_id || checkoutMeta.referenceId;\n\t\t\tconst { subscriptionId } = checkoutMeta;\n\t\t\tconst seats = subscriptionItem.quantity;\n\t\t\tif (referenceId && subscriptionId) {\n\t\t\t\tconst trial =\n\t\t\t\t\tsubscription.trial_start && subscription.trial_end\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\ttrialStart: new Date(subscription.trial_start * 1000),\n\t\t\t\t\t\t\t\ttrialEnd: new Date(subscription.trial_end * 1000),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {};\n\n\t\t\t\tlet dbSubscription = await ctx.context.adapter.update<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\t\tstatus: subscription.status,\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\tperiodStart: new Date(subscriptionItem.current_period_start * 1000),\n\t\t\t\t\t\tperiodEnd: new Date(subscriptionItem.current_period_end * 1000),\n\t\t\t\t\t\tstripeSubscriptionId: checkoutSession.subscription as string,\n\t\t\t\t\t\tcancelAtPeriodEnd: subscription.cancel_at_period_end,\n\t\t\t\t\t\tcancelAt: subscription.cancel_at\n\t\t\t\t\t\t\t? new Date(subscription.cancel_at * 1000)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tcanceledAt: subscription.canceled_at\n\t\t\t\t\t\t\t? new Date(subscription.canceled_at * 1000)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tendedAt: subscription.ended_at\n\t\t\t\t\t\t\t? new Date(subscription.ended_at * 1000)\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\tseats: seats,\n\t\t\t\t\t\t...trial,\n\t\t\t\t\t},\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\tif (trial.trialStart && plan.freeTrial?.onTrialStart) {\n\t\t\t\t\tawait plan.freeTrial.onTrialStart(dbSubscription as Subscription);\n\t\t\t\t}\n\n\t\t\t\tif (!dbSubscription) {\n\t\t\t\t\tdbSubscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tawait options.subscription?.onSubscriptionComplete?.(\n\t\t\t\t\t{\n\t\t\t\t\t\tevent,\n\t\t\t\t\t\tsubscription: dbSubscription as Subscription,\n\t\t\t\t\t\tstripeSubscription: subscription,\n\t\t\t\t\t\tplan,\n\t\t\t\t\t},\n\t\t\t\t\tctx,\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t} catch (e: any) {\n\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${e.message}`);\n\t}\n}\n\nexport async function onSubscriptionCreated(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tevent: Stripe.Event,\n) {\n\ttry {\n\t\tif (!options.subscription?.enabled) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst subscriptionCreated = event.data.object as Stripe.Subscription;\n\t\tconst stripeCustomerId = subscriptionCreated.customer?.toString();\n\t\tif (!stripeCustomerId) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: customer.subscription.created event received without customer ID`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if subscription already exists in database\n\t\tconst { subscriptionId } = subscriptionMetadata.get(\n\t\t\tsubscriptionCreated.metadata,\n\t\t);\n\t\tconst existingSubscription =\n\t\t\tawait ctx.context.adapter.findOne<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: subscriptionId\n\t\t\t\t\t? [{ field: \"id\", value: subscriptionId }]\n\t\t\t\t\t: [{ field: \"stripeSubscriptionId\", value: subscriptionCreated.id }], // Probably won't match since it's not set yet\n\t\t\t});\n\t\tif (existingSubscription) {\n\t\t\tctx.context.logger.info(\n\t\t\t\t`Stripe webhook: Subscription already exists in database (id: ${existingSubscription.id}), skipping creation`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Find reference\n\t\tconst reference = await findReferenceByStripeCustomerId(\n\t\t\tctx,\n\t\t\toptions,\n\t\t\tstripeCustomerId,\n\t\t);\n\t\tif (!reference) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: No user or organization found with stripeCustomerId: ${stripeCustomerId}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tconst { referenceId, customerType } = reference;\n\n\t\tconst subscriptionItem = subscriptionCreated.items.data[0];\n\t\tif (!subscriptionItem) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: Subscription ${subscriptionCreated.id} has no items`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst priceId = subscriptionItem.price.id;\n\t\tconst priceLookupKey = subscriptionItem.price.lookup_key || null;\n\t\tconst plan = await getPlanByPriceInfo(options, priceId, priceLookupKey);\n\t\tif (!plan) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: No matching plan found for priceId: ${priceId}`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst seats = subscriptionItem.quantity;\n\t\tconst periodStart = new Date(subscriptionItem.current_period_start * 1000);\n\t\tconst periodEnd = new Date(subscriptionItem.current_period_end * 1000);\n\n\t\tconst trial =\n\t\t\tsubscriptionCreated.trial_start && subscriptionCreated.trial_end\n\t\t\t\t? {\n\t\t\t\t\t\ttrialStart: new Date(subscriptionCreated.trial_start * 1000),\n\t\t\t\t\t\ttrialEnd: new Date(subscriptionCreated.trial_end * 1000),\n\t\t\t\t\t}\n\t\t\t\t: {};\n\n\t\t// Create the subscription in the database\n\t\tconst newSubscription = await ctx.context.adapter.create<Subscription>({\n\t\t\tmodel: \"subscription\",\n\t\t\tdata: {\n\t\t\t\treferenceId,\n\t\t\t\tstripeCustomerId,\n\t\t\t\tstripeSubscriptionId: subscriptionCreated.id,\n\t\t\t\tstatus: subscriptionCreated.status,\n\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\tperiodStart,\n\t\t\t\tperiodEnd,\n\t\t\t\tseats,\n\t\t\t\t...(plan.limits ? { limits: plan.limits } : {}),\n\t\t\t\t...trial,\n\t\t\t},\n\t\t});\n\n\t\tctx.context.logger.info(\n\t\t\t`Stripe webhook: Created subscription ${subscriptionCreated.id} for ${customerType} ${referenceId} from dashboard`,\n\t\t);\n\n\t\tawait options.subscription.onSubscriptionCreated?.({\n\t\t\tevent,\n\t\t\tsubscription: newSubscription,\n\t\t\tstripeSubscription: subscriptionCreated,\n\t\t\tplan,\n\t\t});\n\t} catch (error: any) {\n\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${error}`);\n\t}\n}\n\nexport async function onSubscriptionUpdated(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tevent: Stripe.Event,\n) {\n\ttry {\n\t\tif (!options.subscription?.enabled) {\n\t\t\treturn;\n\t\t}\n\t\tconst subscriptionUpdated = event.data.object as Stripe.Subscription;\n\t\tconst subscriptionItem = subscriptionUpdated.items.data[0];\n\t\tif (!subscriptionItem) {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook warning: Subscription ${subscriptionUpdated.id} has no items`,\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tconst priceId = subscriptionItem.price.id;\n\t\tconst priceLookupKey = subscriptionItem.price.lookup_key;\n\t\tconst plan = await getPlanByPriceInfo(options, priceId, priceLookupKey);\n\n\t\tconst { subscriptionId } = subscriptionMetadata.get(\n\t\t\tsubscriptionUpdated.metadata,\n\t\t);\n\t\tconst customerId = subscriptionUpdated.customer?.toString();\n\t\tlet subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\tmodel: \"subscription\",\n\t\t\twhere: subscriptionId\n\t\t\t\t? [{ field: \"id\", value: subscriptionId }]\n\t\t\t\t: [{ field: \"stripeSubscriptionId\", value: subscriptionUpdated.id }],\n\t\t});\n\t\tif (!subscription) {\n\t\t\tconst subs = await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [{ field: \"stripeCustomerId\", value: customerId }],\n\t\t\t});\n\t\t\tif (subs.length > 1) {\n\t\t\t\tconst activeSub = subs.find((sub: Subscription) =>\n\t\t\t\t\tisActiveOrTrialing(sub),\n\t\t\t\t);\n\t\t\t\tif (!activeSub) {\n\t\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t\t`Stripe webhook error: Multiple subscriptions found for customerId: ${customerId} and no active subscription is found`,\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tsubscription = activeSub;\n\t\t\t} else {\n\t\t\t\tsubscription = subs[0]!;\n\t\t\t}\n\t\t}\n\n\t\tconst updatedSubscription = await ctx.context.adapter.update<Subscription>({\n\t\t\tmodel: \"subscription\",\n\t\t\tupdate: {\n\t\t\t\t...(plan\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\t\t\tlimits: plan.limits,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t\tstatus: subscriptionUpdated.status,\n\t\t\t\tperiodStart: new Date(subscriptionItem.current_period_start * 1000),\n\t\t\t\tperiodEnd: new Date(subscriptionItem.current_period_end * 1000),\n\t\t\t\tcancelAtPeriodEnd: subscriptionUpdated.cancel_at_period_end,\n\t\t\t\tcancelAt: subscriptionUpdated.cancel_at\n\t\t\t\t\t? new Date(subscriptionUpdated.cancel_at * 1000)\n\t\t\t\t\t: null,\n\t\t\t\tcanceledAt: subscriptionUpdated.canceled_at\n\t\t\t\t\t? new Date(subscriptionUpdated.canceled_at * 1000)\n\t\t\t\t\t: null,\n\t\t\t\tendedAt: subscriptionUpdated.ended_at\n\t\t\t\t\t? new Date(subscriptionUpdated.ended_at * 1000)\n\t\t\t\t\t: null,\n\t\t\t\tseats: subscriptionItem.quantity,\n\t\t\t\tstripeSubscriptionId: subscriptionUpdated.id,\n\t\t\t},\n\t\t\twhere: [\n\t\t\t\t{\n\t\t\t\t\tfield: \"id\",\n\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t\tconst isNewCancellation =\n\t\t\tsubscriptionUpdated.status === \"active\" &&\n\t\t\tisStripePendingCancel(subscriptionUpdated) &&\n\t\t\t!isPendingCancel(subscription);\n\t\tif (isNewCancellation) {\n\t\t\tawait options.subscription.onSubscriptionCancel?.({\n\t\t\t\tsubscription,\n\t\t\t\tcancellationDetails:\n\t\t\t\t\tsubscriptionUpdated.cancellation_details || undefined,\n\t\t\t\tstripeSubscription: subscriptionUpdated,\n\t\t\t\tevent,\n\t\t\t});\n\t\t}\n\t\tawait options.subscription.onSubscriptionUpdate?.({\n\t\t\tevent,\n\t\t\tsubscription: updatedSubscription || subscription,\n\t\t});\n\t\tif (plan) {\n\t\t\tif (\n\t\t\t\tsubscriptionUpdated.status === \"active\" &&\n\t\t\t\tsubscription.status === \"trialing\" &&\n\t\t\t\tplan.freeTrial?.onTrialEnd\n\t\t\t) {\n\t\t\t\tawait plan.freeTrial.onTrialEnd({ subscription }, ctx);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tsubscriptionUpdated.status === \"incomplete_expired\" &&\n\t\t\t\tsubscription.status === \"trialing\" &&\n\t\t\t\tplan.freeTrial?.onTrialExpired\n\t\t\t) {\n\t\t\t\tawait plan.freeTrial.onTrialExpired(subscription, ctx);\n\t\t\t}\n\t\t}\n\t} catch (error: any) {\n\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${error}`);\n\t}\n}\n\nexport async function onSubscriptionDeleted(\n\tctx: GenericEndpointContext,\n\toptions: StripeOptions,\n\tevent: Stripe.Event,\n) {\n\tif (!options.subscription?.enabled) {\n\t\treturn;\n\t}\n\ttry {\n\t\tconst subscriptionDeleted = event.data.object as Stripe.Subscription;\n\t\tconst subscriptionId = subscriptionDeleted.id;\n\t\tconst subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\tmodel: \"subscription\",\n\t\t\twhere: [\n\t\t\t\t{\n\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\t\tif (subscription) {\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tupdate: {\n\t\t\t\t\tstatus: \"canceled\",\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\tcancelAtPeriodEnd: subscriptionDeleted.cancel_at_period_end,\n\t\t\t\t\tcancelAt: subscriptionDeleted.cancel_at\n\t\t\t\t\t\t? new Date(subscriptionDeleted.cancel_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tcanceledAt: subscriptionDeleted.canceled_at\n\t\t\t\t\t\t? new Date(subscriptionDeleted.canceled_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tendedAt: subscriptionDeleted.ended_at\n\t\t\t\t\t\t? new Date(subscriptionDeleted.ended_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t},\n\t\t\t});\n\t\t\tawait options.subscription.onSubscriptionDeleted?.({\n\t\t\t\tevent,\n\t\t\t\tstripeSubscription: subscriptionDeleted,\n\t\t\t\tsubscription,\n\t\t\t});\n\t\t} else {\n\t\t\tctx.context.logger.warn(\n\t\t\t\t`Stripe webhook error: Subscription not found for subscriptionId: ${subscriptionId}`,\n\t\t\t);\n\t\t}\n\t} catch (error: any) {\n\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${error}`);\n\t}\n}\n","import { createAuthMiddleware } from \"@better-auth/core/api\";\nimport { APIError } from \"@better-auth/core/error\";\nimport { sessionMiddleware } from \"better-auth/api\";\nimport { STRIPE_ERROR_CODES } from \"./error-codes\";\nimport type {\n\tAuthorizeReferenceAction,\n\tCustomerType,\n\tStripeCtxSession,\n\tSubscriptionOptions,\n} from \"./types\";\n\nexport const stripeSessionMiddleware = createAuthMiddleware(\n\t{\n\t\tuse: [sessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst session = ctx.context.session as StripeCtxSession;\n\t\treturn {\n\t\t\tsession,\n\t\t};\n\t},\n);\n\nexport const referenceMiddleware = (\n\tsubscriptionOptions: SubscriptionOptions,\n\taction: AuthorizeReferenceAction,\n) =>\n\tcreateAuthMiddleware(async (ctx) => {\n\t\tconst ctxSession = ctx.context.session as StripeCtxSession;\n\t\tif (!ctxSession) {\n\t\t\tthrow APIError.from(\"UNAUTHORIZED\", STRIPE_ERROR_CODES.UNAUTHORIZED);\n\t\t}\n\n\t\tconst customerType: CustomerType =\n\t\t\tctx.body?.customerType || ctx.query?.customerType;\n\t\tconst explicitReferenceId = ctx.body?.referenceId || ctx.query?.referenceId;\n\n\t\tif (customerType === \"organization\") {\n\t\t\t// Organization subscriptions always require authorizeReference\n\t\t\tif (!subscriptionOptions.authorizeReference) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t`Organization subscriptions require authorizeReference to be defined in your stripe plugin config.`,\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.AUTHORIZE_REFERENCE_REQUIRED,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst referenceId =\n\t\t\t\texplicitReferenceId || ctxSession.session.activeOrganizationId;\n\t\t\tif (!referenceId) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_REFERENCE_ID_REQUIRED,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst isAuthorized = await subscriptionOptions.authorizeReference(\n\t\t\t\t{\n\t\t\t\t\tuser: ctxSession.user,\n\t\t\t\t\tsession: ctxSession.session,\n\t\t\t\t\treferenceId,\n\t\t\t\t\taction,\n\t\t\t\t},\n\t\t\t\tctx,\n\t\t\t);\n\t\t\tif (!isAuthorized) {\n\t\t\t\tthrow APIError.from(\"UNAUTHORIZED\", STRIPE_ERROR_CODES.UNAUTHORIZED);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// User subscriptions - pass if no explicit referenceId\n\t\tif (!explicitReferenceId) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Pass if referenceId is user id\n\t\tif (explicitReferenceId === ctxSession.user.id) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (!subscriptionOptions.authorizeReference) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t`Passing referenceId into a subscription action isn't allowed if subscription.authorizeReference isn't defined in your stripe plugin config.`,\n\t\t\t);\n\t\t\tthrow APIError.from(\n\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\tSTRIPE_ERROR_CODES.REFERENCE_ID_NOT_ALLOWED,\n\t\t\t);\n\t\t}\n\t\tconst isAuthorized = await subscriptionOptions.authorizeReference(\n\t\t\t{\n\t\t\t\tuser: ctxSession.user,\n\t\t\t\tsession: ctxSession.session,\n\t\t\t\treferenceId: explicitReferenceId,\n\t\t\t\taction,\n\t\t\t},\n\t\t\tctx,\n\t\t);\n\t\tif (!isAuthorized) {\n\t\t\tthrow APIError.from(\"UNAUTHORIZED\", STRIPE_ERROR_CODES.UNAUTHORIZED);\n\t\t}\n\t});\n","import { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { APIError } from \"@better-auth/core/error\";\nimport type { GenericEndpointContext, User } from \"better-auth\";\nimport { HIDE_METADATA } from \"better-auth\";\nimport { getSessionFromCtx, originCheck } from \"better-auth/api\";\nimport type { Organization } from \"better-auth/plugins/organization\";\nimport { defu } from \"defu\";\nimport type Stripe from \"stripe\";\nimport type { Stripe as StripeType } from \"stripe\";\nimport * as z from \"zod/v4\";\nimport { STRIPE_ERROR_CODES } from \"./error-codes\";\nimport {\n\tonCheckoutSessionCompleted,\n\tonSubscriptionCreated,\n\tonSubscriptionDeleted,\n\tonSubscriptionUpdated,\n} from \"./hooks\";\nimport { customerMetadata, subscriptionMetadata } from \"./metadata\";\nimport { referenceMiddleware, stripeSessionMiddleware } from \"./middleware\";\nimport type {\n\tCustomerType,\n\tStripeCtxSession,\n\tStripeOptions,\n\tSubscription,\n\tSubscriptionOptions,\n\tWithStripeCustomerId,\n} from \"./types\";\nimport {\n\tescapeStripeSearchValue,\n\tgetPlanByName,\n\tgetPlanByPriceInfo,\n\tgetPlans,\n\tisActiveOrTrialing,\n\tisPendingCancel,\n\tisStripePendingCancel,\n} from \"./utils\";\n\n/**\n * Converts a relative URL to an absolute URL using baseURL.\n * @internal\n */\nfunction getUrl(ctx: GenericEndpointContext, url: string) {\n\tif (/^[a-zA-Z][a-zA-Z0-9+\\-.]*:/.test(url)) {\n\t\treturn url;\n\t}\n\treturn `${ctx.context.options.baseURL}${\n\t\turl.startsWith(\"/\") ? url : `/${url}`\n\t}`;\n}\n\n/**\n * Resolves a Stripe price ID from a lookup key.\n * @internal\n */\nasync function resolvePriceIdFromLookupKey(\n\tstripeClient: Stripe,\n\tlookupKey: string,\n): Promise<string | undefined> {\n\tif (!lookupKey) return undefined;\n\tconst prices = await stripeClient.prices.list({\n\t\tlookup_keys: [lookupKey],\n\t\tactive: true,\n\t\tlimit: 1,\n\t});\n\treturn prices.data[0]?.id;\n}\n\n/**\n * Determines the reference ID based on customer type.\n * - `user` (default): uses userId\n * - `organization`: uses activeOrganizationId from session\n * @internal\n */\nfunction getReferenceId(\n\tctxSession: StripeCtxSession,\n\tcustomerType: CustomerType | undefined,\n\toptions: StripeOptions,\n): string {\n\tconst { user, session } = ctxSession;\n\tconst type = customerType || \"user\";\n\n\tif (type === \"organization\") {\n\t\tif (!options.organization?.enabled) {\n\t\t\tthrow APIError.from(\n\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_SUBSCRIPTION_NOT_ENABLED,\n\t\t\t);\n\t\t}\n\n\t\tif (!session.activeOrganizationId) {\n\t\t\tthrow APIError.from(\n\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_NOT_FOUND,\n\t\t\t);\n\t\t}\n\t\treturn session.activeOrganizationId;\n\t}\n\n\treturn user.id;\n}\n\nconst upgradeSubscriptionBodySchema = z.object({\n\t/**\n\t * The name of the plan to subscribe\n\t */\n\tplan: z.string().meta({\n\t\tdescription: 'The name of the plan to upgrade to. Eg: \"pro\"',\n\t}),\n\t/**\n\t * If annual plan should be applied.\n\t */\n\tannual: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription: \"Whether to upgrade to an annual plan. Eg: true\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Reference ID for the subscription based on customerType:\n\t * - `user`: defaults to `user.id`\n\t * - `organization`: defaults to `session.activeOrganizationId`\n\t */\n\treferenceId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: 'Reference ID for the subscription. Eg: \"org_123\"',\n\t\t})\n\t\t.optional(),\n\t/**\n\t * The Stripe subscription ID to upgrade.\n\t * If provided and not found, it'll throw an error.\n\t */\n\tsubscriptionId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'The Stripe subscription ID to upgrade. Eg: \"sub_1ABC2DEF3GHI4JKL\"',\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Customer type for the subscription.\n\t * - `user`: User owns the subscription (default)\n\t * - `organization`: Organization owns the subscription (requires referenceId)\n\t */\n\tcustomerType: z\n\t\t.enum([\"user\", \"organization\"])\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Additional metadata to store with the subscription.\n\t */\n\tmetadata: z.record(z.string(), z.any()).optional(),\n\t/**\n\t * Number of seats for subscriptions.\n\t */\n\tseats: z\n\t\t.number()\n\t\t.meta({\n\t\t\tdescription: \"Number of seats to upgrade to (if applicable). Eg: 1\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * The IETF language tag of the locale Checkout is displayed in.\n\t * If not provided or set to `auto`, the browser's locale is used.\n\t */\n\tlocale: z\n\t\t.custom<StripeType.Checkout.Session.Locale>((localization) => {\n\t\t\treturn typeof localization === \"string\";\n\t\t})\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"The locale to display Checkout in. Eg: 'en', 'ko'. If not provided or set to `auto`, the browser's locale is used.\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * The URL to which Stripe should send customers when payment or setup is complete.\n\t */\n\tsuccessUrl: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Callback URL to redirect back after successful subscription. Eg: \"https://example.com/success\"',\n\t\t})\n\t\t.default(\"/\"),\n\t/**\n\t * If set, checkout shows a back button and customers will be directed here if they cancel payment.\n\t */\n\tcancelUrl: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'If set, checkout shows a back button and customers will be directed here if they cancel payment. Eg: \"https://example.com/pricing\"',\n\t\t})\n\t\t.default(\"/\"),\n\t/**\n\t * The URL to return to from the Billing Portal (used when upgrading existing subscriptions)\n\t */\n\treturnUrl: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'URL to take customers to when they click on the billing portal’s link to return to your website. Eg: \"https://example.com/dashboard\"',\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Disable Redirect\n\t */\n\tdisableRedirect: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription: \"Disable redirect after successful subscription. Eg: true\",\n\t\t})\n\t\t.default(false),\n});\n\n/**\n * ### Endpoint\n *\n * POST `/subscription/upgrade`\n *\n * ### API Methods\n *\n * **server:**\n * `auth.api.upgradeSubscription`\n *\n * **client:**\n * `authClient.subscription.upgrade`\n *\n * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/stripe#api-method-subscription-upgrade)\n */\nexport const upgradeSubscription = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\n\treturn createAuthEndpoint(\n\t\t\"/subscription/upgrade\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: upgradeSubscriptionBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"upgradeSubscription\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"upgrade-subscription\"),\n\t\t\t\toriginCheck((c) => {\n\t\t\t\t\treturn [c.body.successUrl as string, c.body.cancelUrl as string];\n\t\t\t\t}),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { user, session } = ctx.context.session;\n\t\t\tconst customerType = ctx.body.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.body.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tif (!user.emailVerified && subscriptionOptions.requireEmailVerification) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst plan = await getPlanByName(options, ctx.body.plan);\n\t\t\tif (!plan) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// If subscriptionId is provided, find that specific subscription.\n\t\t\t// Otherwise, active subscription will be resolved by referenceId later.\n\t\t\tconst subscriptionToUpdate = ctx.body.subscriptionId\n\t\t\t\t? await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\t\t\t\tvalue: ctx.body.subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t})\n\t\t\t\t: null;\n\t\t\tif (ctx.body.subscriptionId && !subscriptionToUpdate) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tctx.body.subscriptionId &&\n\t\t\t\tsubscriptionToUpdate &&\n\t\t\t\tsubscriptionToUpdate.referenceId !== referenceId\n\t\t\t) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Determine customer id\n\t\t\tlet customerId: string | undefined;\n\t\t\tif (customerType === \"organization\") {\n\t\t\t\t// Organization subscription - get customer ID from organization\n\t\t\t\tcustomerId = subscriptionToUpdate?.stripeCustomerId;\n\t\t\t\tif (!customerId) {\n\t\t\t\t\tconst org = await ctx.context.adapter.findOne<\n\t\t\t\t\t\tOrganization & WithStripeCustomerId\n\t\t\t\t\t>({\n\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\tif (!org) {\n\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_NOT_FOUND,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tcustomerId = org.stripeCustomerId;\n\n\t\t\t\t\t// If org doesn't have a customer ID, create one\n\t\t\t\t\tif (!customerId) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t// First, search for existing organization customer by organizationId\n\t\t\t\t\t\t\tconst existingOrgCustomers = await client.customers.search({\n\t\t\t\t\t\t\t\tquery: `metadata[\"${customerMetadata.keys.organizationId}\"]:\"${org.id}\"`,\n\t\t\t\t\t\t\t\tlimit: 1,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tlet stripeCustomer = existingOrgCustomers.data[0];\n\n\t\t\t\t\t\t\tif (!stripeCustomer) {\n\t\t\t\t\t\t\t\t// Get custom params if provided\n\t\t\t\t\t\t\t\tlet extraCreateParams: Partial<StripeType.CustomerCreateParams> =\n\t\t\t\t\t\t\t\t\t{};\n\t\t\t\t\t\t\t\tif (options.organization?.getCustomerCreateParams) {\n\t\t\t\t\t\t\t\t\textraCreateParams =\n\t\t\t\t\t\t\t\t\t\tawait options.organization.getCustomerCreateParams(\n\t\t\t\t\t\t\t\t\t\t\torg,\n\t\t\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Create Stripe customer for organization\n\t\t\t\t\t\t\t\t// Email can be set via getCustomerCreateParams or updated in billing portal\n\t\t\t\t\t\t\t\t// Use defu to merge params (first argument takes priority)\n\t\t\t\t\t\t\t\tconst customerParams = defu(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tname: org.name,\n\t\t\t\t\t\t\t\t\t\tmetadata: customerMetadata.set(\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\torganizationId: org.id,\n\t\t\t\t\t\t\t\t\t\t\t\tcustomerType: \"organization\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tctx.body.metadata,\n\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\textraCreateParams,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tstripeCustomer = await client.customers.create(customerParams);\n\n\t\t\t\t\t\t\t\t// Call onCustomerCreate callback only for newly created customers\n\t\t\t\t\t\t\t\tawait options.organization?.onCustomerCreate?.(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tstripeCustomer,\n\t\t\t\t\t\t\t\t\t\torganization: {\n\t\t\t\t\t\t\t\t\t\t\t...org,\n\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\t\tvalue: org.id,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tcustomerId = stripeCustomer.id;\n\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\tctx.context.logger.error(e);\n\t\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\t\tSTRIPE_ERROR_CODES.UNABLE_TO_CREATE_CUSTOMER,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// User subscription - get customer ID from user\n\t\t\t\tcustomerId =\n\t\t\t\t\tsubscriptionToUpdate?.stripeCustomerId || user.stripeCustomerId;\n\t\t\t\tif (!customerId) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Try to find existing user Stripe customer by email\n\t\t\t\t\t\tconst existingCustomers = await client.customers.search({\n\t\t\t\t\t\t\tquery: `email:\"${escapeStripeSearchValue(user.email)}\" AND -metadata[\"${customerMetadata.keys.customerType}\"]:\"organization\"`,\n\t\t\t\t\t\t\tlimit: 1,\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tlet stripeCustomer = existingCustomers.data[0];\n\n\t\t\t\t\t\tif (!stripeCustomer) {\n\t\t\t\t\t\t\tstripeCustomer = await client.customers.create({\n\t\t\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\t\t\tname: user.name,\n\t\t\t\t\t\t\t\tmetadata: customerMetadata.set(\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t\t\t\t\tcustomerType: \"user\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tctx.body.metadata,\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Update local DB with Stripe customer ID\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"user\",\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\tvalue: user.id,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tcustomerId = stripeCustomer.id;\n\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\tctx.context.logger.error(e);\n\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\tSTRIPE_ERROR_CODES.UNABLE_TO_CREATE_CUSTOMER,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst subscriptions = subscriptionToUpdate\n\t\t\t\t? [subscriptionToUpdate]\n\t\t\t\t: await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\n\t\t\tconst activeOrTrialingSubscription = subscriptions.find((sub) =>\n\t\t\t\tisActiveOrTrialing(sub),\n\t\t\t);\n\n\t\t\tconst activeSubscriptions = await client.subscriptions\n\t\t\t\t.list({\n\t\t\t\t\tcustomer: customerId,\n\t\t\t\t})\n\t\t\t\t.then((res) => res.data.filter((sub) => isActiveOrTrialing(sub)));\n\n\t\t\tconst activeSubscription = activeSubscriptions.find((sub) => {\n\t\t\t\t// If we have a specific subscription to update, match by ID\n\t\t\t\tif (\n\t\t\t\t\tsubscriptionToUpdate?.stripeSubscriptionId ||\n\t\t\t\t\tctx.body.subscriptionId\n\t\t\t\t) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tsub.id === subscriptionToUpdate?.stripeSubscriptionId ||\n\t\t\t\t\t\tsub.id === ctx.body.subscriptionId\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// Only find subscription for the same referenceId to avoid mixing personal and org subscriptions\n\t\t\t\tif (activeOrTrialingSubscription?.stripeSubscriptionId) {\n\t\t\t\t\treturn sub.id === activeOrTrialingSubscription.stripeSubscriptionId;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t});\n\n\t\t\t// Get the current price ID from the active Stripe subscription\n\t\t\tconst stripeSubscriptionPriceId =\n\t\t\t\tactiveSubscription?.items.data[0]?.price.id;\n\n\t\t\t// Also find any incomplete subscription that we can reuse\n\t\t\tconst incompleteSubscription = subscriptions.find(\n\t\t\t\t(sub) => sub.status === \"incomplete\",\n\t\t\t);\n\n\t\t\tconst priceId = ctx.body.annual\n\t\t\t\t? plan.annualDiscountPriceId\n\t\t\t\t: plan.priceId;\n\t\t\tconst lookupKey = ctx.body.annual\n\t\t\t\t? plan.annualDiscountLookupKey\n\t\t\t\t: plan.lookupKey;\n\t\t\tconst resolvedPriceId = lookupKey\n\t\t\t\t? await resolvePriceIdFromLookupKey(client, lookupKey)\n\t\t\t\t: undefined;\n\n\t\t\tconst priceIdToUse = priceId || resolvedPriceId;\n\t\t\tif (!priceIdToUse) {\n\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Price ID not found for the selected plan\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst isSamePlan = activeOrTrialingSubscription?.plan === ctx.body.plan;\n\t\t\tconst isSameSeats =\n\t\t\t\tactiveOrTrialingSubscription?.seats === (ctx.body.seats || 1);\n\t\t\tconst isSamePriceId = stripeSubscriptionPriceId === priceIdToUse;\n\t\t\tconst isSubscriptionStillValid =\n\t\t\t\t!activeOrTrialingSubscription?.periodEnd ||\n\t\t\t\tactiveOrTrialingSubscription.periodEnd > new Date();\n\n\t\t\tconst isAlreadySubscribed =\n\t\t\t\tactiveOrTrialingSubscription?.status === \"active\" &&\n\t\t\t\tisSamePlan &&\n\t\t\t\tisSameSeats &&\n\t\t\t\tisSamePriceId &&\n\t\t\t\tisSubscriptionStillValid;\n\t\t\tif (isAlreadySubscribed) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.ALREADY_SUBSCRIBED_PLAN,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (activeSubscription && customerId) {\n\t\t\t\t// Find the corresponding database subscription for this Stripe subscription\n\t\t\t\tlet dbSubscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\t\t\tvalue: activeSubscription.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\n\t\t\t\t// If no database record exists for this Stripe subscription, update the existing one\n\t\t\t\tif (!dbSubscription && activeOrTrialingSubscription) {\n\t\t\t\t\tawait ctx.context.adapter.update<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\tstripeSubscriptionId: activeSubscription.id,\n\t\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t\t},\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: activeOrTrialingSubscription.id,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\tdbSubscription = activeOrTrialingSubscription;\n\t\t\t\t}\n\n\t\t\t\tconst { url } = await client.billingPortal.sessions\n\t\t\t\t\t.create({\n\t\t\t\t\t\tcustomer: customerId,\n\t\t\t\t\t\treturn_url: getUrl(ctx, ctx.body.returnUrl || \"/\"),\n\t\t\t\t\t\tflow_data: {\n\t\t\t\t\t\t\ttype: \"subscription_update_confirm\",\n\t\t\t\t\t\t\tafter_completion: {\n\t\t\t\t\t\t\t\ttype: \"redirect\",\n\t\t\t\t\t\t\t\tredirect: {\n\t\t\t\t\t\t\t\t\treturn_url: getUrl(ctx, ctx.body.returnUrl || \"/\"),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tsubscription_update_confirm: {\n\t\t\t\t\t\t\t\tsubscription: activeSubscription.id,\n\t\t\t\t\t\t\t\titems: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tid: activeSubscription.items.data[0]?.id as string,\n\t\t\t\t\t\t\t\t\t\tquantity: ctx.body.seats || 1,\n\t\t\t\t\t\t\t\t\t\tprice: priceIdToUse,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\t.catch(async (e) => {\n\t\t\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\treturn ctx.json({\n\t\t\t\t\turl,\n\t\t\t\t\tredirect: !ctx.body.disableRedirect,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tlet subscription: Subscription | undefined =\n\t\t\t\tactiveOrTrialingSubscription || incompleteSubscription;\n\n\t\t\tif (incompleteSubscription && !activeOrTrialingSubscription) {\n\t\t\t\tconst updated = await ctx.context.adapter.update<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\tupdate: {\n\t\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\t\tseats: ctx.body.seats || 1,\n\t\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t\t},\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\tvalue: incompleteSubscription.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tsubscription = (updated as Subscription) || incompleteSubscription;\n\t\t\t}\n\n\t\t\tif (!subscription) {\n\t\t\t\tsubscription = await ctx.context.adapter.create<Subscription>({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\tdata: {\n\t\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\t\tstripeCustomerId: customerId,\n\t\t\t\t\t\tstatus: \"incomplete\",\n\t\t\t\t\t\treferenceId,\n\t\t\t\t\t\tseats: ctx.body.seats || 1,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (!subscription) {\n\t\t\t\tctx.context.logger.error(\"Subscription ID not found\");\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"NOT_FOUND\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst params = await subscriptionOptions.getCheckoutSessionParams?.(\n\t\t\t\t{\n\t\t\t\t\tuser,\n\t\t\t\t\tsession,\n\t\t\t\t\tplan,\n\t\t\t\t\tsubscription,\n\t\t\t\t},\n\t\t\t\tctx.request,\n\t\t\t\tctx,\n\t\t\t);\n\n\t\t\tconst allSubscriptions = await ctx.context.adapter.findMany<Subscription>(\n\t\t\t\t{\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\twhere: [{ field: \"referenceId\", value: referenceId }],\n\t\t\t\t},\n\t\t\t);\n\t\t\tconst hasEverTrialed = allSubscriptions.some((s) => {\n\t\t\t\t// Check if user has ever had a trial for any plan (not just the same plan)\n\t\t\t\t// This prevents users from getting multiple trials by switching plans\n\t\t\t\tconst hadTrial =\n\t\t\t\t\t!!(s.trialStart || s.trialEnd) || s.status === \"trialing\";\n\t\t\t\treturn hadTrial;\n\t\t\t});\n\n\t\t\tconst freeTrial =\n\t\t\t\t!hasEverTrialed && plan.freeTrial\n\t\t\t\t\t? { trial_period_days: plan.freeTrial.days }\n\t\t\t\t\t: undefined;\n\n\t\t\tconst checkoutSession = await client.checkout.sessions\n\t\t\t\t.create(\n\t\t\t\t\t{\n\t\t\t\t\t\t...(customerId\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tcustomer: customerId,\n\t\t\t\t\t\t\t\t\tcustomer_update:\n\t\t\t\t\t\t\t\t\t\tcustomerType !== \"user\"\n\t\t\t\t\t\t\t\t\t\t\t? ({ address: \"auto\" } as const)\n\t\t\t\t\t\t\t\t\t\t\t: ({ name: \"auto\", address: \"auto\" } as const), // The customer name is automatically set only for users\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\tcustomer_email: user.email,\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\tlocale: ctx.body.locale,\n\t\t\t\t\t\tsuccess_url: getUrl(\n\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t`${\n\t\t\t\t\t\t\t\tctx.context.baseURL\n\t\t\t\t\t\t\t}/subscription/success?callbackURL=${encodeURIComponent(\n\t\t\t\t\t\t\t\tctx.body.successUrl,\n\t\t\t\t\t\t\t)}&subscriptionId=${encodeURIComponent(subscription.id)}`,\n\t\t\t\t\t\t),\n\t\t\t\t\t\tcancel_url: getUrl(ctx, ctx.body.cancelUrl),\n\t\t\t\t\t\tline_items: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tprice: priceIdToUse,\n\t\t\t\t\t\t\t\tquantity: ctx.body.seats || 1,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t\tsubscription_data: {\n\t\t\t\t\t\t\t...freeTrial,\n\t\t\t\t\t\t\tmetadata: subscriptionMetadata.set(\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\t\t\t\t\treferenceId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tctx.body.metadata,\n\t\t\t\t\t\t\t\tparams?.params?.subscription_data?.metadata,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmode: \"subscription\",\n\t\t\t\t\t\tclient_reference_id: referenceId,\n\t\t\t\t\t\t...params?.params,\n\t\t\t\t\t\t// metadata should come after spread to protect internal fields\n\t\t\t\t\t\tmetadata: subscriptionMetadata.set(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t\t\tsubscriptionId: subscription.id,\n\t\t\t\t\t\t\t\treferenceId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tctx.body.metadata,\n\t\t\t\t\t\t\tparams?.params?.metadata,\n\t\t\t\t\t\t),\n\t\t\t\t\t},\n\t\t\t\t\tparams?.options,\n\t\t\t\t)\n\t\t\t\t.catch(async (e) => {\n\t\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\t...checkoutSession,\n\t\t\t\tredirect: !ctx.body.disableRedirect,\n\t\t\t});\n\t\t},\n\t);\n};\n\nconst cancelSubscriptionCallbackQuerySchema = z\n\t.record(z.string(), z.any())\n\t.optional();\n\nexport const cancelSubscriptionCallback = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/cancel/callback\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: cancelSubscriptionCallbackQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"cancelSubscriptionCallback\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || \"/\"));\n\t\t\t}\n\t\t\tconst session = await getSessionFromCtx<User & WithStripeCustomerId>(ctx);\n\t\t\tif (!session) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || \"/\"));\n\t\t\t}\n\t\t\tconst { user } = session;\n\t\t\tconst { callbackURL, subscriptionId } = ctx.query;\n\n\t\t\tif (user?.stripeCustomerId) {\n\t\t\t\ttry {\n\t\t\t\t\tconst subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t});\n\t\t\t\t\tif (\n\t\t\t\t\t\t!subscription ||\n\t\t\t\t\t\tsubscription.status === \"canceled\" ||\n\t\t\t\t\t\tisPendingCancel(subscription)\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t\t\t}\n\n\t\t\t\t\tconst stripeSubscription = await client.subscriptions.list({\n\t\t\t\t\t\tcustomer: user.stripeCustomerId,\n\t\t\t\t\t\tstatus: \"active\",\n\t\t\t\t\t});\n\t\t\t\t\tconst currentSubscription = stripeSubscription.data.find(\n\t\t\t\t\t\t(sub) => sub.id === subscription.stripeSubscriptionId,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst isNewCancellation =\n\t\t\t\t\t\tcurrentSubscription &&\n\t\t\t\t\t\tisStripePendingCancel(currentSubscription) &&\n\t\t\t\t\t\t!isPendingCancel(subscription);\n\t\t\t\t\tif (isNewCancellation) {\n\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tstatus: currentSubscription?.status,\n\t\t\t\t\t\t\t\tcancelAtPeriodEnd:\n\t\t\t\t\t\t\t\t\tcurrentSubscription?.cancel_at_period_end || false,\n\t\t\t\t\t\t\t\tcancelAt: currentSubscription?.cancel_at\n\t\t\t\t\t\t\t\t\t? new Date(currentSubscription.cancel_at * 1000)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\tcanceledAt: currentSubscription?.canceled_at\n\t\t\t\t\t\t\t\t\t? new Date(currentSubscription.canceled_at * 1000)\n\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tawait subscriptionOptions.onSubscriptionCancel?.({\n\t\t\t\t\t\t\tsubscription,\n\t\t\t\t\t\t\tcancellationDetails: currentSubscription.cancellation_details,\n\t\t\t\t\t\t\tstripeSubscription: currentSubscription,\n\t\t\t\t\t\t\tevent: undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\t\"Error checking subscription status from Stripe\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t},\n\t);\n};\n\nconst cancelSubscriptionBodySchema = z.object({\n\treferenceId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"Reference id of the subscription to cancel. Eg: '123'\",\n\t\t})\n\t\t.optional(),\n\tsubscriptionId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"The Stripe subscription ID to cancel. Eg: 'sub_1ABC2DEF3GHI4JKL'\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Customer type for the subscription.\n\t * - `user`: User owns the subscription (default)\n\t * - `organization`: Organization owns the subscription\n\t */\n\tcustomerType: z\n\t\t.enum([\"user\", \"organization\"])\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t})\n\t\t.optional(),\n\treturnUrl: z.string().meta({\n\t\tdescription:\n\t\t\t'URL to take customers to when they click on the billing portal\\'s link to return to your website. Eg: \"/account\"',\n\t}),\n\t/**\n\t * Disable Redirect\n\t */\n\tdisableRedirect: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Disable redirect after successful subscription cancellation. Eg: true\",\n\t\t})\n\t\t.default(false),\n});\n\n/**\n * ### Endpoint\n *\n * POST `/subscription/cancel`\n *\n * ### API Methods\n *\n * **server:**\n * `auth.api.cancelSubscription`\n *\n * **client:**\n * `authClient.subscription.cancel`\n *\n * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/stripe#api-method-subscription-cancel)\n */\nexport const cancelSubscription = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/cancel\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: cancelSubscriptionBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"cancelSubscription\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"cancel-subscription\"),\n\t\t\t\toriginCheck((ctx) => ctx.body.returnUrl),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst customerType = ctx.body.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.body.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tlet subscription = ctx.body.subscriptionId\n\t\t\t\t? await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\t\t\t\tvalue: ctx.body.subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t})\n\t\t\t\t: await ctx.context.adapter\n\t\t\t\t\t\t.findMany<Subscription>({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\twhere: [{ field: \"referenceId\", value: referenceId }],\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then((subs) => subs.find((sub) => isActiveOrTrialing(sub)));\n\t\t\tif (\n\t\t\t\tctx.body.subscriptionId &&\n\t\t\t\tsubscription &&\n\t\t\t\tsubscription.referenceId !== referenceId\n\t\t\t) {\n\t\t\t\tsubscription = undefined;\n\t\t\t}\n\n\t\t\tif (!subscription || !subscription.stripeCustomerId) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst activeSubscriptions = await client.subscriptions\n\t\t\t\t.list({\n\t\t\t\t\tcustomer: subscription.stripeCustomerId,\n\t\t\t\t})\n\t\t\t\t.then((res) => res.data.filter((sub) => isActiveOrTrialing(sub)));\n\t\t\tif (!activeSubscriptions.length) {\n\t\t\t\t/**\n\t\t\t\t * If the subscription is not found, we need to delete the subscription\n\t\t\t\t * from the database. This is a rare case and should not happen.\n\t\t\t\t */\n\t\t\t\tawait ctx.context.adapter.deleteMany({\n\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\twhere: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst activeSubscription = activeSubscriptions.find(\n\t\t\t\t(sub) => sub.id === subscription.stripeSubscriptionId,\n\t\t\t);\n\t\t\tif (!activeSubscription) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst { url } = await client.billingPortal.sessions\n\t\t\t\t.create({\n\t\t\t\t\tcustomer: subscription.stripeCustomerId,\n\t\t\t\t\treturn_url: getUrl(\n\t\t\t\t\t\tctx,\n\t\t\t\t\t\t`${\n\t\t\t\t\t\t\tctx.context.baseURL\n\t\t\t\t\t\t}/subscription/cancel/callback?callbackURL=${encodeURIComponent(\n\t\t\t\t\t\t\tctx.body?.returnUrl || \"/\",\n\t\t\t\t\t\t)}&subscriptionId=${encodeURIComponent(subscription.id)}`,\n\t\t\t\t\t),\n\t\t\t\t\tflow_data: {\n\t\t\t\t\t\ttype: \"subscription_cancel\",\n\t\t\t\t\t\tsubscription_cancel: {\n\t\t\t\t\t\t\tsubscription: activeSubscription.id,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t})\n\t\t\t\t.catch(async (e) => {\n\t\t\t\t\tif (e.message?.includes(\"already set to be canceled\")) {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * in-case we missed the event from stripe, we sync the actual state\n\t\t\t\t\t\t * this is a rare case and should not happen\n\t\t\t\t\t\t */\n\t\t\t\t\t\tif (!isPendingCancel(subscription)) {\n\t\t\t\t\t\t\tconst stripeSub = await client.subscriptions.retrieve(\n\t\t\t\t\t\t\t\tactiveSubscription.id,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tawait ctx.context.adapter.update({\n\t\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\t\tcancelAtPeriodEnd: stripeSub.cancel_at_period_end,\n\t\t\t\t\t\t\t\t\tcancelAt: stripeSub.cancel_at\n\t\t\t\t\t\t\t\t\t\t? new Date(stripeSub.cancel_at * 1000)\n\t\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t\tcanceledAt: stripeSub.canceled_at\n\t\t\t\t\t\t\t\t\t\t? new Date(stripeSub.canceled_at * 1000)\n\t\t\t\t\t\t\t\t\t\t: null,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\turl,\n\t\t\t\tredirect: !ctx.body.disableRedirect,\n\t\t\t});\n\t\t},\n\t);\n};\n\nconst restoreSubscriptionBodySchema = z.object({\n\treferenceId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription: \"Reference id of the subscription to restore. Eg: '123'\",\n\t\t})\n\t\t.optional(),\n\tsubscriptionId: z\n\t\t.string()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"The Stripe subscription ID to restore. Eg: 'sub_1ABC2DEF3GHI4JKL'\",\n\t\t})\n\t\t.optional(),\n\t/**\n\t * Customer type for the subscription.\n\t * - `user`: User owns the subscription (default)\n\t * - `organization`: Organization owns the subscription\n\t */\n\tcustomerType: z\n\t\t.enum([\"user\", \"organization\"])\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t})\n\t\t.optional(),\n});\n\nexport const restoreSubscription = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/restore\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: restoreSubscriptionBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"restoreSubscription\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"restore-subscription\"),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst customerType = ctx.body.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.body.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tlet subscription = ctx.body.subscriptionId\n\t\t\t\t? await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfield: \"stripeSubscriptionId\",\n\t\t\t\t\t\t\t\tvalue: ctx.body.subscriptionId,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t],\n\t\t\t\t\t})\n\t\t\t\t: await ctx.context.adapter\n\t\t\t\t\t\t.findMany<Subscription>({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then((subs) => subs.find((sub) => isActiveOrTrialing(sub)));\n\t\t\tif (\n\t\t\t\tctx.body.subscriptionId &&\n\t\t\t\tsubscription &&\n\t\t\t\tsubscription.referenceId !== referenceId\n\t\t\t) {\n\t\t\t\tsubscription = undefined;\n\t\t\t}\n\t\t\tif (!subscription || !subscription.stripeCustomerId) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!isActiveOrTrialing(subscription)) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_ACTIVE,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!isPendingCancel(subscription)) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_SCHEDULED_FOR_CANCELLATION,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst activeSubscription = await client.subscriptions\n\t\t\t\t.list({\n\t\t\t\t\tcustomer: subscription.stripeCustomerId,\n\t\t\t\t})\n\t\t\t\t.then((res) => res.data.filter((sub) => isActiveOrTrialing(sub))[0]);\n\t\t\tif (!activeSubscription) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Clear scheduled cancellation based on Stripe subscription state\n\t\t\t// Note: Stripe doesn't accept both `cancel_at` and `cancel_at_period_end` simultaneously\n\t\t\tconst updateParams: Stripe.SubscriptionUpdateParams = {};\n\t\t\tif (activeSubscription.cancel_at) {\n\t\t\t\tupdateParams.cancel_at = \"\";\n\t\t\t} else if (activeSubscription.cancel_at_period_end) {\n\t\t\t\tupdateParams.cancel_at_period_end = false;\n\t\t\t}\n\n\t\t\tconst newSub = await client.subscriptions\n\t\t\t\t.update(activeSubscription.id, updateParams)\n\t\t\t\t.catch((e) => {\n\t\t\t\t\tthrow ctx.error(\"BAD_REQUEST\", {\n\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\tupdate: {\n\t\t\t\t\tcancelAtPeriodEnd: false,\n\t\t\t\t\tcancelAt: null,\n\t\t\t\t\tcanceledAt: null,\n\t\t\t\t\tupdatedAt: new Date(),\n\t\t\t\t},\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\treturn ctx.json(newSub);\n\t\t},\n\t);\n};\n\nconst listActiveSubscriptionsQuerySchema = z.optional(\n\tz.object({\n\t\treferenceId: z\n\t\t\t.string()\n\t\t\t.meta({\n\t\t\t\tdescription: \"Reference id of the subscription to list. Eg: '123'\",\n\t\t\t})\n\t\t\t.optional(),\n\t\t/**\n\t\t * Customer type for the subscription.\n\t\t * - `user`: User owns the subscription (default)\n\t\t * - `organization`: Organization owns the subscription\n\t\t */\n\t\tcustomerType: z\n\t\t\t.enum([\"user\", \"organization\"])\n\t\t\t.meta({\n\t\t\t\tdescription:\n\t\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t\t})\n\t\t\t.optional(),\n\t}),\n);\n/**\n * ### Endpoint\n *\n * GET `/subscription/list`\n *\n * ### API Methods\n *\n * **server:**\n * `auth.api.listActiveSubscriptions`\n *\n * **client:**\n * `authClient.subscription.list`\n *\n * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/stripe#api-method-subscription-list)\n */\nexport const listActiveSubscriptions = (options: StripeOptions) => {\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/list\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: listActiveSubscriptionsQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"listActiveSubscriptions\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"list-subscription\"),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst customerType = ctx.query?.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.query?.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tconst subscriptions = await ctx.context.adapter.findMany<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!subscriptions.length) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tconst plans = await getPlans(options.subscription);\n\t\t\tif (!plans) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tconst subs = subscriptions\n\t\t\t\t.map((sub) => {\n\t\t\t\t\tconst plan = plans.find(\n\t\t\t\t\t\t(p) => p.name.toLowerCase() === sub.plan.toLowerCase(),\n\t\t\t\t\t);\n\t\t\t\t\treturn {\n\t\t\t\t\t\t...sub,\n\t\t\t\t\t\tlimits: plan?.limits,\n\t\t\t\t\t\tpriceId: plan?.priceId,\n\t\t\t\t\t};\n\t\t\t\t})\n\t\t\t\t.filter((sub) => isActiveOrTrialing(sub));\n\t\t\treturn ctx.json(subs);\n\t\t},\n\t);\n};\n\nconst subscriptionSuccessQuerySchema = z.record(z.string(), z.any()).optional();\n\nexport const subscriptionSuccess = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/success\",\n\t\t{\n\t\t\tmethod: \"GET\",\n\t\t\tquery: subscriptionSuccessQuerySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"handleSubscriptionSuccess\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || \"/\"));\n\t\t\t}\n\t\t\tconst { callbackURL, subscriptionId } = ctx.query;\n\n\t\t\tconst session = await getSessionFromCtx<User & WithStripeCustomerId>(ctx);\n\t\t\tif (!session) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || \"/\"));\n\t\t\t}\n\n\t\t\tconst subscription = await ctx.context.adapter.findOne<Subscription>({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: subscriptionId,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\t\t\tif (!subscription) {\n\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t`Subscription record not found for subscriptionId: ${subscriptionId}`,\n\t\t\t\t);\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\t// Already active or trialing, no need to update\n\t\t\tif (isActiveOrTrialing(subscription)) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tconst customerId =\n\t\t\t\tsubscription.stripeCustomerId || session.user.stripeCustomerId;\n\t\t\tif (!customerId) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tconst stripeSubscription = await client.subscriptions\n\t\t\t\t.list({ customer: customerId, status: \"active\" })\n\t\t\t\t.then((res) => res.data[0])\n\t\t\t\t.catch((error) => {\n\t\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\t\"Error fetching subscription from Stripe\",\n\t\t\t\t\t\terror,\n\t\t\t\t\t);\n\t\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t\t});\n\t\t\tif (!stripeSubscription) {\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tconst subscriptionItem = stripeSubscription.items.data[0];\n\t\t\tif (!subscriptionItem) {\n\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t`No subscription items found for Stripe subscription ${stripeSubscription.id}`,\n\t\t\t\t);\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tconst plan = await getPlanByPriceInfo(\n\t\t\t\toptions,\n\t\t\t\tsubscriptionItem.price.id,\n\t\t\t\tsubscriptionItem.price.lookup_key,\n\t\t\t);\n\t\t\tif (!plan) {\n\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t`Plan not found for price ${subscriptionItem.price.id}`,\n\t\t\t\t);\n\t\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t\t}\n\n\t\t\tawait ctx.context.adapter.update({\n\t\t\t\tmodel: \"subscription\",\n\t\t\t\tupdate: {\n\t\t\t\t\tstatus: stripeSubscription.status,\n\t\t\t\t\tseats: subscriptionItem.quantity || 1,\n\t\t\t\t\tplan: plan.name.toLowerCase(),\n\t\t\t\t\tperiodEnd: new Date(subscriptionItem.current_period_end * 1000),\n\t\t\t\t\tperiodStart: new Date(subscriptionItem.current_period_start * 1000),\n\t\t\t\t\tstripeSubscriptionId: stripeSubscription.id,\n\t\t\t\t\tcancelAtPeriodEnd: stripeSubscription.cancel_at_period_end,\n\t\t\t\t\tcancelAt: stripeSubscription.cancel_at\n\t\t\t\t\t\t? new Date(stripeSubscription.cancel_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t\tcanceledAt: stripeSubscription.canceled_at\n\t\t\t\t\t\t? new Date(stripeSubscription.canceled_at * 1000)\n\t\t\t\t\t\t: null,\n\t\t\t\t\t...(stripeSubscription.trial_start && stripeSubscription.trial_end\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\ttrialStart: new Date(stripeSubscription.trial_start * 1000),\n\t\t\t\t\t\t\t\ttrialEnd: new Date(stripeSubscription.trial_end * 1000),\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t\twhere: [\n\t\t\t\t\t{\n\t\t\t\t\t\tfield: \"id\",\n\t\t\t\t\t\tvalue: subscription.id,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t});\n\n\t\t\tthrow ctx.redirect(getUrl(ctx, callbackURL));\n\t\t},\n\t);\n};\n\nconst createBillingPortalBodySchema = z.object({\n\t/**\n\t * The IETF language tag of the locale Customer Portal is displayed in.\n\t * If not provided or set to `auto`, the browser's locale is used.\n\t */\n\tlocale: z\n\t\t.custom<StripeType.Checkout.Session.Locale>((localization) => {\n\t\t\treturn typeof localization === \"string\";\n\t\t})\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"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.\",\n\t\t})\n\t\t.optional(),\n\treferenceId: z.string().optional(),\n\t/**\n\t * Customer type for the subscription.\n\t * - `user`: User owns the subscription (default)\n\t * - `organization`: Organization owns the subscription\n\t */\n\tcustomerType: z\n\t\t.enum([\"user\", \"organization\"])\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t'Customer type for the subscription. Eg: \"user\" or \"organization\"',\n\t\t})\n\t\t.optional(),\n\treturnUrl: z.string().default(\"/\"),\n\t/**\n\t * Disable Redirect\n\t */\n\tdisableRedirect: z\n\t\t.boolean()\n\t\t.meta({\n\t\t\tdescription:\n\t\t\t\t\"Disable redirect after creating billing portal session. Eg: true\",\n\t\t})\n\t\t.default(false),\n});\n\nexport const createBillingPortal = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\tconst subscriptionOptions = options.subscription as SubscriptionOptions;\n\treturn createAuthEndpoint(\n\t\t\"/subscription/billing-portal\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tbody: createBillingPortalBodySchema,\n\t\t\tmetadata: {\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"createBillingPortal\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tuse: [\n\t\t\t\tstripeSessionMiddleware,\n\t\t\t\treferenceMiddleware(subscriptionOptions, \"billing-portal\"),\n\t\t\t\toriginCheck((ctx) => ctx.body.returnUrl),\n\t\t\t],\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst { user } = ctx.context.session;\n\t\t\tconst customerType = ctx.body.customerType || \"user\";\n\t\t\tconst referenceId =\n\t\t\t\tctx.body.referenceId ||\n\t\t\t\tgetReferenceId(ctx.context.session, customerType, options);\n\n\t\t\tlet customerId: string | undefined;\n\n\t\t\tif (customerType === \"organization\") {\n\t\t\t\t// Organization billing portal - get customer ID from organization\n\t\t\t\tconst org = await ctx.context.adapter.findOne<\n\t\t\t\t\tOrganization & WithStripeCustomerId\n\t\t\t\t>({\n\t\t\t\t\tmodel: \"organization\",\n\t\t\t\t\twhere: [{ field: \"id\", value: referenceId }],\n\t\t\t\t});\n\t\t\t\tcustomerId = org?.stripeCustomerId;\n\n\t\t\t\tif (!customerId) {\n\t\t\t\t\t// Fallback to subscription's stripeCustomerId\n\t\t\t\t\tconst subscription = await ctx.context.adapter\n\t\t\t\t\t\t.findMany<Subscription>({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\twhere: [{ field: \"referenceId\", value: referenceId }],\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then((subs) => subs.find((sub) => isActiveOrTrialing(sub)));\n\t\t\t\t\tcustomerId = subscription?.stripeCustomerId;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// User billing portal\n\t\t\t\tcustomerId = user.stripeCustomerId;\n\t\t\t\tif (!customerId) {\n\t\t\t\t\tconst subscription = await ctx.context.adapter\n\t\t\t\t\t\t.findMany<Subscription>({\n\t\t\t\t\t\t\tmodel: \"subscription\",\n\t\t\t\t\t\t\twhere: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\tfield: \"referenceId\",\n\t\t\t\t\t\t\t\t\tvalue: referenceId,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.then((subs) => subs.find((sub) => isActiveOrTrialing(sub)));\n\n\t\t\t\t\tcustomerId = subscription?.stripeCustomerId;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!customerId) {\n\t\t\t\tthrow APIError.from(\"NOT_FOUND\", STRIPE_ERROR_CODES.CUSTOMER_NOT_FOUND);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst { url } = await client.billingPortal.sessions.create({\n\t\t\t\t\tlocale: ctx.body.locale,\n\t\t\t\t\tcustomer: customerId,\n\t\t\t\t\treturn_url: getUrl(ctx, ctx.body.returnUrl),\n\t\t\t\t});\n\n\t\t\t\treturn ctx.json({\n\t\t\t\t\turl,\n\t\t\t\t\tredirect: !ctx.body.disableRedirect,\n\t\t\t\t});\n\t\t\t} catch (error: any) {\n\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\"Error creating billing portal session\",\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"INTERNAL_SERVER_ERROR\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.UNABLE_TO_CREATE_BILLING_PORTAL,\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\t);\n};\n\nexport const stripeWebhook = (options: StripeOptions) => {\n\tconst client = options.stripeClient;\n\treturn createAuthEndpoint(\n\t\t\"/stripe/webhook\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\tmetadata: {\n\t\t\t\t...HIDE_METADATA,\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"handleStripeWebhook\",\n\t\t\t\t},\n\t\t\t},\n\t\t\tcloneRequest: true,\n\t\t\tdisableBody: true, // Don't parse the body\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tif (!ctx.request?.body) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.INVALID_REQUEST_BODY,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst sig = ctx.request.headers.get(\"stripe-signature\");\n\t\t\tif (!sig) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.STRIPE_SIGNATURE_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst webhookSecret = options.stripeWebhookSecret;\n\t\t\tif (!webhookSecret) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"INTERNAL_SERVER_ERROR\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.STRIPE_WEBHOOK_SECRET_NOT_FOUND,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst payload = await ctx.request.text();\n\n\t\t\tlet event: Stripe.Event;\n\t\t\ttry {\n\t\t\t\t// Support both Stripe v18 (constructEvent) and v19+ (constructEventAsync)\n\t\t\t\tif (typeof client.webhooks.constructEventAsync === \"function\") {\n\t\t\t\t\t// Stripe v19+ - use async method\n\t\t\t\t\tevent = await client.webhooks.constructEventAsync(\n\t\t\t\t\t\tpayload,\n\t\t\t\t\t\tsig,\n\t\t\t\t\t\twebhookSecret,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Stripe v18 - use sync method\n\t\t\t\t\tevent = client.webhooks.constructEvent(payload, sig, webhookSecret);\n\t\t\t\t}\n\t\t\t} catch (err: any) {\n\t\t\t\tctx.context.logger.error(`${err.message}`);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.FAILED_TO_CONSTRUCT_STRIPE_EVENT,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (!event) {\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.FAILED_TO_CONSTRUCT_STRIPE_EVENT,\n\t\t\t\t);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tswitch (event.type) {\n\t\t\t\t\tcase \"checkout.session.completed\":\n\t\t\t\t\t\tawait onCheckoutSessionCompleted(ctx, options, event);\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"customer.subscription.created\":\n\t\t\t\t\t\tawait onSubscriptionCreated(ctx, options, event);\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"customer.subscription.updated\":\n\t\t\t\t\t\tawait onSubscriptionUpdated(ctx, options, event);\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"customer.subscription.deleted\":\n\t\t\t\t\t\tawait onSubscriptionDeleted(ctx, options, event);\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tawait options.onEvent?.(event);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} catch (e: any) {\n\t\t\t\tctx.context.logger.error(`Stripe webhook failed. Error: ${e.message}`);\n\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\tSTRIPE_ERROR_CODES.STRIPE_WEBHOOK_ERROR,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn ctx.json({ success: true });\n\t\t},\n\t);\n};\n","import type { BetterAuthPluginDBSchema } from \"@better-auth/core/db\";\nimport { mergeSchema } from \"better-auth/db\";\nimport type { StripeOptions } from \"./types\";\n\nexport const subscriptions = {\n\tsubscription: {\n\t\tfields: {\n\t\t\tplan: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\treferenceId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: true,\n\t\t\t},\n\t\t\tstripeCustomerId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tstripeSubscriptionId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tstatus: {\n\t\t\t\ttype: \"string\",\n\t\t\t\tdefaultValue: \"incomplete\",\n\t\t\t},\n\t\t\tperiodStart: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tperiodEnd: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\ttrialStart: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\ttrialEnd: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tcancelAtPeriodEnd: {\n\t\t\t\ttype: \"boolean\",\n\t\t\t\trequired: false,\n\t\t\t\tdefaultValue: false,\n\t\t\t},\n\t\t\tcancelAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tcanceledAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tendedAt: {\n\t\t\t\ttype: \"date\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t\tseats: {\n\t\t\t\ttype: \"number\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\nexport const user = {\n\tuser: {\n\t\tfields: {\n\t\t\tstripeCustomerId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\nexport const organization = {\n\torganization: {\n\t\tfields: {\n\t\t\tstripeCustomerId: {\n\t\t\t\ttype: \"string\",\n\t\t\t\trequired: false,\n\t\t\t},\n\t\t},\n\t},\n} satisfies BetterAuthPluginDBSchema;\n\ntype GetSchemaResult<O extends StripeOptions> = typeof user &\n\t(O[\"subscription\"] extends { enabled: true } ? typeof subscriptions : {}) &\n\t(O[\"organization\"] extends { enabled: true } ? typeof organization : {});\n\nexport const getSchema = <O extends StripeOptions>(\n\toptions: O,\n): GetSchemaResult<O> => {\n\tlet baseSchema: BetterAuthPluginDBSchema = {};\n\n\tif (options.subscription?.enabled) {\n\t\tbaseSchema = {\n\t\t\t...subscriptions,\n\t\t\t...user,\n\t\t};\n\t} else {\n\t\tbaseSchema = {\n\t\t\t...user,\n\t\t};\n\t}\n\n\tif (options.organization?.enabled) {\n\t\tbaseSchema = {\n\t\t\t...baseSchema,\n\t\t\t...organization,\n\t\t};\n\t}\n\n\tif (\n\t\toptions.schema &&\n\t\t!options.subscription?.enabled &&\n\t\t\"subscription\" in options.schema\n\t) {\n\t\tconst { subscription: _subscription, ...restSchema } = options.schema;\n\t\treturn mergeSchema(baseSchema, restSchema) as GetSchemaResult<O>;\n\t}\n\n\treturn mergeSchema(baseSchema, options.schema) as GetSchemaResult<O>;\n};\n","import type { BetterAuthPlugin, User } from \"better-auth\";\nimport { APIError } from \"better-auth\";\nimport type { Organization } from \"better-auth/plugins/organization\";\nimport { defu } from \"defu\";\nimport type Stripe from \"stripe\";\nimport { STRIPE_ERROR_CODES } from \"./error-codes\";\nimport { customerMetadata } from \"./metadata\";\nimport {\n\tcancelSubscription,\n\tcancelSubscriptionCallback,\n\tcreateBillingPortal,\n\tlistActiveSubscriptions,\n\trestoreSubscription,\n\tstripeWebhook,\n\tsubscriptionSuccess,\n\tupgradeSubscription,\n} from \"./routes\";\nimport { getSchema } from \"./schema\";\nimport type {\n\tStripeOptions,\n\tStripePlan,\n\tSubscription,\n\tSubscriptionOptions,\n\tWithStripeCustomerId,\n} from \"./types\";\nimport { escapeStripeSearchValue } from \"./utils\";\n\ndeclare module \"@better-auth/core\" {\n\tinterface BetterAuthPluginRegistry<AuthOptions, Options> {\n\t\tstripe: {\n\t\t\tcreator: typeof stripe;\n\t\t};\n\t}\n}\n\nexport const stripe = <O extends StripeOptions>(options: O) => {\n\tconst client = options.stripeClient;\n\n\tconst subscriptionEndpoints = {\n\t\tupgradeSubscription: upgradeSubscription(options),\n\t\tcancelSubscriptionCallback: cancelSubscriptionCallback(options),\n\t\tcancelSubscription: cancelSubscription(options),\n\t\trestoreSubscription: restoreSubscription(options),\n\t\tlistActiveSubscriptions: listActiveSubscriptions(options),\n\t\tsubscriptionSuccess: subscriptionSuccess(options),\n\t\tcreateBillingPortal: createBillingPortal(options),\n\t};\n\n\treturn {\n\t\tid: \"stripe\",\n\t\tendpoints: {\n\t\t\tstripeWebhook: stripeWebhook(options),\n\t\t\t...((options.subscription?.enabled\n\t\t\t\t? subscriptionEndpoints\n\t\t\t\t: {}) as O[\"subscription\"] extends {\n\t\t\t\tenabled: true;\n\t\t\t}\n\t\t\t\t? typeof subscriptionEndpoints\n\t\t\t\t: {}),\n\t\t},\n\t\tinit(ctx) {\n\t\t\tif (options.organization?.enabled) {\n\t\t\t\tconst orgPlugin = ctx.getPlugin(\"organization\");\n\t\t\t\tif (!orgPlugin) {\n\t\t\t\t\tctx.logger.error(`Organization plugin not found`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst existingHooks = orgPlugin.options.organizationHooks ?? {};\n\n\t\t\t\t/**\n\t\t\t\t * Sync organization name to Stripe customer\n\t\t\t\t */\n\t\t\t\tconst afterUpdateStripeOrg = async (data: {\n\t\t\t\t\torganization: (Organization & WithStripeCustomerId) | null;\n\t\t\t\t\tuser: User;\n\t\t\t\t}) => {\n\t\t\t\t\tconst { organization } = data;\n\t\t\t\t\tif (!organization?.stripeCustomerId) return;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst stripeCustomer = await client.customers.retrieve(\n\t\t\t\t\t\t\torganization.stripeCustomerId,\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\tif (stripeCustomer.deleted) {\n\t\t\t\t\t\t\tctx.logger.warn(\n\t\t\t\t\t\t\t\t`Stripe customer ${organization.stripeCustomerId} was deleted`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Update Stripe customer if name changed\n\t\t\t\t\t\tif (organization.name !== stripeCustomer.name) {\n\t\t\t\t\t\t\tawait client.customers.update(organization.stripeCustomerId, {\n\t\t\t\t\t\t\t\tname: organization.name,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tctx.logger.info(\n\t\t\t\t\t\t\t\t`Synced organization name to Stripe: \"${stripeCustomer.name}\" → \"${organization.name}\"`,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\tctx.logger.error(\n\t\t\t\t\t\t\t`Failed to sync organization to Stripe: ${e.message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t/**\n\t\t\t\t * Block deletion if organization has active subscriptions\n\t\t\t\t */\n\t\t\t\tconst beforeDeleteStripeOrg = async (data: {\n\t\t\t\t\torganization: Organization & WithStripeCustomerId;\n\t\t\t\t\tuser: User;\n\t\t\t\t}) => {\n\t\t\t\t\tconst { organization } = data;\n\t\t\t\t\tif (!organization.stripeCustomerId) return;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// Check if organization has any active subscriptions\n\t\t\t\t\t\tconst subscriptions = await client.subscriptions.list({\n\t\t\t\t\t\t\tcustomer: organization.stripeCustomerId,\n\t\t\t\t\t\t\tstatus: \"all\",\n\t\t\t\t\t\t\tlimit: 100, // 1 ~ 100\n\t\t\t\t\t\t});\n\t\t\t\t\t\tfor (const sub of subscriptions.data) {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\tsub.status !== \"canceled\" &&\n\t\t\t\t\t\t\t\tsub.status !== \"incomplete\" &&\n\t\t\t\t\t\t\t\tsub.status !== \"incomplete_expired\"\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow APIError.from(\n\t\t\t\t\t\t\t\t\t\"BAD_REQUEST\",\n\t\t\t\t\t\t\t\t\tSTRIPE_ERROR_CODES.ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error: any) {\n\t\t\t\t\t\tif (error instanceof APIError) {\n\t\t\t\t\t\t\tthrow error;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tctx.logger.error(\n\t\t\t\t\t\t\t`Failed to check organization subscriptions: ${error.message}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\torgPlugin.options.organizationHooks = {\n\t\t\t\t\t...existingHooks,\n\t\t\t\t\tafterUpdateOrganization: existingHooks.afterUpdateOrganization\n\t\t\t\t\t\t? async (data) => {\n\t\t\t\t\t\t\t\tawait existingHooks.afterUpdateOrganization!(data);\n\t\t\t\t\t\t\t\tawait afterUpdateStripeOrg(data);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: afterUpdateStripeOrg,\n\t\t\t\t\tbeforeDeleteOrganization: existingHooks.beforeDeleteOrganization\n\t\t\t\t\t\t? async (data) => {\n\t\t\t\t\t\t\t\tawait existingHooks.beforeDeleteOrganization!(data);\n\t\t\t\t\t\t\t\tawait beforeDeleteStripeOrg(data);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: beforeDeleteStripeOrg,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\toptions: {\n\t\t\t\t\tdatabaseHooks: {\n\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\tcreate: {\n\t\t\t\t\t\t\t\tasync after(user: User & WithStripeCustomerId, ctx) {\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t!ctx ||\n\t\t\t\t\t\t\t\t\t\t!options.createCustomerOnSignUp ||\n\t\t\t\t\t\t\t\t\t\tuser.stripeCustomerId // Skip if user already has a Stripe customer ID\n\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t// Check if user customer already exists in Stripe by email\n\t\t\t\t\t\t\t\t\t\tconst existingCustomers = await client.customers.search({\n\t\t\t\t\t\t\t\t\t\t\tquery: `email:\"${escapeStripeSearchValue(user.email)}\" AND -metadata[\"${customerMetadata.keys.customerType}\"]:\"organization\"`,\n\t\t\t\t\t\t\t\t\t\t\tlimit: 1,\n\t\t\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t\t\t\tlet stripeCustomer = existingCustomers.data[0];\n\n\t\t\t\t\t\t\t\t\t\t// If user customer exists, link it to prevent duplicate creation\n\t\t\t\t\t\t\t\t\t\tif (stripeCustomer) {\n\t\t\t\t\t\t\t\t\t\t\tawait ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\tawait options.onCustomerCreate?.(\n\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomer,\n\t\t\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t...user,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t\t\t\t\t\t\t\t`Linked existing Stripe customer ${stripeCustomer.id} to user ${user.id}`,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// Create new Stripe customer\n\t\t\t\t\t\t\t\t\t\tlet extraCreateParams: Partial<Stripe.CustomerCreateParams> =\n\t\t\t\t\t\t\t\t\t\t\t{};\n\t\t\t\t\t\t\t\t\t\tif (options.getCustomerCreateParams) {\n\t\t\t\t\t\t\t\t\t\t\textraCreateParams = await options.getCustomerCreateParams(\n\t\t\t\t\t\t\t\t\t\t\t\tuser,\n\t\t\t\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tconst params = defu(\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\t\t\t\t\t\t\tname: user.name,\n\t\t\t\t\t\t\t\t\t\t\t\tmetadata: customerMetadata.set(\n\t\t\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tuserId: user.id,\n\t\t\t\t\t\t\t\t\t\t\t\t\t\tcustomerType: \"user\",\n\t\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\t\textraCreateParams?.metadata,\n\t\t\t\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\textraCreateParams,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\tstripeCustomer = await client.customers.create(params);\n\t\t\t\t\t\t\t\t\t\tawait ctx.context.internalAdapter.updateUser(user.id, {\n\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\tawait options.onCustomerCreate?.(\n\t\t\t\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomer,\n\t\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\t\t...user,\n\t\t\t\t\t\t\t\t\t\t\t\t\tstripeCustomerId: stripeCustomer.id,\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\tctx,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t\t\t\t\t\t\t`Created new Stripe customer ${stripeCustomer.id} for user ${user.id}`,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\t\t\t\t\t\t`Failed to create or link Stripe customer: ${e.message}`,\n\t\t\t\t\t\t\t\t\t\t\te,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tupdate: {\n\t\t\t\t\t\t\t\tasync after(user: User & WithStripeCustomerId, ctx) {\n\t\t\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t\t\t!ctx ||\n\t\t\t\t\t\t\t\t\t\t!user.stripeCustomerId // Only proceed if user has a Stripe customer ID\n\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\treturn;\n\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t// Get the user from the database to check if email actually changed\n\t\t\t\t\t\t\t\t\t\t// The 'user' parameter here is the freshly updated user\n\t\t\t\t\t\t\t\t\t\t// We need to check if the Stripe customer's email matches\n\t\t\t\t\t\t\t\t\t\tconst stripeCustomer = await client.customers.retrieve(\n\t\t\t\t\t\t\t\t\t\t\tuser.stripeCustomerId,\n\t\t\t\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t\t\t\t// Check if customer was deleted\n\t\t\t\t\t\t\t\t\t\tif (stripeCustomer.deleted) {\n\t\t\t\t\t\t\t\t\t\t\tctx.context.logger.warn(\n\t\t\t\t\t\t\t\t\t\t\t\t`Stripe customer ${user.stripeCustomerId} was deleted, cannot update email`,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t// If Stripe customer email doesn't match the user's current email, update it\n\t\t\t\t\t\t\t\t\t\tif (stripeCustomer.email !== user.email) {\n\t\t\t\t\t\t\t\t\t\t\tawait client.customers.update(user.stripeCustomerId, {\n\t\t\t\t\t\t\t\t\t\t\t\temail: user.email,\n\t\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t\t\tctx.context.logger.info(\n\t\t\t\t\t\t\t\t\t\t\t\t`Updated Stripe customer email from ${stripeCustomer.email} to ${user.email}`,\n\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t} catch (e: any) {\n\t\t\t\t\t\t\t\t\t\t// Ignore errors - this is a best-effort sync\n\t\t\t\t\t\t\t\t\t\t// Email might have been deleted or Stripe customer might not exist\n\t\t\t\t\t\t\t\t\t\tctx.context.logger.error(\n\t\t\t\t\t\t\t\t\t\t\t`Failed to sync email to Stripe customer: ${e.message}`,\n\t\t\t\t\t\t\t\t\t\t\te,\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\tschema: getSchema(options),\n\t\toptions: options as NoInfer<O>,\n\t\t$ERROR_CODES: STRIPE_ERROR_CODES,\n\t} satisfies BetterAuthPlugin;\n};\n\nexport type StripePlugin<O extends StripeOptions> = ReturnType<\n\ttypeof stripe<O>\n>;\n\nexport type { Subscription, SubscriptionOptions, StripePlan };\n"],"mappings":"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"}
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.11",
4
+ "version": "1.5.0-beta.13",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
7
7
  "types": "dist/index.d.mts",
@@ -49,17 +49,17 @@
49
49
  "zod": "^4.3.6"
50
50
  },
51
51
  "peerDependencies": {
52
- "better-call": "1.2.0",
52
+ "better-call": "1.2.1",
53
53
  "stripe": "^18 || ^19 || ^20",
54
- "@better-auth/core": "1.5.0-beta.11",
55
- "better-auth": "1.5.0-beta.11"
54
+ "@better-auth/core": "1.5.0-beta.13",
55
+ "better-auth": "1.5.0-beta.13"
56
56
  },
57
57
  "devDependencies": {
58
- "better-call": "1.2.0",
58
+ "better-call": "1.2.1",
59
59
  "stripe": "^20.2.0",
60
60
  "tsdown": "^0.20.1",
61
- "@better-auth/core": "1.5.0-beta.11",
62
- "better-auth": "1.5.0-beta.11"
61
+ "@better-auth/core": "1.5.0-beta.13",
62
+ "better-auth": "1.5.0-beta.13"
63
63
  },
64
64
  "scripts": {
65
65
  "test": "vitest",
@@ -23,6 +23,8 @@ export const STRIPE_ERROR_CODES = defineErrorCodes({
23
23
  ORGANIZATION_NOT_FOUND: "Organization not found",
24
24
  ORGANIZATION_SUBSCRIPTION_NOT_ENABLED:
25
25
  "Organization subscription is not enabled",
26
+ AUTHORIZE_REFERENCE_REQUIRED:
27
+ "Organization subscriptions require authorizeReference callback to be configured",
26
28
  ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION:
27
29
  "Cannot delete organization with active subscription",
28
30
  ORGANIZATION_REFERENCE_ID_REQUIRED:
package/src/index.ts CHANGED
@@ -220,7 +220,7 @@ export const stripe = <O extends StripeOptions>(options: O) => {
220
220
  const params = defu(
221
221
  {
222
222
  email: user.email,
223
- name: user.name ?? undefined,
223
+ name: user.name,
224
224
  metadata: customerMetadata.set(
225
225
  {
226
226
  userId: user.id,
package/src/middleware.ts CHANGED
@@ -43,7 +43,7 @@ export const referenceMiddleware = (
43
43
  );
44
44
  throw APIError.from(
45
45
  "BAD_REQUEST",
46
- STRIPE_ERROR_CODES.ORGANIZATION_SUBSCRIPTION_NOT_ENABLED,
46
+ STRIPE_ERROR_CODES.AUTHORIZE_REFERENCE_REQUIRED,
47
47
  );
48
48
  }
49
49
 
package/src/routes.ts CHANGED
@@ -424,7 +424,7 @@ export const upgradeSubscription = (options: StripeOptions) => {
424
424
  if (!stripeCustomer) {
425
425
  stripeCustomer = await client.customers.create({
426
426
  email: user.email,
427
- name: user.name ?? undefined,
427
+ name: user.name,
428
428
  metadata: customerMetadata.set(
429
429
  {
430
430
  userId: user.id,
@@ -832,7 +832,7 @@ describe("stripe - organization customer", () => {
832
832
  expect(cancelRes.error?.code).toBe("UNAUTHORIZED");
833
833
  });
834
834
 
835
- it("should reject organization subscription when organization.enabled is false", async () => {
835
+ it("should reject organization subscription when authorizeReference is not configured", async () => {
836
836
  const stripeOptionsWithoutOrg: StripeOptions = {
837
837
  ...baseOrgStripeOptions,
838
838
  organization: undefined, // Disable organization support
@@ -878,7 +878,7 @@ describe("stripe - organization customer", () => {
878
878
  fetchOptions: { headers },
879
879
  });
880
880
 
881
- expect(res.error?.code).toBe("ORGANIZATION_SUBSCRIPTION_NOT_ENABLED");
881
+ expect(res.error?.code).toBe("AUTHORIZE_REFERENCE_REQUIRED");
882
882
  });
883
883
 
884
884
  it("should keep user and organization subscriptions separate", async () => {
@@ -4962,7 +4962,7 @@ describe("stripe", () => {
4962
4962
  fetchOptions: { headers },
4963
4963
  });
4964
4964
 
4965
- expect(res.error?.code).toBe("ORGANIZATION_SUBSCRIPTION_NOT_ENABLED");
4965
+ expect(res.error?.code).toBe("AUTHORIZE_REFERENCE_REQUIRED");
4966
4966
  });
4967
4967
 
4968
4968
  it("should reject when no referenceId or activeOrganizationId", async () => {