@better-auth/stripe 1.8.0-beta.3 → 1.8.0-beta.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { l as StripePlan, n as stripe } from "./index-BDmSmcUM.mjs";
1
+ import { l as StripePlan, n as stripe } from "./index-C_aP9Dqi.mjs";
2
2
  //#region src/error-codes.d.ts
3
3
  export declare const STRIPE_ERROR_CODES: {
4
4
  UNAUTHORIZED: import("better-auth").RawError<"UNAUTHORIZED">;
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-CSLu0Cqn.mjs";
1
+ import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-CiZy3Q2W.mjs";
2
2
  //#region src/client.ts
3
3
  const stripeClient = (options) => {
4
4
  return {
@@ -12,18 +12,22 @@ declare const subscriptions: {
12
12
  referenceId: {
13
13
  type: "string";
14
14
  required: true;
15
+ input: false;
15
16
  };
16
17
  stripeCustomerId: {
17
18
  type: "string";
18
19
  required: false;
20
+ input: false;
19
21
  };
20
22
  stripeSubscriptionId: {
21
23
  type: "string";
22
24
  required: false;
25
+ input: false;
23
26
  };
24
27
  status: {
25
28
  type: "string";
26
29
  defaultValue: string;
30
+ input: false;
27
31
  };
28
32
  periodStart: {
29
33
  type: "date";
@@ -69,6 +73,7 @@ declare const subscriptions: {
69
73
  stripeScheduleId: {
70
74
  type: "string";
71
75
  required: false;
76
+ input: false;
72
77
  };
73
78
  };
74
79
  };
@@ -79,6 +84,7 @@ declare const user: {
79
84
  stripeCustomerId: {
80
85
  type: "string";
81
86
  required: false;
87
+ input: false;
82
88
  };
83
89
  };
84
90
  };
@@ -89,6 +95,7 @@ declare const organization: {
89
95
  stripeCustomerId: {
90
96
  type: "string";
91
97
  required: false;
98
+ input: false;
92
99
  };
93
100
  };
94
101
  };
@@ -597,6 +604,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
597
604
  session: StripeCtxSession;
598
605
  }>> | import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
599
606
  referenceId: string;
607
+ customerType: CustomerType;
600
608
  }>> | import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>>)[];
601
609
  }, {
602
610
  url: string;
@@ -684,6 +692,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
684
692
  session: StripeCtxSession;
685
693
  }>> | import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
686
694
  referenceId: string;
695
+ customerType: CustomerType;
687
696
  }>> | import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>>)[];
688
697
  }, {
689
698
  url: string;
@@ -756,6 +765,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
756
765
  session: StripeCtxSession;
757
766
  }>> | import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
758
767
  referenceId: string;
768
+ customerType: CustomerType;
759
769
  }>>)[];
760
770
  }, Stripe.Response<Stripe.Subscription>>;
761
771
  listActiveSubscriptions: import("better-call").StrictEndpoint<"/subscription/list", {
@@ -824,6 +834,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
824
834
  session: StripeCtxSession;
825
835
  }>> | import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
826
836
  referenceId: string;
837
+ customerType: CustomerType;
827
838
  }>>)[];
828
839
  }, {
829
840
  limits: Record<string, unknown> | undefined;
@@ -849,7 +860,10 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
849
860
  }[]>;
850
861
  subscriptionSuccess: import("better-call").StrictEndpoint<"/subscription/success", {
851
862
  method: "GET";
852
- query: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
863
+ query: import("zod").ZodOptional<import("zod").ZodObject<{
864
+ callbackURL: import("zod").ZodOptional<import("zod").ZodString>;
865
+ checkoutSessionId: import("zod").ZodOptional<import("zod").ZodString>;
866
+ }, import("zod/v4/core").$strip>>;
853
867
  metadata: {
854
868
  openapi: {
855
869
  operationId: string;
@@ -926,6 +940,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
926
940
  session: StripeCtxSession;
927
941
  }>> | import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<{
928
942
  referenceId: string;
943
+ customerType: CustomerType;
929
944
  }>> | import("better-call").Middleware<import("better-call").MiddlewareOptions, (inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>>)[];
930
945
  }, {
931
946
  url: string;
@@ -952,6 +967,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
952
967
  stripeCustomerId: {
953
968
  type: "string";
954
969
  required: false;
970
+ input: false;
955
971
  };
956
972
  };
957
973
  };
@@ -967,18 +983,22 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
967
983
  referenceId: {
968
984
  type: "string";
969
985
  required: true;
986
+ input: false;
970
987
  };
971
988
  stripeCustomerId: {
972
989
  type: "string";
973
990
  required: false;
991
+ input: false;
974
992
  };
