@better-auth/stripe 1.6.2 → 1.7.0-beta.0

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 { n as stripe, s as StripePlan } from "./index-DCU1841o.mjs";
1
+ import { l as StripePlan, n as stripe } from "./index-C8Utp7ig.mjs";
2
2
  import * as better_auth0 from "better-auth";
3
3
 
4
4
  //#region src/error-codes.d.ts
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-Cbb53rA7.mjs";
1
+ import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-xtzWxfYf.mjs";
2
2
  //#region src/client.ts
3
3
  const stripeClient = (options) => {
4
4
  return {
@@ -2,9 +2,9 @@ import * as better_auth0 from "better-auth";
2
2
  import { GenericEndpointContext, InferOptionSchema, Session, User } from "better-auth";
3
3
  import * as zod from "zod";
4
4
  import * as better_call0 from "better-call";
5
- import * as zod_v4_core0 from "zod/v4/core";
6
5
  import { Organization } from "better-auth/plugins/organization";
7
6
  import Stripe from "stripe";
7
+ import * as zod_v4_core0 from "zod/v4/core";
8
8
 
9
9
  //#region src/schema.d.ts
10
10
  declare const subscriptions: {
@@ -112,6 +112,8 @@ type StripeCtxSession = {
112
112
  session: Session & WithActiveOrganizationId;
113
113
  user: User & WithStripeCustomerId;
114
114
  };
115
+ type CheckoutSessionLocale = NonNullable<Stripe.Checkout.SessionCreateParams["locale"]>;
116
+ type CheckoutSessionLineItem = NonNullable<Stripe.Checkout.SessionCreateParams["line_items"]>[number];
115
117
  type StripePlan = {
116
118
  /**
117
119
  * Monthly price id
@@ -182,7 +184,7 @@ type StripePlan = {
182
184
  *
183
185
  * @see https://docs.stripe.com/billing/subscriptions/mixed-interval#limitations
184
186
  */
185
- lineItems?: Stripe.Checkout.SessionCreateParams.LineItem[] | undefined;
187
+ lineItems?: CheckoutSessionLineItem[] | undefined;
186
188
  /**
187
189
  * Free trial days
188
190
  */
@@ -533,7 +535,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
533
535
  }>>;
534
536
  metadata: zod.ZodOptional<zod.ZodRecord<zod.ZodString, zod.ZodAny>>;
535
537
  seats: zod.ZodOptional<zod.ZodNumber>;
536
- locale: zod.ZodOptional<zod.ZodCustom<Stripe.Checkout.Session.Locale, Stripe.Checkout.Session.Locale>>;
538
+ locale: zod.ZodOptional<zod.ZodCustom<CheckoutSessionLocale, CheckoutSessionLocale>>;
537
539
  successUrl: zod.ZodDefault<zod.ZodString>;
538
540
  cancelUrl: zod.ZodDefault<zod.ZodString>;
539
541
  returnUrl: zod.ZodOptional<zod.ZodString>;
@@ -565,9 +567,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
565
567
  email: string;
566
568
  emailVerified: boolean;
567
569
  name: string;
568
- image /**
569
- * Sync organization name to Stripe customer
570
- */?: string | null | undefined;
570
+ image?: string | null | undefined;
571
571
  };
572
572
  };
573
573
  }>)[];
