@casual-simulation/aux-records 3.2.3 → 3.2.4-alpha.5940763320

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 (79) hide show
  1. package/AIChatInterface.d.ts +8 -0
  2. package/AIChatInterface.js.map +1 -1
  3. package/AIController.d.ts +10 -4
  4. package/AIController.js +112 -3
  5. package/AIController.js.map +1 -1
  6. package/AuthController.d.ts +4 -8
  7. package/AuthController.js +39 -45
  8. package/AuthController.js.map +1 -1
  9. package/AuthStore.d.ts +236 -4
  10. package/ConfigurationStore.d.ts +12 -0
  11. package/ConfigurationStore.js +2 -0
  12. package/ConfigurationStore.js.map +1 -0
  13. package/DataRecordsController.d.ts +18 -6
  14. package/DataRecordsController.js +31 -5
  15. package/DataRecordsController.js.map +1 -1
  16. package/Errors.d.ts +4 -0
  17. package/EventRecordsController.d.ts +12 -3
  18. package/EventRecordsController.js +27 -5
  19. package/EventRecordsController.js.map +1 -1
  20. package/FileRecordsController.d.ts +13 -3
  21. package/FileRecordsController.js +46 -9
  22. package/FileRecordsController.js.map +1 -1
  23. package/MemoryFileRecordsLookup.d.ts +11 -0
  24. package/MemoryFileRecordsLookup.js +128 -0
  25. package/MemoryFileRecordsLookup.js.map +1 -0
  26. package/MemoryStore.d.ts +191 -0
  27. package/MemoryStore.js +1381 -0
  28. package/MemoryStore.js.map +1 -0
  29. package/MetricsStore.d.ts +186 -0
  30. package/MetricsStore.js +2 -0
  31. package/MetricsStore.js.map +1 -0
  32. package/OpenAIChatInterface.js +1 -0
  33. package/OpenAIChatInterface.js.map +1 -1
  34. package/PolicyController.d.ts +7 -4
  35. package/PolicyController.js +33 -8
  36. package/PolicyController.js.map +1 -1
  37. package/RecordsController.d.ts +185 -7
  38. package/RecordsController.js +588 -70
  39. package/RecordsController.js.map +1 -1
  40. package/RecordsHttpServer.d.ts +8 -0
  41. package/RecordsHttpServer.js +450 -8
  42. package/RecordsHttpServer.js.map +1 -1
  43. package/RecordsStore.d.ts +263 -5
  44. package/StripeInterface.d.ts +331 -0
  45. package/StripeInterface.js +37 -1
  46. package/StripeInterface.js.map +1 -1
  47. package/SubscriptionConfiguration.d.ts +2523 -33
  48. package/SubscriptionConfiguration.js +130 -1
  49. package/SubscriptionConfiguration.js.map +1 -1
  50. package/SubscriptionController.d.ts +23 -6
  51. package/SubscriptionController.js +344 -69
  52. package/SubscriptionController.js.map +1 -1
  53. package/TestUtils.d.ts +7 -6
  54. package/TestUtils.js +28 -14
  55. package/TestUtils.js.map +1 -1
  56. package/Utils.js +9 -0
  57. package/Utils.js.map +1 -1
  58. package/index.d.ts +5 -4
  59. package/index.js +5 -4
  60. package/index.js.map +1 -1
  61. package/package.json +2 -2
  62. package/MemoryAuthStore.d.ts +0 -33
  63. package/MemoryAuthStore.js +0 -186
  64. package/MemoryAuthStore.js.map +0 -1
  65. package/MemoryDataRecordsStore.d.ts +0 -10
  66. package/MemoryDataRecordsStore.js +0 -98
  67. package/MemoryDataRecordsStore.js.map +0 -1
  68. package/MemoryEventRecordsStore.d.ts +0 -10
  69. package/MemoryEventRecordsStore.js +0 -89
  70. package/MemoryEventRecordsStore.js.map +0 -1
  71. package/MemoryFileRecordsStore.d.ts +0 -25
  72. package/MemoryFileRecordsStore.js +0 -310
  73. package/MemoryFileRecordsStore.js.map +0 -1
  74. package/MemoryPolicyStore.d.ts +0 -43
  75. package/MemoryPolicyStore.js +0 -255
  76. package/MemoryPolicyStore.js.map +0 -1
  77. package/MemoryRecordsStore.d.ts +0 -13
  78. package/MemoryRecordsStore.js +0 -67
  79. package/MemoryRecordsStore.js.map +0 -1
