@forklaunch/implementation-billing-base 0.1.17 → 0.2.1

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.
Files changed (41) hide show
  1. package/lib/__test__/schemaEquality.test.js +35 -14
  2. package/lib/eject/domain/schemas/checkoutSession.schema.ts +24 -4
  3. package/lib/eject/domain/schemas/paymentLink.schema.ts +24 -4
  4. package/lib/eject/services/billingPortal.service.ts +104 -32
  5. package/lib/eject/services/checkoutSession.service.ts +115 -32
  6. package/lib/eject/services/paymentLink.service.ts +116 -41
  7. package/lib/eject/services/plan.service.ts +60 -22
  8. package/lib/eject/services/subscription.service.ts +83 -26
  9. package/lib/schemas/checkoutSession.schema.d.ts +97 -11
  10. package/lib/schemas/checkoutSession.schema.d.ts.map +1 -1
  11. package/lib/schemas/paymentLink.schema.d.ts +101 -12
  12. package/lib/schemas/paymentLink.schema.d.ts.map +1 -1
  13. package/lib/schemas/typebox/checkoutSession.schema.d.ts +130 -10
  14. package/lib/schemas/typebox/checkoutSession.schema.d.ts.map +1 -1
  15. package/lib/schemas/typebox/checkoutSession.schema.js +9 -3
  16. package/lib/schemas/typebox/paymentLink.schema.d.ts +144 -12
  17. package/lib/schemas/typebox/paymentLink.schema.d.ts.map +1 -1
  18. package/lib/schemas/typebox/paymentLink.schema.js +9 -3
  19. package/lib/schemas/zod/checkoutSession.schema.d.ts +66 -12
  20. package/lib/schemas/zod/checkoutSession.schema.d.ts.map +1 -1
  21. package/lib/schemas/zod/checkoutSession.schema.js +9 -3
  22. package/lib/schemas/zod/paymentLink.schema.d.ts +66 -12
  23. package/lib/schemas/zod/paymentLink.schema.d.ts.map +1 -1
  24. package/lib/schemas/zod/paymentLink.schema.js +9 -3
  25. package/lib/services/billingPortal.service.d.ts +25 -7
  26. package/lib/services/billingPortal.service.d.ts.map +1 -1
  27. package/lib/services/billingPortal.service.js +87 -29
  28. package/lib/services/checkoutSession.service.d.ts +63 -20
  29. package/lib/services/checkoutSession.service.d.ts.map +1 -1
  30. package/lib/services/checkoutSession.service.js +67 -16
  31. package/lib/services/paymentLink.service.d.ts +39 -20
  32. package/lib/services/paymentLink.service.d.ts.map +1 -1
  33. package/lib/services/paymentLink.service.js +88 -24
  34. package/lib/services/plan.service.d.ts +19 -7
  35. package/lib/services/plan.service.d.ts.map +1 -1
  36. package/lib/services/plan.service.js +49 -17
  37. package/lib/services/subscription.service.d.ts +21 -7
  38. package/lib/services/subscription.service.d.ts.map +1 -1
  39. package/lib/services/subscription.service.js +72 -20
  40. package/lib/tsconfig.tsbuildinfo +1 -1
  41. package/package.json +6 -6
@@ -60,35 +60,48 @@ const zodBillingPortalSchema = ZodBillingPortalSchema({ uuidId: false });
60
60
  const typeboxBillingPortalSchema = TypeboxBillingPortalSchema({
61
61
  uuidId: false
62
62
  });
63
- const zodCreateCheckoutSessionSchema =
64
- ZodCreateCheckoutSessionSchema(DummyEnum);
65
- const typeboxCreateCheckoutSessionSchema =
66
- TypeboxCreateCheckoutSessionSchema(DummyEnum);
63
+ const zodCreateCheckoutSessionSchema = ZodCreateCheckoutSessionSchema(
64
+ DummyEnum,
65
+ DummyEnum
66
+ );
67
+ const typeboxCreateCheckoutSessionSchema = TypeboxCreateCheckoutSessionSchema(
68
+ DummyEnum,
69
+ DummyEnum
70
+ );
67
71
  const zodUpdateCheckoutSessionSchema = ZodUpdateCheckoutSessionSchema({
68
72
  uuidId: false
69
- })(DummyEnum);
73
+ })(DummyEnum, DummyEnum);
70
74
  const typeboxUpdateCheckoutSessionSchema = TypeboxUpdateCheckoutSessionSchema({
71
75
  uuidId: false
72
- })(DummyEnum);
76
+ })(DummyEnum, DummyEnum);
73
77
  const zodCheckoutSessionSchema = ZodCheckoutSessionSchema({ uuidId: true })(
78
+ DummyEnum,
74
79
  DummyEnum
75
80
  );