@@ -577,74 +577,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
577
577
  }, {
578
578
  url: string;
579
579
  redirect: boolean;
580
- } | {
581
- redirect: boolean;
582
- id: string;
583
- object: "checkout.session";
584
- adaptive_pricing: Stripe.Checkout.Session.AdaptivePricing | null;
585
- after_expiration: Stripe.Checkout.Session.AfterExpiration | null;
586
- allow_promotion_codes: boolean | null;
587
- amount_subtotal: number | null;
588
- amount_total: number | null;
589
- automatic_tax: Stripe.Checkout.Session.AutomaticTax;
590
- billing_address_collection: Stripe.Checkout.Session.BillingAddressCollection | null;
591
- branding_settings?: Stripe.Checkout.Session.BrandingSettings;
592
- cancel_url: string | null;
593
- client_reference_id: string | null;
594
- client_secret: string | null;
595
- collected_information: Stripe.Checkout.Session.CollectedInformation | null;
596
- consent: Stripe.Checkout.Session.Consent | null;
597
- consent_collection: Stripe.Checkout.Session.ConsentCollection | null;
598
- created: number;
599
- currency: string | null;
600
- currency_conversion: Stripe.Checkout.Session.CurrencyConversion | null;
601
- custom_fields: Array<Stripe.Checkout.Session.CustomField>;
602
- custom_text: Stripe.Checkout.Session.CustomText;
603
- customer: string | Stripe.Customer | Stripe.DeletedCustomer | null;
604
- customer_account: string | null;
605
- customer_creation: Stripe.Checkout.Session.CustomerCreation | null;
606
- customer_details: Stripe.Checkout.Session.CustomerDetails | null;
607
- customer_email: string | null;
608
- discounts: Array<Stripe.Checkout.Session.Discount> | null;
609
- excluded_payment_method_types?: Array<string>;
610
- expires_at: number;
611
- invoice: string | Stripe.Invoice | null;
612
- invoice_creation: Stripe.Checkout.Session.InvoiceCreation | null;
613
- line_items?: Stripe.ApiList<Stripe.LineItem>;
614
- livemode: boolean;
615
- locale: Stripe.Checkout.Session.Locale | null;
616
- metadata: Stripe.Metadata | null;
617
- mode: Stripe.Checkout.Session.Mode;
618
- name_collection?: Stripe.Checkout.Session.NameCollection;
619
- optional_items?: Array<Stripe.Checkout.Session.OptionalItem> | null;
620
- origin_context: Stripe.Checkout.Session.OriginContext | null;
621
- payment_intent: string | Stripe.PaymentIntent | null;
622
- payment_link: string | Stripe.PaymentLink | null;
623
- payment_method_collection: Stripe.Checkout.Session.PaymentMethodCollection | null;
624
- payment_method_configuration_details: Stripe.Checkout.Session.PaymentMethodConfigurationDetails | null;
625
- payment_method_options: Stripe.Checkout.Session.PaymentMethodOptions | null;
626
- payment_method_types: Array<string>;
627
- payment_status: Stripe.Checkout.Session.PaymentStatus;
628
- permissions: Stripe.Checkout.Session.Permissions | null;
629
- phone_number_collection?: Stripe.Checkout.Session.PhoneNumberCollection;
630
- presentment_details?: Stripe.Checkout.Session.PresentmentDetails;
631
- recovered_from: string | null;
632
- redirect_on_completion?: Stripe.Checkout.Session.RedirectOnCompletion;
633
- return_url?: string;
634
- saved_payment_method_options: Stripe.Checkout.Session.SavedPaymentMethodOptions | null;
635
- setup_intent: string | Stripe.SetupIntent | null;
636
- shipping_address_collection: Stripe.Checkout.Session.ShippingAddressCollection | null;
637
- shipping_cost: Stripe.Checkout.Session.ShippingCost | null;
638
- shipping_options: Array<Stripe.Checkout.Session.ShippingOption>;
639
- status: Stripe.Checkout.Session.Status | null;
640
- submit_type: Stripe.Checkout.Session.SubmitType | null;
641
- subscription: string | Stripe.Subscription | null;
642
- success_url: string | null;
643
- tax_id_collection?: Stripe.Checkout.Session.TaxIdCollection;
644
- total_details: Stripe.Checkout.Session.TotalDetails | null;
645
- ui_mode: Stripe.Checkout.Session.UiMode | null;
646
- url: string | null;
647
- wallet_options: Stripe.Checkout.Session.WalletOptions | null;
580
+ } | (Stripe.Checkout.Session & {
648
581
  lastResponse: {
649
582
  headers: {
650
583
  [key: string]: string;
@@ -655,7 +588,9 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
655
588
  idempotencyKey?: string;
656
589
  stripeAccount?: string;
657
590
  };
658
- }>;
591
+ } & {
592
+ redirect: boolean;
593
+ })>;
659
594
  cancelSubscription: better_call0.StrictEndpoint<"/subscription/cancel", {
660
595
  method: "POST";
661
596
  body: zod.ZodObject<{
@@ -693,9 +628,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
693
628
  email: string;
694
629
  emailVerified: boolean;
695
630
  name: string;
696
- image /**
697
- * Sync organization name to Stripe customer
698
- */?: string | null | undefined;
631
+ image?: string | null | undefined;
699
632
  };
700
633
  };
701
634
  }>)[];
@@ -741,9 +674,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
741
674
  email: string;
742
675
  emailVerified: boolean;
743
676
  name: string;
744
- image /**
745
- * Sync organization name to Stripe customer
746
- */?: string | null | undefined;
677
+ image?: string | null | undefined;
747
678
  };
748
679
  };
749
680
  }>)[];
@@ -785,9 +716,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
785
716
  email: string;
786
717
  emailVerified: boolean;
787
718
  name: string;
788
- image /**
789
- * Sync organization name to Stripe customer
790
- */?: string | null | undefined;
719
+ image?: string | null | undefined;
791
720
  };
