@forklaunch/implementation-billing-stripe 1.2.12 → 1.3.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/domain/schemas/billingPortal.schema.d.ts +2 -2
- package/lib/domain/schemas/index.js +27 -14
- package/lib/domain/schemas/index.mjs +33 -14
- package/lib/domain/schemas/plan.schema.d.ts +2 -2
- package/lib/domain/schemas/typebox/billingPortal.schema.d.ts +2 -2
- package/lib/domain/schemas/typebox/checkoutSession.schema.d.ts +3 -3
- package/lib/domain/schemas/typebox/checkoutSession.schema.d.ts.map +1 -1
- package/lib/domain/schemas/typebox/paymentLink.schema.d.ts +2 -1
- package/lib/domain/schemas/typebox/paymentLink.schema.d.ts.map +1 -1
- package/lib/domain/schemas/typebox/plan.schema.d.ts +2 -2
- package/lib/domain/schemas/typebox/subscription.schema.d.ts +1 -1
- package/lib/domain/schemas/zod/billingPortal.schema.d.ts +2 -2
- package/lib/domain/schemas/zod/checkoutSession.schema.d.ts +3 -3
- package/lib/domain/schemas/zod/checkoutSession.schema.d.ts.map +1 -1
- package/lib/domain/schemas/zod/paymentLink.schema.d.ts.map +1 -1
- package/lib/domain/schemas/zod/plan.schema.d.ts +2 -2
- package/lib/domain/schemas/zod/subscription.schema.d.ts +1 -1
- package/lib/domain/schemas/zod/subscription.schema.d.ts.map +1 -1
- package/lib/domain/types/billingPortal.mapper.types.d.ts +8 -0
- package/lib/domain/types/billingPortal.mapper.types.d.ts.map +1 -1
- package/lib/domain/types/checkoutSession.mapper.types.d.ts +6 -0
- package/lib/domain/types/checkoutSession.mapper.types.d.ts.map +1 -1
- package/lib/domain/types/paymentLink.mapper.types.d.ts +20 -0
- package/lib/domain/types/paymentLink.mapper.types.d.ts.map +1 -1
- package/lib/domain/types/plan.mapper.types.d.ts +10 -0
- package/lib/domain/types/plan.mapper.types.d.ts.map +1 -1
- package/lib/domain/types/stripe.dto.types.d.ts +6 -8
- package/lib/domain/types/stripe.dto.types.d.ts.map +1 -1
- package/lib/domain/types/stripe.entity.types.d.ts.map +1 -1
- package/lib/domain/types/subscription.mapper.types.d.ts +15 -0
- package/lib/domain/types/subscription.mapper.types.d.ts.map +1 -1
- package/lib/eject/domain/schemas/billingPortal.schema.ts +1 -1
- package/lib/eject/domain/schemas/checkoutSession.schema.ts +5 -3
- package/lib/eject/domain/schemas/paymentLink.schema.ts +12 -1
- package/lib/eject/domain/schemas/plan.schema.ts +1 -1
- package/lib/eject/domain/schemas/subscription.schema.ts +2 -1
- package/lib/eject/domain/types/billingPortal.mapper.types.ts +17 -0
- package/lib/eject/domain/types/checkoutSession.mapper.types.ts +9 -0
- package/lib/eject/domain/types/paymentLink.mapper.types.ts +36 -0
- package/lib/eject/domain/types/plan.mapper.types.ts +16 -0
- package/lib/eject/domain/types/stripe.dto.types.ts +6 -8
- package/lib/eject/domain/types/stripe.entity.types.ts +0 -6
- package/lib/eject/domain/types/subscription.mapper.types.ts +21 -0
- package/lib/eject/services/billingPortal.service.ts +24 -0
- package/lib/eject/services/checkoutSession.service.ts +54 -9
- package/lib/eject/services/paymentLink.service.ts +149 -25
- package/lib/eject/services/plan.service.ts +34 -4
- package/lib/eject/services/subscription.service.ts +42 -1
- package/lib/eject/services/webhook.service.ts +10 -1
- package/lib/services/billingPortal.service.d.ts.map +1 -1
- package/lib/services/checkoutSession.service.d.ts +8 -0
- package/lib/services/checkoutSession.service.d.ts.map +1 -1
- package/lib/services/index.js +238 -25
- package/lib/services/index.mjs +238 -25
- package/lib/services/paymentLink.service.d.ts +12 -0
- package/lib/services/paymentLink.service.d.ts.map +1 -1
- package/lib/services/plan.service.d.ts.map +1 -1
- package/lib/services/subscription.service.d.ts.map +1 -1
- package/lib/services/webhook.service.d.ts.map +1 -1
- package/package.json +8 -8
package/lib/services/index.js
CHANGED
|
@@ -60,10 +60,12 @@ var StripeBillingPortalService = class {
|
|
|
60
60
|
billingPortalSessionExpiryDurationMs = 5 * 60 * 1e3;
|
|
61
61
|
mappers;
|
|
62
62
|
async createBillingPortalSession(billingPortalDto, ...args) {
|
|
63
|
+
await this.mappers.CreateBillingPortalMapper.validateCreate?.(billingPortalDto);
|
|
63
64
|
const session = await this.stripeClient.billingPortal.sessions.create({
|
|
64
65
|
...billingPortalDto.stripeFields,
|
|
65
66
|
customer: billingPortalDto.customerId
|
|
66
67
|
});
|
|
68
|
+
await this.mappers.CreateBillingPortalMapper.validateProviderCreate?.(session);
|
|
67
69
|
return await this.baseBillingPortalService.createBillingPortalSession(
|
|
68
70
|
{
|
|
69
71
|
...billingPortalDto,
|
|
@@ -88,10 +90,20 @@ var StripeBillingPortalService = class {
|
|
|
88
90
|
const existingSession = await this.baseBillingPortalService.getBillingPortalSession({
|
|
89
91
|
id: billingPortalDto.id
|
|
90
92
|
});
|
|
93
|
+
if (!this.options?.enableDatabaseBackup && this.mappers.UpdateBillingPortalMapper.toCachedDto && billingPortalDto.customerId !== void 0 && billingPortalDto.customerId !== existingSession.customerId) {
|
|
94
|
+
throw new Error("Cached session identity cannot change");
|
|
95
|
+
}
|
|
96
|
+
if (!this.options?.enableDatabaseBackup && this.mappers.UpdateBillingPortalMapper.toCachedDto && this.mappers.UpdateBillingPortalMapper.validateCachedUpdate) {
|
|
97
|
+
await this.mappers.UpdateBillingPortalMapper.validateCachedUpdate(
|
|
98
|
+
billingPortalDto,
|
|
99
|
+
existingSession
|
|
100
|
+
);
|
|
101
|
+
}
|
|
91
102
|
const session = await this.stripeClient.billingPortal.sessions.create({
|
|
92
103
|
...billingPortalDto.stripeFields,
|
|
93
104
|
customer: billingPortalDto.customerId || existingSession.customerId
|
|
94
105
|
});
|
|
106
|
+
await this.mappers.CreateBillingPortalMapper.validateProviderCreate?.(session);
|
|
95
107
|
return await this.baseBillingPortalService.updateBillingPortalSession(
|
|
96
108
|
{
|
|
97
109
|
...billingPortalDto,
|
|
@@ -138,6 +150,7 @@ var StripeCheckoutSessionService = class {
|
|
|
138
150
|
schemaValidator;
|
|
139
151
|
mappers;
|
|
140
152
|
async createCheckoutSession(checkoutSessionDto, ...args) {
|
|
153
|
+
await this.mappers.CreateCheckoutSessionMapper.validateCreate?.(checkoutSessionDto);
|
|
141
154
|
const session = await this.stripeClient.checkout.sessions.create({
|
|
142
155
|
...checkoutSessionDto.stripeFields,
|
|
143
156
|
mode: "subscription",
|
|
@@ -146,6 +159,7 @@ var StripeCheckoutSessionService = class {
|
|
|
146
159
|
success_url: checkoutSessionDto.successRedirectUri,
|
|
147
160
|
cancel_url: checkoutSessionDto.cancelRedirectUri
|
|
148
161
|
});
|
|
162
|
+
await this.mappers.CreateCheckoutSessionMapper.validateProviderCreate?.(session);
|
|
149
163
|
return await this.baseCheckoutSessionService.createCheckoutSession(
|
|
150
164
|
{
|
|
151
165
|
...checkoutSessionDto,
|
|
@@ -160,6 +174,17 @@ var StripeCheckoutSessionService = class {
|
|
|
160
174
|
);
|
|
161
175
|
}
|
|
162
176
|
async getCheckoutSession(idDto) {
|
|
177
|
+
const readCachedDto = this.mappers.CheckoutSessionMapper.readCachedDto;
|
|
178
|
+
if (readCachedDto) {
|
|
179
|
+
const existing = await this.baseCheckoutSessionService.getCheckoutSession(idDto);
|
|
180
|
+
if (existing.id !== idDto.id) {
|
|
181
|
+
throw new Error("Cached checkout identity does not match");
|
|
182
|
+
}
|
|
183
|
+
return readCachedDto(
|
|
184
|
+
existing,
|
|
185
|
+
(providerId) => this.stripeClient.checkout.sessions.retrieve(providerId)
|
|
186
|
+
);
|
|
187
|
+
}
|
|
163
188
|
const session = await this.stripeClient.checkout.sessions.retrieve(
|
|
164
189
|
idDto.id
|
|
165
190
|
);
|
|
@@ -167,33 +192,73 @@ var StripeCheckoutSessionService = class {
|
|
|
167
192
|
databaseCheckoutSession.stripeFields = session;
|
|
168
193
|
return databaseCheckoutSession;
|
|
169
194
|
}
|
|
195
|
+
/**
|
|
196
|
+
* The Stripe id (`cs_...`) stored with a checkout session when it was
|
|
197
|
+
* created. Public ids are local; Stripe only knows its own id. The stored
|
|
198
|
+
* provider object's id wins; a record without one is still usable when its
|
|
199
|
+
* own id is a Stripe id. Anything else fails here rather than sending Stripe
|
|
200
|
+
* a local id.
|
|
201
|
+
*/
|
|
202
|
+
async stripeCheckoutSessionId(id) {
|
|
203
|
+
const checkoutSession = await this.baseCheckoutSessionService.getCheckoutSession({ id });
|
|
204
|
+
const stored = checkoutSession?.stripeFields?.id;
|
|
205
|
+
const stripeId = stored === void 0 ? checkoutSession?.id : stored;
|
|
206
|
+
if (typeof stripeId !== "string" || !/^cs_[A-Za-z0-9_]+$/.test(stripeId)) {
|
|
207
|
+
throw new Error(
|
|
208
|
+
`Checkout session ${id} has no stored Stripe checkout session id`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return stripeId;
|
|
212
|
+
}
|
|
170
213
|
async expireCheckoutSession({ id }) {
|
|
171
|
-
await this.stripeClient.checkout.sessions.expire(
|
|
214
|
+
await this.stripeClient.checkout.sessions.expire(
|
|
215
|
+
await this.stripeCheckoutSessionId(id)
|
|
216
|
+
);
|
|
172
217
|
await this.baseCheckoutSessionService.expireCheckoutSession({ id });
|
|
173
218
|
}
|
|
174
219
|
async handleCheckoutSuccess({ id }) {
|
|
175
|
-
await this.stripeClient.checkout.sessions.update(
|
|
176
|
-
|
|
177
|
-
|
|
220
|
+
await this.stripeClient.checkout.sessions.update(
|
|
221
|
+
await this.stripeCheckoutSessionId(id),
|
|
222
|
+
{
|
|
223
|
+
metadata: {
|
|
224
|
+
status: "SUCCESS"
|
|
225
|
+
}
|
|
178
226
|
}
|
|
179
|
-
|
|
227
|
+
);
|
|
180
228
|
await this.baseCheckoutSessionService.handleCheckoutSuccess({ id });
|
|
181
229
|
}
|
|
182
230
|
async handleCheckoutFailure({ id }) {
|
|
183
|
-
await this.stripeClient.checkout.sessions.update(
|
|
184
|
-
|
|
185
|
-
|
|
231
|
+
await this.stripeClient.checkout.sessions.update(
|
|
232
|
+
await this.stripeCheckoutSessionId(id),
|
|
233
|
+
{
|
|
234
|
+
metadata: {
|
|
235
|
+
status: "FAILED"
|
|
236
|
+
}
|
|
186
237
|
}
|
|
187
|
-
|
|
238
|
+
);
|
|
188
239
|
await this.baseCheckoutSessionService.handleCheckoutFailure({ id });
|
|
189
240
|
}
|
|
190
241
|
};
|
|
191
242
|
|
|
192
243
|
// services/paymentLink.service.ts
|
|
193
244
|
var import_services3 = require("@forklaunch/implementation-billing-base/services");
|
|
245
|
+
function validatePaymentLinkCreateFields(value) {
|
|
246
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !Array.isArray(value.line_items) || !value.line_items.every(
|
|
247
|
+
(item) => item !== null && typeof item === "object" && !Array.isArray(item)
|
|
248
|
+
)) {
|
|
249
|
+
throw new Error(
|
|
250
|
+
"Payment link provider options require a line_items array of objects"
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
194
254
|
var StripePaymentLinkService = class {
|
|
195
255
|
constructor(stripeClient, em, cache, openTelemetryCollector, schemaValidator, mappers, options) {
|
|
196
256
|
this.options = options;
|
|
257
|
+
const limit = options?.maxConfiguredListRecords === void 0 ? 100 : options.maxConfiguredListRecords;
|
|
258
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 1e3) {
|
|
259
|
+
throw new Error("Invalid configured payment link list limit");
|
|
260
|
+
}
|
|
261
|
+
this.maxConfiguredListRecords = limit;
|
|
197
262
|
this.stripeClient = stripeClient;
|
|
198
263
|
this.em = em;
|
|
199
264
|
this.cache = cache;
|
|
@@ -211,6 +276,7 @@ var StripePaymentLinkService = class {
|
|
|
211
276
|
}
|
|
212
277
|
options;
|
|
213
278
|
basePaymentLinkService;
|
|
279
|
+
maxConfiguredListRecords;
|
|
214
280
|
stripeClient;
|
|
215
281
|
em;
|
|
216
282
|
cache;
|
|
@@ -218,11 +284,16 @@ var StripePaymentLinkService = class {
|
|
|
218
284
|
schemaValidator;
|
|
219
285
|
mappers;
|
|
220
286
|
async createPaymentLink(paymentLinkDto, ...args) {
|
|
287
|
+
await this.mappers.CreatePaymentLinkMapper.validateCreate?.(paymentLinkDto);
|
|
288
|
+
validatePaymentLinkCreateFields(paymentLinkDto.stripeFields);
|
|
221
289
|
const session = await this.stripeClient.paymentLinks.create({
|
|
222
290
|
...paymentLinkDto.stripeFields,
|
|
223
291
|
payment_method_types: paymentLinkDto.paymentMethods,
|
|
224
292
|
currency: paymentLinkDto.currency
|
|
225
293
|
});
|
|
294
|
+
await this.mappers.CreatePaymentLinkMapper.validateProviderCreate?.(
|
|
295
|
+
session
|
|
296
|
+
);
|
|
226
297
|
const paymentLink = await this.basePaymentLinkService.createPaymentLink(
|
|
227
298
|
{
|
|
228
299
|
...paymentLinkDto,
|
|
@@ -239,20 +310,55 @@ var StripePaymentLinkService = class {
|
|
|
239
310
|
paymentLink.stripeFields = session;
|
|
240
311
|
return paymentLink;
|
|
241
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* The Stripe id (`plink_...`) stored with a payment link when it was created.
|
|
315
|
+
* Public ids are local; Stripe only knows its own id. The stored provider
|
|
316
|
+
* object's id wins; a record without one is still usable when its own id is a
|
|
317
|
+
* Stripe id. Anything else fails here rather than sending Stripe a local id.
|
|
318
|
+
*/
|
|
319
|
+
stripePaymentLinkId(paymentLink, id) {
|
|
320
|
+
const stored = paymentLink?.stripeFields?.id;
|
|
321
|
+
const stripeId = stored === void 0 ? paymentLink?.id : stored;
|
|
322
|
+
if (typeof stripeId !== "string" || !/^plink_[A-Za-z0-9_]+$/.test(stripeId)) {
|
|
323
|
+
throw new Error(
|
|
324
|
+
`Payment link ${id} has no stored Stripe payment link id`
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
return stripeId;
|
|
328
|
+
}
|
|
242
329
|
async updatePaymentLink(paymentLinkDto, ...args) {
|
|
243
|
-
const
|
|
244
|
-
paymentLinkDto.id
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
330
|
+
const existing = await this.basePaymentLinkService.getPaymentLink({
|
|
331
|
+
id: paymentLinkDto.id
|
|
332
|
+
});
|
|
333
|
+
if (this.mappers.UpdatePaymentLinkMapper.validateCachedUpdate) {
|
|
334
|
+
await this.mappers.UpdatePaymentLinkMapper.validateCachedUpdate(
|
|
335
|
+
paymentLinkDto,
|
|
336
|
+
existing
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
const stripeId = this.stripePaymentLinkId(existing, paymentLinkDto.id);
|
|
340
|
+
const session = await this.stripeClient.paymentLinks.update(stripeId, {
|
|
341
|
+
...paymentLinkDto.stripeFields,
|
|
342
|
+
payment_method_types: paymentLinkDto.paymentMethods
|
|
343
|
+
});
|
|
344
|
+
if (session.id !== stripeId) {
|
|
345
|
+
throw new Error("Invalid Stripe billing response");
|
|
346
|
+
}
|
|
347
|
+
const toLocalUpdate = this.mappers.UpdatePaymentLinkMapper.toLocalUpdate;
|
|
348
|
+
if (toLocalUpdate) {
|
|
349
|
+
const patch = await toLocalUpdate(paymentLinkDto, session);
|
|
350
|
+
return this.basePaymentLinkService.updatePaymentLink(
|
|
351
|
+
patch,
|
|
352
|
+
this.em,
|
|
353
|
+
session,
|
|
354
|
+
...args
|
|
355
|
+
);
|
|
356
|
+
}
|
|
250
357
|
const paymentLink = await this.basePaymentLinkService.updatePaymentLink(
|
|
251
358
|
await this.mappers.PaymentLinkMapper.toDto(
|
|
252
359
|
await this.mappers.UpdatePaymentLinkMapper.toEntity(
|
|
253
360
|
{
|
|
254
361
|
...paymentLinkDto,
|
|
255
|
-
id: session.id,
|
|
256
362
|
amount: session.line_items?.data.reduce(
|
|
257
363
|
(total, item) => total + item.amount_total,
|
|
258
364
|
0
|
|
@@ -268,13 +374,28 @@ var StripePaymentLinkService = class {
|
|
|
268
374
|
return paymentLink;
|
|
269
375
|
}
|
|
270
376
|
async getPaymentLink({ id }) {
|
|
377
|
+
const readCachedDto = this.mappers.PaymentLinkMapper.readCachedDto;
|
|
378
|
+
if (readCachedDto) {
|
|
379
|
+
const existing = await this.basePaymentLinkService.getPaymentLink({ id });
|
|
380
|
+
if (existing.id !== id) {
|
|
381
|
+
throw new Error("Cached payment link identity does not match");
|
|
382
|
+
}
|
|
383
|
+
return readCachedDto(
|
|
384
|
+
existing,
|
|
385
|
+
(providerId) => this.stripeClient.paymentLinks.retrieve(providerId)
|
|
386
|
+
);
|
|
387
|
+
}
|
|
271
388
|
const stripePaymentLink = await this.stripeClient.paymentLinks.retrieve(id);
|
|
272
389
|
const databasePaymentLink = await this.basePaymentLinkService.getPaymentLink({ id });
|
|
273
390
|
databasePaymentLink.stripeFields = stripePaymentLink;
|
|
274
391
|
return databasePaymentLink;
|
|
275
392
|
}
|
|
276
393
|
async expirePaymentLink({ id }) {
|
|
277
|
-
|
|
394
|
+
const stripeId = this.stripePaymentLinkId(
|
|
395
|
+
await this.basePaymentLinkService.getPaymentLink({ id }),
|
|
396
|
+
id
|
|
397
|
+
);
|
|
398
|
+
await this.stripeClient.paymentLinks.update(stripeId, {
|
|
278
399
|
metadata: {
|
|
279
400
|
status: "EXPIRED"
|
|
280
401
|
}
|
|
@@ -282,7 +403,11 @@ var StripePaymentLinkService = class {
|
|
|
282
403
|
await this.basePaymentLinkService.expirePaymentLink({ id });
|
|
283
404
|
}
|
|
284
405
|
async handlePaymentSuccess({ id }) {
|
|
285
|
-
|
|
406
|
+
const stripeId = this.stripePaymentLinkId(
|
|
407
|
+
await this.basePaymentLinkService.getPaymentLink({ id }),
|
|
408
|
+
id
|
|
409
|
+
);
|
|
410
|
+
await this.stripeClient.paymentLinks.update(stripeId, {
|
|
286
411
|
metadata: {
|
|
287
412
|
status: "COMPLETED"
|
|
288
413
|
}
|
|
@@ -290,7 +415,11 @@ var StripePaymentLinkService = class {
|
|
|
290
415
|
await this.basePaymentLinkService.handlePaymentSuccess({ id });
|
|
291
416
|
}
|
|
292
417
|
async handlePaymentFailure({ id }) {
|
|
293
|
-
|
|
418
|
+
const stripeId = this.stripePaymentLinkId(
|
|
419
|
+
await this.basePaymentLinkService.getPaymentLink({ id }),
|
|
420
|
+
id
|
|
421
|
+
);
|
|
422
|
+
await this.stripeClient.paymentLinks.update(stripeId, {
|
|
294
423
|
metadata: {
|
|
295
424
|
status: "FAILED"
|
|
296
425
|
}
|
|
@@ -299,6 +428,26 @@ var StripePaymentLinkService = class {
|
|
|
299
428
|
}
|
|
300
429
|
async listPaymentLinks(idsDto) {
|
|
301
430
|
this.openTelemetryCollector.log("info", idsDto ?? "idsDto is undefined");
|
|
431
|
+
const { readCachedDto, validateCachedRead } = this.mappers.PaymentLinkMapper;
|
|
432
|
+
if (readCachedDto && validateCachedRead) {
|
|
433
|
+
const cached = await this.basePaymentLinkService.listPaymentLinks(
|
|
434
|
+
idsDto,
|
|
435
|
+
this.maxConfiguredListRecords
|
|
436
|
+
);
|
|
437
|
+
for (const value of cached) validateCachedRead(value);
|
|
438
|
+
const active = [];
|
|
439
|
+
for (const value of cached) {
|
|
440
|
+
const fresh = await readCachedDto(
|
|
441
|
+
value,
|
|
442
|
+
(providerId) => this.stripeClient.paymentLinks.retrieve(providerId)
|
|
443
|
+
);
|
|
444
|
+
if (typeof fresh.stripeFields.active !== "boolean") {
|
|
445
|
+
throw new Error("Invalid payment link active state");
|
|
446
|
+
}
|
|
447
|
+
if (fresh.stripeFields.active) active.push(fresh);
|
|
448
|
+
}
|
|
449
|
+
return active;
|
|
450
|
+
}
|
|
302
451
|
const stripePaymentLinks = await this.stripeClient.paymentLinks.list({
|
|
303
452
|
active: true
|
|
304
453
|
});
|
|
@@ -342,6 +491,7 @@ var StripePlanService = class {
|
|
|
342
491
|
schemaValidator;
|
|
343
492
|
mappers;
|
|
344
493
|
async createPlan(planDto, em) {
|
|
494
|
+
await this.mappers.CreatePlanMapper.validateCreate?.(planDto);
|
|
345
495
|
let stripePlan = await this.stripeClient.plans.create({
|
|
346
496
|
...planDto.stripeFields,
|
|
347
497
|
amount: planDto.price,
|
|
@@ -349,9 +499,12 @@ var StripePlanService = class {
|
|
|
349
499
|
product: planDto.name,
|
|
350
500
|
currency: planDto.currency
|
|
351
501
|
});
|
|
352
|
-
|
|
502
|
+
await this.mappers.CreatePlanMapper.validateProviderCreate?.(stripePlan);
|
|
503
|
+
const createdId = stripePlan.id;
|
|
504
|
+
stripePlan = await this.stripeClient.plans.retrieve(createdId, {
|
|
353
505
|
expand: ["product"]
|
|
354
506
|
});
|
|
507
|
+
await this.mappers.PlanMapper.validateProviderRead?.(createdId, stripePlan);
|
|
355
508
|
const plan = await this.basePlanService.createPlan(
|
|
356
509
|
{
|
|
357
510
|
...planDto,
|
|
@@ -371,10 +524,15 @@ var StripePlanService = class {
|
|
|
371
524
|
const plan = await this.stripeClient.plans.retrieve(planEntity.externalId, {
|
|
372
525
|
expand: ["product"]
|
|
373
526
|
});
|
|
527
|
+
await this.mappers.PlanMapper.validateProviderRead?.(
|
|
528
|
+
planEntity.externalId,
|
|
529
|
+
plan
|
|
530
|
+
);
|
|
374
531
|
planEntity.stripeFields = plan.product;
|
|
375
532
|
return planEntity;
|
|
376
533
|
}
|
|
377
534
|
async updatePlan(planDto, em) {
|
|
535
|
+
await this.mappers.UpdatePlanMapper.validateUpdate?.(planDto);
|
|
378
536
|
const planEntity = await this.basePlanService.getPlan(
|
|
379
537
|
{
|
|
380
538
|
id: planDto.id
|
|
@@ -384,6 +542,14 @@ var StripePlanService = class {
|
|
|
384
542
|
const existingPlan = await this.stripeClient.plans.retrieve(
|
|
385
543
|
planEntity.externalId
|
|
386
544
|
);
|
|
545
|
+
await this.mappers.PlanMapper.validateProviderRead?.(
|
|
546
|
+
planEntity.externalId,
|
|
547
|
+
existingPlan
|
|
548
|
+
);
|
|
549
|
+
await this.mappers.UpdatePlanMapper.validateProviderUpdate?.(
|
|
550
|
+
planDto,
|
|
551
|
+
existingPlan
|
|
552
|
+
);
|
|
387
553
|
const existingProduct = existingPlan.product;
|
|
388
554
|
if (!existingProduct) {
|
|
389
555
|
throw new Error("Plan product not found");
|
|
@@ -398,14 +564,16 @@ var StripePlanService = class {
|
|
|
398
564
|
amount: planDto.price ?? existingPlan.amount ?? void 0,
|
|
399
565
|
product: productId
|
|
400
566
|
});
|
|
401
|
-
|
|
567
|
+
await this.mappers.CreatePlanMapper.validateProviderCreate?.(updatedPlan);
|
|
568
|
+
const createdId = updatedPlan.id;
|
|
569
|
+
updatedPlan = await this.stripeClient.plans.retrieve(createdId, {
|
|
402
570
|
expand: ["product"]
|
|
403
571
|
});
|
|
572
|
+
await this.mappers.PlanMapper.validateProviderRead?.(createdId, updatedPlan);
|
|
404
573
|
const updatedPlanEntity = await this.basePlanService.updatePlan(
|
|
405
574
|
{
|
|
406
575
|
...planDto,
|
|
407
576
|
externalId: updatedPlan.id,
|
|
408
|
-
name: planDto.name,
|
|
409
577
|
billingProvider: "stripe"
|
|
410
578
|
},
|
|
411
579
|
em,
|
|
@@ -436,6 +604,10 @@ var StripePlanService = class {
|
|
|
436
604
|
expand: ["product"]
|
|
437
605
|
}
|
|
438
606
|
);
|
|
607
|
+
await this.mappers.PlanMapper.validateProviderRead?.(
|
|
608
|
+
plan.externalId,
|
|
609
|
+
fetchedPlan
|
|
610
|
+
);
|
|
439
611
|
return fetchedPlan.product;
|
|
440
612
|
} catch {
|
|
441
613
|
return null;
|
|
@@ -475,6 +647,7 @@ var StripeSubscriptionService = class {
|
|
|
475
647
|
schemaValidator;
|
|
476
648
|
mappers;
|
|
477
649
|
async createSubscription(subscriptionDto, em) {
|
|
650
|
+
await this.mappers.CreateSubscriptionMapper.validateCreate?.(subscriptionDto);
|
|
478
651
|
const subscription = await this.stripeClient.subscriptions.create({
|
|
479
652
|
...subscriptionDto.stripeFields,
|
|
480
653
|
customer: subscriptionDto.partyId,
|
|
@@ -484,6 +657,7 @@ var StripeSubscriptionService = class {
|
|
|
484
657
|
}
|
|
485
658
|
]
|
|
486
659
|
});
|
|
660
|
+
await this.mappers.CreateSubscriptionMapper.validateProviderCreate?.(subscription);
|
|
487
661
|
return await this.baseSubscriptionService.createSubscription(
|
|
488
662
|
{
|
|
489
663
|
...subscriptionDto,
|
|
@@ -502,6 +676,10 @@ var StripeSubscriptionService = class {
|
|
|
502
676
|
const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
|
|
503
677
|
subscriptionEntity.externalId
|
|
504
678
|
);
|
|
679
|
+
await this.mappers.SubscriptionMapper.validateProviderRead?.(
|
|
680
|
+
subscriptionEntity.externalId,
|
|
681
|
+
stripeSubscription
|
|
682
|
+
);
|
|
505
683
|
subscriptionEntity.stripeFields = stripeSubscription;
|
|
506
684
|
return subscriptionEntity;
|
|
507
685
|
}
|
|
@@ -513,6 +691,10 @@ var StripeSubscriptionService = class {
|
|
|
513
691
|
const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
|
|
514
692
|
subscriptionEntity.externalId
|
|
515
693
|
);
|
|
694
|
+
await this.mappers.SubscriptionMapper.validateProviderRead?.(
|
|
695
|
+
subscriptionEntity.externalId,
|
|
696
|
+
stripeSubscription
|
|
697
|
+
);
|
|
516
698
|
subscriptionEntity.stripeFields = stripeSubscription;
|
|
517
699
|
return subscriptionEntity;
|
|
518
700
|
}
|
|
@@ -524,6 +706,10 @@ var StripeSubscriptionService = class {
|
|
|
524
706
|
const stripeSubscription = await this.stripeClient.subscriptions.retrieve(
|
|
525
707
|
subscriptionEntity.externalId
|
|
526
708
|
);
|
|
709
|
+
await this.mappers.SubscriptionMapper.validateProviderRead?.(
|
|
710
|
+
subscriptionEntity.externalId,
|
|
711
|
+
stripeSubscription
|
|
712
|
+
);
|
|
527
713
|
subscriptionEntity.stripeFields = stripeSubscription;
|
|
528
714
|
return subscriptionEntity;
|
|
529
715
|
}
|
|
@@ -537,9 +723,21 @@ var StripeSubscriptionService = class {
|
|
|
537
723
|
if (!subscriptionEntity.externalId) {
|
|
538
724
|
throw new Error("Subscription not found");
|
|
539
725
|
}
|
|
726
|
+
await this.mappers.UpdateSubscriptionMapper.validateUpdate?.(
|
|
727
|
+
subscriptionDto,
|
|
728
|
+
subscriptionEntity
|
|
729
|
+
);
|
|
540
730
|
const existingStripeSubscription = await this.stripeClient.subscriptions.retrieve(
|
|
541
731
|
subscriptionEntity.externalId
|
|
542
732
|
);
|
|
733
|
+
await this.mappers.SubscriptionMapper.validateProviderRead?.(
|
|
734
|
+
subscriptionEntity.externalId,
|
|
735
|
+
existingStripeSubscription
|
|
736
|
+
);
|
|
737
|
+
await this.mappers.UpdateSubscriptionMapper.validateProviderUpdate?.(
|
|
738
|
+
subscriptionDto,
|
|
739
|
+
existingStripeSubscription
|
|
740
|
+
);
|
|
543
741
|
const updatedSubscription = await this.stripeClient.subscriptions.update(
|
|
544
742
|
subscriptionEntity.externalId,
|
|
545
743
|
{
|
|
@@ -550,6 +748,10 @@ var StripeSubscriptionService = class {
|
|
|
550
748
|
}))
|
|
551
749
|
}
|
|
552
750
|
);
|
|
751
|
+
await this.mappers.SubscriptionMapper.validateProviderRead?.(
|
|
752
|
+
subscriptionEntity.externalId,
|
|
753
|
+
updatedSubscription
|
|
754
|
+
);
|
|
553
755
|
const updatedSubscriptionEntity = await this.baseSubscriptionService.updateSubscription(
|
|
554
756
|
{
|
|
555
757
|
...subscriptionDto,
|
|
@@ -584,9 +786,14 @@ var StripeSubscriptionService = class {
|
|
|
584
786
|
const stripeSubscriptions = await Promise.all(
|
|
585
787
|
subscriptions.map(async (subscription) => {
|
|
586
788
|
try {
|
|
587
|
-
|
|
789
|
+
const provider = await this.stripeClient.subscriptions.retrieve(
|
|
588
790
|
subscription.externalId
|
|
589
791
|
);
|
|
792
|
+
await this.mappers.SubscriptionMapper.validateProviderRead?.(
|
|
793
|
+
subscription.externalId,
|
|
794
|
+
provider
|
|
795
|
+
);
|
|
796
|
+
return provider;
|
|
590
797
|
} catch {
|
|
591
798
|
return null;
|
|
592
799
|
}
|
|
@@ -628,6 +835,12 @@ var BillingProviderEnum = {
|
|
|
628
835
|
|
|
629
836
|
// services/webhook.service.ts
|
|
630
837
|
var isActiveStatus = (status) => status === "active" || status === "trialing";
|
|
838
|
+
var portalExpiry = (created) => {
|
|
839
|
+
if (!Number.isSafeInteger(created) || created < 0 || created > 253402300499) {
|
|
840
|
+
throw new Error("Billing webhook payload is invalid");
|
|
841
|
+
}
|
|
842
|
+
return new Date((created + 300) * 1e3);
|
|
843
|
+
};
|
|
631
844
|
var StripeWebhookService = class {
|
|
632
845
|
partyEnum;
|
|
633
846
|
webhookEventEntity;
|
|
@@ -723,7 +936,7 @@ var StripeWebhookService = class {
|
|
|
723
936
|
{
|
|
724
937
|
id: event.data.object.id,
|
|
725
938
|
customerId: event.data.object.customer,
|
|
726
|
-
expiresAt:
|
|
939
|
+
expiresAt: portalExpiry(event.data.object.created),
|
|
727
940
|
uri: event.data.object.url
|
|
728
941
|
}
|
|
729
942
|
);
|