@better-auth/stripe 1.2.4-beta.7 → 1.2.4-beta.8

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,17 +1,17 @@
1
1
 
2
- > @better-auth/stripe@1.2.4-beta.7 build /home/runner/work/better-auth/better-auth/packages/stripe
2
+ > @better-auth/stripe@1.2.4-beta.8 build /home/runner/work/better-auth/better-auth/packages/stripe
3
3
  > unbuild
4
4
 
5
5
  [info] Automatically detected entries: src/index, src/client [esm] [cjs] [dts]
6
6
  [info] Building stripe
7
7
  [success] Build succeeded for stripe
8
- [log] dist/index.cjs (total size: 31.2 kB, chunk size: 31.2 kB, exports: stripe)
8
+ [log] dist/index.cjs (total size: 33.2 kB, chunk size: 33.2 kB, exports: stripe)
9
9
 
10
10
  [log] dist/client.cjs (total size: 160 B, chunk size: 160 B, exports: stripeClient)
11
11
 
12
- [log] dist/index.mjs (total size: 31 kB, chunk size: 31 kB, exports: stripe)
12
+ [log] dist/index.mjs (total size: 33 kB, chunk size: 33 kB, exports: stripe)
13
13
 
14
14
  [log] dist/client.mjs (total size: 133 B, chunk size: 133 B, exports: stripeClient)
15
15
 
16
- Σ Total dist size (byte size): 174 kB
16
+ Σ Total dist size (byte size): 183 kB
17
17
  [log]