792
721
  };
793
722
  }>)[];
@@ -829,7 +758,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
829
758
  createBillingPortal: better_call0.StrictEndpoint<"/subscription/billing-portal", {
830
759
  method: "POST";
831
760
  body: zod.ZodObject<{
832
- locale: zod.ZodOptional<zod.ZodCustom<Stripe.Checkout.Session.Locale, Stripe.Checkout.Session.Locale>>;
761
+ locale: zod.ZodOptional<zod.ZodCustom<CheckoutSessionLocale, CheckoutSessionLocale>>;
833
762
  referenceId: zod.ZodOptional<zod.ZodString>;
834
763
  customerType: zod.ZodOptional<zod.ZodEnum<{
835
764
  user: "user";
@@ -863,9 +792,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
863
792
  email: string;
864
793
  emailVerified: boolean;
865
794
  name: string;
866
- image /**
867
- * Sync organization name to Stripe customer
868
- */?: string | null | undefined;
795
+ image?: string | null | undefined;
869
796
  };
870
797
  };
871
798
  }>)[];
@@ -1013,4 +940,4 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
1013
940
  };
1014
941
  type StripePlugin<O extends StripeOptions> = ReturnType<typeof stripe<O>>;
1015
942
  //#endregion
1016
- export { StripeCtxSession as a, Subscription as c, WithStripeCustomerId as d, CustomerType as i, SubscriptionOptions as l, stripe as n, StripeOptions as o, AuthorizeReferenceAction as r, StripePlan as s, StripePlugin as t, WithActiveOrganizationId as u };
943
+ export { CheckoutSessionLocale as a, StripeOptions as c, SubscriptionOptions as d, WithActiveOrganizationId as f, CheckoutSessionLineItem as i, StripePlan as l, stripe as n, CustomerType as o, WithStripeCustomerId as p, AuthorizeReferenceAction as r, StripeCtxSession as s, StripePlugin as t, Subscription as u };
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { a as StripeCtxSession, c as Subscription, d as WithStripeCustomerId, i as CustomerType, l as SubscriptionOptions, n as stripe, o as StripeOptions, r as AuthorizeReferenceAction, s as StripePlan, t as StripePlugin, u as WithActiveOrganizationId } from "./index-DCU1841o.mjs";
2
- export { AuthorizeReferenceAction, CustomerType, StripeCtxSession, StripeOptions, StripePlan, StripePlugin, Subscription, SubscriptionOptions, WithActiveOrganizationId, WithStripeCustomerId, stripe };
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-C8Utp7ig.mjs";
2
+ export { AuthorizeReferenceAction, CheckoutSessionLineItem, CheckoutSessionLocale, CustomerType, StripeCtxSession, StripeOptions, StripePlan, StripePlugin, Subscription, SubscriptionOptions, WithActiveOrganizationId, WithStripeCustomerId, stripe };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-Cbb53rA7.mjs";
1
+ import { n as STRIPE_ERROR_CODES, t as PACKAGE_VERSION } from "./version-xtzWxfYf.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";
@@ -463,24 +463,37 @@ const referenceMiddleware = (subscriptionOptions, action) => createAuthMiddlewar
463
463
  //#endregion
464
464
  //#region src/routes.ts
465
465
  /**
466
- * Converts a relative URL to an absolute URL using baseURL.
466
+ * Resolves a Stripe price object, either from a lookup key or by retrieving
467
+ * by ID. Used to inspect `recurring.usage_type` for metered billing.
467
468
  * @internal
468
469
  */