@@ -8,17 +8,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { INVALID_KEY_ERROR_MESSAGE, } from './AuthController';
11
+ import { STRIPE_EVENT_INVOICE_PAID_SCHEMA, } from './StripeInterface';
11
12
  import { isActiveSubscription, tryParseJson } from './Utils';
12
13
  /**
13
14
  * Defines a class that is able to handle subscriptions.
14
15
  */
15
16
  export class SubscriptionController {
16
- constructor(stripe, auth, authStore, config) {
17
+ constructor(stripe, auth, authStore, recordsStore, config) {
17
18
  this._stripe = stripe;
18
19
  this._auth = auth;
19
20
  this._authStore = authStore;
21
+ this._recordsStore = recordsStore;
20
22
  this._config = config;
21
23
  }
24
+ _getConfig() {
25
+ return __awaiter(this, void 0, void 0, function* () {
26
+ return yield this._config.getSubscriptionConfiguration();
27
+ });
28
+ }
22
29
  /**
23
30
  * Gets the status of the given user's scription.
24
31
  * @param request
@@ -33,40 +40,96 @@ export class SubscriptionController {
33
40
  };
34
41
  }
35
42
  try {
36
- if (typeof request.userId !== 'string' || request.userId === '') {
43
+ if (request.userId && request.studioId) {
37
44
  return {
38
45
  success: false,
39
- errorCode: 'unacceptable_user_id',
40
- errorMessage: 'The given user ID is invalid. It must be a correctly formatted string.',
46
+ errorCode: 'unacceptable_request',
47
+ errorMessage: 'The given request is invalid. It must not specify both a user ID and a studio ID.',
41
48
  };
42
49
  }
43
- const keyResult = yield this._auth.validateSessionKey(request.sessionKey);
44
- if (keyResult.success === false) {
45
- return keyResult;
50
+ if (request.userId) {
51
+ if (typeof request.userId !== 'string' ||
52
+ request.userId === '') {
53
+ return {
54
+ success: false,
55
+ errorCode: 'unacceptable_user_id',
56
+ errorMessage: 'The given user ID is invalid. It must be a correctly formatted string.',
57
+ };
58
+ }
46
59
  }
47
- else if (keyResult.userId !== request.userId) {
48
- console.log('[SubscriptionController] [getSubscriptionStatus] Request User ID doesnt match session key User ID!');
60
+ else if (request.studioId) {
61
+ if (typeof request.studioId !== 'string' ||
62
+ request.studioId === '') {
63
+ return {
64
+ success: false,
65
+ errorCode: 'unacceptable_studio_id',
66
+ errorMessage: 'The given studio ID is invalid. It must be a correctly formatted string.',
67
+ };
68
+ }
69
+ }
70
+ else {
49
71
  return {
50
72
  success: false,
51
- errorCode: 'invalid_key',
52
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
73
+ errorCode: 'unacceptable_request',
74
+ errorMessage: 'The given request is invalid. It must have a valid user ID or studio ID.',
53
75
  };
54
76
  }
55
- const user = yield this._authStore.findUser(keyResult.userId);
56
- let customerId = user.stripeCustomerId;
77
+ const keyResult = yield this._auth.validateSessionKey(request.sessionKey);
78
+ let customerId;
79
+ let role;
80
+ if (keyResult.success === false) {
81
+ return keyResult;
82
+ }
83
+ else {
84
+ if (request.userId) {
85
+ if (keyResult.userId !== request.userId) {
86
+ console.log('[SubscriptionController] [getSubscriptionStatus] Request User ID doesnt match session key User ID!');
87
+ return {
88
+ success: false,
89
+ errorCode: 'invalid_key',
90
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
91
+ };
92
+ }
93
+ const user = yield this._authStore.findUser(keyResult.userId);
94
+ customerId = user.stripeCustomerId;
95
+ role = 'user';
96
+ }
97
+ else if (request.studioId) {
98
+ const assignments = yield this._recordsStore.listStudioAssignments(request.studioId, {
99
+ userId: keyResult.userId,
100
+ role: 'admin',
101
+ });
102
+ if (assignments.length <= 0) {
103
+ console.log('[SubscriptionController] [getSubscriptionStatus] Request user does not have access to studio!');
104
+ return {
105
+ success: false,
106
+ errorCode: 'invalid_key',
107
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
108
+ };
109
+ }
110
+ const studio = yield this._recordsStore.getStudioById(request.studioId);
111
+ customerId = studio.stripeCustomerId;
112
+ role = 'studio';
113
+ }
114
+ }
115
+ // const user = await this._authStore.findUser(keyResult.userId);
116
+ // let customerId = user.stripeCustomerId;
57
117
  if (!customerId) {
118
+ const config = yield this._getConfig();
58
119
  return {
59
120
  success: true,
60
121
  userId: keyResult.userId,
122
+ studioId: request.studioId,
61
123
  publishableKey: this._stripe.publishableKey,
62
124
  subscriptions: [],
63
- purchasableSubscriptions: yield this._getPurchasableSubscriptions(),
125
+ purchasableSubscriptions: yield this._getPurchasableSubscriptions(role, config),
64
126
  };
65
127
  }
66
128
  const listResult = yield this._stripe.listActiveSubscriptionsForCustomer(customerId);
129
+ const config = yield this._getConfig();
67
130
  const subscriptions = listResult.subscriptions.map((s) => {
68
131
  const item = s.items[0];
69
- const subscriptionInfo = this._config.subscriptions.find((sub) => {
132
+ const subscriptionInfo = config.subscriptions.find((sub) => {
70
133
  return sub.eligibleProducts.some((p) => p === item.price.product.id);
71
134
  });
72
135
  const featureList = subscriptionInfo === null || subscriptionInfo === void 0 ? void 0 : subscriptionInfo.featureList;
@@ -89,10 +152,11 @@ export class SubscriptionController {
89
152
  });
90
153
  const purchasableSubscriptions = subscriptions.length > 0
91
154
  ? []
92
- : yield this._getPurchasableSubscriptions();
155
+ : yield this._getPurchasableSubscriptions(role, config);
93
156
  return {
94
157
  success: true,
95
158
  userId: keyResult.userId,
159
+ studioId: request.studioId,
96
160
  publishableKey: this._stripe.publishableKey,
97
161
  subscriptions,
98
162
  purchasableSubscriptions,
@@ -108,11 +172,21 @@ export class SubscriptionController {
108
172
  }
109
173
  });
110
174
  }
111
- _getPurchasableSubscriptions() {
175
+ _getPurchasableSubscriptionsForRole(role, config) {
176
+ return config.subscriptions.filter((s) => {
177
+ var _a, _b, _c;
178
+ const isPurchasable = (_a = s.purchasable) !== null && _a !== void 0 ? _a : true;
179
+ const isUserOnly = (_b = s.userOnly) !== null && _b !== void 0 ? _b : false;
180
+ const isStudioOnly = (_c = s.studioOnly) !== null && _c !== void 0 ? _c : false;
181
+ const matchesRole = (isUserOnly && role === 'user') ||
182
+ (isStudioOnly && role === 'studio') ||
183
+ (!isUserOnly && !isStudioOnly);
184
+ return isPurchasable && matchesRole;
185
+ });
186
+ }
187
+ _getPurchasableSubscriptions(role, config) {
112
188
  return __awaiter(this, void 0, void 0, function* () {
113
- const promises = this._config.subscriptions
114
- .filter((s) => { var _a; return (_a = s.purchasable) !== null && _a !== void 0 ? _a : true; })
115
- .map((s) => __awaiter(this, void 0, void 0, function* () {
189
+ const promises = this._getPurchasableSubscriptionsForRole(role, config).map((s) => __awaiter(this, void 0, void 0, function* () {
116
190
  return ({
117
191
  sub: s,
118
192
  info: yield this._stripe.getProductAndPriceInfo(s.product),
@@ -153,11 +227,38 @@ export class SubscriptionController {
153
227
  };
154
228
  }
155
229
  try {
156
- if (typeof request.userId !== 'string' || request.userId === '') {
230
+ if (request.userId && request.studioId) {
157
231
  return {
158
232
  success: false,
159
- errorCode: 'unacceptable_user_id',
160
- errorMessage: 'The given user ID is invalid. It must be a correctly formatted string.',
233
+ errorCode: 'unacceptable_request',
234
+ errorMessage: 'The given request is invalid. It must not specify both a user ID and a studio ID.',
235
+ };
236
+ }
237
+ if (request.userId) {
238
+ if (typeof request.userId !== 'string' ||
239
+ request.userId === '') {
240
+ return {
241
+ success: false,
242
+ errorCode: 'unacceptable_user_id',
243
+ errorMessage: 'The given user ID is invalid. It must be a correctly formatted string.',
244
+ };
245
+ }
246
+ }
247
+ else if (request.studioId) {
248
+ if (typeof request.studioId !== 'string' ||
249
+ request.studioId === '') {
250
+ return {
251
+ success: false,
252
+ errorCode: 'unacceptable_studio_id',
253
+ errorMessage: 'The given studio ID is invalid. It must be a correctly formatted string.',
254
+ };
255
+ }
256
+ }
257
+ else {
258
+ return {
259
+ success: false,
260
+ errorCode: 'unacceptable_request',
261
+ errorMessage: 'The given request is invalid. It must have a valid user ID or studio ID.',
161
262
  };
162
263
  }
163
264
  if (!!request.subscriptionId &&
@@ -177,29 +278,80 @@ export class SubscriptionController {
177
278
  };
178
279
  }
179
280
  const keyResult = yield this._auth.validateSessionKey(request.sessionKey);
281
+ let customerId;
282
+ let customerName;
283
+ let customerEmail;
284
+ let customerPhone;
285
+ let role;
286
+ let user;
287
+ let studio;
288
+ let customerMetadata = {};
289
+ let metadata = {};
180
290
  if (keyResult.success === false) {
181
291
  return keyResult;
182
292
  }
183
- else if (keyResult.userId !== request.userId) {
184
- console.log('[SubscriptionController] [createManageSubscriptionLink] Request User ID doesnt match session key User ID!');
185
- return {
186
- success: false,
187
- errorCode: 'invalid_key',
188
- errorMessage: INVALID_KEY_ERROR_MESSAGE,
189
- };
293
+ else if (request.userId) {
294
+ if (keyResult.userId !== request.userId) {
295
+ console.log('[SubscriptionController] [createManageSubscriptionLink] Request User ID doesnt match session key User ID!');
296
+ return {
297
+ success: false,
298
+ errorCode: 'invalid_key',
299
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
300
+ };
301
+ }
302
+ user = yield this._authStore.findUser(keyResult.userId);
303
+ customerId = user.stripeCustomerId;
304
+ customerName = user.name;
305
+ customerEmail = user.email;
306
+ customerPhone = user.phoneNumber;
307
+ metadata.userId = user.id;
308
+ customerMetadata.role = 'user';
309
+ customerMetadata.userId = user.id;
310
+ role = 'user';
311
+ console.log(`[SubscriptionController] [createManageSubscriptionLink] Creating a checkout/management session for User (${keyResult.userId}).`);
190
312
  }
191
- // if (this._config.subscriptions.length <= 0) {
192
- // return {
193
- // success: false,
194
- // errorCode: 'not_supported',
195
- // errorMessage: 'This method is not supported.',
196
- // };
197
- // }
198
- console.log(`[SubscriptionController] [createManageSubscriptionLink] Creating a checkout/management session for User (${keyResult.userId}).`);
199
- const user = yield this._authStore.findUser(keyResult.userId);
200
- let customerId = user.stripeCustomerId;
313
+ else if (request.studioId) {
314
+ const assignments = yield this._recordsStore.listStudioAssignments(request.studioId, {
315
+ role: 'admin',
316
+ });
317
+ const userAssignment = assignments.find((a) => a.userId === keyResult.userId);
318
+ if (!userAssignment) {
319
+ console.log('[SubscriptionController] [getSubscriptionStatus] Request user does not have access to studio!');
320
+ return {
321
+ success: false,
322
+ errorCode: 'invalid_key',
323
+ errorMessage: INVALID_KEY_ERROR_MESSAGE,
324
+ };
325
+ }
326
+ studio = yield this._recordsStore.getStudioById(request.studioId);
327
+ customerId = studio.stripeCustomerId;
328
+ customerName = studio.displayName;
329
+ customerMetadata.role = 'studio';
330
+ customerMetadata.studioId = studio.id;
331
+ metadata.studioId = studio.id;
332
+ let primaryAssignment;
333
+ if (userAssignment.isPrimaryContact) {
334
+ primaryAssignment = userAssignment;
335
+ }
336
+ else {
337
+ primaryAssignment = assignments.find((a) => a.isPrimaryContact);
338
+ }
339
+ if (primaryAssignment) {
340
+ customerEmail = primaryAssignment.user.email;
341
+ customerPhone = primaryAssignment.user.phoneNumber;
342
+ metadata.contactUserId = keyResult.userId;
343
+ customerMetadata.contactUserId = keyResult.userId;
344
+ }
345
+ role = 'studio';
346
+ console.log(`[SubscriptionController] [createManageSubscriptionLink] Creating a checkout/management session for Studio (userId: ${keyResult.userId}, studioId: ${studio.id}).`);
347
+ }
348
+ else {
349
+ throw new Error('Should not reach this point');
350
+ }
351
+ metadata.subjectId = keyResult.userId;
352
+ const config = yield this._getConfig();
201
353
  if (!customerId) {
202
- if (this._config.subscriptions.length <= 0) {
354
+ if (config.subscriptions.length <= 0) {
203
355
  return {
204
356
  success: false,
205
357
  errorCode: 'not_supported',
@@ -208,16 +360,25 @@ export class SubscriptionController {
208
360
  }
209
361
  console.log('[SubscriptionController] [createManageSubscriptionLink] No Stripe Customer ID. Creating New Customer and Checkout Session in Stripe.');
210
362
  const result = yield this._stripe.createCustomer({
211
- name: user.name,
212
- email: user.email,
213
- phone: user.phoneNumber,
363
+ name: customerName,
364
+ email: customerEmail,
365
+ phone: customerPhone,
366
+ metadata: customerMetadata,
214
367
  });
215
- customerId = user.stripeCustomerId = result.id;
216
- console.log(`[SubscriptionController] [createManageSubscriptionLink] Saving Stripe Customer ID (${customerId}) to User Record (${user.id}).`);
217
- yield this._authStore.saveUser(Object.assign({}, user));
218
- return yield this._createCheckoutSession(request, user, customerId);
368
+ customerId = result.id;
369
+ if (user) {
370
+ user.stripeCustomerId = customerId;
371
+ console.log(`[SubscriptionController] [createManageSubscriptionLink] Saving Stripe Customer ID (${customerId}) to User Record (${user.id}).`);
372
+ yield this._authStore.saveUser(Object.assign({}, user));
373
+ }
374
+ else if (studio) {
375
+ studio.stripeCustomerId = customerId;
376
+ console.log(`[SubscriptionController] [createManageSubscriptionLink] Saving Stripe Customer ID (${customerId}) to Studio Record (${studio.id}).`);
377
+ yield this._recordsStore.updateStudio(Object.assign({}, studio));
378
+ }
379
+ return yield this._createCheckoutSession(request, customerId, metadata, role, user, studio);
219
380
  }
220
- console.log(`[SubscriptionController] [createManageSubscriptionLink] User (${user.id}) Has Stripe Customer ID (${user.stripeCustomerId}). Checking active subscriptions for customer.`);
381
+ console.log(`[SubscriptionController] [createManageSubscriptionLink] Has Stripe Customer ID (${customerId}). Checking active subscriptions for customer.`);
221
382
  const subs = yield this._stripe.listActiveSubscriptionsForCustomer(customerId);
222
383
  const hasSubscription = subs.subscriptions.some((s) => {
223
384
  const isManagable = s.status === 'active' ||
@@ -229,12 +390,12 @@ export class SubscriptionController {
229
390
  if (!isManagable) {
230
391
  return false;
231
392
  }
232
- const hasManagableProduct = this._config.subscriptions.some((sub) => sub.eligibleProducts.some((p) => s.items.some((i) => i.price.product.id === p)));
393
+ const hasManagableProduct = config.subscriptions.some((sub) => sub.eligibleProducts.some((p) => s.items.some((i) => i.price.product.id === p)));
233
394
  return hasManagableProduct;
234
395
  });
235
396
  if (hasSubscription) {
236
397
  console.log(`[SubscriptionController] [createManageSubscriptionLink] Customer has a managable subscription. Creating a portal session.`);
237
- const session = yield this._stripe.createPortalSession(Object.assign(Object.assign({}, ((_a = this._config.portalConfig) !== null && _a !== void 0 ? _a : {})), { customer: customerId, return_url: this._config.returnUrl }));
398
+ const session = yield this._stripe.createPortalSession(Object.assign(Object.assign({}, ((_a = config.portalConfig) !== null && _a !== void 0 ? _a : {})), { customer: customerId, return_url: returnRoute(config.returnUrl, user, studio) }));
238
399
  console.log(`[SubscriptionController] [createManageSubscriptionLink] Portal session success!`);
239
400
  return {
240
401
  success: true,
@@ -242,10 +403,10 @@ export class SubscriptionController {
242
403
  };
243
404
  }
244
405
  console.log(`[SubscriptionController] [createManageSubscriptionLink] Customer does not have a managable subscription. Creating a checkout session.`);
245
- return yield this._createCheckoutSession(request, user, customerId);
406
+ return yield this._createCheckoutSession(request, customerId, metadata, role, user, studio);
246
407
  }
247
408
  catch (err) {
248
- console.log('[SubscriptionController] An error occurred while creating a manage subscription link:', err);
409
+ console.error('[SubscriptionController] An error occurred while creating a manage subscription link:', err);
249
410
  return {
250
411
  success: false,
251
412
  errorCode: 'server_error',
@@ -254,24 +415,26 @@ export class SubscriptionController {
254
415
  }
255
416
  });
256
417
  }
257
- _createCheckoutSession(request, user, customerId) {
418
+ _createCheckoutSession(request, customerId, metadata, role, user, studio) {
258
419
  var _a;
259
420
  return __awaiter(this, void 0, void 0, function* () {
421
+ const config = yield this._getConfig();
422
+ const purchasableSubscriptions = this._getPurchasableSubscriptionsForRole(role, config);
260
423
  let sub;
261
424
  if (request.subscriptionId) {
262
- sub = this._config.subscriptions.find((s) => s.id === request.subscriptionId);
425
+ sub = purchasableSubscriptions.find((s) => s.id === request.subscriptionId);
263
426
  if (sub) {
264
427
  console.log(`[SubscriptionController] [createManageSubscriptionLink] Using specified subscription (${request.subscriptionId}).`);
265
428
  }
266
429
  }
267
430
  if (!sub) {
268
- sub = this._config.subscriptions.find((s) => s.defaultSubscription);
431
+ sub = purchasableSubscriptions.find((s) => s.defaultSubscription);
269
432
  if (sub) {
270
433
  console.log(`[SubscriptionController] [createManageSubscriptionLink] Using default subscription.`);
271
434
  }
272
435
  }
273
436
  if (!sub) {
274
- sub = this._config.subscriptions[0];
437
+ sub = purchasableSubscriptions[0];
275
438
  console.log(`[SubscriptionController] [createManageSubscriptionLink] Using first subscription.`);
276
439
  }
277
440
  const productInfo = yield this._stripe.getProductAndPriceInfo(sub.product);
@@ -293,14 +456,12 @@ export class SubscriptionController {
293
456
  }
294
457
  }
295
458
  console.log(`[SubscriptionController] [createManageSubscriptionLink] Creating Checkout Session.`);
296
- const session = yield this._stripe.createCheckoutSession(Object.assign(Object.assign({}, ((_a = this._config.checkoutConfig) !== null && _a !== void 0 ? _a : {})), { customer: customerId, success_url: this._config.successUrl, cancel_url: this._config.cancelUrl, line_items: [
459
+ const session = yield this._stripe.createCheckoutSession(Object.assign(Object.assign({}, ((_a = config.checkoutConfig) !== null && _a !== void 0 ? _a : {})), { customer: customerId, success_url: returnRoute(config.successUrl, user, studio), cancel_url: returnRoute(config.cancelUrl, user, studio), line_items: [
297
460
  {
298
461
  price: productInfo.default_price.id,
299
462
  quantity: 1,
300
463
  },
301
- ], mode: 'subscription', metadata: {
302
- userId: user.id,
303
- } }));
464
+ ], mode: 'subscription', metadata: metadata }));
304
465
  console.log(`[SubscriptionController] [createManageSubscriptionLink] Checkout Session Success!`);
305
466
  return {
306
467
  success: true,
@@ -338,11 +499,12 @@ export class SubscriptionController {
338
499
  errorMessage: 'The request was not valid.',
339
500
  };
340
501
  }
502
+ const config = yield this._getConfig();
341
503
  const body = request.requestBody;
342
504
  const signature = request.signature;
343
505
  let event;
344
506
  try {
345
- event = this._stripe.constructWebhookEvent(body, signature, this._config.webhookSecret);
507
+ event = this._stripe.constructWebhookEvent(body, signature, config.webhookSecret);
346
508
  }
347
509
  catch (err) {
348
510
  console.log(`[SubscriptionController] [handleStripeWebhook] Unable to construct webhook event:`, err);
@@ -361,7 +523,7 @@ export class SubscriptionController {
361
523
  let item;
362
524
  let sub;
363
525
  items_loop: for (let i of items) {
364
- for (let s of this._config.subscriptions) {
526
+ for (let s of config.subscriptions) {
365
527
  if (s.eligibleProducts.some((p) => p === i.price.product)) {
366
528
  sub = s;
367
529
  item = i;
@@ -380,18 +542,120 @@ export class SubscriptionController {
380
542
  const active = isActiveSubscription(status);
381
543
  const tier = (_a = sub.tier) !== null && _a !== void 0 ? _a : 'beta';
382
544
  const customerId = subscription.customer;
545
+ const stripeSubscriptionId = subscription.id;
383
546
  console.log(`[SubscriptionController] [handleStripeWebhook] Customer ID: ${customerId}. Subscription status: ${status}. Tier: ${tier}. Is Active: ${active}.`);
384
- const user = yield this._authStore.findUserByStripeCustomerId(customerId);
385
- if (!user) {
547
+ let user = yield this._authStore.findUserByStripeCustomerId(customerId);
548
+ let studio;
549
+ if (user) {
550
+ yield this._authStore.updateSubscriptionInfo({
551
+ userId: user.id,
552
+ subscriptionStatus: status,
553
+ subscriptionId: sub.id,
554
+ stripeSubscriptionId,
555
+ stripeCustomerId: customerId,
556
+ currentPeriodEndMs: null,
557
+ currentPeriodStartMs: null,
558
+ });
559
+ }
560
+ else {
386
561
  console.log(`[SubscriptionController] [handleStripeWebhook] No user found for Customer ID (${customerId})`);
562
+ studio =
563
+ yield this._recordsStore.getStudioByStripeCustomerId(customerId);
564
+ if (studio) {
565
+ yield this._authStore.updateSubscriptionInfo({
566
+ studioId: studio.id,
567
+ subscriptionStatus: status,
568
+ subscriptionId: sub.id,
569
+ stripeSubscriptionId,
570
+ stripeCustomerId: customerId,
571
+ currentPeriodEndMs: null,
572
+ currentPeriodStartMs: null,
573
+ });
574
+ }
575
+ else {
576
+ console.log(`[SubscriptionController] [handleStripeWebhook] No studio found for Customer ID (${customerId})`);
577
+ }
578
+ }
579
+ return {
580
+ success: true,
581
+ };
582
+ }
583
+ else if (event.type === 'invoice.paid') {
584
+ const parseResult = STRIPE_EVENT_INVOICE_PAID_SCHEMA.safeParse(event);
585
+ if (parseResult.success === false) {
586
+ console.error(`[SubscriptionController] [handleStripeWebhook] Unable to parse stripe event!`, parseResult.error);
387
587
  return {
388
588
  success: true,
389
589
  };
390
590
  }
391
- if (user.subscriptionStatus !== status ||
392
- user.subscriptionId !== sub.id) {
393
- console.log(`[SubscriptionController] [handleStripeWebhook] User subscription status doesn't match stored. Updating...`);
394
- yield this._authStore.saveUser(Object.assign(Object.assign({}, user), { subscriptionStatus: status, subscriptionId: sub.id }));
591
+ const invoice = parseResult.data.data.object;
592
+ const stripeSubscriptionId = invoice.subscription;
593
+ const subscription = yield this._stripe.getSubscriptionById(stripeSubscriptionId);
594
+ const status = subscription.status;
595
+ const customerId = invoice.customer;
596
+ const lineItems = invoice.lines.data;
597
+ const periodStartMs = subscription.current_period_start * 1000;
598
+ const periodEndMs = subscription.current_period_end * 1000;
599
+ const { sub, item } = findMatchingSubscription(lineItems);
600
+ const authInvoice = {
601
+ currency: invoice.currency,
602
+ description: invoice.description,
603
+ paid: invoice.paid,
604
+ status: invoice.status,
605
+ tax: invoice.tax,
606
+ total: invoice.total,
607
+ subtotal: invoice.subtotal,
608
+ stripeInvoiceId: invoice.id,
609
+ stripeHostedInvoiceUrl: invoice.hosted_invoice_url,
610
+ stripeInvoicePdfUrl: invoice.invoice_pdf,
611
+ };
612
+ console.log(`[SubscriptionController] [handleStripeWebhook] New invoice paid for customer ID (${customerId}). Subscription ID: ${subscription.id}. Period start: ${periodStartMs}. Period end: ${periodEndMs}.`);
613
+ const user = yield this._authStore.findUserByStripeCustomerId(customerId);
614
+ if (user) {
615
+ console.log(`[SubscriptionController] [handleStripeWebhook] Found user (${user.id}) with customer ID (${customerId}).`);
616
+ yield this._authStore.updateSubscriptionPeriod({
617
+ userId: user.id,
618
+ subscriptionStatus: status,
619
+ subscriptionId: sub.id,
620
+ stripeSubscriptionId,
621
+ stripeCustomerId: customerId,
622
+ currentPeriodEndMs: periodEndMs,
623
+ currentPeriodStartMs: periodStartMs,
624
+ invoice: authInvoice,
625
+ });
626
+ }
627
+ else {
628
+ console.log(`[SubscriptionController] [handleStripeWebhook] No user found for customer ID (${customerId}).`);
629
+ const studio = yield this._recordsStore.getStudioByStripeCustomerId(customerId);
630
+ if (studio) {
631
+ yield this._authStore.updateSubscriptionPeriod({
632
+ studioId: studio.id,
633
+ subscriptionStatus: status,
634
+ subscriptionId: sub.id,
635
+ stripeSubscriptionId,
636
+ stripeCustomerId: customerId,
637
+ currentPeriodEndMs: periodEndMs,
638
+ currentPeriodStartMs: periodStartMs,
639
+ invoice: authInvoice,
640
+ });
641
+ }
642
+ else {
643
+ console.log(`[SubscriptionController] [handleStripeWebhook] No studio found for customer ID (${customerId}).`);
644
+ }
645
+ }
646
+ function findMatchingSubscription(lineItems) {
647
+ let item;
648
+ let sub;
649
+ items_loop: for (let i of lineItems) {
650
+ for (let s of config.subscriptions) {
651
+ if (s.eligibleProducts.some((p) => p === i.price.product)) {
652
+ sub = s;
653
+ item = i;
654
+ break items_loop;
655
+ }
656
+ }
657
+ }
658
+ return { item, sub };
395
659
  }
396
660
  }
397
661
  return {
@@ -438,4 +702,15 @@ function isValidSubscription(sub) {
438
702
  typeof sub.product === 'string' &&
439
703
  typeof sub.defaultSubscription === 'boolean');
440
704
  }
705
+ function returnRoute(basePath, user, studio) {
706
+ if (user) {
707
+ return basePath;
708
+ }
709
+ else {
710
+ return studiosRoute(basePath, studio.id, studio.displayName);
711
+ }
712
+ }
713
+ function studiosRoute(basePath, studioId, studioName) {
714
+ return new URL(`/studios/${encodeURIComponent(studioId)}/${encodeURIComponent(studioName)}`, basePath).href;
715
+ }
441
716
  //# sourceMappingURL=SubscriptionController.js.map