@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.
- package/.turbo/turbo-build.log +4 -4
- package/dist/index.cjs +92 -42
- package/dist/index.d.cts +43 -0
- package/dist/index.d.mts +43 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.mjs +92 -42
- package/package.json +2 -2
- package/src/hooks.ts +3 -3
- package/src/index.ts +126 -54
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
|
|
2
|
-
> @better-auth/stripe@1.2.4-beta.
|
|
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:
|
|
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:
|
|
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):
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
)}&
|
|
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.
|
|
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,
|
|
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: "
|
|
549
|
-
value:
|
|
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: "
|
|
573
|
-
value:
|
|
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: "
|
|
615
|
-
value:
|
|
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
|
-
)}&
|
|
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.
|
|
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,
|
|
756
|
-
const
|
|
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: "
|
|
761
|
-
value:
|
|
817
|
+
field: "id",
|
|
818
|
+
value: subscriptionId
|
|
762
819
|
}
|
|
763
820
|
]
|
|
764
821
|
});
|
|
765
|
-
|
|
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 &&
|
|
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: "
|
|
812
|
-
value:
|
|
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
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
)}&
|
|
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.
|
|
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,
|
|
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: "
|
|
547
|
-
value:
|
|
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: "
|
|
571
|
-
value:
|
|
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: "
|
|
613
|
-
value:
|
|
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
|
-
)}&
|
|
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.
|
|
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,
|
|
754
|
-
const
|
|
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: "
|
|
759
|
-
value:
|
|
815
|
+
field: "id",
|
|
816
|
+
value: subscriptionId
|
|
760
817
|
}
|
|
761
818
|
]
|
|
762
819
|
});
|
|
763
|
-
|
|
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 &&
|
|
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: "
|
|
810
|
-
value:
|
|
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.
|
|
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.
|
|
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
|
|
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:
|
|
103
|
-
? [{ field: "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
)}&
|
|
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.
|
|
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,
|
|
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: "
|
|
369
|
-
value:
|
|
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: "
|
|
398
|
-
value:
|
|
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 =
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
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
|
-
)}&
|
|
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.
|
|
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,
|
|
672
|
+
const { callbackURL, subscriptionId } = ctx.query;
|
|
598
673
|
|
|
599
|
-
const
|
|
674
|
+
const subscription = await ctx.context.adapter.findOne<Subscription>({
|
|
600
675
|
model: "subscription",
|
|
601
676
|
where: [
|
|
602
677
|
{
|
|
603
|
-
field: "
|
|
604
|
-
value:
|
|
678
|
+
field: "id",
|
|
679
|
+
value: subscriptionId,
|
|
605
680
|
},
|
|
606
681
|
],
|
|
607
682
|
});
|
|
608
683
|
|
|
609
|
-
|
|
610
|
-
|
|
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 &&
|
|
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: "
|
|
663
|
-
value:
|
|
734
|
+
field: "id",
|
|
735
|
+
value: subscription.id,
|
|
664
736
|
},
|
|
665
737
|
],
|
|
666
738
|
});
|