975
993
  stripeSubscriptionId: {
976
994
  type: "string";
977
995
  required: false;
996
+ input: false;
978
997
  };
979
998
  status: {
980
999
  type: "string";
981
1000
  defaultValue: string;
1001
+ input: false;
982
1002
  };
983
1003
  periodStart: {
984
1004
  type: "date";
@@ -1024,6 +1044,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
1024
1044
  stripeScheduleId: {
1025
1045
  type: "string";
1026
1046
  required: false;
1047
+ input: false;
1027
1048
  };
1028
1049
  };
1029
1050
  };
@@ -1035,6 +1056,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
1035
1056
  stripeCustomerId: {
1036
1057
  type: "string";
1037
1058
  required: false;
1059
+ input: false;
1038
1060
  };
1039
1061
  };
1040
1062
  };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as CheckoutSessionLocale, c as StripeOptions, d as SubscriptionOptions, f as WithActiveOrganizationId, i as CheckoutSessionLineItem, l as StripePlan, n as stripe, o as CustomerType, p as WithStripeCustomerId, r as AuthorizeReferenceAction, s as StripeCtxSession, t as StripePlugin, u as Subscription } from "./index-BDmSmcUM.mjs";
1
+ import { a as CheckoutSessionLocale, c as StripeOptions, d as SubscriptionOptions, f as WithActiveOrganizationId, i as CheckoutSessionLineItem, l as StripePlan, n as stripe, o as CustomerType, p as WithStripeCustomerId, r as AuthorizeReferenceAction, s as StripeCtxSession, t as StripePlugin, u as Subscription } from "./index-C_aP9Dqi.mjs";
2
2
  export { type AuthorizeReferenceAction, type CheckoutSessionLineItem, type CheckoutSessionLocale, type CustomerType, type StripeCtxSession, type StripeOptions, type StripePlan, StripePlugin, type Subscription, type SubscriptionOptions, type WithActiveOrganizationId, type WithStripeCustomerId, stripe };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-CSLu0Cqn.mjs";