76
81
  const typeboxCheckoutSessionSchema = TypeboxCheckoutSessionSchema({
77
82
  uuidId: true
78
- })(DummyEnum);
79
- const zodCreatePaymentLinkSchema = ZodCreatePaymentLinkSchema(DummyEnum);
80
- const typeboxCreatePaymentLinkSchema =
81
- TypeboxCreatePaymentLinkSchema(DummyEnum);
83
+ })(DummyEnum, DummyEnum);
84
+ const zodCreatePaymentLinkSchema = ZodCreatePaymentLinkSchema(
85
+ DummyEnum,
86
+ DummyEnum
87
+ );
88
+ const typeboxCreatePaymentLinkSchema = TypeboxCreatePaymentLinkSchema(
89
+ DummyEnum,
90
+ DummyEnum
91
+ );
82
92
  const zodUpdatePaymentLinkSchema = ZodUpdatePaymentLinkSchema({
83
93
  uuidId: false
84
- })(DummyEnum);
94
+ })(DummyEnum, DummyEnum);
85
95
  const typeboxUpdatePaymentLinkSchema = TypeboxUpdatePaymentLinkSchema({
86
96
  uuidId: false
87
- })(DummyEnum);
88
- const zodPaymentLinkSchema = ZodPaymentLinkSchema({ uuidId: true })(DummyEnum);
97
+ })(DummyEnum, DummyEnum);
98
+ const zodPaymentLinkSchema = ZodPaymentLinkSchema({ uuidId: true })(
99
+ DummyEnum,
100
+ DummyEnum
101
+ );
89
102
  const typeboxPaymentLinkSchema = TypeboxPaymentLinkSchema({
90
103
  uuidId: false
91
- })(DummyEnum);
104
+ })(DummyEnum, DummyEnum);
92
105
  const zodCreatePlanSchema = ZodCreatePlanSchema(DummyEnum, DummyEnum);
93
106
  const typeboxCreatePlanSchema = TypeboxCreatePlanSchema(DummyEnum, DummyEnum);