package/dist/index.cjs CHANGED
@@ -95,11 +95,11 @@ async function onSubscriptionUpdated(ctx, options, event) {
95
95
  const subscriptionUpdated = event.data.object;
96
96
  const priceId = subscriptionUpdated.items.data[0].price.id;
97
97
  const plan = await getPlanByPriceId(options, priceId);
98
- const referenceId = subscriptionUpdated.metadata?.referenceId;
98
+ const subscriptionId = subscriptionUpdated.metadata?.subscriptionId;
99
99
  const customerId = subscriptionUpdated.customer?.toString();
100
100
  let subscription = await ctx.context.adapter.findOne({
101
101
  model: "subscription",
102
- where: referenceId ? [{ field: "referenceId", value: referenceId }] : [{ field: "stripeSubscriptionId", value: subscriptionUpdated.id }]
102
+ where: subscriptionId ? [{ field: "id", value: subscriptionId }] : [{ field: "stripeSubscriptionId", value: subscriptionUpdated.id }]
103
103
  });
104
104
  if (!subscription) {
105
105
  const subs = await ctx.context.adapter.findMany({
@@ -313,24 +313,64 @@ const stripe = (options) => {
313
313
  {
314
314
  method: "POST",
315
315
  body: zod.z.object({
316
+ /**
317
+ * The name of the plan to subscribe
318
+ */
316
319
  plan: zod.z.string({
317
320
  description: "The name of the plan to upgrade to"
318
321
  }),
322
+ /**
323
+ * If annual plan should be applied.
324
+ */
319
325
  annual: zod.z.boolean({
320
326
  description: "Whether to upgrade to an annual plan"
321
327
  }).optional(),
322
- referenceId: zod.z.string().optional(),
328
+ /**
329
+ * Reference id of the subscription to upgrade
330
+ * This is used to identify the subscription to upgrade
331
+ * If not provided, the user's id will be used
332
+ */
333
+ referenceId: zod.z.string({
334
+ description: "Reference id of the subscription to upgrade"
335
+ }).optional(),
336
+ /**
337
+ * This is to allow a specific subscription to be upgrade.
338
+ * If subscription id is provided, and subscription isn't found,
339
+ * it'll throw an error.
340
+ */
341
+ subscriptionId: zod.z.string({
342
+ description: "The id of the subscription to upgrade"
343
+ }).optional(),
344
+ /**
345
+ * Any additional data you want to store in your database
346
+ * subscriptions
347
+ */
323
348
  metadata: zod.z.record(zod.z.string(), zod.z.any()).optional(),
349
+ /**
350
+ * If a subscription
351
+ */
324
352
  seats: zod.z.number({
325
353
  description: "Number of seats to upgrade to (if applicable)"
326
354
  }).optional(),
355
+ /**
356
+ * Success url to redirect back after successful subscription
357
+ */
327
358
  successUrl: zod.z.string({
328
359
  description: "callback url to redirect back after successful subscription"
329
360
  }).default("/"),
361
+ /**
362
+ * Cancel URL
363
+ */
330
364
  cancelUrl: zod.z.string({
331
365
  description: "callback url to redirect back after successful subscription"
332
366
  }).default("/"),
367
+ /**
368
+ * Return URL
369
+ */
333
370
  returnUrl: zod.z.string().optional(),
371
+ /**
372
+ * Disable Redirect
373
+ */
334
374
  disableRedirect: zod.z.boolean().default(false)
335
375
  }),
336
376
  use: [
@@ -355,7 +395,16 @@ const stripe = (options) => {
355
395
  message: STRIPE_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND
356
396
  });
357
397
  }
358
- let customerId = user.stripeCustomerId;
398
+ const subscriptionToUpdate = ctx.body.subscriptionId ? await ctx.context.adapter.findOne({
399
+ model: "subscription",
400
+ where: [{ field: "id", value: ctx.body.subscriptionId }]
401
+ }) : null;
402
+ if (ctx.body.subscriptionId && !subscriptionToUpdate) {
403
+ throw new api.APIError("BAD_REQUEST", {
404
+ message: STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND
405
+ });
406
+ }
407
+ let customerId = subscriptionToUpdate?.stripeCustomerId || user.stripeCustomerId;
359
408
  if (!customerId) {
360
409
  try {
361
410
  const stripeCustomer = await client.customers.create(
@@ -395,7 +444,7 @@ const stripe = (options) => {
395
444
  customer: customerId,
396
445
  status: "active"
397
446
  }).then((res) => res.data[0]).catch((e) => null) : null;
398
- const subscriptions = await ctx.context.adapter.findMany({
447
+ const subscriptions = subscriptionToUpdate ? [subscriptionToUpdate] : await ctx.context.adapter.findMany({
399
448
  model: "subscription",
400
449
  where: [
401
450
  {
@@ -485,7 +534,7 @@ const stripe = (options) => {
485
534
  ctx,
486
535
  `${ctx.context.baseURL}/subscription/success?callbackURL=${encodeURIComponent(
487
536
  ctx.body.successUrl
488
- )}&reference=${encodeURIComponent(referenceId)}`
537
+ )}&subscriptionId=${encodeURIComponent(subscription.id)}`
489
538
  ),
490
539
  cancel_url: getUrl(ctx, ctx.body.cancelUrl),
491
540
  line_items: [
@@ -528,7 +577,7 @@ const stripe = (options) => {
528
577
  use: [api.originCheck((ctx) => ctx.query.callbackURL)]
529
578
  },
530
579
  async (ctx) => {
531
- if (!ctx.query || !ctx.query.callbackURL || !ctx.query.reference) {
580
+ if (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {
532
581
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
533
582
  }
534
583
  const session = await api.getSessionFromCtx(
@@ -538,15 +587,15 @@ const stripe = (options) => {
538
587
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
539
588
  }
540
589
  const { user } = session;
541
- const { callbackURL, reference } = ctx.query;
590
+ const { callbackURL, subscriptionId } = ctx.query;
542
591
  if (user?.stripeCustomerId) {
543
592
  try {
544
593
  const subscription = await ctx.context.adapter.findOne({
545
594
  model: "subscription",
546
595
  where: [
547
596
  {
548
- field: "referenceId",
549
- value: reference
597
+ field: "id",
598
+ value: subscriptionId
550
599
  }
551
600
  ]
552
601
  });
@@ -569,8 +618,8 @@ const stripe = (options) => {
569
618
  },
570
619
  where: [
571
620
  {
572
- field: "referenceId",
573
- value: reference
621
+ field: "id",
622
+ value: subscription.id
574
623
  }
575
624
  ]
576
625
  });
@@ -597,6 +646,7 @@ const stripe = (options) => {
597
646
  method: "POST",
598
647
  body: zod.z.object({
599
648
  referenceId: zod.z.string().optional(),
649
+ subscriptionId: zod.z.string().optional(),
600
650
  returnUrl: zod.z.string()
601
651
  }),
602
652
  use: [
@@ -607,15 +657,22 @@ const stripe = (options) => {
607
657
  },
608
658
  async (ctx) => {
609
659
  const referenceId = ctx.body?.referenceId || ctx.context.session.user.id;
610
- const subscription = await ctx.context.adapter.findOne({
660
+ const subscription = ctx.body.subscriptionId ? await ctx.context.adapter.findOne({
611
661
  model: "subscription",
612
662
  where: [
613
663
  {
614
- field: "referenceId",
615
- value: referenceId
664
+ field: "id",
665
+ value: ctx.body.subscriptionId
616
666
  }
617
667
  ]
618
- });
668
+ }) : await ctx.context.adapter.findMany({
669
+ model: "subscription",
670
+ where: [{ field: "referenceId", value: referenceId }]
671
+ }).then(
672
+ (subs) => subs.find(
673
+ (sub) => sub.status === "active" || sub.status === "trialing"
674
+ )
675
+ );
619
676
  if (!subscription || !subscription.stripeCustomerId) {
620
677
  throw ctx.error("BAD_REQUEST", {
621
678
  message: STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND
@@ -656,7 +713,7 @@ const stripe = (options) => {
656
713
  ctx,
657
714
  `${ctx.context.baseURL}/subscription/cancel/callback?callbackURL=${encodeURIComponent(
658
715
  ctx.body?.returnUrl || "/"
659
- )}&reference=${encodeURIComponent(referenceId)}`
716
+ )}&subscriptionId=${encodeURIComponent(subscription.id)}`
660
717
  ),
661
718
  flow_data: {
662
719
  type: "subscription_cancel",
@@ -742,7 +799,7 @@ const stripe = (options) => {
742
799
  use: [api.originCheck((ctx) => ctx.query.callbackURL)]
743
800
  },
744
801
  async (ctx) => {
745
- if (!ctx.query || !ctx.query.callbackURL || !ctx.query.reference) {
802
+ if (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {
746
803
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
747
804
  }
748
805
  const session = await api.getSessionFromCtx(
@@ -752,36 +809,21 @@ const stripe = (options) => {
752
809
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
753
810
  }
754
811
  const { user } = session;
755
- const { callbackURL, reference } = ctx.query;
756
- const subscriptions = await ctx.context.adapter.findMany({
812
+ const { callbackURL, subscriptionId } = ctx.query;
813
+ const subscription = await ctx.context.adapter.findOne({
757
814
  model: "subscription",
758
815
  where: [
759
816
  {
760
- field: "referenceId",
761
- value: reference
817
+ field: "id",
818
+ value: subscriptionId
762
819
  }
763
820
  ]
764
821
  });
765
- const activeSubscription = subscriptions.find(
766
- (sub) => sub.status === "active" || sub.status === "trialing"
767
- );
768
- if (activeSubscription) {
822
+ if (subscription?.status === "active" || subscription?.status === "trialing") {
769
823
  return ctx.redirect(getUrl(ctx, callbackURL));
770
824
  }
771
825
  if (user?.stripeCustomerId) {
772
826
  try {
773
- const subscription = await ctx.context.adapter.findOne({
774
- model: "subscription",
775
- where: [
776
- {
777
- field: "referenceId",
778
- value: reference
779
- }
780
- ]
781
- });
782
- if (!subscription || subscription.status === "active") {
783
- throw ctx.redirect(getUrl(ctx, callbackURL));
784
- }
785
827
  const stripeSubscription = await client.subscriptions.list({
786
828
  customer: user.stripeCustomerId,
787
829
  status: "active"
@@ -791,7 +833,7 @@ const stripe = (options) => {
791
833
  options,
792
834
  stripeSubscription.items.data[0]?.plan.id
793
835
  );
794
- if (plan && subscriptions.length > 0) {
836
+ if (plan && subscription) {
795
837
  await ctx.context.adapter.update({
796
838
  model: "subscription",
797
839
  update: {
@@ -804,12 +846,20 @@ const stripe = (options) => {
804
846
  periodStart: new Date(
805
847
  stripeSubscription.current_period_start * 1e3
806
848
  ),
807
- stripeSubscriptionId: stripeSubscription.id
849
+ stripeSubscriptionId: stripeSubscription.id,
850
+ ...stripeSubscription.trial_start && stripeSubscription.trial_end ? {
851
+ trialStart: new Date(
852
+ stripeSubscription.trial_start * 1e3
853
+ ),
854
+ trialEnd: new Date(
855
+ stripeSubscription.trial_end * 1e3
856
+ )
857
+ } : {}
808
858
  },
809
859
  where: [
810
860
  {
811
- field: "referenceId",
812
- value: reference
861
+ field: "id",
862
+ value: subscription.id
813
863
  }
814
864
  ]
815
865
  });
package/dist/index.d.cts CHANGED
@@ -330,6 +330,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
330
330
  metadata?: Record<string, any> | undefined;
331
331
  annual?: boolean | undefined;
332
332
  referenceId?: string | undefined;
333
+ subscriptionId?: string | undefined;
333
334
  seats?: number | undefined;
334
335
  successUrl?: string | undefined;
335
336
  cancelUrl?: string | undefined;
@@ -502,14 +503,50 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
502
503
  options: {
503
504
  method: "POST";
504
505
  body: z.ZodObject<{
506
+ /**
507
+ * The name of the plan to subscribe
508
+ */
505
509
  plan: z.ZodString;
510
+ /**
511
+ * If annual plan should be applied.
512
+ */
506
513
  annual: z.ZodOptional<z.ZodBoolean>;
514
+ /**
515
+ * Reference id of the subscription to upgrade
516
+ * This is used to identify the subscription to upgrade
517
+ * If not provided, the user's id will be used
518
+ */
507
519
  referenceId: z.ZodOptional<z.ZodString>;
520
+ /**
521
+ * This is to allow a specific subscription to be upgrade.
522
+ * If subscription id is provided, and subscription isn't found,
523
+ * it'll throw an error.
524
+ */
525
+ subscriptionId: z.ZodOptional<z.ZodString>;
526
+ /**
527
+ * Any additional data you want to store in your database
528
+ * subscriptions
529
+ */
508
530
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
531
+ /**
532
+ * If a subscription
533
+ */
509
534
  seats: z.ZodOptional<z.ZodNumber>;
535
+ /**
536
+ * Success url to redirect back after successful subscription
537
+ */
510
538
  successUrl: z.ZodDefault<z.ZodString>;
539
+ /**
540
+ * Cancel URL
541
+ */
511
542
  cancelUrl: z.ZodDefault<z.ZodString>;
543
+ /**
544
+ * Return URL
545
+ */
512
546
  returnUrl: z.ZodOptional<z.ZodString>;
547
+ /**
548
+ * Disable Redirect
549
+ */
513
550
  disableRedirect: z.ZodDefault<z.ZodBoolean>;
514
551
  }, "strip", z.ZodTypeAny, {
515
552
  plan: string;
@@ -519,6 +556,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
519
556
  metadata?: Record<string, any> | undefined;
520
557
  annual?: boolean | undefined;
521
558
  referenceId?: string | undefined;
559
+ subscriptionId?: string | undefined;
522
560
  seats?: number | undefined;
523
561
  returnUrl?: string | undefined;
524
562
  }, {
@@ -526,6 +564,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
526
564
  metadata?: Record<string, any> | undefined;
527
565
  annual?: boolean | undefined;
528
566
  referenceId?: string | undefined;
567
+ subscriptionId?: string | undefined;
529
568
  seats?: number | undefined;
530
569
  successUrl?: string | undefined;
531
570
  cancelUrl?: string | undefined;
@@ -618,6 +657,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
618
657
  body: {
619
658
  returnUrl: string;
620
659
  referenceId?: string | undefined;
660
+ subscriptionId?: string | undefined;
621
661
  };
622
662
  method?: "POST" | undefined;
623
663
  query?: Record<string, any> | undefined;
@@ -646,13 +686,16 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
646
686
  method: "POST";
647
687
  body: z.ZodObject<{
648
688
  referenceId: z.ZodOptional<z.ZodString>;
689
+ subscriptionId: z.ZodOptional<z.ZodString>;
649
690
  returnUrl: z.ZodString;
650
691
  }, "strip", z.ZodTypeAny, {
651
692
  returnUrl: string;
652
693
  referenceId?: string | undefined;
694
+ subscriptionId?: string | undefined;
653
695
  }, {
654
696
  returnUrl: string;
655
697
  referenceId?: string | undefined;
698
+ subscriptionId?: string | undefined;
656
699
  }>;
657
700
  use: (((inputContext: {
658
701
  body?: any;
package/dist/index.d.mts CHANGED
@@ -330,6 +330,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
330
330
  metadata?: Record<string, any> | undefined;
331
331
  annual?: boolean | undefined;
332
332
  referenceId?: string | undefined;
333
+ subscriptionId?: string | undefined;
333
334
  seats?: number | undefined;
334
335
  successUrl?: string | undefined;
335
336
  cancelUrl?: string | undefined;
@@ -502,14 +503,50 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
502
503
  options: {
503
504
  method: "POST";
504
505
  body: z.ZodObject<{
506
+ /**
507
+ * The name of the plan to subscribe
508
+ */
505
509
  plan: z.ZodString;
510
+ /**
511
+ * If annual plan should be applied.
512
+ */
506
513
  annual: z.ZodOptional<z.ZodBoolean>;
514
+ /**
515
+ * Reference id of the subscription to upgrade
516
+ * This is used to identify the subscription to upgrade
517
+ * If not provided, the user's id will be used
518
+ */
507
519
  referenceId: z.ZodOptional<z.ZodString>;
520
+ /**
521
+ * This is to allow a specific subscription to be upgrade.
522
+ * If subscription id is provided, and subscription isn't found,
523
+ * it'll throw an error.
524
+ */
525
+ subscriptionId: z.ZodOptional<z.ZodString>;
526
+ /**
527
+ * Any additional data you want to store in your database
528
+ * subscriptions
529
+ */
508
530
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
531
+ /**
532
+ * If a subscription
533
+ */
509
534
  seats: z.ZodOptional<z.ZodNumber>;
535
+ /**
536
+ * Success url to redirect back after successful subscription
537
+ */
510
538
  successUrl: z.ZodDefault<z.ZodString>;
539
+ /**
540
+ * Cancel URL
541
+ */
511
542
  cancelUrl: z.ZodDefault<z.ZodString>;
543
+ /**
544
+ * Return URL
545
+ */
512
546
  returnUrl: z.ZodOptional<z.ZodString>;
547
+ /**
548
+ * Disable Redirect
549
+ */
513
550
  disableRedirect: z.ZodDefault<z.ZodBoolean>;
514
551
  }, "strip", z.ZodTypeAny, {
515
552
  plan: string;
@@ -519,6 +556,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
519
556
  metadata?: Record<string, any> | undefined;
520
557
  annual?: boolean | undefined;
521
558
  referenceId?: string | undefined;
559
+ subscriptionId?: string | undefined;
522
560
  seats?: number | undefined;
523
561
  returnUrl?: string | undefined;
524
562
  }, {
@@ -526,6 +564,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
526
564
  metadata?: Record<string, any> | undefined;
527
565
  annual?: boolean | undefined;
528
566
  referenceId?: string | undefined;
567
+ subscriptionId?: string | undefined;
529
568
  seats?: number | undefined;
530
569
  successUrl?: string | undefined;
531
570
  cancelUrl?: string | undefined;
@@ -618,6 +657,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
618
657
  body: {
619
658
  returnUrl: string;
620
659
  referenceId?: string | undefined;
660
+ subscriptionId?: string | undefined;
621
661
  };
622
662
  method?: "POST" | undefined;
623
663
  query?: Record<string, any> | undefined;
@@ -646,13 +686,16 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
646
686
  method: "POST";
647
687
  body: z.ZodObject<{
648
688
  referenceId: z.ZodOptional<z.ZodString>;
689
+ subscriptionId: z.ZodOptional<z.ZodString>;
649
690
  returnUrl: z.ZodString;
650
691
  }, "strip", z.ZodTypeAny, {
651
692
  returnUrl: string;
652
693
  referenceId?: string | undefined;
694
+ subscriptionId?: string | undefined;
653
695
  }, {
654
696
  returnUrl: string;
655
697
  referenceId?: string | undefined;
698
+ subscriptionId?: string | undefined;
656
699
  }>;
657
700
  use: (((inputContext: {
658
701
  body?: any;
package/dist/index.d.ts CHANGED
@@ -330,6 +330,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
330
330
  metadata?: Record<string, any> | undefined;
331
331
  annual?: boolean | undefined;
332
332
  referenceId?: string | undefined;
333
+ subscriptionId?: string | undefined;
333
334
  seats?: number | undefined;
334
335
  successUrl?: string | undefined;
335
336
  cancelUrl?: string | undefined;
@@ -502,14 +503,50 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
502
503
  options: {
503
504
  method: "POST";
504
505
  body: z.ZodObject<{
506
+ /**
507
+ * The name of the plan to subscribe
508
+ */
505
509
  plan: z.ZodString;
510
+ /**
511
+ * If annual plan should be applied.
512
+ */
506
513
  annual: z.ZodOptional<z.ZodBoolean>;
514
+ /**
515
+ * Reference id of the subscription to upgrade
516
+ * This is used to identify the subscription to upgrade
517
+ * If not provided, the user's id will be used
518
+ */
507
519
  referenceId: z.ZodOptional<z.ZodString>;
520
+ /**
521
+ * This is to allow a specific subscription to be upgrade.
522
+ * If subscription id is provided, and subscription isn't found,
523
+ * it'll throw an error.
524
+ */
525
+ subscriptionId: z.ZodOptional<z.ZodString>;
526
+ /**
527
+ * Any additional data you want to store in your database
528
+ * subscriptions
529
+ */
508
530
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
531
+ /**
532
+ * If a subscription
533
+ */
509
534
  seats: z.ZodOptional<z.ZodNumber>;
535
+ /**
536
+ * Success url to redirect back after successful subscription
537
+ */
510
538
  successUrl: z.ZodDefault<z.ZodString>;
539
+ /**
540
+ * Cancel URL
541
+ */
511
542
  cancelUrl: z.ZodDefault<z.ZodString>;
543
+ /**
544
+ * Return URL
545
+ */
512
546
  returnUrl: z.ZodOptional<z.ZodString>;
547
+ /**
548
+ * Disable Redirect
549
+ */
513
550
  disableRedirect: z.ZodDefault<z.ZodBoolean>;
514
551
  }, "strip", z.ZodTypeAny, {
515
552
  plan: string;
@@ -519,6 +556,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
519
556
  metadata?: Record<string, any> | undefined;
520
557
  annual?: boolean | undefined;
521
558
  referenceId?: string | undefined;
559
+ subscriptionId?: string | undefined;
522
560
  seats?: number | undefined;
523
561
  returnUrl?: string | undefined;
524
562
  }, {
@@ -526,6 +564,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
526
564
  metadata?: Record<string, any> | undefined;
527
565
  annual?: boolean | undefined;
528
566
  referenceId?: string | undefined;
567
+ subscriptionId?: string | undefined;
529
568
  seats?: number | undefined;
530
569
  successUrl?: string | undefined;
531
570
  cancelUrl?: string | undefined;
@@ -618,6 +657,7 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
618
657
  body: {
619
658
  returnUrl: string;
620
659
  referenceId?: string | undefined;
660
+ subscriptionId?: string | undefined;
621
661
  };
622
662
  method?: "POST" | undefined;
623
663
  query?: Record<string, any> | undefined;
@@ -646,13 +686,16 @@ declare const stripe: <O extends StripeOptions>(options: O) => {
646
686
  method: "POST";
647
687
  body: z.ZodObject<{
648
688
  referenceId: z.ZodOptional<z.ZodString>;
689
+ subscriptionId: z.ZodOptional<z.ZodString>;
649
690
  returnUrl: z.ZodString;
650
691
  }, "strip", z.ZodTypeAny, {
651
692
  returnUrl: string;
652
693
  referenceId?: string | undefined;
694
+ subscriptionId?: string | undefined;
653
695
  }, {
654
696
  returnUrl: string;
655
697
  referenceId?: string | undefined;
698
+ subscriptionId?: string | undefined;
656
699
  }>;
657
700
  use: (((inputContext: {
658
701
  body?: any;
package/dist/index.mjs CHANGED
@@ -93,11 +93,11 @@ async function onSubscriptionUpdated(ctx, options, event) {
93
93
  const subscriptionUpdated = event.data.object;
94
94
  const priceId = subscriptionUpdated.items.data[0].price.id;
95
95
  const plan = await getPlanByPriceId(options, priceId);
96
- const referenceId = subscriptionUpdated.metadata?.referenceId;
96
+ const subscriptionId = subscriptionUpdated.metadata?.subscriptionId;
97
97
  const customerId = subscriptionUpdated.customer?.toString();
98
98
  let subscription = await ctx.context.adapter.findOne({
99
99
  model: "subscription",
100
- where: referenceId ? [{ field: "referenceId", value: referenceId }] : [{ field: "stripeSubscriptionId", value: subscriptionUpdated.id }]
100
+ where: subscriptionId ? [{ field: "id", value: subscriptionId }] : [{ field: "stripeSubscriptionId", value: subscriptionUpdated.id }]
101
101
  });
102
102
  if (!subscription) {
103
103
  const subs = await ctx.context.adapter.findMany({
@@ -311,24 +311,64 @@ const stripe = (options) => {
311
311
  {
312
312
  method: "POST",
313
313
  body: z.object({
314
+ /**
315
+ * The name of the plan to subscribe
316
+ */
314
317
  plan: z.string({
315
318
  description: "The name of the plan to upgrade to"
316
319
  }),
320
+ /**
321
+ * If annual plan should be applied.
322
+ */
317
323
  annual: z.boolean({
318
324
  description: "Whether to upgrade to an annual plan"
319
325
  }).optional(),
320
- referenceId: z.string().optional(),
326
+ /**
327
+ * Reference id of the subscription to upgrade
328
+ * This is used to identify the subscription to upgrade
329
+ * If not provided, the user's id will be used
330
+ */
331
+ referenceId: z.string({
332
+ description: "Reference id of the subscription to upgrade"
333
+ }).optional(),
334
+ /**
335
+ * This is to allow a specific subscription to be upgrade.
336
+ * If subscription id is provided, and subscription isn't found,
337
+ * it'll throw an error.
338
+ */
339
+ subscriptionId: z.string({
340
+ description: "The id of the subscription to upgrade"
341
+ }).optional(),
342
+ /**
343
+ * Any additional data you want to store in your database
344
+ * subscriptions
345
+ */
321
346
  metadata: z.record(z.string(), z.any()).optional(),
347
+ /**
348
+ * If a subscription
349
+ */
322
350
  seats: z.number({
323
351
  description: "Number of seats to upgrade to (if applicable)"
324
352
  }).optional(),
353
+ /**
354
+ * Success url to redirect back after successful subscription
355
+ */
325
356
  successUrl: z.string({
326
357
  description: "callback url to redirect back after successful subscription"
327
358
  }).default("/"),
359
+ /**
360
+ * Cancel URL
361
+ */
328
362
  cancelUrl: z.string({
329
363
  description: "callback url to redirect back after successful subscription"
330
364
  }).default("/"),
365
+ /**
366
+ * Return URL
367
+ */
331
368
  returnUrl: z.string().optional(),
369
+ /**
370
+ * Disable Redirect
371
+ */
332
372
  disableRedirect: z.boolean().default(false)
333
373
  }),
334
374
  use: [
@@ -353,7 +393,16 @@ const stripe = (options) => {
353
393
  message: STRIPE_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND
354
394
  });
355
395
  }
356
- let customerId = user.stripeCustomerId;
396
+ const subscriptionToUpdate = ctx.body.subscriptionId ? await ctx.context.adapter.findOne({
397
+ model: "subscription",
398
+ where: [{ field: "id", value: ctx.body.subscriptionId }]
399
+ }) : null;
400
+ if (ctx.body.subscriptionId && !subscriptionToUpdate) {
401
+ throw new APIError("BAD_REQUEST", {
402
+ message: STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND
403
+ });
404
+ }
405
+ let customerId = subscriptionToUpdate?.stripeCustomerId || user.stripeCustomerId;
357
406
  if (!customerId) {
358
407
  try {
359
408
  const stripeCustomer = await client.customers.create(
@@ -393,7 +442,7 @@ const stripe = (options) => {
393
442
  customer: customerId,
394
443
  status: "active"
395
444
  }).then((res) => res.data[0]).catch((e) => null) : null;
396
- const subscriptions = await ctx.context.adapter.findMany({
445
+ const subscriptions = subscriptionToUpdate ? [subscriptionToUpdate] : await ctx.context.adapter.findMany({
397
446
  model: "subscription",
398
447
  where: [
399
448
  {
@@ -483,7 +532,7 @@ const stripe = (options) => {
483
532
  ctx,
484
533
  `${ctx.context.baseURL}/subscription/success?callbackURL=${encodeURIComponent(
485
534
  ctx.body.successUrl
486
- )}&reference=${encodeURIComponent(referenceId)}`
535
+ )}&subscriptionId=${encodeURIComponent(subscription.id)}`
487
536
  ),
488
537
  cancel_url: getUrl(ctx, ctx.body.cancelUrl),
489
538
  line_items: [
@@ -526,7 +575,7 @@ const stripe = (options) => {
526
575
  use: [originCheck((ctx) => ctx.query.callbackURL)]
527
576
  },
528
577
  async (ctx) => {
529
- if (!ctx.query || !ctx.query.callbackURL || !ctx.query.reference) {
578
+ if (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {
530
579
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
531
580
  }
532
581
  const session = await getSessionFromCtx(
@@ -536,15 +585,15 @@ const stripe = (options) => {
536
585
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
537
586
  }
538
587
  const { user } = session;
539
- const { callbackURL, reference } = ctx.query;
588
+ const { callbackURL, subscriptionId } = ctx.query;
540
589
  if (user?.stripeCustomerId) {
541
590
  try {
542
591
  const subscription = await ctx.context.adapter.findOne({
543
592
  model: "subscription",
544
593
  where: [
545
594
  {
546
- field: "referenceId",
547
- value: reference
595
+ field: "id",
596
+ value: subscriptionId
548
597
  }
549
598
  ]
550
599
  });
@@ -567,8 +616,8 @@ const stripe = (options) => {
567
616
  },
568
617
  where: [
569
618
  {
570
- field: "referenceId",
571
- value: reference
619
+ field: "id",
620
+ value: subscription.id
572
621
  }
573
622
  ]
574
623
  });
@@ -595,6 +644,7 @@ const stripe = (options) => {
595
644
  method: "POST",
596
645
  body: z.object({
597
646
  referenceId: z.string().optional(),
647
+ subscriptionId: z.string().optional(),
598
648
  returnUrl: z.string()
599
649
  }),
600
650
  use: [
@@ -605,15 +655,22 @@ const stripe = (options) => {
605
655
  },
606
656
  async (ctx) => {
607
657
  const referenceId = ctx.body?.referenceId || ctx.context.session.user.id;
608
- const subscription = await ctx.context.adapter.findOne({
658
+ const subscription = ctx.body.subscriptionId ? await ctx.context.adapter.findOne({
609
659
  model: "subscription",
610
660
  where: [
611
661
  {
612
- field: "referenceId",
613
- value: referenceId
662
+ field: "id",
663
+ value: ctx.body.subscriptionId
614
664
  }
615
665
  ]
616
- });
666
+ }) : await ctx.context.adapter.findMany({
667
+ model: "subscription",
668
+ where: [{ field: "referenceId", value: referenceId }]
669
+ }).then(
670
+ (subs) => subs.find(
671
+ (sub) => sub.status === "active" || sub.status === "trialing"
672
+ )
673
+ );
617
674
  if (!subscription || !subscription.stripeCustomerId) {
618
675
  throw ctx.error("BAD_REQUEST", {
619
676
  message: STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND
@@ -654,7 +711,7 @@ const stripe = (options) => {
654
711
  ctx,
655
712
  `${ctx.context.baseURL}/subscription/cancel/callback?callbackURL=${encodeURIComponent(
656
713
  ctx.body?.returnUrl || "/"
657
- )}&reference=${encodeURIComponent(referenceId)}`
714
+ )}&subscriptionId=${encodeURIComponent(subscription.id)}`
658
715
  ),
659
716
  flow_data: {
660
717
  type: "subscription_cancel",
@@ -740,7 +797,7 @@ const stripe = (options) => {
740
797
  use: [originCheck((ctx) => ctx.query.callbackURL)]
741
798
  },
742
799
  async (ctx) => {
743
- if (!ctx.query || !ctx.query.callbackURL || !ctx.query.reference) {
800
+ if (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {
744
801
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
745
802
  }
746
803
  const session = await getSessionFromCtx(
@@ -750,36 +807,21 @@ const stripe = (options) => {
750
807
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
751
808
  }
752
809
  const { user } = session;
753
- const { callbackURL, reference } = ctx.query;
754
- const subscriptions = await ctx.context.adapter.findMany({
810
+ const { callbackURL, subscriptionId } = ctx.query;
811
+ const subscription = await ctx.context.adapter.findOne({
755
812
  model: "subscription",
756
813
  where: [
757
814
  {
758
- field: "referenceId",
759
- value: reference
815
+ field: "id",
816
+ value: subscriptionId
760
817
  }
761
818
  ]
762
819
  });
763
- const activeSubscription = subscriptions.find(
764
- (sub) => sub.status === "active" || sub.status === "trialing"
765
- );
766
- if (activeSubscription) {
820
+ if (subscription?.status === "active" || subscription?.status === "trialing") {
767
821
  return ctx.redirect(getUrl(ctx, callbackURL));
768
822
  }
769
823
  if (user?.stripeCustomerId) {
770
824
  try {
771
- const subscription = await ctx.context.adapter.findOne({
772
- model: "subscription",
773
- where: [
774
- {
775
- field: "referenceId",
776
- value: reference
777
- }
778
- ]
779
- });
780
- if (!subscription || subscription.status === "active") {
781
- throw ctx.redirect(getUrl(ctx, callbackURL));
782
- }
783
825
  const stripeSubscription = await client.subscriptions.list({
784
826
  customer: user.stripeCustomerId,
785
827
  status: "active"
@@ -789,7 +831,7 @@ const stripe = (options) => {
789
831
  options,
790
832
  stripeSubscription.items.data[0]?.plan.id
791
833
  );
792
- if (plan && subscriptions.length > 0) {
834
+ if (plan && subscription) {
793
835
  await ctx.context.adapter.update({
794
836
  model: "subscription",
795
837
  update: {
@@ -802,12 +844,20 @@ const stripe = (options) => {
802
844
  periodStart: new Date(
803
845
  stripeSubscription.current_period_start * 1e3
804
846
  ),
805
- stripeSubscriptionId: stripeSubscription.id
847
+ stripeSubscriptionId: stripeSubscription.id,
848
+ ...stripeSubscription.trial_start && stripeSubscription.trial_end ? {
849
+ trialStart: new Date(
850
+ stripeSubscription.trial_start * 1e3
851
+ ),
852
+ trialEnd: new Date(
853
+ stripeSubscription.trial_end * 1e3
854
+ )
855
+ } : {}
806
856
  },
807
857
  where: [
808
858
  {
809
- field: "referenceId",
810
- value: reference
859
+ field: "id",
860
+ value: subscription.id
811
861
  }
812
862
  ]
813
863
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@better-auth/stripe",
3
3
  "author": "Bereket Engida",
4
- "version": "1.2.4-beta.7",
4
+ "version": "1.2.4-beta.8",
5
5
  "main": "dist/index.cjs",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "zod": "^3.24.1",
38
- "better-auth": "^1.2.4-beta.7"
38
+ "better-auth": "^1.2.4-beta.8"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@types/better-sqlite3": "^7.6.12",
package/src/hooks.ts CHANGED
@@ -95,12 +95,12 @@ export async function onSubscriptionUpdated(
95
95
  const priceId = subscriptionUpdated.items.data[0].price.id;
96
96
  const plan = await getPlanByPriceId(options, priceId);
97
97
 
98
- const referenceId = subscriptionUpdated.metadata?.referenceId;
98
+ const subscriptionId = subscriptionUpdated.metadata?.subscriptionId;
99
99
  const customerId = subscriptionUpdated.customer?.toString();
100
100
  let subscription = await ctx.context.adapter.findOne<Subscription>({
101
101
  model: "subscription",
102
- where: referenceId
103
- ? [{ field: "referenceId", value: referenceId }]
102
+ where: subscriptionId
103
+ ? [{ field: "id", value: subscriptionId }]
104
104
  : [{ field: "stripeSubscriptionId", value: subscriptionUpdated.id }],
105
105
  });
106
106
  if (!subscription) {
package/src/index.ts CHANGED
@@ -83,34 +83,78 @@ export const stripe = <O extends StripeOptions>(options: O) => {
83
83
  {
84
84
  method: "POST",
85
85
  body: z.object({
86
+ /**
87
+ * The name of the plan to subscribe
88
+ */
86
89
  plan: z.string({
87
90
  description: "The name of the plan to upgrade to",
88
91
  }),
92
+ /**
93
+ * If annual plan should be applied.
94
+ */
89
95
  annual: z
90
96
  .boolean({
91
97
  description: "Whether to upgrade to an annual plan",
92
98
  })
93
99
  .optional(),
94
- referenceId: z.string().optional(),
100
+ /**
101
+ * Reference id of the subscription to upgrade
102
+ * This is used to identify the subscription to upgrade
103
+ * If not provided, the user's id will be used
104
+ */
105
+ referenceId: z
106
+ .string({
107
+ description: "Reference id of the subscription to upgrade",
108
+ })
109
+ .optional(),
110
+ /**
111
+ * This is to allow a specific subscription to be upgrade.
112
+ * If subscription id is provided, and subscription isn't found,
113
+ * it'll throw an error.
114
+ */
115
+ subscriptionId: z
116
+ .string({
117
+ description: "The id of the subscription to upgrade",
118
+ })
119
+ .optional(),
120
+ /**
121
+ * Any additional data you want to store in your database
122
+ * subscriptions
123
+ */
95
124
  metadata: z.record(z.string(), z.any()).optional(),
125
+ /**
126
+ * If a subscription
127
+ */
96
128
  seats: z
97
129
  .number({
98
130
  description: "Number of seats to upgrade to (if applicable)",
99
131
  })
100
132
  .optional(),
133
+ /**
134
+ * Success url to redirect back after successful subscription
135
+ */
101
136
  successUrl: z
102
137
  .string({
103
138
  description:
104
139
  "callback url to redirect back after successful subscription",
105
140
  })
106
141
  .default("/"),
142
+ /**
143
+ * Cancel URL
144
+ */
107
145
  cancelUrl: z
108
146
  .string({
109
147
  description:
110
148
  "callback url to redirect back after successful subscription",
111
149
  })
112
150
  .default("/"),
151
+ /**
152
+ * Return URL
153
+ */
113
154
  returnUrl: z.string().optional(),
155
+ /**
156
+ * Disable Redirect
157
+ */
114
158
  disableRedirect: z.boolean().default(false),
115
159
  }),
116
160
  use: [
@@ -138,7 +182,22 @@ export const stripe = <O extends StripeOptions>(options: O) => {
138
182
  message: STRIPE_ERROR_CODES.SUBSCRIPTION_PLAN_NOT_FOUND,
139
183
  });
140
184
  }
141
- let customerId = user.stripeCustomerId;
185
+ const subscriptionToUpdate = ctx.body.subscriptionId
186
+ ? await ctx.context.adapter.findOne<Subscription>({
187
+ model: "subscription",
188
+ where: [{ field: "id", value: ctx.body.subscriptionId }],
189
+ })
190
+ : null;
191
+
192
+ if (ctx.body.subscriptionId && !subscriptionToUpdate) {
193
+ throw new APIError("BAD_REQUEST", {
194
+ message: STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
195
+ });
196
+ }
197
+
198
+ let customerId =
199
+ subscriptionToUpdate?.stripeCustomerId || user.stripeCustomerId;
200
+
142
201
  if (!customerId) {
143
202
  try {
144
203
  const stripeCustomer = await client.customers.create(
@@ -184,15 +243,18 @@ export const stripe = <O extends StripeOptions>(options: O) => {
184
243
  .then((res) => res.data[0])
185
244
  .catch((e) => null)
186
245
  : null;
187
- const subscriptions = await ctx.context.adapter.findMany<Subscription>({
188
- model: "subscription",
189
- where: [
190
- {
191
- field: "referenceId",
192
- value: ctx.body.referenceId || user.id,
193
- },
194
- ],
195
- });
246
+
247
+ const subscriptions = subscriptionToUpdate
248
+ ? [subscriptionToUpdate]
249
+ : await ctx.context.adapter.findMany<Subscription>({
250
+ model: "subscription",
251
+ where: [
252
+ {
253
+ field: "referenceId",
254
+ value: ctx.body.referenceId || user.id,
255
+ },
256
+ ],
257
+ });
196
258
 
197
259
  const existingSubscription = subscriptions.find(
198
260
  (sub) => sub.status === "active" || sub.status === "trialing",
@@ -300,7 +362,7 @@ export const stripe = <O extends StripeOptions>(options: O) => {
300
362
  ctx.context.baseURL
301
363
  }/subscription/success?callbackURL=${encodeURIComponent(
302
364
  ctx.body.successUrl,
303
- )}&reference=${encodeURIComponent(referenceId)}`,
365
+ )}&subscriptionId=${encodeURIComponent(subscription.id)}`,
304
366
  ),
305
367
  cancel_url: getUrl(ctx, ctx.body.cancelUrl),
306
368
  line_items: [
@@ -346,7 +408,7 @@ export const stripe = <O extends StripeOptions>(options: O) => {
346
408
  use: [originCheck((ctx) => ctx.query.callbackURL)],
347
409
  },
348
410
  async (ctx) => {
349
- if (!ctx.query || !ctx.query.callbackURL || !ctx.query.reference) {
411
+ if (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {
350
412
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
351
413
  }
352
414
  const session = await getSessionFromCtx<{ stripeCustomerId: string }>(
@@ -356,7 +418,7 @@ export const stripe = <O extends StripeOptions>(options: O) => {
356
418
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
357
419
  }
358
420
  const { user } = session;
359
- const { callbackURL, reference } = ctx.query;
421
+ const { callbackURL, subscriptionId } = ctx.query;
360
422
 
361
423
  if (user?.stripeCustomerId) {
362
424
  try {
@@ -365,8 +427,8 @@ export const stripe = <O extends StripeOptions>(options: O) => {
365
427
  model: "subscription",
366
428
  where: [
367
429
  {
368
- field: "referenceId",
369
- value: reference,
430
+ field: "id",
431
+ value: subscriptionId,
370
432
  },
371
433
  ],
372
434
  });
@@ -394,8 +456,8 @@ export const stripe = <O extends StripeOptions>(options: O) => {
394
456
  },
395
457
  where: [
396
458
  {
397
- field: "referenceId",
398
- value: reference,
459
+ field: "id",
460
+ value: subscription.id,
399
461
  },
400
462
  ],
401
463
  });
@@ -422,6 +484,7 @@ export const stripe = <O extends StripeOptions>(options: O) => {
422
484
  method: "POST",
423
485
  body: z.object({
424
486
  referenceId: z.string().optional(),
487
+ subscriptionId: z.string().optional(),
425
488
  returnUrl: z.string(),
426
489
  }),
427
490
  use: [
@@ -433,15 +496,27 @@ export const stripe = <O extends StripeOptions>(options: O) => {
433
496
  async (ctx) => {
434
497
  const referenceId =
435
498
  ctx.body?.referenceId || ctx.context.session.user.id;
436
- const subscription = await ctx.context.adapter.findOne<Subscription>({
437
- model: "subscription",
438
- where: [
439
- {
440
- field: "referenceId",
441
- value: referenceId,
442
- },
443
- ],
444
- });
499
+ const subscription = ctx.body.subscriptionId
500
+ ? await ctx.context.adapter.findOne<Subscription>({
501
+ model: "subscription",
502
+ where: [
503
+ {
504
+ field: "id",
505
+ value: ctx.body.subscriptionId,
506
+ },
507
+ ],
508
+ })
509
+ : await ctx.context.adapter
510
+ .findMany<Subscription>({
511
+ model: "subscription",
512
+ where: [{ field: "referenceId", value: referenceId }],
513
+ })
514
+ .then((subs) =>
515
+ subs.find(
516
+ (sub) => sub.status === "active" || sub.status === "trialing",
517
+ ),
518
+ );
519
+
445
520
  if (!subscription || !subscription.stripeCustomerId) {
446
521
  throw ctx.error("BAD_REQUEST", {
447
522
  message: STRIPE_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
@@ -491,7 +566,7 @@ export const stripe = <O extends StripeOptions>(options: O) => {
491
566
  ctx.context.baseURL
492
567
  }/subscription/cancel/callback?callbackURL=${encodeURIComponent(
493
568
  ctx.body?.returnUrl || "/",
494
- )}&reference=${encodeURIComponent(referenceId)}`,
569
+ )}&subscriptionId=${encodeURIComponent(subscription.id)}`,
495
570
  ),
496
571
  flow_data: {
497
572
  type: "subscription_cancel",
@@ -584,7 +659,7 @@ export const stripe = <O extends StripeOptions>(options: O) => {
584
659
  use: [originCheck((ctx) => ctx.query.callbackURL)],
585
660
  },
586
661
  async (ctx) => {
587
- if (!ctx.query || !ctx.query.callbackURL || !ctx.query.reference) {
662
+ if (!ctx.query || !ctx.query.callbackURL || !ctx.query.subscriptionId) {
588
663
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
589
664
  }
590
665
  const session = await getSessionFromCtx<{ stripeCustomerId: string }>(
@@ -594,41 +669,27 @@ export const stripe = <O extends StripeOptions>(options: O) => {
594
669
  throw ctx.redirect(getUrl(ctx, ctx.query?.callbackURL || "/"));
595
670
  }
596
671
  const { user } = session;
597
- const { callbackURL, reference } = ctx.query;
672
+ const { callbackURL, subscriptionId } = ctx.query;
598
673
 
599
- const subscriptions = await ctx.context.adapter.findMany<Subscription>({
674
+ const subscription = await ctx.context.adapter.findOne<Subscription>({
600
675
  model: "subscription",
601
676
  where: [
602
677
  {
603
- field: "referenceId",
604
- value: reference,
678
+ field: "id",
679
+ value: subscriptionId,
605
680
  },
606
681
  ],
607
682
  });
608
683
 
609
- const activeSubscription = subscriptions.find(
610
- (sub) => sub.status === "active" || sub.status === "trialing",
611
- );
612
-
613
- if (activeSubscription) {
684
+ if (
685
+ subscription?.status === "active" ||
686
+ subscription?.status === "trialing"
687
+ ) {
614
688
  return ctx.redirect(getUrl(ctx, callbackURL));
615
689
  }
616
690
 
617
691
  if (user?.stripeCustomerId) {
618
692
  try {
619
- const subscription =
620
- await ctx.context.adapter.findOne<Subscription>({
621
- model: "subscription",
622
- where: [
623
- {
624
- field: "referenceId",
625
- value: reference,
626
- },
627
- ],
628
- });
629
- if (!subscription || subscription.status === "active") {
630
- throw ctx.redirect(getUrl(ctx, callbackURL));
631
- }
632
693
  const stripeSubscription = await client.subscriptions
633
694
  .list({
634
695
  customer: user.stripeCustomerId,
@@ -642,7 +703,7 @@ export const stripe = <O extends StripeOptions>(options: O) => {
642
703
  stripeSubscription.items.data[0]?.plan.id,
643
704
  );
644
705
 
645
- if (plan && subscriptions.length > 0) {
706
+ if (plan && subscription) {
646
707
  await ctx.context.adapter.update({
647
708
  model: "subscription",
648
709
  update: {
@@ -656,11 +717,22 @@ export const stripe = <O extends StripeOptions>(options: O) => {
656
717
  stripeSubscription.current_period_start * 1000,
657
718
  ),
658
719
  stripeSubscriptionId: stripeSubscription.id,
720
+ ...(stripeSubscription.trial_start &&
721
+ stripeSubscription.trial_end
722
+ ? {
723
+ trialStart: new Date(
724
+ stripeSubscription.trial_start * 1000,
725
+ ),
726
+ trialEnd: new Date(
727
+ stripeSubscription.trial_end * 1000,
728
+ ),
729
+ }
730
+ : {}),
659
731
  },
660
732
  where: [
661
733
  {
662
- field: "referenceId",
663
- value: reference,
734
+ field: "id",
735
+ value: subscription.id,
664
736
  },
665
737
  ],
666
738
  });