469
- function getUrl(ctx, url) {
470
- if (/^[a-zA-Z][a-zA-Z0-9+\-.]*:/.test(url)) return url;
471
- return `${ctx.context.options.baseURL}${url.startsWith("/") ? url : `/${url}`}`;
470
+ async function resolveStripePrice(stripeClient, priceId, lookupKey) {
471
+ try {
472
+ if (lookupKey) {
473
+ const priceData = (await stripeClient.prices.list({
474
+ lookup_keys: [lookupKey],
475
+ active: true,
476
+ limit: 1
477
+ })).data[0];
478
+ if (priceData) return priceData;
479
+ }
480
+ if (priceId) return await stripeClient.prices.retrieve(priceId);
481
+ } catch {}
472
482
  }
473
483
  /**
474
- * Resolves a Stripe price ID from a lookup key.
484
+ * Checks if a Stripe price uses metered (usage-based) billing.
475
485
  * @internal
476
486
  */
477
- async function resolvePriceIdFromLookupKey(stripeClient, lookupKey) {
478
- if (!lookupKey) return void 0;
479
- return (await stripeClient.prices.list({
480
- lookup_keys: [lookupKey],
481
- active: true,
482
- limit: 1
483
- })).data[0]?.id;
487
+ function isMeteredPrice(price) {
488
+ return price?.recurring?.usage_type === "metered";
489
+ }
490
+ /**
491
+ * Converts a relative URL to an absolute URL using baseURL.
492
+ * @internal
493
+ */
494
+ function getUrl(ctx, url) {
495
+ if (/^[a-zA-Z][a-zA-Z0-9+\-.]*:/.test(url)) return url;
496
+ return `${ctx.context.options.baseURL}${url.startsWith("/") ? url : `/${url}`}`;
484
497
  }
485
498
  /**
486
499
  * Determines the reference ID based on customer type.
@@ -677,10 +690,10 @@ const upgradeSubscription = (options) => {
677
690
  const stripeSubscriptionPriceId = planItem?.price.id;
678
691
  const incompleteSubscription = subscriptions.find((sub) => sub.status === "incomplete");
679
692
  const priceId = ctx.body.annual ? plan.annualDiscountPriceId : plan.priceId;
680
- const lookupKey = ctx.body.annual ? plan.annualDiscountLookupKey : plan.lookupKey;
681
- const resolvedPriceId = lookupKey ? await resolvePriceIdFromLookupKey(client, lookupKey) : void 0;
682
- const priceIdToUse = priceId || resolvedPriceId;
693
+ const resolvedPrice = await resolveStripePrice(client, priceId, ctx.body.annual ? plan.annualDiscountLookupKey : plan.lookupKey);
694
+ const priceIdToUse = resolvedPrice?.id ?? priceId;
683
695
  if (!priceIdToUse) throw ctx.error("BAD_REQUEST", { message: "Price ID not found for the selected plan" });
696
+ const isMetered = isMeteredPrice(resolvedPrice);
684
697
  const isAutoManagedSeats = !!(plan.seatPriceId && customerType === "organization");
685
698
  let memberCount = 0;
686
699
  if (isAutoManagedSeats) memberCount = await ctx.context.adapter.count({
@@ -780,7 +793,7 @@ const upgradeSubscription = (options) => {
780
793
  if (itemPriceId === stripeSubscriptionPriceId) {
781
794
  newPhaseItems.push({
782
795
  price: priceIdToUse,
783
- quantity: isAutoManagedSeats ? 1 : ctx.body.seats || 1
796
+ ...isMetered ? {} : { quantity: isAutoManagedSeats ? 1 : ctx.body.seats || 1 }
784
797
  });
785
798
  continue;
786
799
  }
@@ -853,7 +866,7 @@ const upgradeSubscription = (options) => {
853
866
  itemUpdates.push({
854
867
  id: si.id,
855
868
  price: priceIdToUse,
856
- quantity: isAutoManagedSeats ? 1 : ctx.body.seats || 1
869
+ ...isMetered ? {} : { quantity: isAutoManagedSeats ? 1 : ctx.body.seats || 1 }
857
870
  });
858
871
  continue;
859
872
  }
@@ -898,7 +911,7 @@ const upgradeSubscription = (options) => {
898
911
  items: [{
899
912
  id: planItem.id,
900
913
  price: priceIdToUse,
901
- ...isAutoManagedSeats ? {} : { quantity: ctx.body.seats || 1 }
914
+ ...isAutoManagedSeats || isMetered ? {} : { quantity: ctx.body.seats || 1 }
902
915
  }]
903
916
  }
904
917
  }
@@ -955,54 +968,54 @@ const upgradeSubscription = (options) => {
955
968
  })).some((s) => {
956
969
  return !!(s.trialStart || s.trialEnd) || s.status === "trialing";
957
970
  }) && plan.freeTrial ? { trial_period_days: plan.freeTrial.days } : void 0;
958
- const checkoutSession = await client.checkout.sessions.create({
959
- ...customerId ? {
960
- customer: customerId,
961
- customer_update: customerType !== "user" ? { address: "auto" } : {
962
- name: "auto",
963
- address: "auto"
964
- }
965
- } : { customer_email: user.email },
966
- locale: ctx.body.locale,
967
- success_url: getUrl(ctx, `${ctx.context.baseURL}/subscription/success?callbackURL=${encodeURIComponent(ctx.body.successUrl)}&checkoutSessionId={CHECKOUT_SESSION_ID}`),
968
- cancel_url: getUrl(ctx, ctx.body.cancelUrl),
969
- line_items: [
970
- ...!isSeatOnlyPlan ? [{
971
- price: priceIdToUse,
972
- quantity: isAutoManagedSeats ? 1 : ctx.body.seats || 1
973
- }] : [],
974
- ...isAutoManagedSeats ? [{
975
- price: plan.seatPriceId,
976
- quantity: memberCount
977
- }] : [],
978
- ...plan.lineItems ?? []
979
- ],
980
- subscription_data: {
981
- ...freeTrial,
971
+ const response = {
972
+ ...await client.checkout.sessions.create({
973
+ ...customerId ? {
974
+ customer: customerId,
975
+ customer_update: customerType !== "user" ? { address: "auto" } : {
976
+ name: "auto",
977
+ address: "auto"
978
+ }
979
+ } : { customer_email: user.email },
980
+ locale: ctx.body.locale,
981
+ success_url: getUrl(ctx, `${ctx.context.baseURL}/subscription/success?callbackURL=${encodeURIComponent(ctx.body.successUrl)}&checkoutSessionId={CHECKOUT_SESSION_ID}`),
982
+ cancel_url: getUrl(ctx, ctx.body.cancelUrl),
983
+ line_items: [
984
+ ...!isSeatOnlyPlan ? [{
985
+ price: priceIdToUse,
986
+ ...isMetered ? {} : { quantity: isAutoManagedSeats ? 1 : ctx.body.seats || 1 }
987
+ }] : [],
988
+ ...isAutoManagedSeats ? [{
989
+ price: plan.seatPriceId,
990
+ quantity: memberCount
991
+ }] : [],
992
+ ...plan.lineItems ?? []
993
+ ],
994
+ subscription_data: {
995
+ ...freeTrial,
996
+ metadata: subscriptionMetadata.set({
997
+ userId: user.id,
998
+ subscriptionId: subscription.id,
999
+ referenceId
1000
+ }, ctx.body.metadata, params?.params?.subscription_data?.metadata)
1001
+ },
1002
+ mode: "subscription",
1003
+ client_reference_id: referenceId,
1004
+ ...params?.params,
982
1005
  metadata: subscriptionMetadata.set({
983
1006
  userId: user.id,
984
1007
  subscriptionId: subscription.id,
985
1008
  referenceId
986
- }, ctx.body.metadata, params?.params?.subscription_data?.metadata)
987
- },
988
- mode: "subscription",
989
- client_reference_id: referenceId,
990
- ...params?.params,
991
- metadata: subscriptionMetadata.set({
992
- userId: user.id,
993
- subscriptionId: subscription.id,
994
- referenceId
995
- }, ctx.body.metadata, params?.params?.metadata)
996
- }, params?.options).catch(async (e) => {
997
- throw ctx.error("BAD_REQUEST", {
998
- message: e.message,
999
- code: e.code
1000
- });
1001
- });
1002
- return ctx.json({
1003
- ...checkoutSession,
1009
+ }, ctx.body.metadata, params?.params?.metadata)
1010
+ }, params?.options).catch(async (e) => {
1011
+ throw ctx.error("BAD_REQUEST", {
1012
+ message: e.message,
1013
+ code: e.code
1014
+ });
1015
+ }),
1004
1016
  redirect: !ctx.body.disableRedirect
1005
- });
1017
+ };
1018
+ return ctx.json(response);
1006
1019
  });
1007
1020
  };
1008
1021
  const cancelSubscriptionBodySchema = z.object({
@@ -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.6.2";
30
+ const PACKAGE_VERSION = "1.7.0-beta.0";
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.6.2",
3
+ "version": "1.7.0-beta.0",
4
4
  "description": "Stripe plugin for Better Auth",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -56,16 +56,16 @@
56
56
  },
57
57
  "devDependencies": {
58
58
  "better-call": "1.3.5",
59
- "stripe": "^20.4.0",
59
+ "stripe": "^22.0.1",
60
60
  "tsdown": "0.21.1",
61
- "@better-auth/core": "1.6.2",
62
- "better-auth": "1.6.2"
61
+ "@better-auth/core": "1.7.0-beta.0",
62
+ "better-auth": "1.7.0-beta.0"
63
63
  },
64
64
  "peerDependencies": {
65
65
  "better-call": "1.3.5",
66
- "stripe": "^18 || ^19 || ^20",
67
- "@better-auth/core": "^1.6.2",
68
- "better-auth": "^1.6.2"
66
+ "stripe": "^18 || ^19 || ^20 || ^21 || ^22",
67
+ "@better-auth/core": "^1.7.0-beta.0",
68
+ "better-auth": "^1.7.0-beta.0"
69
69
  },
70
70
  "scripts": {
71
71
  "build": "tsdown",