@better-auth/stripe 1.7.0-beta.5 → 1.7.0-beta.6

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.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-BkrVCPsb.mjs";
1
+ import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-DN_gseFy.mjs";
2
2
  //#region src/client.ts
3
3
  const stripeClient = (options) => {
4
4
  return {
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-BkrVCPsb.mjs";
1
+ import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-DN_gseFy.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";
@@ -534,6 +534,23 @@ function getReferenceId(ctxSession, customerType, options) {
534
534
  }
535
535
  return user.id;
536
536
  }
537
+ /**
538
+ * Retrieve the subscription a row points to, or `null` if it no longer exists
539
+ * (`resource_missing`) so callers can treat the row as stale.
540
+ * @internal
541
+ */
542
+ async function retrieveStripeSubscription(client, ctx, stripeSubscriptionId) {
543
+ return await client.subscriptions.retrieve(stripeSubscriptionId).catch((e) => {
544
+ /**
545
+ * @see https://docs.stripe.com/error-codes
546
+ */
547
+ if (e?.code === "resource_missing") return null;
548
+ throw ctx.error("BAD_REQUEST", {
549
+ code: e.code,
550
+ message: e.message
551
+ });
552
+ });
553
+ }
537
554
  const upgradeSubscriptionBodySchema = z.object({
538
555
  plan: z.string().meta({ description: "The name of the plan to upgrade to. Eg: \"pro\"" }),
539
556
  annual: z.boolean().meta({ description: "Whether to upgrade to an annual plan. Eg: true" }).optional(),
@@ -577,7 +594,11 @@ const upgradeSubscription = (options) => {
577
594
  stripeSessionMiddleware,
578
595
  referenceMiddleware(subscriptionOptions, "upgrade-subscription"),
579
596
  originCheck((c) => {
580
- return [c.body.successUrl, c.body.cancelUrl];
597
+ return [
598
+ c.body.successUrl,
599
+ c.body.cancelUrl,
600
+ c.body.returnUrl
601
+ ];
581
602
  })
582
603
  ]
583
604
  }, async (ctx) => {
@@ -675,6 +696,10 @@ const upgradeSubscription = (options) => {
675
696
  break;
676
697
  }
677
698
  }
699
+ if (stripeCustomer) {
700
+ const ownerId = customerMetadata.get(stripeCustomer.metadata).userId;
701
+ if (!!ownerId && ownerId !== user.id || !user.emailVerified) stripeCustomer = void 0;
702
+ }
678
703
  if (!stripeCustomer) stripeCustomer = await client.customers.create({
679
704
  email: user.email,
680
705
  name: user.name,
@@ -1100,23 +1125,18 @@ const cancelSubscription = (options) => {
1100
1125
  }).then((subs) => subs.find((sub) => isActiveOrTrialing(sub)));
1101
1126
  if (ctx.body.subscriptionId && subscription && subscription.referenceId !== referenceId) subscription = void 0;
1102
1127
  if (!subscription || !subscription.stripeCustomerId) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND);
1103
- const activeSubscriptions = await client.subscriptions.list({ customer: subscription.stripeCustomerId }).then((res) => res.data.filter((sub) => isActiveOrTrialing(sub)));
1104
- if (!activeSubscriptions.length) {
1105
- /**
1106
- * If the subscription is not found, we need to delete the subscription
1107
- * from the database. This is a rare case and should not happen.
1108
- */
1109
- await ctx.context.adapter.deleteMany({
1128
+ if (!subscription.stripeSubscriptionId) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND);
1129
+ const activeSubscription = await retrieveStripeSubscription(client, ctx, subscription.stripeSubscriptionId);
1130
+ if (!activeSubscription || !isActiveOrTrialing(activeSubscription)) {
1131
+ await ctx.context.adapter.delete({
1110
1132
  model: "subscription",
1111
1133
  where: [{
1112
- field: "referenceId",
1113
- value: referenceId
1134
+ field: "id",
1135
+ value: subscription.id
1114
1136
  }]
1115
1137
  });
1116
1138
  throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND);
1117
1139
  }
1118
- const activeSubscription = activeSubscriptions.find((sub) => sub.id === subscription.stripeSubscriptionId);
1119
- if (!activeSubscription) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND);
1120
1140
  const { url } = await client.billingPortal.sessions.create({
1121
1141
  customer: subscription.stripeCustomerId,
1122
1142
  return_url: getUrl(ctx, ctx.body?.returnUrl || "/"),
@@ -1219,8 +1239,9 @@ const restoreSubscription = (options) => {
1219
1239
  const releasedSub = await client.subscriptions.retrieve(subscription.stripeSubscriptionId);
1220
1240
  return ctx.json(releasedSub);
1221
1241
  }
1222
- const activeSubscription = await client.subscriptions.list({ customer: subscription.stripeCustomerId }).then((res) => res.data.filter((sub) => isActiveOrTrialing(sub))[0]);
1223
- if (!activeSubscription) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND);
1242
+ if (!subscription.stripeSubscriptionId) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND);
1243
+ const activeSubscription = await retrieveStripeSubscription(client, ctx, subscription.stripeSubscriptionId);
1244
+ if (!activeSubscription || !isActiveOrTrialing(activeSubscription)) throw APIError$1.from("BAD_REQUEST", STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND);
1224
1245
  const updateParams = {};
1225
1246
  if (activeSubscription.cancel_at) updateParams.cancel_at = "";
1226
1247
  else if (activeSubscription.cancel_at_period_end) updateParams.cancel_at_period_end = false;
@@ -1307,8 +1328,7 @@ const subscriptionSuccess = (options) => {
1307
1328
  use: [originCheck((ctx) => ctx.query.callbackURL)]
1308
1329
  }, async (ctx) => {
1309
1330
  let callbackURL = ctx.query?.callbackURL || "/";
1310
- const session = await getSessionFromCtx(ctx);
1311
- if (!session) throw ctx.redirect(getUrl(ctx, callbackURL));
1331
+ if (!await getSessionFromCtx(ctx)) throw ctx.redirect(getUrl(ctx, callbackURL));
1312
1332
  if (!ctx.query?.checkoutSessionId) throw ctx.redirect(getUrl(ctx, callbackURL));
1313
1333
  /**
1314
1334
  * Replace the Stripe {CHECKOUT_SESSION_ID} template variable in callbackURL.
@@ -1337,12 +1357,9 @@ const subscriptionSuccess = (options) => {
1337
1357
  throw ctx.redirect(getUrl(ctx, callbackURL));
1338
1358
  }
1339
1359
  if (isActiveOrTrialing(subscription)) throw ctx.redirect(getUrl(ctx, callbackURL));
1340
- const customerId = subscription.stripeCustomerId || session.user.stripeCustomerId;
1341
- if (!customerId) throw ctx.redirect(getUrl(ctx, callbackURL));
1342
- const stripeSubscription = await client.subscriptions.list({
1343
- customer: customerId,
1344
- status: "active"
1345
- }).then((res) => res.data[0]).catch((error) => {
1360
+ const stripeSubscriptionId = typeof checkoutSession.subscription === "string" ? checkoutSession.subscription : checkoutSession.subscription?.id;
1361
+ if (!stripeSubscriptionId || checkoutSession.payment_status === "unpaid") throw ctx.redirect(getUrl(ctx, callbackURL));
1362
+ const stripeSubscription = await client.subscriptions.retrieve(stripeSubscriptionId).catch((error) => {
1346
1363
  ctx.context.logger.error("Error fetching subscription from Stripe", error);
1347
1364
  throw ctx.redirect(getUrl(ctx, callbackURL));
1348
1365
  });
@@ -1665,12 +1682,11 @@ const stripe = (options) => {
1665
1682
  const { organization } = data;
1666
1683
  if (!organization.stripeCustomerId) return;
1667
1684
  try {
1668
- const subscriptions = await client.subscriptions.list({
1685
+ for await (const sub of client.subscriptions.list({
1669
1686
  customer: organization.stripeCustomerId,
1670
1687
  status: "all",
1671
1688
  limit: 100
1672
- });
1673
- for (const sub of subscriptions.data) if (sub.status !== "canceled" && sub.status !== "incomplete" && sub.status !== "incomplete_expired") throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES.ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION);
1689
+ })) if (sub.status !== "canceled" && sub.status !== "incomplete" && sub.status !== "incomplete_expired") throw APIError.from("BAD_REQUEST", STRIPE_ERROR_CODES.ORGANIZATION_HAS_ACTIVE_SUBSCRIPTION);
1674
1690
  } catch (error) {
1675
1691
  if (error instanceof APIError) throw error;
1676
1692
  ctx.logger.error(`Failed to check organization subscriptions: ${error.message}`);
@@ -1775,6 +1791,10 @@ const stripe = (options) => {
1775
1791
  break;
1776
1792
  }
1777
1793
  }
1794
+ if (stripeCustomer) {
1795
+ const ownerId = customerMetadata.get(stripeCustomer.metadata).userId;
1796
+ if (!!ownerId && ownerId !== user.id || !user.emailVerified) stripeCustomer = void 0;
1797
+ }
1778
1798
  if (stripeCustomer) {
1779
1799
  await ctx.context.internalAdapter.updateUser(user.id, { stripeCustomerId: stripeCustomer.id });
1780
1800
  await options.onCustomerCreate?.({
@@ -27,6 +27,6 @@ const STRIPE_ERROR_CODES = defineErrorCodes({
27
27
  });
28
28
  //#endregion
29
29
  //#region src/version.ts
30
- const PACKAGE_VERSION = "1.7.0-beta.5";
30
+ const PACKAGE_VERSION = "1.7.0-beta.6";
31
31
  //#endregion
32
32
  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.7.0-beta.5",
3
+ "version": "1.7.0-beta.6",
4
4
  "description": "Stripe plugin for Better Auth",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -58,14 +58,14 @@
58
58
  "better-call": "1.3.6",
59
59
  "stripe": "^22.0.1",
60
60
  "tsdown": "0.21.1",
61
- "@better-auth/core": "1.7.0-beta.5",
62
- "better-auth": "1.7.0-beta.5"
61
+ "@better-auth/core": "1.7.0-beta.6",
62
+ "better-auth": "1.7.0-beta.6"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "better-call": "1.3.6",
66
66
  "stripe": "^18 || ^19 || ^20 || ^21 || ^22",
67
- "@better-auth/core": "^1.7.0-beta.5",
68
- "better-auth": "^1.7.0-beta.5"
67
+ "@better-auth/core": "^1.7.0-beta.6",
68
+ "better-auth": "^1.7.0-beta.6"
69
69
  },
70
70
  "scripts": {
71
71
  "build": "tsdown",