1
+ import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-CiZy3Q2W.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";
@@ -152,31 +152,58 @@ async function resolvePlanItem(options, items) {
152
152
  * @internal
153
153
  */
154
154
  async function findReferenceByStripeCustomerId(ctx, options, stripeCustomerId) {
155
- if (options.organization?.enabled) {
156
- const org = await ctx.context.adapter.findOne({
157
- model: "organization",
158
- where: [{
159
- field: "stripeCustomerId",
160
- value: stripeCustomerId
161
- }]
162
- });
163
- if (org) return {
155
+ const findCandidates = (model) => ctx.context.adapter.findMany({
156
+ model,
157
+ where: [{
158
+ field: "stripeCustomerId",
159
+ value: stripeCustomerId
160
+ }],
161
+ limit: 2
162
+ });
163
+ const orgs = options.organization?.enabled ? await findCandidates("organization") : [];
164
+ const users = await findCandidates("user");
165
+ if (orgs.length + users.length < 2) {
166
+ if (orgs[0]) return {
164
167
  customerType: "organization",
165
- referenceId: org.id
168
+ referenceId: orgs[0].id
169
+ };
170
+ if (users[0]) return {
171
+ customerType: "user",
172
+ referenceId: users[0].id
166
173
  };
174
+ return null;
167
175
  }
168
- const user = await ctx.context.adapter.findOne({
169
- model: "user",
176
+ const customer = await options.stripeClient.customers.retrieve(stripeCustomerId);
177
+ const { customerType, userId, organizationId } = customerMetadata.get(customer.deleted ? null : customer.metadata);
178
+ const namesOwner = customerType === "user" || customerType === "organization";
179
+ const referenceId = customerType === "organization" ? organizationId : userId;
180
+ if (!namesOwner || !referenceId) {
181
+ ctx.context.logger.warn(`Stripe webhook warning: Multiple records share stripeCustomerId ${stripeCustomerId} and the customer does not identify its owner`);
182
+ return null;
183
+ }
184
+ const mismatch = `Stripe webhook warning: The owner recorded on Stripe customer ${stripeCustomerId} does not hold that customer id`;
185
+ if (customerType === "organization" && !options.organization?.enabled) {
186
+ ctx.context.logger.warn(mismatch);
187
+ return null;
188
+ }
189
+ const record = await ctx.context.adapter.findOne({
190
+ model: customerType,
170
191
  where: [{
171
192
  field: "stripeCustomerId",
172
193
  value: stripeCustomerId
194
+ }, {
195
+ field: "id",
196
+ value: referenceId
173
197
  }]
174
198
  });
175
- if (user) return {
176
- customerType: "user",
177
- referenceId: user.id
199
+ if (!record) {
200
+ ctx.context.logger.warn(mismatch);
201
+ return null;
202
+ }
203
+ return {
204
+ customerType,
205
+ referenceId: record.id
178
206
  };
179
- return null;
180
207
  }
181
208
  async function onCheckoutSessionCompleted(ctx, options, event) {
182
209
  try {
@@ -487,10 +514,16 @@ const referenceMiddleware = (options, action) => createAuthMiddleware(async (ctx
487
514
  referenceId,
488
515
  action
489
516
  }, ctx)) throw APIError$1.from("UNAUTHORIZED", STRIPE_ERROR_CODES.UNAUTHORIZED);
490
- return { referenceId };
517
+ return {
518
+ referenceId,
519
+ customerType
520
+ };
491
521
  }
492
522
  const referenceId = explicitReferenceId || ctxSession.user.id;
493
- if (!explicitReferenceId || explicitReferenceId === ctxSession.user.id) return { referenceId };
523
+ if (!explicitReferenceId || explicitReferenceId === ctxSession.user.id) return {
524
+ referenceId,
525
+ customerType: "user"
526
+ };
494
527
  if (!subscriptionOptions.authorizeReference) {
495
528
  ctx.context.logger.error(`Passing referenceId into a subscription action isn't allowed if subscription.authorizeReference isn't defined in your stripe plugin config.`);
496
529
  throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.REFERENCE_ID_NOT_ALLOWED);
@@ -501,7 +534,10 @@ const referenceMiddleware = (options, action) => createAuthMiddleware(async (ctx
501
534
  referenceId,
502
535
  action
503
536
  }, ctx)) throw APIError$1.from("UNAUTHORIZED", STRIPE_ERROR_CODES.UNAUTHORIZED);
504
- return { referenceId };
537
+ return {
538
+ referenceId,
539
+ customerType: "user"
540
+ };
505
541
  });
506
542
  //#endregion
507
543
  //#region src/routes.ts
@@ -652,7 +688,7 @@ const upgradeSubscription = (options) => {
652
688
  ]
653
689
  }, async (ctx) => {
654
690
  const { user, session } = ctx.context.session;
655
- const customerType = ctx.body.customerType || "user";
691
+ const customerType = ctx.context.customerType;
656
692
  const referenceId = ctx.context.referenceId;
657
693
  if (!user.emailVerified && subscriptionOptions.requireEmailVerification) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.EMAIL_VERIFICATION_REQUIRED);
658
694
  const plan = await getPlanByName(options, ctx.body.plan);
@@ -1384,23 +1420,33 @@ const listActiveSubscriptions = (options) => {
1384
1420
  return ctx.json(subs);
1385
1421
  });
1386
1422
  };
