@darraghor/nest-backend-libs 5.7.5 → 6.0.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 (190) hide show
  1. package/README.md +92 -34
  2. package/dist/authorization/authz.module.js.map +1 -1
  3. package/dist/authorization/config/AuthConfigurationService.js.map +1 -1
  4. package/dist/authorization/guards/ClaimsAuthorisationGuard.js.map +1 -1
  5. package/dist/authorization/services/UserValidation.service.js.map +1 -1
  6. package/dist/authorization/strategies/apikeystrategy.js.map +1 -1
  7. package/dist/authorization/strategies/authzstrategy.js.map +1 -1
  8. package/dist/authzclient/AuthClientConfigurationService.js.map +1 -1
  9. package/dist/authzclient/authz-client.module.js.map +1 -1
  10. package/dist/authzclient/authz.service.js.map +1 -1
  11. package/dist/cli/commands/WriteApiClientCommand.js.map +1 -1
  12. package/dist/core-config/CoreConfig.module.js.map +1 -1
  13. package/dist/core-config/CoreConfigurationService.js.map +1 -1
  14. package/dist/database-postgres/PostgresTypeOrmConfigurationProvider.js.map +1 -1
  15. package/dist/database-sqlite/SqliteTypeOrmConfigurationProvider.js.map +1 -1
  16. package/dist/exports/authorization.d.ts +14 -0
  17. package/dist/exports/authorization.js +12 -0
  18. package/dist/exports/authorization.js.map +1 -0
  19. package/dist/exports/core.d.ts +11 -0
  20. package/dist/exports/core.js +10 -0
  21. package/dist/exports/core.js.map +1 -0
  22. package/dist/exports/database.d.ts +5 -0
  23. package/dist/exports/database.js +6 -0
  24. package/dist/exports/database.js.map +1 -0
  25. package/dist/exports/email.d.ts +4 -0
  26. package/dist/exports/email.js +4 -0
  27. package/dist/exports/email.js.map +1 -0
  28. package/dist/exports/invitations.d.ts +6 -0
  29. package/dist/exports/invitations.js +6 -0
  30. package/dist/exports/invitations.js.map +1 -0
  31. package/dist/exports/organisations.d.ts +11 -0
  32. package/dist/exports/organisations.js +12 -0
  33. package/dist/exports/organisations.js.map +1 -0
  34. package/dist/exports/stripe-legacy.d.ts +6 -0
  35. package/dist/exports/stripe-legacy.js +7 -0
  36. package/dist/exports/stripe-legacy.js.map +1 -0
  37. package/dist/exports/stripe.d.ts +11 -0
  38. package/dist/exports/stripe.js +9 -0
  39. package/dist/exports/stripe.js.map +1 -0
  40. package/dist/exports/twitter.d.ts +5 -0
  41. package/dist/exports/twitter.js +5 -0
  42. package/dist/exports/twitter.js.map +1 -0
  43. package/dist/exports/users.d.ts +10 -0
  44. package/dist/exports/users.js +11 -0
  45. package/dist/exports/users.js.map +1 -0
  46. package/dist/health/Health.controller.js.map +1 -1
  47. package/dist/index.d.ts +11 -0
  48. package/dist/index.js +11 -0
  49. package/dist/index.js.map +1 -1
  50. package/dist/invitations/InvitationConfigurationService.js.map +1 -1
  51. package/dist/invitations/invitation.controller.js +5 -1
  52. package/dist/invitations/invitation.controller.js.map +1 -1
  53. package/dist/invitations/invitation.module.js.map +1 -1
  54. package/dist/invitations/invitation.service.js.map +1 -1
  55. package/dist/logger/LoggingConfigurationService.js.map +1 -1
  56. package/dist/logger/logger.module.js.map +1 -1
  57. package/dist/organisation/organisation.controller.js.map +1 -1
  58. package/dist/organisation/organisation.service.js.map +1 -1
  59. package/dist/organisation-memberships/organisation-memberships.controller.js.map +1 -1
  60. package/dist/organisation-memberships/organisation-memberships.service.js.map +1 -1
  61. package/dist/organisation-subscriptions/all-subscriptions.controller.js.map +1 -1
  62. package/dist/organisation-subscriptions/entities/organisation-subscription.entity.js +2 -1
  63. package/dist/organisation-subscriptions/entities/organisation-subscription.entity.js.map +1 -1
  64. package/dist/organisation-subscriptions/organisation-subscriptions.controller.js.map +1 -1
  65. package/dist/organisation-subscriptions/organisation-subscriptions.service.js.map +1 -1
  66. package/dist/payment-sessions/payment-session.controller.js +3 -1
  67. package/dist/payment-sessions/payment-session.controller.js.map +1 -1
  68. package/dist/payment-sessions/payment-session.service.js.map +1 -1
  69. package/dist/root-app/SwaggerGen.js.map +1 -1
  70. package/dist/root-app/app.controller.js.map +1 -1
  71. package/dist/root-app/core-app.module.js.map +1 -1
  72. package/dist/root-app/notfound.interceptor.js.map +1 -1
  73. package/dist/runningCommandLine/CliCommandService.js.map +1 -1
  74. package/dist/smtp-email-client/EmailConfigurationService.js.map +1 -1
  75. package/dist/smtp-email-client/email-client.service.js.map +1 -1
  76. package/dist/smtp-email-client/email.controller.js.map +1 -1
  77. package/dist/smtp-email-client/smtp-email-client.module.js.map +1 -1
  78. package/dist/smtp-email-client/smtp-email-handler.js.map +1 -1
  79. package/dist/stripe-client/StripeClientConfigurationService.js +1 -0
  80. package/dist/stripe-client/StripeClientConfigurationService.js.map +1 -1
  81. package/dist/stripe-client/controllers/stripe-checkout-controller.d.ts +1 -0
  82. package/dist/stripe-client/controllers/stripe-checkout-controller.js +1 -0
  83. package/dist/stripe-client/controllers/stripe-checkout-controller.js.map +1 -1
  84. package/dist/stripe-client/controllers/stripe-customer-portal-controller.js.map +1 -1
  85. package/dist/stripe-client/controllers/stripe-events-controller.js +1 -0
  86. package/dist/stripe-client/controllers/stripe-events-controller.js.map +1 -1
  87. package/dist/stripe-client/controllers/stripe-unauthenticated-checkout-controller.js +1 -0
  88. package/dist/stripe-client/controllers/stripe-unauthenticated-checkout-controller.js.map +1 -1
  89. package/dist/stripe-client/controllers/stripe-webhook-controller.js.map +1 -1
  90. package/dist/stripe-client/services/auth-stripe-checkout.service.js +1 -0
  91. package/dist/stripe-client/services/auth-stripe-checkout.service.js.map +1 -1
  92. package/dist/stripe-client/services/queued-payment-event.handler.d.ts +1 -0
  93. package/dist/stripe-client/services/queued-payment-event.handler.js +2 -0
  94. package/dist/stripe-client/services/queued-payment-event.handler.js.map +1 -1
  95. package/dist/stripe-client/services/stripe-checkout.service.d.ts +1 -0
  96. package/dist/stripe-client/services/stripe-checkout.service.js +2 -0
  97. package/dist/stripe-client/services/stripe-checkout.service.js.map +1 -1
  98. package/dist/stripe-client/services/stripe-webhook-handler.service.js.map +1 -1
  99. package/dist/stripe-client/services/subscriptionRecord.mapper.js.map +1 -1
  100. package/dist/stripe-client/stripe-account.module.d.ts +1 -0
  101. package/dist/stripe-client/stripe-account.module.js +2 -0
  102. package/dist/stripe-client/stripe-account.module.js.map +1 -1
  103. package/dist/stripe-client/stripe-account.options.d.ts +2 -0
  104. package/dist/stripe-client/stripe-account.options.js.map +1 -1
  105. package/dist/stripe-payments/controllers/secure-stripe-checkout.controller.d.ts +10 -0
  106. package/dist/stripe-payments/controllers/secure-stripe-checkout.controller.js +65 -0
  107. package/dist/stripe-payments/controllers/secure-stripe-checkout.controller.js.map +1 -0
  108. package/dist/stripe-payments/controllers/secure-stripe-events.controller.d.ts +9 -0
  109. package/dist/stripe-payments/controllers/secure-stripe-events.controller.js +65 -0
  110. package/dist/stripe-payments/controllers/secure-stripe-events.controller.js.map +1 -0
  111. package/dist/stripe-payments/controllers/secure-stripe-webhook.controller.d.ts +14 -0
  112. package/dist/stripe-payments/controllers/secure-stripe-webhook.controller.js +112 -0
  113. package/dist/stripe-payments/controllers/secure-stripe-webhook.controller.js.map +1 -0
  114. package/dist/stripe-payments/entities/stripe-checkout-attempt.entity.d.ts +15 -0
  115. package/dist/stripe-payments/entities/stripe-checkout-attempt.entity.js +88 -0
  116. package/dist/stripe-payments/entities/stripe-checkout-attempt.entity.js.map +1 -0
  117. package/dist/stripe-payments/entities/stripe-payment-event.entity.d.ts +16 -0
  118. package/dist/stripe-payments/entities/stripe-payment-event.entity.js +101 -0
  119. package/dist/stripe-payments/entities/stripe-payment-event.entity.js.map +1 -0
  120. package/dist/stripe-payments/entities/stripe-payment-state.entity.d.ts +9 -0
  121. package/dist/stripe-payments/entities/stripe-payment-state.entity.js +53 -0
  122. package/dist/stripe-payments/entities/stripe-payment-state.entity.js.map +1 -0
  123. package/dist/stripe-payments/models/secure-checkout.dto.d.ts +14 -0
  124. package/dist/stripe-payments/models/secure-checkout.dto.js +105 -0
  125. package/dist/stripe-payments/models/secure-checkout.dto.js.map +1 -0
  126. package/dist/stripe-payments/models/secure-payment-response.dto.d.ts +7 -0
  127. package/dist/stripe-payments/models/secure-payment-response.dto.js +30 -0
  128. package/dist/stripe-payments/models/secure-payment-response.dto.js.map +1 -0
  129. package/dist/stripe-payments/services/default-stripe-payments-entitlement-store.d.ts +12 -0
  130. package/dist/stripe-payments/services/default-stripe-payments-entitlement-store.js +49 -0
  131. package/dist/stripe-payments/services/default-stripe-payments-entitlement-store.js.map +1 -0
  132. package/dist/stripe-payments/services/secure-stripe-checkout.service.d.ts +24 -0
  133. package/dist/stripe-payments/services/secure-stripe-checkout.service.js +213 -0
  134. package/dist/stripe-payments/services/secure-stripe-checkout.service.js.map +1 -0
  135. package/dist/stripe-payments/services/secure-stripe-client.provider.d.ts +2 -0
  136. package/dist/stripe-payments/services/secure-stripe-client.provider.js +15 -0
  137. package/dist/stripe-payments/services/secure-stripe-client.provider.js.map +1 -0
  138. package/dist/stripe-payments/services/secure-stripe-product.service.d.ts +9 -0
  139. package/dist/stripe-payments/services/secure-stripe-product.service.js +54 -0
  140. package/dist/stripe-payments/services/secure-stripe-product.service.js.map +1 -0
  141. package/dist/stripe-payments/services/secure-stripe-webhook.service.d.ts +14 -0
  142. package/dist/stripe-payments/services/secure-stripe-webhook.service.js +58 -0
  143. package/dist/stripe-payments/services/secure-stripe-webhook.service.js.map +1 -0
  144. package/dist/stripe-payments/services/secure-subscription.service.d.ts +18 -0
  145. package/dist/stripe-payments/services/secure-subscription.service.js +217 -0
  146. package/dist/stripe-payments/services/secure-subscription.service.js.map +1 -0
  147. package/dist/stripe-payments/services/stripe-payment-event.processor.d.ts +15 -0
  148. package/dist/stripe-payments/services/stripe-payment-event.processor.js +78 -0
  149. package/dist/stripe-payments/services/stripe-payment-event.processor.js.map +1 -0
  150. package/dist/stripe-payments/services/stripe-payment-event.service.d.ts +20 -0
  151. package/dist/stripe-payments/services/stripe-payment-event.service.js +178 -0
  152. package/dist/stripe-payments/services/stripe-payment-event.service.js.map +1 -0
  153. package/dist/stripe-payments/services/stripe-payment-fulfillment.service.d.ts +31 -0
  154. package/dist/stripe-payments/services/stripe-payment-fulfillment.service.js +331 -0
  155. package/dist/stripe-payments/services/stripe-payment-fulfillment.service.js.map +1 -0
  156. package/dist/stripe-payments/services/stripe-payments-operations.service.d.ts +25 -0
  157. package/dist/stripe-payments/services/stripe-payments-operations.service.js +59 -0
  158. package/dist/stripe-payments/services/stripe-payments-operations.service.js.map +1 -0
  159. package/dist/stripe-payments/services/stripe-payments-telemetry.service.d.ts +7 -0
  160. package/dist/stripe-payments/services/stripe-payments-telemetry.service.js +40 -0
  161. package/dist/stripe-payments/services/stripe-payments-telemetry.service.js.map +1 -0
  162. package/dist/stripe-payments/stripe-payment.config.d.ts +19 -0
  163. package/dist/stripe-payments/stripe-payment.config.js +98 -0
  164. package/dist/stripe-payments/stripe-payment.config.js.map +1 -0
  165. package/dist/stripe-payments/stripe-payment.config.test.d.ts +1 -0
  166. package/dist/stripe-payments/stripe-payment.config.test.js +59 -0
  167. package/dist/stripe-payments/stripe-payment.config.test.js.map +1 -0
  168. package/dist/stripe-payments/stripe-payments.extensions.d.ts +69 -0
  169. package/dist/stripe-payments/stripe-payments.extensions.js +30 -0
  170. package/dist/stripe-payments/stripe-payments.extensions.js.map +1 -0
  171. package/dist/stripe-payments/stripe-payments.module.d.ts +12 -0
  172. package/dist/stripe-payments/stripe-payments.module.js +118 -0
  173. package/dist/stripe-payments/stripe-payments.module.js.map +1 -0
  174. package/dist/stripe-payments/stripe-payments.options.d.ts +21 -0
  175. package/dist/stripe-payments/stripe-payments.options.js +2 -0
  176. package/dist/stripe-payments/stripe-payments.options.js.map +1 -0
  177. package/dist/super-powers/super-powers.controller.js.map +1 -1
  178. package/dist/super-powers/super-powers.service.js.map +1 -1
  179. package/dist/twitter-client/TwitterClientConfigurationService.js.map +1 -1
  180. package/dist/twitter-client/services/twitter-client.service.js.map +1 -1
  181. package/dist/twitter-client/twitter-account.module.js.map +1 -1
  182. package/dist/typeorm/entities.d.ts +15 -0
  183. package/dist/typeorm/entities.js +32 -0
  184. package/dist/typeorm/entities.js.map +1 -0
  185. package/dist/user/user.controller.d.ts +1 -1
  186. package/dist/user/user.controller.js.map +1 -1
  187. package/dist/user/user.service.js.map +1 -1
  188. package/dist/user-api-key/user-apikey.controller.js.map +1 -1
  189. package/dist/user-api-key/user-apikey.service.js.map +1 -1
  190. package/package.json +44 -3
