@forklaunch/implementation-billing-stripe 0.4.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/eject/services/billingPortal.service.ts +2 -2
- package/lib/eject/services/checkoutSession.service.ts +1 -0
- package/lib/eject/services/index.ts +1 -0
- package/lib/eject/services/paymentLink.service.ts +7 -7
- package/lib/eject/services/plan.service.ts +70 -55
- package/lib/eject/services/subscription.service.ts +96 -64
- package/lib/services/index.d.mts +5 -9
- package/lib/services/index.d.ts +5 -9
- package/lib/services/index.js +153 -110
- package/lib/services/index.mjs +151 -109
- package/package.json +11 -11
package/lib/services/index.mjs
CHANGED
|
@@ -57,12 +57,13 @@ var StripeBillingPortalService = class {
|
|
|
57
57
|
});
|
|
58
58
|
const session = await this.stripeClient.billingPortal.sessions.create({
|
|
59
59
|
...billingPortalDto.stripeFields,
|
|
60
|
-
customer: existingSession.customerId
|
|
60
|
+
customer: billingPortalDto.customerId || existingSession.customerId
|
|
61
61
|
});
|
|
62
62
|
return await this.baseBillingPortalService.updateBillingPortalSession(
|
|
63
63
|
{
|
|
64
64
|
...billingPortalDto,
|
|
65
|
-
id:
|
|
65
|
+
id: existingSession.id,
|
|
66
|
+
// Use the original database ID, not the new Stripe session ID
|
|
66
67
|
uri: session.url,
|
|
67
68
|
expiresAt: new Date(
|
|
68
69
|
Date.now() + this.billingPortalSessionExpiryDurationMs
|
|
@@ -105,6 +106,7 @@ var StripeCheckoutSessionService = class {
|
|
|
105
106
|
async createCheckoutSession(checkoutSessionDto, ...args) {
|
|
106
107
|
const session = await this.stripeClient.checkout.sessions.create({
|
|
107
108
|
...checkoutSessionDto.stripeFields,
|
|
109
|
+
mode: "subscription",
|
|
108
110
|
payment_method_types: checkoutSessionDto.paymentMethods,
|
|
109
111
|
currency: checkoutSessionDto.currency,
|
|
110
112
|
success_url: checkoutSessionDto.successRedirectUri,
|
|
@@ -190,10 +192,10 @@ var StripePaymentLinkService = class {
|
|
|
190
192
|
{
|
|
191
193
|
...paymentLinkDto,
|
|
192
194
|
id: session.id,
|
|
193
|
-
amount: session.line_items?.data.reduce(
|
|
195
|
+
amount: paymentLinkDto.amount ?? session.line_items?.data.reduce(
|
|
194
196
|
(total, item) => total + item.amount_total,
|
|
195
197
|
0
|
|
196
|
-
)
|
|
198
|
+
)
|
|
197
199
|
},
|
|
198
200
|
this.em,
|
|
199
201
|
session,
|
|
@@ -259,24 +261,21 @@ var StripePaymentLinkService = class {
|
|
|
259
261
|
await this.basePaymentLinkService.handlePaymentFailure({ id });
|
|
260
262
|
}
|
|
261
263
|
async listPaymentLinks(idsDto) {
|
|
264
|
+
this.openTelemetryCollector.log("info", idsDto ?? "idsDto is undefined");
|
|
262
265
|
const stripePaymentLinks = await this.stripeClient.paymentLinks.list({
|
|
263
266
|
active: true
|
|
264
267
|
});
|
|
265
268
|
const databasePaymentLinks = await this.basePaymentLinkService.listPaymentLinks(idsDto);
|
|
266
|
-
return
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
paymentLink.stripeFields = stripePaymentLink;
|
|
277
|
-
return paymentLink;
|
|
278
|
-
})
|
|
279
|
-
);
|
|
269
|
+
return databasePaymentLinks.map((paymentLink) => {
|
|
270
|
+
const stripePaymentLink = stripePaymentLinks.data.find(
|
|
271
|
+
(sp) => sp.id === paymentLink.id
|
|
272
|
+
);
|
|
273
|
+
if (!stripePaymentLink) {
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
paymentLink.stripeFields = stripePaymentLink;
|
|
277
|
+
return paymentLink;
|
|
278
|
+
}).filter((paymentLink) => paymentLink !== null);
|
|
280
279
|
}
|
|
281
280
|
};
|
|
282
281
|
|
|
@@ -307,6 +306,7 @@ var StripePlanService = class {
|
|
|
307
306
|
async createPlan(planDto, em) {
|
|
308
307
|
const stripePlan = await this.stripeClient.plans.create({
|
|
309
308
|
...planDto.stripeFields,
|
|
309
|
+
amount: planDto.price,
|
|
310
310
|
interval: planDto.cadence,
|
|
311
311
|
product: planDto.name,
|
|
312
312
|
currency: planDto.currency
|
|
@@ -323,68 +323,76 @@ var StripePlanService = class {
|
|
|
323
323
|
return plan;
|
|
324
324
|
}
|
|
325
325
|
async getPlan(idDto, em) {
|
|
326
|
-
const
|
|
327
|
-
|
|
328
|
-
this.options?.databaseTableName ?? "plan",
|
|
329
|
-
{ externalId: idDto.id }
|
|
330
|
-
))?.id;
|
|
331
|
-
if (!id) {
|
|
326
|
+
const planEntity = await this.basePlanService.getPlan(idDto, em);
|
|
327
|
+
if (!planEntity.externalId) {
|
|
332
328
|
throw new Error("Plan not found");
|
|
333
329
|
}
|
|
334
|
-
const
|
|
330
|
+
const plan = await this.stripeClient.plans.retrieve(planEntity.externalId);
|
|
335
331
|
planEntity.stripeFields = plan;
|
|
336
332
|
return planEntity;
|
|
337
333
|
}
|
|
338
334
|
async updatePlan(planDto, em) {
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
interval: planDto.cadence ?? existingPlan.interval,
|
|
344
|
-
product: planDto.name,
|
|
345
|
-
currency: planDto.currency ?? existingPlan.currency
|
|
346
|
-
})
|
|
347
|
-
);
|
|
348
|
-
const planEntity = await this.basePlanService.updatePlan(
|
|
349
|
-
await this.mappers.UpdatePlanMapper.toEntity(
|
|
350
|
-
{
|
|
351
|
-
...planDto,
|
|
352
|
-
externalId: plan.id,
|
|
353
|
-
billingProvider: "stripe"
|
|
354
|
-
},
|
|
355
|
-
em ?? this.em,
|
|
356
|
-
plan
|
|
357
|
-
),
|
|
335
|
+
const planEntity = await this.basePlanService.getPlan(
|
|
336
|
+
{
|
|
337
|
+
id: planDto.id
|
|
338
|
+
},
|
|
358
339
|
em
|
|
359
340
|
);
|
|
360
|
-
|
|
361
|
-
|
|
341
|
+
const existingPlan = await this.stripeClient.plans.retrieve(
|
|
342
|
+
planEntity.externalId
|
|
343
|
+
);
|
|
344
|
+
const existingProduct = existingPlan.product;
|
|
345
|
+
if (!existingProduct) {
|
|
346
|
+
throw new Error("Plan product not found");
|
|
347
|
+
}
|
|
348
|
+
const productId = typeof existingProduct === "string" ? existingProduct : existingProduct.id;
|
|
349
|
+
await this.stripeClient.plans.del(planEntity.externalId);
|
|
350
|
+
const updatedPlan = await this.stripeClient.plans.create({
|
|
351
|
+
...planDto.stripeFields,
|
|
352
|
+
interval: planDto.cadence ?? existingPlan.interval,
|
|
353
|
+
currency: planDto.currency ?? existingPlan.currency,
|
|
354
|
+
amount: planDto.price ?? existingPlan.amount ?? void 0,
|
|
355
|
+
product: productId
|
|
356
|
+
});
|
|
357
|
+
const updatedPlanEntity = await this.basePlanService.updatePlan(
|
|
358
|
+
{
|
|
359
|
+
...planDto,
|
|
360
|
+
externalId: updatedPlan.id,
|
|
361
|
+
name: planDto.name,
|
|
362
|
+
billingProvider: "stripe"
|
|
363
|
+
},
|
|
364
|
+
em,
|
|
365
|
+
updatedPlan
|
|
366
|
+
);
|
|
367
|
+
updatedPlanEntity.stripeFields = updatedPlan;
|
|
368
|
+
return updatedPlanEntity;
|
|
362
369
|
}
|
|
363
370
|
async deletePlan(idDto, em) {
|
|
364
|
-
await this.
|
|
371
|
+
const plan = await this.basePlanService.getPlan(idDto, em);
|
|
372
|
+
if (!plan.externalId) {
|
|
373
|
+
throw new Error("Plan not found");
|
|
374
|
+
}
|
|
375
|
+
await this.stripeClient.plans.del(plan.externalId);
|
|
365
376
|
await this.basePlanService.deletePlan(idDto, em);
|
|
366
377
|
}
|
|
367
378
|
async listPlans(idsDto, em) {
|
|
368
|
-
const plans = await this.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const planIds = (await em?.findAll(
|
|
372
|
-
this.options?.databaseTableName ?? "plan",
|
|
373
|
-
{ where: { externalId: { $in: plans.data.map((plan) => plan.id) } } }
|
|
374
|
-
))?.filter((s) => idsDto?.ids?.includes(s.id))?.map((s) => s.id);
|
|
375
|
-
if (!planIds) {
|
|
376
|
-
throw new Error("Plans not found");
|
|
379
|
+
const plans = await this.basePlanService.listPlans(idsDto, em);
|
|
380
|
+
if (!plans || plans.length === 0) {
|
|
381
|
+
return [];
|
|
377
382
|
}
|
|
378
|
-
|
|
379
|
-
(
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
)
|
|
383
|
+
const stripePlans = await Promise.all(
|
|
384
|
+
plans.map(async (plan) => {
|
|
385
|
+
try {
|
|
386
|
+
return await this.stripeClient.plans.retrieve(plan.externalId);
|
|
387
|
+
} catch {
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
})
|
|
387
391
|
);
|
|
392
|
+
return plans.map((plan, index) => ({
|
|
393
|
+
...plan,
|
|
394
|
+
stripeFields: stripePlans[index]
|
|
395
|
+
})).filter((plan) => plan.stripeFields !== null);
|
|
388
396
|
}
|
|
389
397
|
};
|
|
390
398
|
|
|
@@ -434,94 +442,127 @@ var StripeSubscriptionService = class {
|
|
|
434
442
|
}
|
|
435
443
|
async getSubscription(idDto, em) {
|
|
436
444
|
const subscriptionEntity = await this.baseSubscriptionService.getSubscription(idDto, em);
|
|
445
|
+
if (!subscriptionEntity.externalId) {
|
|
446
|
+
throw new Error("Subscription not found");
|
|
447
|
+
}
|
|
437
448
|
const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
|
|
438
|
-
|
|
449
|
+
subscriptionEntity.externalId
|
|
439
450
|
);
|
|
440
451
|
subscriptionEntity.stripeFields = stripeSubscription;
|
|
441
452
|
return subscriptionEntity;
|
|
442
453
|
}
|
|
443
454
|
async getUserSubscription(idDto, em) {
|
|
444
455
|
const subscriptionEntity = await this.baseSubscriptionService.getUserSubscription(idDto, em);
|
|
456
|
+
if (!subscriptionEntity.externalId) {
|
|
457
|
+
throw new Error("Subscription not found");
|
|
458
|
+
}
|
|
445
459
|
const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
|
|
446
|
-
|
|
460
|
+
subscriptionEntity.externalId
|
|
447
461
|
);
|
|
448
462
|
subscriptionEntity.stripeFields = stripeSubscription;
|
|
449
463
|
return subscriptionEntity;
|
|
450
464
|
}
|
|
451
465
|
async getOrganizationSubscription(idDto, em) {
|
|
452
|
-
const
|
|
453
|
-
|
|
454
|
-
{ externalId: idDto.id }
|
|
455
|
-
))?.id;
|
|
456
|
-
if (!id) {
|
|
466
|
+
const subscriptionEntity = await this.baseSubscriptionService.getOrganizationSubscription(idDto, em);
|
|
467
|
+
if (!subscriptionEntity.externalId) {
|
|
457
468
|
throw new Error("Subscription not found");
|
|
458
469
|
}
|
|
459
|
-
const subscriptionEntity = await this.baseSubscriptionService.getOrganizationSubscription(
|
|
460
|
-
{ id },
|
|
461
|
-
em
|
|
462
|
-
);
|
|
463
470
|
const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
|
|
464
|
-
|
|
471
|
+
subscriptionEntity.externalId
|
|
465
472
|
);
|
|
466
473
|
subscriptionEntity.stripeFields = stripeSubscription;
|
|
467
474
|
return subscriptionEntity;
|
|
468
475
|
}
|
|
469
476
|
async updateSubscription(subscriptionDto, em) {
|
|
470
|
-
const
|
|
471
|
-
|
|
477
|
+
const subscriptionEntity = await this.baseSubscriptionService.getSubscription(
|
|
478
|
+
{
|
|
479
|
+
id: subscriptionDto.id
|
|
480
|
+
},
|
|
481
|
+
em
|
|
482
|
+
);
|
|
483
|
+
if (!subscriptionEntity.externalId) {
|
|
484
|
+
throw new Error("Subscription not found");
|
|
485
|
+
}
|
|
486
|
+
const existingStripeSubscription = await this.stripeClient.subscriptions.retrieve(
|
|
487
|
+
subscriptionEntity.externalId
|
|
488
|
+
);
|
|
489
|
+
const updatedSubscription = await this.stripeClient.subscriptions.update(
|
|
490
|
+
subscriptionEntity.externalId,
|
|
472
491
|
{
|
|
473
492
|
...subscriptionDto.stripeFields,
|
|
474
|
-
items:
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
]
|
|
493
|
+
items: existingStripeSubscription.items.data.map((item) => ({
|
|
494
|
+
id: item.id,
|
|
495
|
+
plan: subscriptionDto.productId || item.plan?.id
|
|
496
|
+
}))
|
|
479
497
|
}
|
|
480
498
|
);
|
|
481
|
-
|
|
499
|
+
const updatedSubscriptionEntity = await this.baseSubscriptionService.updateSubscription(
|
|
482
500
|
{
|
|
483
501
|
...subscriptionDto,
|
|
484
|
-
externalId:
|
|
485
|
-
billingProvider: "stripe"
|
|
486
|
-
providerFields: subscription
|
|
502
|
+
externalId: updatedSubscription.id,
|
|
503
|
+
billingProvider: "stripe"
|
|
487
504
|
},
|
|
488
505
|
em ?? this.em,
|
|
489
|
-
|
|
506
|
+
updatedSubscription
|
|
490
507
|
);
|
|
508
|
+
updatedSubscriptionEntity.stripeFields = updatedSubscription;
|
|
509
|
+
return updatedSubscriptionEntity;
|
|
491
510
|
}
|
|
492
511
|
async deleteSubscription(idDto, em) {
|
|
493
|
-
await this.
|
|
512
|
+
const subscription = await this.baseSubscriptionService.getSubscription(
|
|
513
|
+
idDto,
|
|
514
|
+
em
|
|
515
|
+
);
|
|
516
|
+
if (!subscription.externalId) {
|
|
517
|
+
throw new Error("Subscription not found");
|
|
518
|
+
}
|
|
519
|
+
await this.stripeClient.subscriptions.cancel(subscription.externalId);
|
|
494
520
|
await this.baseSubscriptionService.deleteSubscription(idDto, em);
|
|
495
521
|
}
|
|
496
522
|
async listSubscriptions(idsDto, em) {
|
|
497
|
-
const subscriptions =
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
))?.map((s) => s.id);
|
|
504
|
-
if (!ids) {
|
|
505
|
-
throw new Error("Subscriptions not found");
|
|
523
|
+
const subscriptions = await this.baseSubscriptionService.listSubscriptions(
|
|
524
|
+
idsDto,
|
|
525
|
+
em
|
|
526
|
+
);
|
|
527
|
+
if (!subscriptions || subscriptions.length === 0) {
|
|
528
|
+
return [];
|
|
506
529
|
}
|
|
507
|
-
|
|
508
|
-
(
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
530
|
+
const stripeSubscriptions = await Promise.all(
|
|
531
|
+
subscriptions.map(async (subscription) => {
|
|
532
|
+
try {
|
|
533
|
+
return await this.stripeClient.subscriptions.retrieve(
|
|
534
|
+
subscription.externalId
|
|
512
535
|
);
|
|
513
|
-
|
|
514
|
-
return
|
|
536
|
+
} catch {
|
|
537
|
+
return null;
|
|
515
538
|
}
|
|
516
|
-
)
|
|
539
|
+
})
|
|
517
540
|
);
|
|
541
|
+
return subscriptions.map((subscription, index) => ({
|
|
542
|
+
...subscription,
|
|
543
|
+
stripeFields: stripeSubscriptions[index]
|
|
544
|
+
})).filter((subscription) => subscription.stripeFields !== null);
|
|
518
545
|
}
|
|
519
546
|
async cancelSubscription(idDto, em) {
|
|
520
|
-
await this.
|
|
547
|
+
const subscription = await this.baseSubscriptionService.getSubscription(
|
|
548
|
+
idDto,
|
|
549
|
+
em
|
|
550
|
+
);
|
|
551
|
+
if (!subscription.externalId) {
|
|
552
|
+
throw new Error("Subscription not found");
|
|
553
|
+
}
|
|
554
|
+
await this.stripeClient.subscriptions.cancel(subscription.externalId);
|
|
521
555
|
await this.baseSubscriptionService.cancelSubscription(idDto, em);
|
|
522
556
|
}
|
|
523
557
|
async resumeSubscription(idDto, em) {
|
|
524
|
-
await this.
|
|
558
|
+
const subscription = await this.baseSubscriptionService.getSubscription(
|
|
559
|
+
idDto,
|
|
560
|
+
em
|
|
561
|
+
);
|
|
562
|
+
if (!subscription.externalId) {
|
|
563
|
+
throw new Error("Subscription not found");
|
|
564
|
+
}
|
|
565
|
+
await this.stripeClient.subscriptions.resume(subscription.externalId);
|
|
525
566
|
await this.baseSubscriptionService.resumeSubscription(idDto, em);
|
|
526
567
|
}
|
|
527
568
|
};
|
|
@@ -727,6 +768,7 @@ var StripeWebhookService = class {
|
|
|
727
768
|
|
|
728
769
|
// services/index.ts
|
|
729
770
|
export * from "@forklaunch/interfaces-billing/interfaces";
|
|
771
|
+
export * from "@forklaunch/interfaces-billing/types";
|
|
730
772
|
export {
|
|
731
773
|
StripeBillingPortalService,
|
|
732
774
|
StripeCheckoutSessionService,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forklaunch/implementation-billing-stripe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Stripe implementation for forklaunch billing",
|
|
5
5
|
"homepage": "https://github.com/forklaunch/forklaunch-js#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -42,20 +42,20 @@
|
|
|
42
42
|
"lib/**"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@forklaunch/common": "^0.6.
|
|
46
|
-
"@forklaunch/core": "^0.15.
|
|
47
|
-
"@forklaunch/internal": "^0.3.
|
|
48
|
-
"@forklaunch/validator": "^0.10.
|
|
49
|
-
"@mikro-orm/core": "^6.5.
|
|
45
|
+
"@forklaunch/common": "^0.6.17",
|
|
46
|
+
"@forklaunch/core": "^0.15.6",
|
|
47
|
+
"@forklaunch/internal": "^0.3.17",
|
|
48
|
+
"@forklaunch/validator": "^0.10.17",
|
|
49
|
+
"@mikro-orm/core": "^6.5.7",
|
|
50
50
|
"@sinclair/typebox": "^0.34.41",
|
|
51
51
|
"ajv": "^8.17.1",
|
|
52
|
-
"stripe": "^
|
|
53
|
-
"zod": "^4.1.
|
|
54
|
-
"@forklaunch/
|
|
55
|
-
"@forklaunch/
|
|
52
|
+
"stripe": "^19.1.0",
|
|
53
|
+
"zod": "^4.1.12",
|
|
54
|
+
"@forklaunch/interfaces-billing": "0.8.0",
|
|
55
|
+
"@forklaunch/implementation-billing-base": "0.8.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
58
|
+
"@typescript/native-preview": "7.0.0-dev.20251007.1",
|
|
59
59
|
"depcheck": "^1.4.7",
|
|
60
60
|
"prettier": "^3.6.2",
|
|
61
61
|
"typedoc": "^0.28.13"
|