1387
- const subscriptionSuccessQuerySchema = z.record(z.string(), z.any()).optional();
1423
+ const subscriptionSuccessQuerySchema = z.object({
1424
+ callbackURL: z.string().optional(),
1425
+ checkoutSessionId: z.string().optional()
1426
+ }).optional();
1427
+ /**
1428
+ * Fill the Stripe "{CHECKOUT_SESSION_ID}" template variable in callbackURL.
1429
+ * @see https://docs.stripe.com/payments/checkout/custom-success-page?payment-ui=stripe-hosted#modify-the-success-url
1430
+ */
1431
+ function fillCheckoutSessionId(callbackURL, checkoutSessionId) {
1432
+ return callbackURL.replaceAll("{CHECKOUT_SESSION_ID}", checkoutSessionId);
1433
+ }
1388
1434
  const subscriptionSuccess = (options) => {
1389
1435
  const client = options.stripeClient;
1390
1436
  return createAuthEndpoint("/subscription/success", {
1391
1437
  method: "GET",
1392
1438
  query: subscriptionSuccessQuerySchema,
1393
1439
  metadata: { openapi: { operationId: "handleSubscriptionSuccess" } },
1394
- use: [originCheck((ctx) => ctx.query.callbackURL)]
1440
+ use: [originCheck((ctx) => {
1441
+ const { callbackURL, checkoutSessionId } = ctx.query ?? {};
1442
+ if (!callbackURL || !checkoutSessionId) return callbackURL;
1443
+ return [callbackURL, fillCheckoutSessionId(callbackURL, checkoutSessionId)];
1444
+ })]
1395
1445
  }, async (ctx) => {
1396
1446
  let callbackURL = ctx.query?.callbackURL || "/";
1397
1447
  if (!await getSessionFromCtx(ctx)) throw ctx.redirect(getUrl(ctx, callbackURL));
1398
1448
  if (!ctx.query?.checkoutSessionId) throw ctx.redirect(getUrl(ctx, callbackURL));
1399
- /**
1400
- * Replace the Stripe {CHECKOUT_SESSION_ID} template variable in callbackURL.
1401
- * @see https://docs.stripe.com/payments/checkout/custom-success-page?payment-ui=stripe-hosted#modify-the-success-url
1402
- */
1403
- callbackURL = callbackURL.replaceAll("{CHECKOUT_SESSION_ID}", ctx.query.checkoutSessionId);
1449
+ callbackURL = fillCheckoutSessionId(callbackURL, ctx.query.checkoutSessionId);
1404
1450
  const checkoutSession = await client.checkout.sessions.retrieve(ctx.query.checkoutSessionId).catch((error) => {
1405
1451
  ctx.context.logger.error("Error retrieving checkout session from Stripe", error);
1406
1452
  return null;
@@ -1501,7 +1547,7 @@ const createBillingPortal = (options) => {
1501
1547
  ]
1502
1548
  }, async (ctx) => {
1503
1549
  const { user } = ctx.context.session;
1504
- const customerType = ctx.body.customerType || "user";
1550
+ const customerType = ctx.context.customerType;
1505
1551
  const referenceId = ctx.context.referenceId;
1506
1552
  let customerId;
1507
1553
  if (customerType === "organization") {
@@ -1608,19 +1654,23 @@ const subscriptions = { subscription: { fields: {
1608
1654
  },
1609
1655
  referenceId: {
1610
1656
  type: "string",
1611
- required: true
1657
+ required: true,
1658
+ input: false
1612
1659
  },
1613
1660
  stripeCustomerId: {
1614
1661
  type: "string",
1615
- required: false
1662
+ required: false,
1663
+ input: false
1616
1664
  },
1617
1665
  stripeSubscriptionId: {
1618
1666
  type: "string",
1619
- required: false
1667
+ required: false,
1668
+ input: false
1620
1669
  },
1621
1670
  status: {
1622
1671
  type: "string",
1623
- defaultValue: "incomplete"
1672
+ defaultValue: "incomplete",
1673
+ input: false
1624
1674
  },
1625
1675
  periodStart: {
1626
1676
  type: "date",
@@ -1665,16 +1715,19 @@ const subscriptions = { subscription: { fields: {
1665
1715
  },
1666
1716
  stripeScheduleId: {
1667
1717
  type: "string",
1668
- required: false
1718
+ required: false,
1719
+ input: false
1669
1720
  }
1670
1721
  } } };
1671
1722
  const user = { user: { fields: { stripeCustomerId: {
1672
1723
  type: "string",
1673
- required: false
1724
+ required: false,
1725
+ input: false
1674
1726
  } } } };
1675
1727
  const organization = { organization: { fields: { stripeCustomerId: {
1676
1728
  type: "string",
1677
- required: false
1729
+ required: false,
1730
+ input: false
1678
1731
  } } } };
1679
1732
  const getSchema = (options) => {
1680
1733
  let baseSchema = {};
@@ -30,6 +30,6 @@ const STRIPE_ERROR_CODES = defineErrorCodes({
30
30
  });
31
31
  //#endregion
32
32
  //#region src/version.ts
33
- const PACKAGE_VERSION = "1.8.0-beta.3";
33
+ const PACKAGE_VERSION = "1.8.0-beta.5";
34
34
  //#endregion
35
35
  export { STRIPE_ERROR_CODES as n, PACKAGE_VERSION as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/stripe",
3
- "version": "1.8.0-beta.3",
3
+ "version": "1.8.0-beta.5",
4
4
  "description": "Stripe plugin for Better Auth",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -55,17 +55,17 @@
55
55
  "zod": "^4.5.4"
56
56
  },
57
57
  "devDependencies": {
58
- "better-call": "1.4.4",
58
+ "better-call": "1.4.5",
59
59
  "stripe": "^23.0.0",
60
60
  "tsdown": "0.23.1",
61
- "@better-auth/core": "1.8.0-beta.3",
62
- "better-auth": "1.8.0-beta.3"
61
+ "@better-auth/core": "1.8.0-beta.5",
62
+ "better-auth": "1.8.0-beta.5"
63
63
  },
64
64
  "peerDependencies": {
65
- "better-call": "1.4.4",
65
+ "better-call": "1.4.5",
66
66
  "stripe": "^18 || ^19 || ^20 || ^21 || ^22 || ^23",
67
- "@better-auth/core": "^1.8.0-beta.3",
68
- "better-auth": "^1.8.0-beta.3"
67
+ "@better-auth/core": "^1.8.0-beta.5",
68
+ "better-auth": "^1.8.0-beta.5"
69
69
  },
70
70
  "scripts": {
71
71
  "build": "tsdown",