@@ -0,0 +1,213 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ var SecureStripeCheckoutService_1;
14
+ import { ConflictException, Inject, Injectable, Logger, ServiceUnavailableException, } from "@nestjs/common";
15
+ import Stripe from "stripe";
16
+ import { InjectRepository } from "@nestjs/typeorm";
17
+ import { QueryFailedError, Repository } from "typeorm";
18
+ import { StripeCheckoutAttempt } from "../entities/stripe-checkout-attempt.entity.js";
19
+ import { SecureStripeProductService } from "./secure-stripe-product.service.js";
20
+ import { STRIPE_PAYMENTS_ACCESS_POLICY, STRIPE_PAYMENTS_ENTITLEMENT_STORE, } from "../stripe-payments.extensions.js";
21
+ import { StripePaymentsTelemetryService } from "./stripe-payments-telemetry.service.js";
22
+ const idempotencyKeyPattern = /^[A-Za-z0-9._-]{8,255}$/;
23
+ let SecureStripeCheckoutService = SecureStripeCheckoutService_1 = class SecureStripeCheckoutService {
24
+ stripe;
25
+ attemptRepository;
26
+ productService;
27
+ entitlementStore;
28
+ accessPolicy;
29
+ telemetry;
30
+ logger = new Logger(SecureStripeCheckoutService_1.name);
31
+ constructor(stripe, attemptRepository, productService, entitlementStore, accessPolicy, telemetry) {
32
+ this.stripe = stripe;
33
+ this.attemptRepository = attemptRepository;
34
+ this.productService = productService;
35
+ this.entitlementStore = entitlementStore;
36
+ this.accessPolicy = accessPolicy;
37
+ this.telemetry = telemetry;
38
+ }
39
+ async createCheckoutSession(request, user, idempotencyKey) {
40
+ const key = this.requireIdempotencyKey(idempotencyKey);
41
+ await this.accessPolicy.assertCanManageOrganisation({
42
+ organisationUuid: request.organisationUuid,
43
+ user,
44
+ operation: "checkout",
45
+ });
46
+ const product = this.productService.getByKey(request.productKey);
47
+ const successUrl = this.productService.buildRedirectUrl(request.successFrontendPath);
48
+ const cancelUrl = request.cancelFrontendPath
49
+ ? this.productService.buildRedirectUrl(request.cancelFrontendPath)
50
+ : undefined;
51
+ const existingAttempt = await this.attemptRepository.findOne({
52
+ where: { idempotencyKey: key },
53
+ });
54
+ if (existingAttempt) {
55
+ this.assertMatchingAttempt(existingAttempt, request, user, product.priceId);
56
+ if (existingAttempt.status === "created" &&
57
+ existingAttempt.stripeSessionId &&
58
+ existingAttempt.stripeSessionUrl) {
59
+ return {
60
+ stripeSessionId: existingAttempt.stripeSessionId,
61
+ stripeSessionUrl: existingAttempt.stripeSessionUrl,
62
+ };
63
+ }
64
+ if (existingAttempt.updatedDate.getTime() >
65
+ Date.now() - 10 * 60 * 1000) {
66
+ throw new ConflictException("Checkout attempt is already in progress");
67
+ }
68
+ }
69
+ const attempt = existingAttempt ??
70
+ this.attemptRepository.create({
71
+ idempotencyKey: key,
72
+ organisationUuid: request.organisationUuid,
73
+ userUuid: user.uuid,
74
+ productKey: product.key,
75
+ priceId: product.priceId,
76
+ mode: product.mode,
77
+ status: "creating",
78
+ });
79
+ attempt.status = "creating";
80
+ attempt.errorMessage = undefined;
81
+ try {
82
+ await this.attemptRepository.save(attempt);
83
+ }
84
+ catch (error) {
85
+ if (!this.isUniqueViolation(error)) {
86
+ throw error;
87
+ }
88
+ const concurrentAttempt = await this.attemptRepository.findOne({
89
+ where: { idempotencyKey: key },
90
+ });
91
+ if (!concurrentAttempt) {
92
+ throw error;
93
+ }
94
+ this.assertMatchingAttempt(concurrentAttempt, request, user, product.priceId);
95
+ if (concurrentAttempt.status === "created" &&
96
+ concurrentAttempt.stripeSessionId &&
97
+ concurrentAttempt.stripeSessionUrl) {
98
+ return {
99
+ stripeSessionId: concurrentAttempt.stripeSessionId,
100
+ stripeSessionUrl: concurrentAttempt.stripeSessionUrl,
101
+ };
102
+ }
103
+ throw new ConflictException("Checkout attempt is already in progress");
104
+ }
105
+ try {
106
+ const metadata = {
107
+ organisationUuid: request.organisationUuid,
108
+ userUuid: user.uuid,
109
+ productKey: product.key,
110
+ internalSku: product.internalSku,
111
+ checkoutAttemptId: String(attempt.id),
112
+ };
113
+ const session = await this.stripe.checkout.sessions.create({
114
+ mode: product.mode,
115
+ client_reference_id: String(attempt.id),
116
+ line_items: [{ price: product.priceId, quantity: 1 }],
117
+ success_url: successUrl,
118
+ cancel_url: cancelUrl,
119
+ metadata,
120
+ ...(product.mode === "subscription"
121
+ ? { subscription_data: { metadata } }
122
+ : { payment_intent_data: { metadata } }),
123
+ }, { idempotencyKey: key });
124
+ if (!session.url) {
125
+ throw new Error("Stripe did not return a Checkout URL");
126
+ }
127
+ attempt.status = "created";
128
+ attempt.stripeSessionId = session.id;
129
+ attempt.stripeSessionUrl = session.url;
130
+ await this.attemptRepository.save(attempt);
131
+ await this.telemetry.record({
132
+ name: "checkout.created",
133
+ attemptId: attempt.id,
134
+ organisationUuid: attempt.organisationUuid,
135
+ productKey: attempt.productKey,
136
+ stripeSessionId: session.id,
137
+ });
138
+ return {
139
+ stripeSessionId: session.id,
140
+ stripeSessionUrl: session.url,
141
+ };
142
+ }
143
+ catch (error) {
144
+ attempt.status = "failed";
145
+ const errorMessage = error instanceof Error
146
+ ? error.message.slice(0, 500)
147
+ : "Stripe error";
148
+ attempt.errorMessage = errorMessage;
149
+ await this.attemptRepository.save(attempt);
150
+ await this.telemetry.record({
151
+ name: "checkout.failed",
152
+ attemptId: attempt.id,
153
+ organisationUuid: attempt.organisationUuid,
154
+ productKey: attempt.productKey,
155
+ error: errorMessage,
156
+ });
157
+ this.logger.error("Stripe Checkout session creation failed", {
158
+ attemptId: attempt.id,
159
+ productKey: product.key,
160
+ error: error instanceof Error ? error.message : String(error),
161
+ });
162
+ throw new ServiceUnavailableException("Unable to start checkout right now. Please try again.");
163
+ }
164
+ }
165
+ async createCustomerPortalSession(request, user, idempotencyKey) {
166
+ const key = this.requireIdempotencyKey(idempotencyKey);
167
+ const subscription = await this.entitlementStore.findByUuid(request.subscriptionRecordUuid);
168
+ await this.accessPolicy.assertCanManageOrganisation({
169
+ organisationUuid: subscription.organisationUuid,
170
+ user,
171
+ operation: "customer-portal",
172
+ });
173
+ if (!/^cus_[A-Za-z0-9]+$/.test(subscription.paymentSystemCustomerId)) {
174
+ throw new ConflictException("This subscription has no valid Stripe customer");
175
+ }
176
+ const session = await this.stripe.billingPortal.sessions.create({
177
+ customer: subscription.paymentSystemCustomerId,
178
+ return_url: this.productService.buildRedirectUrl(request.returnUrl),
179
+ }, { idempotencyKey: key });
180
+ return { sessionUrl: session.url };
181
+ }
182
+ requireIdempotencyKey(idempotencyKey) {
183
+ if (!idempotencyKey || !idempotencyKeyPattern.test(idempotencyKey)) {
184
+ throw new ConflictException("An Idempotency-Key header is required for payment requests");
185
+ }
186
+ return idempotencyKey;
187
+ }
188
+ assertMatchingAttempt(attempt, request, user, priceId) {
189
+ if (attempt.organisationUuid !== request.organisationUuid ||
190
+ attempt.userUuid !== user.uuid ||
191
+ attempt.productKey !== request.productKey ||
192
+ attempt.priceId !== priceId) {
193
+ throw new ConflictException("The Idempotency-Key was already used for another checkout");
194
+ }
195
+ }
196
+ isUniqueViolation(error) {
197
+ return (error instanceof QueryFailedError &&
198
+ error
199
+ .driverError.code === "23505");
200
+ }
201
+ };
202
+ SecureStripeCheckoutService = SecureStripeCheckoutService_1 = __decorate([
203
+ Injectable(),
204
+ __param(0, Inject("SecureStripeClient")),
205
+ __param(1, InjectRepository(StripeCheckoutAttempt)),
206
+ __param(3, Inject(STRIPE_PAYMENTS_ENTITLEMENT_STORE)),
207
+ __param(4, Inject(STRIPE_PAYMENTS_ACCESS_POLICY)),
208
+ __metadata("design:paramtypes", [Stripe,
209
+ Repository,
210
+ SecureStripeProductService, Object, Object, StripePaymentsTelemetryService])
211
+ ], SecureStripeCheckoutService);
212
+ export { SecureStripeCheckoutService };
213
+ //# sourceMappingURL=secure-stripe-checkout.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-stripe-checkout.service.js","sourceRoot":"","sources":["../../../src/stripe-payments/services/secure-stripe-checkout.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Provider } from "@nestjs/common";
2
+ export declare const secureStripeClientProvider: Provider;
@@ -0,0 +1,15 @@
1
+ import Stripe from "stripe";
2
+ import { SECURE_STRIPE_CONFIGURATION, } from "../stripe-payment.config.js";
3
+ export const secureStripeClientProvider = {
4
+ provide: "SecureStripeClient",
5
+ useFactory: (configuration) => new Stripe(configuration.accessToken, {
6
+ apiVersion: Stripe.API_VERSION,
7
+ appInfo: {
8
+ name: "Miller Secure Payments",
9
+ url: "https://usemiller.dev",
10
+ },
11
+ maxNetworkRetries: 2,
12
+ }),
13
+ inject: [SECURE_STRIPE_CONFIGURATION],
14
+ };
15
+ //# sourceMappingURL=secure-stripe-client.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-stripe-client.provider.js","sourceRoot":"","sources":["../../../src/stripe-payments/services/secure-stripe-client.provider.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EACH,2BAA2B,GAE9B,MAAM,6BAA6B,CAAC;AAErC,MAAM,CAAC,MAAM,0BAA0B,GAAa;IAChD,OAAO,EAAE,oBAAoB;IAC7B,UAAU,EAAE,CAAC,aAAwC,EAAU,EAAE,CAC7D,IAAI,MAAM,CAAC,aAAa,CAAC,WAAW,EAAE;QAClC,UAAU,EAAE,MAAM,CAAC,WAAW;QAC9B,OAAO,EAAE;YACL,IAAI,EAAE,wBAAwB;YAC9B,GAAG,EAAE,uBAAuB;SAC/B;QACD,iBAAiB,EAAE,CAAC;KACvB,CAAC;IACN,MAAM,EAAE,CAAC,2BAA2B,CAAC;CACxC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { SecureStripeConfiguration, SecureStripeProduct } from "../stripe-payment.config.js";
2
+ export declare class SecureStripeProductService {
3
+ private readonly configuration;
4
+ constructor(configuration: SecureStripeConfiguration);
5
+ getByKey(productKey: string): SecureStripeProduct;
6
+ getByPriceId(priceId: string): SecureStripeProduct;
7
+ getConfiguredProducts(): readonly SecureStripeProduct[];
8
+ buildRedirectUrl(path: string): string;
9
+ }
@@ -0,0 +1,54 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { BadRequestException, Inject, Injectable } from "@nestjs/common";
14
+ import { SECURE_STRIPE_CONFIGURATION, } from "../stripe-payment.config.js";
15
+ let SecureStripeProductService = class SecureStripeProductService {
16
+ configuration;
17
+ constructor(configuration) {
18
+ this.configuration = configuration;
19
+ }
20
+ getByKey(productKey) {
21
+ const product = this.configuration.products.get(productKey);
22
+ if (!product) {
23
+ throw new BadRequestException("Unknown payment product");
24
+ }
25
+ return product;
26
+ }
27
+ getByPriceId(priceId) {
28
+ const product = [...this.configuration.products.values()].find((candidate) => candidate.priceId === priceId);
29
+ if (!product) {
30
+ throw new Error("Stripe returned a price outside the configured catalog");
31
+ }
32
+ return product;
33
+ }
34
+ getConfiguredProducts() {
35
+ return [...this.configuration.products.values()];
36
+ }
37
+ buildRedirectUrl(path) {
38
+ const url = new URL(path, `${this.configuration.redirectsBaseUrl}/`);
39
+ const baseUrl = new URL(`${this.configuration.redirectsBaseUrl}/`);
40
+ if (url.origin !== baseUrl.origin ||
41
+ !path.startsWith("/") ||
42
+ path.startsWith("//")) {
43
+ throw new BadRequestException("Redirect path must remain on the configured application origin");
44
+ }
45
+ return url.toString();
46
+ }
47
+ };
48
+ SecureStripeProductService = __decorate([
49
+ Injectable(),
50
+ __param(0, Inject(SECURE_STRIPE_CONFIGURATION)),
51
+ __metadata("design:paramtypes", [Object])
52
+ ], SecureStripeProductService);
53
+ export { SecureStripeProductService };
54
+ //# sourceMappingURL=secure-stripe-product.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-stripe-product.service.js","sourceRoot":"","sources":["../../../src/stripe-payments/services/secure-stripe-product.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EAAC,mBAAmB,EAAE,MAAM,EAAE,UAAU,EAAC,MAAM,gBAAgB,CAAC;AACvE,OAAO,EACH,2BAA2B,GAG9B,MAAM,6BAA6B,CAAC;AAG9B,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IAGd,aAAa;IAFlC,YAEqB,aAAwC;6BAAxC,aAAa;IAC/B,CAAC;IAEJ,QAAQ,CAAC,UAAkB;QACvB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5D,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,MAAM,IAAI,mBAAmB,CAAC,yBAAyB,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,YAAY,CAAC,OAAe;QACxB,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAC1D,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,OAAO,KAAK,OAAO,CAC/C,CAAC;QACF,IAAI,CAAC,OAAO,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CACX,wDAAwD,CAC3D,CAAC;QACN,CAAC;QACD,OAAO,OAAO,CAAC;IACnB,CAAC;IAED,qBAAqB;QACjB,OAAO,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,gBAAgB,CAAC,IAAY;QACzB,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,gBAAgB,GAAG,CAAC,CAAC;QACrE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,gBAAgB,GAAG,CAAC,CAAC;QACnE,IACI,GAAG,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM;YAC7B,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YACrB,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EACvB,CAAC;YACC,MAAM,IAAI,mBAAmB,CACzB,gEAAgE,CACnE,CAAC;QACN,CAAC;QACD,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;IAC1B,CAAC;CACJ,CAAA;AA5CY,0BAA0B;IADtC,UAAU,EAAE;IAGJ,WAAA,MAAM,CAAC,2BAA2B,CAAC,CAAA;;GAF/B,0BAA0B,CA4CtC"}
@@ -0,0 +1,14 @@
1
+ import Stripe from "stripe";
2
+ import { SecureStripeConfiguration } from "../stripe-payment.config.js";
3
+ import { StripePaymentEventService } from "./stripe-payment-event.service.js";
4
+ export interface RawStripeWebhookRequest {
5
+ headers: Record<string, string | string[] | undefined>;
6
+ rawBody?: Buffer;
7
+ }
8
+ export declare class SecureStripeWebhookService {
9
+ private readonly stripe;
10
+ private readonly configuration;
11
+ private readonly paymentEventService;
12
+ constructor(stripe: Stripe, configuration: SecureStripeConfiguration, paymentEventService: StripePaymentEventService);
13
+ handleWebhook(request: RawStripeWebhookRequest): Promise<void>;
14
+ }
@@ -0,0 +1,58 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { BadRequestException, Inject, Injectable, ServiceUnavailableException, } from "@nestjs/common";
14
+ import Stripe from "stripe";
15
+ import { SECURE_STRIPE_CONFIGURATION, } from "../stripe-payment.config.js";
16
+ import { StripePaymentEventService } from "./stripe-payment-event.service.js";
17
+ let SecureStripeWebhookService = class SecureStripeWebhookService {
18
+ stripe;
19
+ configuration;
20
+ paymentEventService;
21
+ constructor(stripe, configuration, paymentEventService) {
22
+ this.stripe = stripe;
23
+ this.configuration = configuration;
24
+ this.paymentEventService = paymentEventService;
25
+ }
26
+ async handleWebhook(request) {
27
+ if (!request.rawBody) {
28
+ throw new BadRequestException("Webhook body was not received as raw bytes");
29
+ }
30
+ const signatureHeader = request.headers["stripe-signature"];
31
+ if (typeof signatureHeader !== "string") {
32
+ throw new BadRequestException("Missing Stripe webhook signature");
33
+ }
34
+ let event;
35
+ try {
36
+ event = this.stripe.webhooks.constructEvent(request.rawBody, signatureHeader, this.configuration.webhookVerificationKey);
37
+ }
38
+ catch {
39
+ throw new BadRequestException("Invalid Stripe webhook signature");
40
+ }
41
+ try {
42
+ await this.paymentEventService.receive(event);
43
+ }
44
+ catch {
45
+ // A non-2xx response tells Stripe to retry delivery. The event row is
46
+ // deliberately durable so a later delivery can enqueue it again.
47
+ throw new ServiceUnavailableException("Payment event could not be queued");
48
+ }
49
+ }
50
+ };
51
+ SecureStripeWebhookService = __decorate([
52
+ Injectable(),
53
+ __param(0, Inject("SecureStripeClient")),
54
+ __param(1, Inject(SECURE_STRIPE_CONFIGURATION)),
55
+ __metadata("design:paramtypes", [Stripe, Object, StripePaymentEventService])
56
+ ], SecureStripeWebhookService);
57
+ export { SecureStripeWebhookService };
58
+ //# sourceMappingURL=secure-stripe-webhook.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"secure-stripe-webhook.service.js","sourceRoot":"","sources":["../../../src/stripe-payments/services/secure-stripe-webhook.service.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,OAAO,EACH,mBAAmB,EACnB,MAAM,EACN,UAAU,EACV,2BAA2B,GAC9B,MAAM,gBAAgB,CAAC;AACxB,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EACH,2BAA2B,GAE9B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAC,yBAAyB,EAAC,MAAM,mCAAmC,CAAC;AAQrE,IAAM,0BAA0B,GAAhC,MAAM,0BAA0B;IAGd,MAAM;IAEN,aAAa;IACb,mBAAmB;IALxC,YAEqB,MAAc,EAEd,aAAwC,EACxC,mBAA8C;sBAH9C,MAAM;6BAEN,aAAa;mCACb,mBAAmB;IACrC,CAAC;IAEJ,KAAK,CAAC,aAAa,CAAC,OAAgC;QAChD,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,IAAI,mBAAmB,CACzB,4CAA4C,CAC/C,CAAC;QACN,CAAC;QACD,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QAC5D,IAAI,OAAO,eAAe,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,mBAAmB,CAAC,kCAAkC,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,KAAmB,CAAC;QACxB,IAAI,CAAC;YACD,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CACvC,OAAO,CAAC,OAAO,EACf,eAAe,EACf,IAAI,CAAC,aAAa,CAAC,sBAAsB,CAC5C,CAAC;QACN,CAAC;QAAC,MAAM,CAAC;YACL,MAAM,IAAI,mBAAmB,CAAC,kCAAkC,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,CAAC;YACD,MAAM,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAClD,CAAC;QAAC,MAAM,CAAC;YACL,sEAAsE;YACtE,iEAAiE;YACjE,MAAM,IAAI,2BAA2B,CACjC,mCAAmC,CACtC,CAAC;QACN,CAAC;IACL,CAAC;CACJ,CAAA;AAzCY,0BAA0B;IADtC,UAAU,EAAE;IAGJ,WAAA,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAE5B,WAAA,MAAM,CAAC,2BAA2B,CAAC,CAAA;qCADX,MAAM,UAGO,yBAAyB;GAN1D,0BAA0B,CAyCtC"}
@@ -0,0 +1,18 @@
1
+ import { OrganisationSubscriptionRecord } from "../../organisation-subscriptions/entities/organisation-subscription.entity.js";
2
+ import { Queue } from "bullmq";
3
+ import { Repository } from "typeorm";
4
+ import type { StripePaymentsEntitlementInput } from "../stripe-payments.extensions.js";
5
+ export type SecureSubscriptionInput = StripePaymentsEntitlementInput;
6
+ export declare class SecureSubscriptionService {
7
+ private readonly subscriptionRepository;
8
+ private readonly activationQueue;
9
+ private readonly logger;
10
+ constructor(subscriptionRepository: Repository<OrganisationSubscriptionRecord>, activationQueue: Queue);
11
+ findByUuid(uuid: string): Promise<OrganisationSubscriptionRecord>;
12
+ findByTransactionId(paymentSystemTransactionId: string): Promise<OrganisationSubscriptionRecord | null>;
13
+ findByCustomerId(paymentSystemCustomerId: string, mode?: string): Promise<OrganisationSubscriptionRecord[]>;
14
+ save(input: SecureSubscriptionInput): Promise<OrganisationSubscriptionRecord>;
15
+ revokeCustomerPayments(customerId: string, input: Pick<SecureSubscriptionInput, "stripeEventId" | "stripeEventCreatedAt" | "stripeStatus">): Promise<void>;
16
+ revokePayment(paymentSystemTransactionId: string, input: Pick<SecureSubscriptionInput, "stripeEventId" | "stripeEventCreatedAt" | "stripeStatus">): Promise<boolean>;
17
+ private saveRecord;
18
+ }
@@ -0,0 +1,217 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ var SecureSubscriptionService_1;
14
+ import { Injectable, Logger } from "@nestjs/common";
15
+ import { InjectQueue } from "@nestjs/bullmq";
16
+ import { Organisation } from "../../organisation/entities/organisation.entity.js";
17
+ import { OrganisationSubscriptionRecord } from "../../organisation-subscriptions/entities/organisation-subscription.entity.js";
18
+ import { Queue } from "bullmq";
19
+ import { InjectRepository } from "@nestjs/typeorm";
20
+ import { QueryFailedError, Repository } from "typeorm";
21
+ import { StripePaymentState } from "../entities/stripe-payment-state.entity.js";
22
+ let SecureSubscriptionService = SecureSubscriptionService_1 = class SecureSubscriptionService {
23
+ subscriptionRepository;
24
+ activationQueue;
25
+ logger = new Logger(SecureSubscriptionService_1.name);
26
+ constructor(subscriptionRepository, activationQueue) {
27
+ this.subscriptionRepository = subscriptionRepository;
28
+ this.activationQueue = activationQueue;
29
+ }
30
+ async findByUuid(uuid) {
31
+ const record = await this.subscriptionRepository.findOne({
32
+ where: { uuid },
33
+ relations: { organisation: true },
34
+ });
35
+ if (!record) {
36
+ throw new Error("Subscription record not found");
37
+ }
38
+ return record;
39
+ }
40
+ async findByTransactionId(paymentSystemTransactionId) {
41
+ return this.subscriptionRepository.findOne({
42
+ where: { paymentSystemTransactionId },
43
+ relations: { organisation: true },
44
+ });
45
+ }
46
+ async findByCustomerId(paymentSystemCustomerId, mode) {
47
+ return this.subscriptionRepository.find({
48
+ where: {
49
+ paymentSystemCustomerId,
50
+ ...(mode ? { paymentSystemMode: mode } : {}),
51
+ },
52
+ relations: { organisation: true },
53
+ });
54
+ }
55
+ async save(input) {
56
+ const { record, shouldActivate } = await this.saveRecord(input);
57
+ if (shouldActivate) {
58
+ await this.activationQueue.add("activation-changed", {
59
+ organisationUuid: record.organisation.uuid,
60
+ subscriptionUuid: record.uuid,
61
+ productKey: record.internalSku,
62
+ active: record.validUntil > new Date(),
63
+ }, {
64
+ jobId: `subscription-activation:${record.uuid}:${String(record.validUntil.getTime())}`,
65
+ attempts: 5,
66
+ backoff: { type: "exponential", delay: 2_000 },
67
+ removeOnComplete: { age: 86_400, count: 10_000 },
68
+ removeOnFail: { age: 604_800, count: 10_000 },
69
+ });
70
+ }
71
+ return record;
72
+ }
73
+ async revokeCustomerPayments(customerId, input) {
74
+ const records = await this.findByCustomerId(customerId, "payment");
75
+ for (const record of records) {
76
+ await this.save({
77
+ paymentSystemTransactionId: record.paymentSystemTransactionId,
78
+ paymentSystemProductId: record.paymentSystemProductId,
79
+ paymentSystemCustomerId: record.paymentSystemCustomerId,
80
+ paymentSystemCustomerEmail: record.paymentSystemCustomerEmail,
81
+ paymentSystemMode: "payment",
82
+ paymentSystemName: "stripe",
83
+ validUntil: new Date(),
84
+ internalSku: record.internalSku,
85
+ productDisplayName: record.productDisplayName,
86
+ organisationUuid: record.organisation.uuid,
87
+ stripeEventId: input.stripeEventId,
88
+ stripeEventCreatedAt: input.stripeEventCreatedAt,
89
+ stripeStatus: input.stripeStatus,
90
+ });
91
+ }
92
+ }
93
+ async revokePayment(paymentSystemTransactionId, input) {
94
+ const record = await this.findByTransactionId(paymentSystemTransactionId);
95
+ if (record?.paymentSystemMode !== "payment") {
96
+ return false;
97
+ }
98
+ await this.save({
99
+ paymentSystemTransactionId: record.paymentSystemTransactionId,
100
+ paymentSystemProductId: record.paymentSystemProductId,
101
+ paymentSystemCustomerId: record.paymentSystemCustomerId,
102
+ paymentSystemCustomerEmail: record.paymentSystemCustomerEmail,
103
+ paymentSystemMode: "payment",
104
+ paymentSystemName: "stripe",
105
+ validUntil: new Date(),
106
+ internalSku: record.internalSku,
107
+ productDisplayName: record.productDisplayName,
108
+ organisationUuid: record.organisation.uuid,
109
+ stripeEventId: input.stripeEventId,
110
+ stripeEventCreatedAt: input.stripeEventCreatedAt,
111
+ stripeStatus: input.stripeStatus,
112
+ });
113
+ return true;
114
+ }
115
+ async saveRecord(input) {
116
+ try {
117
+ return await this.subscriptionRepository.manager.transaction(async (manager) => {
118
+ await manager.query("SELECT pg_advisory_xact_lock(hashtext($1))", [input.paymentSystemTransactionId]);
119
+ const subscriptionRepository = manager.getRepository(OrganisationSubscriptionRecord);
120
+ const stateRepository = manager.getRepository(StripePaymentState);
121
+ const state = await stateRepository.findOne({
122
+ where: {
123
+ paymentSystemTransactionId: input.paymentSystemTransactionId,
124
+ },
125
+ });
126
+ let record = await subscriptionRepository.findOne({
127
+ where: {
128
+ paymentSystemTransactionId: input.paymentSystemTransactionId,
129
+ },
130
+ relations: { organisation: true },
131
+ });
132
+ const isDuplicateEvent = state?.lastStripeEventCreatedAt.getTime() ===
133
+ input.stripeEventCreatedAt.getTime() &&
134
+ state.lastStripeEventId === input.stripeEventId;
135
+ if (record &&
136
+ state &&
137
+ (state.lastStripeEventCreatedAt >
138
+ input.stripeEventCreatedAt ||
139
+ isDuplicateEvent)) {
140
+ return {
141
+ record,
142
+ // Retry the durable activation notification if the
143
+ // previous attempt failed after the DB commit.
144
+ shouldActivate: isDuplicateEvent,
145
+ };
146
+ }
147
+ const isNewRecord = !record;
148
+ if (!record) {
149
+ const organisation = input.organisationUuid
150
+ ? await manager
151
+ .getRepository(Organisation)
152
+ .findOne({
153
+ where: { uuid: input.organisationUuid },
154
+ })
155
+ : null;
156
+ if (!organisation) {
157
+ throw new Error("Payment could not be matched to an organisation");
158
+ }
159
+ record = subscriptionRepository.create({
160
+ organisation,
161
+ });
162
+ }
163
+ const previousValidUntil = isNewRecord
164
+ ? undefined
165
+ : record.validUntil.getTime();
166
+ record.paymentSystemTransactionId =
167
+ input.paymentSystemTransactionId;
168
+ record.paymentSystemProductId =
169
+ input.paymentSystemProductId;
170
+ record.paymentSystemCustomerId =
171
+ input.paymentSystemCustomerId;
172
+ record.paymentSystemCustomerEmail =
173
+ input.paymentSystemCustomerEmail;
174
+ record.paymentSystemMode = input.paymentSystemMode;
175
+ record.paymentSystemName = input.paymentSystemName;
176
+ record.validUntil = input.validUntil;
177
+ record.internalSku = input.internalSku;
178
+ record.productDisplayName = input.productDisplayName;
179
+ const savedRecord = await subscriptionRepository.save(record);
180
+ const shouldActivate = isNewRecord ||
181
+ state?.lastStripeEventId !== input.stripeEventId ||
182
+ previousValidUntil !== input.validUntil.getTime();
183
+ const paymentState = state ??
184
+ stateRepository.create({
185
+ paymentSystemTransactionId: input.paymentSystemTransactionId,
186
+ });
187
+ paymentState.lastStripeEventId = input.stripeEventId;
188
+ paymentState.lastStripeEventCreatedAt =
189
+ input.stripeEventCreatedAt;
190
+ paymentState.status = input.stripeStatus;
191
+ await stateRepository.save(paymentState);
192
+ return { record: savedRecord, shouldActivate };
193
+ });
194
+ }
195
+ catch (error) {
196
+ if (error instanceof QueryFailedError &&
197
+ error
198
+ .driverError.code === "23505") {
199
+ const existing = await this.findByTransactionId(input.paymentSystemTransactionId);
200
+ if (existing) {
201
+ this.logger.warn(`Ignored concurrent duplicate payment ${input.paymentSystemTransactionId}`);
202
+ return { record: existing, shouldActivate: false };
203
+ }
204
+ }
205
+ throw error;
206
+ }
207
+ }
208
+ };
209
+ SecureSubscriptionService = SecureSubscriptionService_1 = __decorate([
210
+ Injectable(),
211
+ __param(0, InjectRepository(OrganisationSubscriptionRecord)),
212
+ __param(1, InjectQueue("subscription-activation-changed")),
213
+ __metadata("design:paramtypes", [Repository,
214
+ Queue])
215
+ ], SecureSubscriptionService);
216
+ export { SecureSubscriptionService };
217
+ //# sourceMappingURL=secure-subscription.service.js.map