94
107
  const zodUpdatePlanSchema = ZodUpdatePlanSchema({ uuidId: false })(
@@ -178,6 +191,8 @@ describe('schema equality', () => {
178
191
  paymentMethods: [DummyEnum.A, DummyEnum.B],
179
192
  successRedirectUri: 'https://example.com',
180
193
  cancelRedirectUri: 'https://example.com',
194
+ expiresAt: new Date(),
195
+ status: DummyEnum.A,
181
196
  extraFields: {
182
197
  test: 'test'
183
198
  }
@@ -214,6 +229,8 @@ describe('schema equality', () => {
214
229
  paymentMethods: [DummyEnum.A, DummyEnum.B],
215
230
  successRedirectUri: 'https://example.com',
216
231
  cancelRedirectUri: 'https://example.com',
232
+ expiresAt: new Date(),
233
+ status: DummyEnum.A,
217
234
  extraFields: {
218
235
  test: 'test'
219
236
  }
@@ -237,6 +254,8 @@ describe('schema equality', () => {
237
254
  metadata: {
238
255
  test: 'test'
239
256
  },
257
+ expiresAt: new Date(),
258
+ status: DummyEnum.A,
240
259
  extraFields: {
241
260
  test: 'test'
242
261
  }
@@ -278,6 +297,8 @@ describe('schema equality', () => {
278
297
  metadata: {
279
298
  test: 'test'
280
299
  },
300
+ expiresAt: new Date(),
301
+ status: DummyEnum.A,
281
302
  extraFields: {
282
303
  test: 'test'
283
304
  }
@@ -10,37 +10,57 @@ import {
10
10
  } from '@{{app_name}}/core';
11
11
 
12
12
  export const CreateCheckoutSessionSchema = <
13
- T extends Record<string, LiteralSchema>
13
+ T extends Record<string, LiteralSchema>,
14
+ U extends Record<string, LiteralSchema>
14
15
  >(
15
- PaymentMethodEnum: T
16
+ PaymentMethodEnum: T,
17
+ StatusEnum: U
16
18
  ) => ({
17
19
  customerId: string,
18
20
  paymentMethods: array(enum_(PaymentMethodEnum)),
19
21
  successRedirectUri: string,
20
22
  cancelRedirectUri: string,
23
+ expiresAt: date,
24
+ status: enum_(StatusEnum),
21
25
  extraFields: optional(unknown)
22
26
  });
23
27
 
24
28
  export const UpdateCheckoutSessionSchema =
25
29
  ({ uuidId }: { uuidId: boolean }) =>
26
- <T extends Record<string, LiteralSchema>>(PaymentMethodEnum: T) => ({
30
+ <
31
+ T extends Record<string, LiteralSchema>,
32
+ U extends Record<string, LiteralSchema>
33
+ >(
34
+ PaymentMethodEnum: T,
35
+ StatusEnum: U
36
+ ) => ({
27
37
  id: uuidId ? uuid : string,
28
38
  customerId: optional(string),
29
39
  paymentMethods: optional(array(enum_(PaymentMethodEnum))),
30
40
  successRedirectUri: optional(string),
31
41
  cancelRedirectUri: optional(string),
42
+ expiresAt: optional(date),
43
+ status: optional(enum_(StatusEnum)),
32
44
  extraFields: optional(unknown)
33
45
  });
34
46
 
35
47
  export const CheckoutSessionSchema =
36
48
  ({ uuidId }: { uuidId: boolean }) =>
37
- <T extends Record<string, LiteralSchema>>(PaymentMethodEnum: T) => ({
49
+ <
50
+ T extends Record<string, LiteralSchema>,
51
+ U extends Record<string, LiteralSchema>
52
+ >(
53
+ PaymentMethodEnum: T,
54
+ StatusEnum: U
55
+ ) => ({
38
56
  id: uuidId ? uuid : string,
39
57
  customerId: string,
40
58
  metadata: optional(unknown),
41
59
  paymentMethods: array(enum_(PaymentMethodEnum)),
42
60
  successRedirectUri: string,
43
61
  cancelRedirectUri: string,
62
+ expiresAt: date,
63
+ status: enum_(StatusEnum),
44
64
  extraFields: optional(unknown),
45
65
  createdAt: optional(date),
46
66
  updatedAt: optional(date)
@@ -10,9 +10,11 @@ import {
10
10
  } from '@{{app_name}}/core';
11
11
 
12
12
  export const CreatePaymentLinkSchema = <
13
- T extends Record<string, LiteralSchema>
13
+ T extends Record<string, LiteralSchema>,
14
+ U extends Record<string, LiteralSchema>
14
15
  >(
15
- CurrencyEnum: T
16
+ CurrencyEnum: T,
17
+ StatusEnum: U
16
18
  ) => ({
17
19
  amount: number,
18
20
  currency: enum_(CurrencyEnum),
@@ -20,12 +22,20 @@ export const CreatePaymentLinkSchema = <
20
22
  metadata: optional(unknown),
21
23
  successRedirectUri: string,
22
24
  cancelRedirectUri: string,
25
+ expiresAt: date,
26
+ status: enum_(StatusEnum),
23
27
  extraFields: optional(unknown)
24
28
  });
25
29
 
26
30
  export const UpdatePaymentLinkSchema =
27
31
  ({ uuidId }: { uuidId: boolean }) =>
28
- <T extends Record<string, LiteralSchema>>(CurrencyEnum: T) => ({
32
+ <
33
+ T extends Record<string, LiteralSchema>,
34
+ U extends Record<string, LiteralSchema>
35
+ >(
36
+ CurrencyEnum: T,
37
+ StatusEnum: U
38
+ ) => ({
29
39
  id: uuidId ? uuid : string,
30
40
  amount: optional(number),
31
41
  currency: optional(enum_(CurrencyEnum)),
@@ -33,12 +43,20 @@ export const UpdatePaymentLinkSchema =
33
43
  metadata: optional(unknown),
34
44
  successRedirectUri: optional(string),
35
45
  cancelRedirectUri: optional(string),
46
+ expiresAt: optional(date),
47
+ status: optional(enum_(StatusEnum)),
36
48
  extraFields: optional(unknown)
37
49
  });
38
50
 
39
51
  export const PaymentLinkSchema =
40
52
  ({ uuidId }: { uuidId: boolean }) =>
41
- <T extends Record<string, LiteralSchema>>(CurrencyEnum: T) => ({
53
+ <
54
+ T extends Record<string, LiteralSchema>,
55
+ U extends Record<string, LiteralSchema>
56
+ >(
57
+ CurrencyEnum: T,
58
+ StatusEnum: U
59
+ ) => ({
42
60
  id: uuidId ? uuid : string,
43
61
  amount: number,
44
62
  currency: enum_(CurrencyEnum),
@@ -46,6 +64,8 @@ export const PaymentLinkSchema =
46
64
  metadata: optional(unknown),
47
65
  successRedirectUri: string,
48
66
  cancelRedirectUri: string,
67
+ expiresAt: date,
68
+ status: enum_(StatusEnum),
49
69
  extraFields: optional(unknown),
50
70
  createdAt: optional(date),
51
71
  updatedAt: optional(date)
@@ -1,15 +1,17 @@
1
1
  import { IdDto, InstanceTypeRecord } from '@forklaunch/common';
2
2
  import { createCacheKey, TtlCache } from '@forklaunch/core/cache';
3
+ import {
4
+ evaluateTelemetryOptions,
5
+ MetricsDefinition,
6
+ OpenTelemetryCollector,
7
+ TelemetryOptions
8
+ } from '@forklaunch/core/http';
3
9
  import {
4
10
  InternalDtoMapper,
5
11
  RequestDtoMapperConstructor,
6
12
  ResponseDtoMapperConstructor,
7
13
  transformIntoInternalDtoMapper
8
14
  } from '@forklaunch/core/mappers';
9
- import {
10
- MetricsDefinition,
11
- OpenTelemetryCollector
12
- } from '@forklaunch/core/http';
13
15
  import { BillingPortalService } from '@forklaunch/interfaces-billing/interfaces';
14
16
  import {
15
17
  BillingPortalDto,
@@ -17,6 +19,7 @@ import {
17
19
  UpdateBillingPortalDto
18
20
  } from '@forklaunch/interfaces-billing/types';
19
21
  import { AnySchemaValidator } from '@forklaunch/validator';
22
+ import { EntityManager } from '@mikro-orm/core';
20
23
 
21
24
  export class BaseBillingPortalService<
22
25
  SchemaValidator extends AnySchemaValidator,
@@ -41,17 +44,24 @@ export class BaseBillingPortalService<
41
44
  }
42
45
  > implements BillingPortalService
43
46
  {
44
- #mapperss: InternalDtoMapper<
45
- InstanceTypeRecord<typeof this.mapperss>,
47
+ #mappers: InternalDtoMapper<
48
+ InstanceTypeRecord<typeof this.mappers>,
46
49
  Entities,
47
50
  Dto
48
51
  >;
52
+ private evaluatedTelemetryOptions: {
53
+ logging?: boolean;
54
+ metrics?: boolean;
55
+ tracing?: boolean;
56
+ };
57
+ private enableDatabaseBackup: boolean;
49
58
 
50
59
  constructor(
60
+ protected em: EntityManager,
51
61
  protected cache: TtlCache,
52
62
  protected openTelemetryCollector: OpenTelemetryCollector<Metrics>,
53
63
  protected schemaValidator: SchemaValidator,
54
- protected mapperss: {
64
+ protected mappers: {
55
65
  BillingPortalDtoMapper: ResponseDtoMapperConstructor<
56
66
  SchemaValidator,
57
67
  Dto['BillingPortalDtoMapper'],
@@ -67,9 +77,21 @@ export class BaseBillingPortalService<
67
77
  Dto['UpdateBillingPortalDtoMapper'],
68
78
  Entities['UpdateBillingPortalDtoMapper']
69
79
  >;
80
+ },
81
+ readonly options?: {
82
+ telemetry?: TelemetryOptions;
83
+ enableDatabaseBackup?: boolean;
70
84
  }
71
85
  ) {
72
- this.#mapperss = transformIntoInternalDtoMapper(mapperss, schemaValidator);
86
+ this.#mappers = transformIntoInternalDtoMapper(mappers, schemaValidator);
87
+ this.enableDatabaseBackup = options?.enableDatabaseBackup ?? false;
88
+ this.evaluatedTelemetryOptions = options?.telemetry
89
+ ? evaluateTelemetryOptions(options.telemetry).enabled
90
+ : {
91
+ logging: false,
92
+ metrics: false,
93
+ tracing: false
94
+ };
73
95
  }
74
96
 
75
97
  protected createCacheKey = createCacheKey('billing_portal_session');
@@ -77,65 +99,115 @@ export class BaseBillingPortalService<
77
99
  async createBillingPortalSession(
78
100
  billingPortalDto: Dto['CreateBillingPortalDtoMapper']
79
101
  ): Promise<Dto['BillingPortalDtoMapper']> {
80
- const billingPortalSession =
81
- this.#mapperss.CreateBillingPortalDtoMapper.deserializeDtoToEntity(
102
+ if (this.evaluatedTelemetryOptions.logging) {
103
+ this.openTelemetryCollector.info(
104
+ 'Creating billing portal session',
82
105
  billingPortalDto
83
106
  );
107
+ }
84
108
 
85
- this.openTelemetryCollector.debug(
86
- 'Create billing portal session',
87
- billingPortalSession
88
- );
109
+ const billingPortal =
110
+ await this.#mappers.CreateBillingPortalDtoMapper.deserializeDtoToEntity(
111
+ billingPortalDto,
112
+ this.em
113
+ );
114
+
115
+ if (this.enableDatabaseBackup) {
116
+ await this.em.persistAndFlush(billingPortal);
117
+ }
118
+
119
+ const createdBillingPortalDto =
120
+ await this.#mappers.BillingPortalDtoMapper.serializeEntityToDto(
121
+ billingPortal
122
+ );
89
123
 
90
124
  await this.cache.putRecord({
91
- key: this.createCacheKey(billingPortalSession.id),
92
- value: billingPortalSession,
125
+ key: this.createCacheKey(createdBillingPortalDto.id),
126
+ value: createdBillingPortalDto,
93
127
  ttlMilliseconds: this.cache.getTtlMilliseconds()
94
128
  });
95
129
 
96
- return this.#mapperss.BillingPortalDtoMapper.serializeEntityToDto(
97
- billingPortalSession
98
- );
130
+ return createdBillingPortalDto;
99
131
  }
100
132
 
101
133
  async getBillingPortalSession(
102
134
  idDto: IdDto
103
135
  ): Promise<Dto['BillingPortalDtoMapper']> {
104
- const billingPortalSessionDetails = await this.cache.readRecord<
136
+ if (this.evaluatedTelemetryOptions.logging) {
137
+ this.openTelemetryCollector.info('Getting billing portal session', idDto);
138
+ }
139
+
140
+ const billingPortalDetails = await this.cache.readRecord<
105
141
  Entities['BillingPortalDtoMapper']
106
142
  >(this.createCacheKey(idDto.id));
107
- if (!billingPortalSessionDetails) {
143
+
144
+ if (!billingPortalDetails) {
108
145
  throw new Error('Session not found');
109
146
  }
110
147
 
111
- return this.#mapperss.BillingPortalDtoMapper.serializeEntityToDto(
112
- billingPortalSessionDetails.value
113
- );
148
+ return billingPortalDetails.value;
114
149
  }
115
150
 
116
151
  async updateBillingPortalSession(
117
152
  billingPortalDto: UpdateBillingPortalDto
118
153
  ): Promise<Dto['BillingPortalDtoMapper']> {
119
- const billingPortalSession =
120
- this.#mapperss.UpdateBillingPortalDtoMapper.deserializeDtoToEntity(
154
+ if (this.evaluatedTelemetryOptions.logging) {
155
+ this.openTelemetryCollector.info(
156
+ 'Updating billing portal session',
121
157
  billingPortalDto
122
158
  );
123
- // Save the updated session to your database or external service
159
+ }
160
+
161
+ const existingBillingPortal = (
162
+ await this.cache.readRecord<Entities['BillingPortalDtoMapper']>(
163
+ this.createCacheKey(billingPortalDto.id)
164
+ )
165
+ )?.value;
166
+
167
+ if (!existingBillingPortal) {
168
+ throw new Error('Session not found');
169
+ }
170
+
171
+ const billingPortal =
172
+ await this.#mappers.UpdateBillingPortalDtoMapper.deserializeDtoToEntity(
173
+ billingPortalDto,
174
+ this.em
175
+ );
176
+
177
+ if (this.enableDatabaseBackup) {
178
+ await this.em.persistAndFlush({
179
+ billingPortal
180
+ });
181
+ }
182
+
183
+ const updatedBillingPortalDto = {
184
+ ...existingBillingPortal,
185
+ ...(await this.#mappers.BillingPortalDtoMapper.serializeEntityToDto(
186
+ billingPortal
187
+ ))
188
+ };
189
+
124
190
  await this.cache.putRecord({
125
- key: this.createCacheKey(billingPortalSession.id),
126
- value: billingPortalSession,
191
+ key: this.createCacheKey(updatedBillingPortalDto.id),
192
+ value: updatedBillingPortalDto,
127
193
  ttlMilliseconds: this.cache.getTtlMilliseconds()
128
194
  });
129
195
 
130
- return this.#mapperss.BillingPortalDtoMapper.serializeEntityToDto(
131
- billingPortalSession
132
- );
196
+ return updatedBillingPortalDto;
133
197
  }
134
198
 
135
199
  async expireBillingPortalSession(idDto: IdDto): Promise<void> {
200
+ if (this.evaluatedTelemetryOptions.logging) {
201
+ this.openTelemetryCollector.info(
202
+ 'Expiring billing portal session',
203
+ idDto
204
+ );
205
+ }
206
+
136
207
  const sessionExists = await this.cache.readRecord(
137
208
  this.createCacheKey(idDto.id)
138
209
  );
210
+
139
211
  if (!sessionExists) {
140
212
  throw new Error('Session not found');
141
213
  }
@@ -1,15 +1,17 @@
1
1
  import { IdDto, InstanceTypeRecord } from '@forklaunch/common';
2
2
  import { createCacheKey, TtlCache } from '@forklaunch/core/cache';
3
+ import {
4
+ evaluateTelemetryOptions,
5
+ MetricsDefinition,
6
+ OpenTelemetryCollector,
7
+ TelemetryOptions
8
+ } from '@forklaunch/core/http';
3
9
  import {
4
10
  InternalDtoMapper,
5
11
  RequestDtoMapperConstructor,
6
12
  ResponseDtoMapperConstructor,
7
13
  transformIntoInternalDtoMapper
8
14
  } from '@forklaunch/core/mappers';
9
- import {
10
- MetricsDefinition,
11
- OpenTelemetryCollector
12
- } from '@forklaunch/core/http';
13
15
  import { CheckoutSessionService } from '@forklaunch/interfaces-billing/interfaces';
14
16
  import {
15
17
  CheckoutSessionDto,
@@ -17,42 +19,75 @@ import {
17
19
  UpdateCheckoutSessionDto
18
20
  } from '@forklaunch/interfaces-billing/types';
19
21
  import { AnySchemaValidator } from '@forklaunch/validator';
22
+ import { EntityManager } from '@mikro-orm/core';
20
23
 
21
24
  export class BaseCheckoutSessionService<
22
25
  SchemaValidator extends AnySchemaValidator,
23
26
  PaymentMethodEnum,
27
+ StatusEnum,
24
28
  Metrics extends MetricsDefinition = MetricsDefinition,
25
29
  Dto extends {
26
- CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
27
- CreateCheckoutSessionDtoMapper: CreateCheckoutSessionDto<PaymentMethodEnum>;
28
- UpdateCheckoutSessionDtoMapper: UpdateCheckoutSessionDto<PaymentMethodEnum>;
30
+ CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum, StatusEnum>;
31
+ CreateCheckoutSessionDtoMapper: CreateCheckoutSessionDto<
32
+ PaymentMethodEnum,
33
+ StatusEnum
34
+ >;
35
+ UpdateCheckoutSessionDtoMapper: UpdateCheckoutSessionDto<
36
+ PaymentMethodEnum,
37
+ StatusEnum
38
+ >;
29
39
  } = {
30
- CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
31
- CreateCheckoutSessionDtoMapper: CreateCheckoutSessionDto<PaymentMethodEnum>;
32
- UpdateCheckoutSessionDtoMapper: UpdateCheckoutSessionDto<PaymentMethodEnum>;
40
+ CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum, StatusEnum>;
41
+ CreateCheckoutSessionDtoMapper: CreateCheckoutSessionDto<
42
+ PaymentMethodEnum,
43
+ StatusEnum
44
+ >;
45
+ UpdateCheckoutSessionDtoMapper: UpdateCheckoutSessionDto<
46
+ PaymentMethodEnum,
47
+ StatusEnum
48
+ >;
33
49
  },
34
50
  Entities extends {
35
- CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
36
- CreateCheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
37
- UpdateCheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
51
+ CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum, StatusEnum>;
52
+ CreateCheckoutSessionDtoMapper: CheckoutSessionDto<
53
+ PaymentMethodEnum,
54
+ StatusEnum
55
+ >;
56
+ UpdateCheckoutSessionDtoMapper: CheckoutSessionDto<
57
+ PaymentMethodEnum,
58
+ StatusEnum
59
+ >;
38
60
  } = {
39
- CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
40
- CreateCheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
41
- UpdateCheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum>;
61
+ CheckoutSessionDtoMapper: CheckoutSessionDto<PaymentMethodEnum, StatusEnum>;
62
+ CreateCheckoutSessionDtoMapper: CheckoutSessionDto<
63
+ PaymentMethodEnum,
64
+ StatusEnum
65
+ >;
66
+ UpdateCheckoutSessionDtoMapper: CheckoutSessionDto<
67
+ PaymentMethodEnum,
68
+ StatusEnum
69
+ >;
42
70
  }
43
- > implements CheckoutSessionService<PaymentMethodEnum>
71
+ > implements CheckoutSessionService<PaymentMethodEnum, StatusEnum>
44
72
  {
45
- #mapperss: InternalDtoMapper<
46
- InstanceTypeRecord<typeof this.mapperss>,
73
+ #mappers: InternalDtoMapper<
74
+ InstanceTypeRecord<typeof this.mappers>,
47
75
  Entities,
48
76
  Dto
49
77
  >;
78
+ private evaluatedTelemetryOptions: {
79
+ logging?: boolean;
80
+ metrics?: boolean;
81
+ tracing?: boolean;
82
+ };
83
+ private enableDatabaseBackup: boolean;
50
84
 
51
85
  constructor(
86
+ protected readonly em: EntityManager,
52
87
  protected readonly cache: TtlCache,
53
88
  protected readonly openTelemetryCollector: OpenTelemetryCollector<Metrics>,
54
89
  protected readonly schemaValidator: SchemaValidator,
55
- protected readonly mapperss: {
90
+ protected readonly mappers: {
56
91
  CheckoutSessionDtoMapper: ResponseDtoMapperConstructor<
57
92
  SchemaValidator,
58
93
  Dto['CheckoutSessionDtoMapper'],
@@ -68,9 +103,21 @@ export class BaseCheckoutSessionService<
68
103
  Dto['UpdateCheckoutSessionDtoMapper'],
69
104
  Entities['UpdateCheckoutSessionDtoMapper']
70
105
  >;
106
+ },
107
+ readonly options?: {
108
+ enableDatabaseBackup?: boolean;
109
+ telemetry?: TelemetryOptions;
71
110
  }
72
111
  ) {
73
- this.#mapperss = transformIntoInternalDtoMapper(mapperss, schemaValidator);
112
+ this.#mappers = transformIntoInternalDtoMapper(mappers, schemaValidator);
113
+ this.enableDatabaseBackup = options?.enableDatabaseBackup ?? false;
114
+ this.evaluatedTelemetryOptions = options?.telemetry
115
+ ? evaluateTelemetryOptions(options.telemetry).enabled
116
+ : {
117
+ logging: false,
118
+ metrics: false,
119
+ tracing: false
120
+ };
74
121
  }
75
122
 
76
123
  protected createCacheKey = createCacheKey('checkout_session');
@@ -78,21 +125,35 @@ export class BaseCheckoutSessionService<
78
125
  async createCheckoutSession(
79
126
  checkoutSessionDto: Dto['CreateCheckoutSessionDtoMapper']
80
127
  ): Promise<Dto['CheckoutSessionDtoMapper']> {
81
- const checkoutSession =
82
- this.#mapperss.CreateCheckoutSessionDtoMapper.deserializeDtoToEntity(
128
+ if (this.evaluatedTelemetryOptions.logging) {
129
+ this.openTelemetryCollector.info(
130
+ 'Creating checkout session',
83
131
  checkoutSessionDto
84
132
  );
133
+ }
134
+
135
+ const checkoutSession =
136
+ await this.#mappers.CreateCheckoutSessionDtoMapper.deserializeDtoToEntity(
137
+ checkoutSessionDto,
138
+ this.em
139
+ );
140
+
141
+ const createdCheckoutSessionDto =
142
+ await this.#mappers.CheckoutSessionDtoMapper.serializeEntityToDto(
143
+ checkoutSession
144
+ );
145
+
146
+ if (this.enableDatabaseBackup) {
147
+ await this.em.persistAndFlush(checkoutSession);
148
+ }
85
149
 
86
- // Store the checkoutSession details in the cache
87
150
  await this.cache.putRecord({
88
- key: this.createCacheKey(checkoutSession.id),
89
- value: checkoutSession,
151
+ key: this.createCacheKey(createdCheckoutSessionDto.id),
152
+ value: createdCheckoutSessionDto,
90
153
  ttlMilliseconds: this.cache.getTtlMilliseconds()
91
154
  });
92
155
 
93
- return this.#mapperss.CheckoutSessionDtoMapper.serializeEntityToDto(
94
- checkoutSession
95
- );
156
+ return createdCheckoutSessionDto;
96
157
  }
97
158
 
98
159
  async getCheckoutSession({
@@ -105,7 +166,7 @@ export class BaseCheckoutSessionService<
105
166
  throw new Error('Session not found');
106
167
  }
107
168
 
108
- return this.#mapperss.CheckoutSessionDtoMapper.serializeEntityToDto(
169
+ return this.#mappers.CheckoutSessionDtoMapper.serializeEntityToDto(
109
170
  checkoutSessionDetails.value
110
171
  );
111
172
  }
@@ -121,12 +182,34 @@ export class BaseCheckoutSessionService<
121
182
  }
122
183
 
123
184
  async handleCheckoutSuccess({ id }: IdDto): Promise<void> {
124
- this.openTelemetryCollector.info('Checkout success', { id });
185
+ if (this.evaluatedTelemetryOptions.logging) {
186
+ this.openTelemetryCollector.info('Checkout success', { id });
187
+ }
188
+
189
+ if (this.enableDatabaseBackup) {
190
+ const checkoutSession = await this.em.upsert('CheckoutSession', {
191
+ id,
192
+ status: 'SUCCESS'
193
+ });
194
+ await this.em.persistAndFlush(checkoutSession);
195
+ }
196
+
125
197
  await this.cache.deleteRecord(this.createCacheKey(id));
126
198
  }
127
199
 
128
200
  async handleCheckoutFailure({ id }: IdDto): Promise<void> {
129
- this.openTelemetryCollector.info('Checkout failure', { id });
201
+ if (this.evaluatedTelemetryOptions.logging) {
202
+ this.openTelemetryCollector.info('Checkout failure', { id });
203
+ }
204
+
205
+ if (this.enableDatabaseBackup) {
206
+ const checkoutSession = await this.em.upsert('CheckoutSession', {
207
+ id,
208
+ status: 'FAILED'
209
+ });
210
+ await this.em.persistAndFlush(checkoutSession);
211
+ }
212
+
130
213
  await this.cache.deleteRecord(this.createCacheKey(id));
131
214
  }
132
215
  }