@checkfirst/nestjs-outlook 7.1.1 → 7.1.3

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 (37) hide show
  1. package/dist/constants.d.ts +3 -0
  2. package/dist/constants.js +4 -1
  3. package/dist/constants.js.map +1 -1
  4. package/dist/controllers/microsoft-auth.controller.js +20 -0
  5. package/dist/controllers/microsoft-auth.controller.js.map +1 -1
  6. package/dist/entities/outlook-webhook-subscription.entity.d.ts +1 -0
  7. package/dist/entities/outlook-webhook-subscription.entity.js +5 -0
  8. package/dist/entities/outlook-webhook-subscription.entity.js.map +1 -1
  9. package/dist/enums/event-types.enum.d.ts +3 -0
  10. package/dist/enums/event-types.enum.js +3 -0
  11. package/dist/enums/event-types.enum.js.map +1 -1
  12. package/dist/errors/mailbox-inactive.error.d.ts +4 -0
  13. package/dist/errors/mailbox-inactive.error.js +12 -0
  14. package/dist/errors/mailbox-inactive.error.js.map +1 -0
  15. package/dist/index.d.ts +1 -0
  16. package/dist/index.js +1 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/migrations/1776600000000-AddLastNotificationAtToSubscriptions.d.ts +5 -0
  19. package/dist/migrations/1776600000000-AddLastNotificationAtToSubscriptions.js +18 -0
  20. package/dist/migrations/1776600000000-AddLastNotificationAtToSubscriptions.js.map +1 -0
  21. package/dist/repositories/outlook-webhook-subscription.repository.d.ts +5 -1
  22. package/dist/repositories/outlook-webhook-subscription.repository.js +23 -1
  23. package/dist/repositories/outlook-webhook-subscription.repository.js.map +1 -1
  24. package/dist/services/auth/microsoft-auth.service.d.ts +6 -3
  25. package/dist/services/auth/microsoft-auth.service.js +49 -8
  26. package/dist/services/auth/microsoft-auth.service.js.map +1 -1
  27. package/dist/services/calendar/calendar.service.d.ts +3 -11
  28. package/dist/services/calendar/calendar.service.js +22 -247
  29. package/dist/services/calendar/calendar.service.js.map +1 -1
  30. package/dist/services/calendar/lifecycle-event-handler.service.d.ts +3 -1
  31. package/dist/services/calendar/lifecycle-event-handler.service.js +35 -5
  32. package/dist/services/calendar/lifecycle-event-handler.service.js.map +1 -1
  33. package/dist/services/subscription/microsoft-subscription.service.d.ts +24 -0
  34. package/dist/services/subscription/microsoft-subscription.service.js +395 -2
  35. package/dist/services/subscription/microsoft-subscription.service.js.map +1 -1
  36. package/dist/tsconfig.tsbuildinfo +1 -1
  37. package/package.json +1 -1
@@ -20,10 +20,12 @@ const lifecycle_event_types_enum_1 = require("../../enums/lifecycle-event-types.
20
20
  const event_types_enum_1 = require("../../enums/event-types.enum");
21
21
  const outlook_webhook_subscription_repository_1 = require("../../repositories/outlook-webhook-subscription.repository");
22
22
  const calendar_service_1 = require("./calendar.service");
23
+ const microsoft_subscription_service_1 = require("../subscription/microsoft-subscription.service");
23
24
  const user_id_converter_service_1 = require("../shared/user-id-converter.service");
24
25
  let LifecycleEventHandlerService = LifecycleEventHandlerService_1 = class LifecycleEventHandlerService {
25
- constructor(calendarService, subscriptionRepository, eventEmitter, userIdConverter) {
26
+ constructor(calendarService, subscriptionService, subscriptionRepository, eventEmitter, userIdConverter) {
26
27
  this.calendarService = calendarService;
28
+ this.subscriptionService = subscriptionService;
27
29
  this.subscriptionRepository = subscriptionRepository;
28
30
  this.eventEmitter = eventEmitter;
29
31
  this.userIdConverter = userIdConverter;
@@ -82,7 +84,7 @@ let LifecycleEventHandlerService = LifecycleEventHandlerService_1 = class Lifecy
82
84
  };
83
85
  }
84
86
  this.logger.log(`[REAUTHORIZATION_REQUIRED] Attempting to renew subscription ${subscriptionId}`);
85
- const renewedSubscription = await this.calendarService.renewWebhookSubscription(subscriptionId, subscription.userId);
87
+ const renewedSubscription = await this.subscriptionService.renewWebhookSubscription(subscriptionId, subscription.userId);
86
88
  const expirationDate = renewedSubscription.expirationDateTime
87
89
  ? new Date(renewedSubscription.expirationDateTime).toISOString()
88
90
  : 'unknown';
@@ -126,15 +128,43 @@ let LifecycleEventHandlerService = LifecycleEventHandlerService_1 = class Lifecy
126
128
  }
127
129
  await this.subscriptionRepository.deactivateSubscription(subscriptionId);
128
130
  this.logger.log(`[SUBSCRIPTION_REMOVED] Deactivated subscription ${subscriptionId} in database`);
131
+ const externalUserId = await this.userIdConverter.internalToExternal(subscription.userId);
132
+ let recreated = false;
133
+ try {
134
+ this.logger.log(`[SUBSCRIPTION_REMOVED] Attempting to re-create subscription for user ${subscription.userId}`);
135
+ await this.subscriptionService.createWebhookSubscription(externalUserId);
136
+ recreated = true;
137
+ this.logger.log(`[SUBSCRIPTION_REMOVED] Successfully re-created subscription for user ${subscription.userId}`);
138
+ this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.SUBSCRIPTION_RECREATED, {
139
+ subscriptionId,
140
+ tenantId,
141
+ userId: subscription.userId,
142
+ reason: 'subscription_removed',
143
+ });
144
+ }
145
+ catch (recreateError) {
146
+ const recreateMsg = recreateError instanceof Error ? recreateError.message : 'Unknown error';
147
+ this.logger.error(`[SUBSCRIPTION_REMOVED] Failed to re-create subscription for user ${subscription.userId}: ${recreateMsg}`);
148
+ this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.SUBSCRIPTION_RECREATION_FAILED, {
149
+ subscriptionId,
150
+ tenantId,
151
+ userId: subscription.userId,
152
+ reason: 'subscription_removed',
153
+ error: recreateMsg,
154
+ });
155
+ }
129
156
  this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.LIFECYCLE_SUBSCRIPTION_REMOVED, {
130
157
  subscriptionId,
131
158
  tenantId,
132
159
  userId: subscription.userId,
133
160
  resource: subscription.resource,
161
+ recreated,
134
162
  });
135
163
  return {
136
164
  success: true,
137
- message: 'Subscription marked as inactive',
165
+ message: recreated
166
+ ? 'Subscription removed and re-created successfully'
167
+ : 'Subscription marked as inactive (re-creation failed)',
138
168
  };
139
169
  }
140
170
  catch (error) {
@@ -159,8 +189,7 @@ let LifecycleEventHandlerService = LifecycleEventHandlerService_1 = class Lifecy
159
189
  }
160
190
  this.logger.log(`[MISSED] Starting delta sync for user ${subscription.userId} to recover missed changes`);
161
191
  const externalUserId = await this.userIdConverter.internalToExternal(subscription.userId);
162
- const changes = await this.calendarService.fetchAndSortChanges(externalUserId, false);
163
- const changesCount = changes.length;
192
+ const changesCount = await this.calendarService.syncDeltaChanges(externalUserId, subscriptionId);
164
193
  this.logger.log(`[MISSED] Delta sync completed. Found ${changesCount} changes for subscription ${subscriptionId}`);
165
194
  this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.LIFECYCLE_MISSED, {
166
195
  subscriptionId,
@@ -194,6 +223,7 @@ exports.LifecycleEventHandlerService = LifecycleEventHandlerService = LifecycleE
194
223
  (0, common_1.Injectable)(),
195
224
  __param(0, (0, common_1.Inject)((0, common_1.forwardRef)(() => calendar_service_1.CalendarService))),
196
225
  __metadata("design:paramtypes", [calendar_service_1.CalendarService,
226
+ microsoft_subscription_service_1.MicrosoftSubscriptionService,
197
227
  outlook_webhook_subscription_repository_1.OutlookWebhookSubscriptionRepository,
198
228
  event_emitter_1.EventEmitter2,
199
229
  user_id_converter_service_1.UserIdConverterService])
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle-event-handler.service.js","sourceRoot":"","sources":["../../../src/services/calendar/lifecycle-event-handler.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lifecycle-event-handler.service.js","sourceRoot":"","sources":["../../../src/services/calendar/lifecycle-event-handler.service.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,12 @@
1
+ import { EventEmitter2 } from '@nestjs/event-emitter';
2
+ import { Repository } from 'typeorm';
3
+ import { Subscription } from '../../types';
4
+ import { MicrosoftAuthService } from '../auth/microsoft-auth.service';
5
+ import { OutlookWebhookSubscriptionRepository } from '../../repositories/outlook-webhook-subscription.repository';
6
+ import { OutlookWebhookSubscription } from '../../entities/outlook-webhook-subscription.entity';
7
+ import { MicrosoftUser } from '../../entities/microsoft-user.entity';
8
+ import { MicrosoftOutlookConfig } from '../../interfaces/config/outlook-config.interface';
9
+ import { UserIdConverterService } from '../shared/user-id-converter.service';
1
10
  export interface MicrosoftSubscription {
2
11
  id: string;
3
12
  resource: string;
@@ -23,16 +32,31 @@ export interface SubscriptionCleanupResult {
23
32
  }>;
24
33
  }
25
34
  export declare class MicrosoftSubscriptionService {
35
+ private readonly microsoftAuthService;
36
+ private readonly webhookSubscriptionRepository;
37
+ private readonly eventEmitter;
38
+ private readonly microsoftConfig;
39
+ private readonly microsoftUserRepository;
40
+ private readonly userIdConverter;
26
41
  private readonly logger;
27
42
  private readonly graphApiBaseUrl;
28
43
  private readonly msAuthUrl;
44
+ constructor(microsoftAuthService: MicrosoftAuthService, webhookSubscriptionRepository: OutlookWebhookSubscriptionRepository, eventEmitter: EventEmitter2, microsoftConfig: MicrosoftOutlookConfig, microsoftUserRepository: Repository<MicrosoftUser>, userIdConverter: UserIdConverterService);
29
45
  getActiveSubscriptions(accessToken: string): Promise<MicrosoftSubscription[]>;
30
46
  getActiveSubscriptionsForClient(clientId: number, accessToken: string): Promise<MicrosoftSubscription[]>;
31
47
  getActiveSubscriptionsForUser(userId: number, accessToken: string): Promise<MicrosoftSubscription[]>;
32
48
  deleteSubscription(subscriptionId: string, accessToken: string): Promise<void>;
49
+ createWebhookSubscription(externalUserId: string): Promise<Subscription>;
50
+ renewWebhookSubscription(subscriptionId: string, internalUserId: number): Promise<Subscription>;
51
+ deleteWebhookSubscription(subscriptionId: string, userId: string | number): Promise<boolean>;
52
+ getSubscription(subscriptionId: string): Promise<OutlookWebhookSubscription | null>;
53
+ getActiveSubscriptionForUser(externalUserId: string): Promise<string | null>;
54
+ trackNotificationReceived(subscriptionId: string): void;
33
55
  cleanupSubscriptions(options: SubscriptionCleanupOptions): Promise<SubscriptionCleanupResult>;
34
56
  cleanupSubscriptionsForClient(clientId: number, accessToken: string): Promise<SubscriptionCleanupResult>;
35
57
  cleanupSubscriptionsForUser(userId: number, accessToken: string): Promise<SubscriptionCleanupResult>;
36
58
  revokeTokens(refreshToken: string): Promise<void>;
37
59
  fullCleanup(refreshToken: string, accessToken: string, filter?: SubscriptionFilter): Promise<SubscriptionCleanupResult>;
60
+ renewSubscriptions(): Promise<void>;
61
+ verifySubscriptionHealth(): Promise<void>;
38
62
  }
@@ -5,14 +5,37 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
5
5
  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;
6
6
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
7
  };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
8
14
  var MicrosoftSubscriptionService_1;
9
15
  Object.defineProperty(exports, "__esModule", { value: true });
10
16
  exports.MicrosoftSubscriptionService = void 0;
17
+ const crypto_1 = require("crypto");
11
18
  const common_1 = require("@nestjs/common");
19
+ const event_emitter_1 = require("@nestjs/event-emitter");
20
+ const schedule_1 = require("@nestjs/schedule");
21
+ const typeorm_1 = require("@nestjs/typeorm");
22
+ const typeorm_2 = require("typeorm");
12
23
  const axios_1 = require("axios");
24
+ const microsoft_auth_service_1 = require("../auth/microsoft-auth.service");
25
+ const outlook_webhook_subscription_repository_1 = require("../../repositories/outlook-webhook-subscription.repository");
26
+ const microsoft_user_entity_1 = require("../../entities/microsoft-user.entity");
27
+ const constants_1 = require("../../constants");
28
+ const event_types_enum_1 = require("../../enums/event-types.enum");
29
+ const user_id_converter_service_1 = require("../shared/user-id-converter.service");
13
30
  const outlook_api_executor_util_1 = require("../../utils/outlook-api-executor.util");
14
31
  let MicrosoftSubscriptionService = MicrosoftSubscriptionService_1 = class MicrosoftSubscriptionService {
15
- constructor() {
32
+ constructor(microsoftAuthService, webhookSubscriptionRepository, eventEmitter, microsoftConfig, microsoftUserRepository, userIdConverter) {
33
+ this.microsoftAuthService = microsoftAuthService;
34
+ this.webhookSubscriptionRepository = webhookSubscriptionRepository;
35
+ this.eventEmitter = eventEmitter;
36
+ this.microsoftConfig = microsoftConfig;
37
+ this.microsoftUserRepository = microsoftUserRepository;
38
+ this.userIdConverter = userIdConverter;
16
39
  this.logger = new common_1.Logger(MicrosoftSubscriptionService_1.name);
17
40
  this.graphApiBaseUrl = 'https://graph.microsoft.com/v1.0';
18
41
  this.msAuthUrl = 'https://login.microsoftonline.com/common/oauth2/v2.0';
@@ -68,6 +91,247 @@ let MicrosoftSubscriptionService = MicrosoftSubscriptionService_1 = class Micros
68
91
  throw error;
69
92
  }
70
93
  }
94
+ async createWebhookSubscription(externalUserId) {
95
+ var _a, _b;
96
+ const internalUserId = await this.userIdConverter.externalToInternal(externalUserId, { cache: false });
97
+ const correlationId = `webhook-${internalUserId}-${Date.now()}`;
98
+ this.logger.log(`[${correlationId}] Starting webhook subscription creation for user ${internalUserId}`);
99
+ try {
100
+ this.logger.log(`[${correlationId}] Fetching access token for user ${internalUserId}`);
101
+ const accessToken = await this.microsoftAuthService.getUserAccessToken({ internalUserId, cache: false });
102
+ this.logger.log(`[${correlationId}] Successfully obtained access token`);
103
+ const expirationDateTime = new Date();
104
+ expirationDateTime.setHours(expirationDateTime.getHours() + 72);
105
+ const appUrl = this.microsoftConfig.backendBaseUrl || "http://localhost:3000";
106
+ const basePath = this.microsoftConfig.basePath;
107
+ const basePathUrl = basePath ? `${appUrl}/${basePath}` : appUrl;
108
+ const webhookPath = this.microsoftConfig.calendarWebhookPath || '/calendar/webhook';
109
+ const notificationUrl = `${basePathUrl}${webhookPath}`;
110
+ const subscriptionData = {
111
+ changeType: "created,updated,deleted",
112
+ notificationUrl,
113
+ lifecycleNotificationUrl: notificationUrl,
114
+ resource: "/me/events",
115
+ expirationDateTime: expirationDateTime.toISOString(),
116
+ clientState: `user_${internalUserId}_${(0, crypto_1.randomUUID)()}`,
117
+ };
118
+ this.logger.log(`[${correlationId}] Creating webhook subscription with notificationUrl: ${notificationUrl}`);
119
+ this.logger.debug(`[${correlationId}] Subscription data: ${JSON.stringify(subscriptionData)}`);
120
+ this.logger.log(`[${correlationId}] Sending POST request to Microsoft Graph API`);
121
+ const response = await (0, outlook_api_executor_util_1.executeGraphApiCall)(() => axios_1.default.post(`${this.graphApiBaseUrl}/subscriptions`, subscriptionData, {
122
+ headers: {
123
+ Authorization: `Bearer ${accessToken}`,
124
+ "Content-Type": "application/json",
125
+ "Prefer": 'IdType="ImmutableId"',
126
+ },
127
+ }), {
128
+ logger: this.logger,
129
+ resourceName: `create webhook subscription for user ${internalUserId}`,
130
+ maxRetries: 7,
131
+ });
132
+ if (!(response === null || response === void 0 ? void 0 : response.data)) {
133
+ throw new Error('Subscription creation returned null response');
134
+ }
135
+ this.logger.log(`[${correlationId}] Created webhook subscription ${response.data.id || "unknown"} for user ${internalUserId}`);
136
+ this.logger.log(`[${correlationId}] Saving subscription to database (internalUserId: ${internalUserId}, externalUserId: ${externalUserId})`);
137
+ await this.webhookSubscriptionRepository.saveSubscription({
138
+ subscriptionId: response.data.id,
139
+ userId: internalUserId,
140
+ resource: response.data.resource,
141
+ changeType: response.data.changeType,
142
+ clientState: response.data.clientState || "",
143
+ notificationUrl: response.data.notificationUrl,
144
+ expirationDateTime: response.data.expirationDateTime
145
+ ? new Date(response.data.expirationDateTime)
146
+ : new Date(),
147
+ });
148
+ this.logger.log(`[${correlationId}] Successfully stored subscription in database`);
149
+ this.logger.log(`[${correlationId}] Webhook subscription creation completed successfully`);
150
+ return response.data;
151
+ }
152
+ catch (error) {
153
+ if (axios_1.default.isAxiosError(error)) {
154
+ this.logger.error(`[${correlationId}] Microsoft Graph API error: Status ${(_a = error.response) === null || _a === void 0 ? void 0 : _a.status}, ` +
155
+ `Message: ${JSON.stringify((_b = error.response) === null || _b === void 0 ? void 0 : _b.data)}`);
156
+ }
157
+ else {
158
+ this.logger.error(`[${correlationId}] Failed to create webhook subscription:`, error);
159
+ }
160
+ throw new Error(`Failed to create webhook subscription: ${error instanceof Error ? error.message : 'Unknown error'}`);
161
+ }
162
+ }
163
+ async renewWebhookSubscription(subscriptionId, internalUserId) {
164
+ var _a, _b;
165
+ const correlationId = `renew-${subscriptionId}-${Date.now()}`;
166
+ try {
167
+ this.logger.log(`[${correlationId}] Attempting to renew subscription ${subscriptionId} for user ${internalUserId}`);
168
+ const user = await this.microsoftUserRepository.findOne({
169
+ where: { id: internalUserId, isActive: true }
170
+ });
171
+ if (!user) {
172
+ this.logger.warn(`[${correlationId}] User ${internalUserId} not found or inactive. ` +
173
+ `Deactivating subscription ${subscriptionId}`);
174
+ await this.webhookSubscriptionRepository.deactivateSubscription(subscriptionId);
175
+ throw new Error(`Cannot renew subscription ${subscriptionId}: ` +
176
+ `User ${internalUserId} not found or inactive. ` +
177
+ `Subscription has been automatically deactivated.`);
178
+ }
179
+ this.logger.debug(`[${correlationId}] User ${internalUserId} validated successfully`);
180
+ const accessToken = await this.microsoftAuthService.getUserAccessToken({
181
+ internalUserId
182
+ });
183
+ this.logger.debug(`[${correlationId}] Access token obtained`);
184
+ const expirationDateTime = new Date();
185
+ expirationDateTime.setHours(expirationDateTime.getHours() + 72);
186
+ const renewalData = {
187
+ expirationDateTime: expirationDateTime.toISOString(),
188
+ };
189
+ this.logger.debug(`[${correlationId}] Calling Microsoft Graph API to renew subscription`);
190
+ const response = await (0, outlook_api_executor_util_1.executeGraphApiCall)(() => axios_1.default.patch(`${this.graphApiBaseUrl}/subscriptions/${subscriptionId}`, renewalData, {
191
+ headers: {
192
+ Authorization: `Bearer ${accessToken}`,
193
+ "Content-Type": "application/json",
194
+ "Prefer": 'IdType="ImmutableId"',
195
+ },
196
+ }), {
197
+ logger: this.logger,
198
+ resourceName: `renew webhook subscription ${subscriptionId} for user ${internalUserId}`,
199
+ maxRetries: 7,
200
+ });
201
+ if (!(response === null || response === void 0 ? void 0 : response.data)) {
202
+ throw new Error('Subscription renewal returned null response');
203
+ }
204
+ this.logger.debug(`[${correlationId}] Microsoft Graph API returned status: ${response.status}`);
205
+ if (response.data.expirationDateTime) {
206
+ await this.webhookSubscriptionRepository.updateSubscriptionExpiration(subscriptionId, new Date(response.data.expirationDateTime));
207
+ this.logger.debug(`[${correlationId}] Updated local database with new expiration: ${response.data.expirationDateTime}`);
208
+ }
209
+ this.logger.log(`[${correlationId}] Successfully renewed subscription ${subscriptionId}. ` +
210
+ `New expiration: ${response.data.expirationDateTime}`);
211
+ return response.data;
212
+ }
213
+ catch (error) {
214
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
215
+ if (axios_1.default.isAxiosError(error)) {
216
+ const statusCode = (_a = error.response) === null || _a === void 0 ? void 0 : _a.status;
217
+ if (statusCode === 404) {
218
+ this.logger.warn(`[${correlationId}] Subscription ${subscriptionId} not found at Microsoft. ` +
219
+ `Deactivating and attempting re-creation.`);
220
+ await this.webhookSubscriptionRepository.deactivateSubscription(subscriptionId);
221
+ try {
222
+ const externalUserId = await this.userIdConverter.internalToExternal(internalUserId);
223
+ await this.createWebhookSubscription(externalUserId);
224
+ this.logger.log(`[${correlationId}] Successfully re-created subscription for user ${internalUserId} after 404`);
225
+ this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.SUBSCRIPTION_RECREATED, {
226
+ subscriptionId,
227
+ userId: internalUserId,
228
+ reason: 'renewal_404',
229
+ });
230
+ return {};
231
+ }
232
+ catch (recreateError) {
233
+ const recreateMsg = recreateError instanceof Error ? recreateError.message : 'Unknown error';
234
+ this.logger.error(`[${correlationId}] Failed to re-create subscription for user ${internalUserId}: ${recreateMsg}`);
235
+ this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.SUBSCRIPTION_RECREATION_FAILED, {
236
+ subscriptionId,
237
+ userId: internalUserId,
238
+ reason: 'renewal_404',
239
+ error: recreateMsg,
240
+ });
241
+ }
242
+ throw new Error(`Subscription ${subscriptionId} not found at Microsoft. ` +
243
+ `Subscription has been deactivated and re-creation failed.`);
244
+ }
245
+ if (statusCode === 401 || statusCode === 403) {
246
+ this.logger.error(`[${correlationId}] Authentication failed for subscription ${subscriptionId}. ` +
247
+ `Status: ${statusCode}, Response: ${JSON.stringify((_b = error.response) === null || _b === void 0 ? void 0 : _b.data)}. ` +
248
+ `Deactivating subscription to prevent repeated failures.`);
249
+ await this.webhookSubscriptionRepository.deactivateSubscription(subscriptionId);
250
+ this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.SUBSCRIPTION_AUTH_FAILED, {
251
+ subscriptionId,
252
+ userId: internalUserId,
253
+ statusCode,
254
+ });
255
+ }
256
+ if (statusCode === 429) {
257
+ this.logger.warn(`[${correlationId}] Rate limited by Microsoft Graph API for subscription ${subscriptionId}`);
258
+ }
259
+ }
260
+ this.logger.error(`[${correlationId}] Failed to renew subscription ${subscriptionId}: ${errorMessage}`);
261
+ throw new Error(`Failed to renew webhook subscription: ${errorMessage}`);
262
+ }
263
+ }
264
+ async deleteWebhookSubscription(subscriptionId, userId) {
265
+ var _a;
266
+ const correlationId = `delete-sub-${subscriptionId}-${Date.now()}`;
267
+ try {
268
+ this.logger.log(`[${correlationId}] Deleting calendar subscription ${subscriptionId} for user ${userId}`);
269
+ const internalUserId = await this.userIdConverter.toInternalUserId(userId);
270
+ const accessToken = await this.microsoftAuthService.getUserAccessToken({
271
+ internalUserId,
272
+ includeInactive: true
273
+ });
274
+ this.logger.debug(`[${correlationId}] Access token obtained`);
275
+ this.logger.debug(`[${correlationId}] Calling Microsoft Graph API to delete subscription`);
276
+ await this.deleteSubscription(subscriptionId, accessToken);
277
+ this.logger.log(`[${correlationId}] Successfully deleted subscription ${subscriptionId} at Microsoft`);
278
+ await this.webhookSubscriptionRepository.deactivateSubscription(subscriptionId);
279
+ this.logger.debug(`[${correlationId}] Deactivated subscription in local database`);
280
+ const otherActiveSubscriptions = await this.webhookSubscriptionRepository.count({
281
+ where: {
282
+ userId: internalUserId,
283
+ isActive: true,
284
+ subscriptionId: (0, typeorm_2.Not)(subscriptionId)
285
+ }
286
+ });
287
+ if (otherActiveSubscriptions === 0) {
288
+ const updateCriteria = typeof userId === 'string' ? { externalUserId: userId } : { id: userId };
289
+ await this.microsoftUserRepository.update(updateCriteria, { isActive: false });
290
+ this.logger.debug(`[${correlationId}] Marked Microsoft user as inactive - no other subscriptions remain`);
291
+ }
292
+ else {
293
+ this.logger.debug(`[${correlationId}] User still has ${otherActiveSubscriptions} other active subscription(s), keeping user active`);
294
+ }
295
+ this.logger.log(`[${correlationId}] Successfully deleted calendar subscription ${subscriptionId}`);
296
+ return true;
297
+ }
298
+ catch (error) {
299
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
300
+ if (axios_1.default.isAxiosError(error) && ((_a = error.response) === null || _a === void 0 ? void 0 : _a.status) === 404) {
301
+ this.logger.log(`[${correlationId}] Subscription ${subscriptionId} not found at Microsoft, ` +
302
+ `cleaning up local database`);
303
+ await this.webhookSubscriptionRepository.deactivateSubscription(subscriptionId);
304
+ this.logger.log(`[${correlationId}] Successfully cleaned up orphaned subscription ${subscriptionId}`);
305
+ return true;
306
+ }
307
+ this.logger.error(`[${correlationId}] Failed to delete subscription ${subscriptionId}: ${errorMessage}`);
308
+ throw new Error(`Failed to delete webhook subscription: ${errorMessage}`);
309
+ }
310
+ }
311
+ async getSubscription(subscriptionId) {
312
+ return this.webhookSubscriptionRepository.findBySubscriptionId(subscriptionId);
313
+ }
314
+ async getActiveSubscriptionForUser(externalUserId) {
315
+ var _a;
316
+ try {
317
+ const internalUserId = await this.userIdConverter.externalToInternal(externalUserId, { cache: false });
318
+ this.logger.log(`[getActiveSubscriptionForUser] Getting active subscription for user ${externalUserId} (internalUserId: ${internalUserId})`);
319
+ const subscription = await this.webhookSubscriptionRepository.findActiveByUserId(internalUserId);
320
+ this.logger.log(`[getActiveSubscriptionForUser] Found subscription: ${subscription === null || subscription === void 0 ? void 0 : subscription.subscriptionId}`);
321
+ return (_a = subscription === null || subscription === void 0 ? void 0 : subscription.subscriptionId) !== null && _a !== void 0 ? _a : null;
322
+ }
323
+ catch (_b) {
324
+ this.logger.debug(`No active subscription for user ${externalUserId}`);
325
+ return null;
326
+ }
327
+ }
328
+ trackNotificationReceived(subscriptionId) {
329
+ this.webhookSubscriptionRepository
330
+ .updateLastNotificationAt(subscriptionId)
331
+ .catch((err) => {
332
+ this.logger.warn(`Failed to update lastNotificationAt for subscription ${subscriptionId}: ${err instanceof Error ? err.message : 'Unknown error'}`);
333
+ });
334
+ }
71
335
  async cleanupSubscriptions(options) {
72
336
  const { accessToken, filter } = options;
73
337
  const result = {
@@ -158,9 +422,138 @@ let MicrosoftSubscriptionService = MicrosoftSubscriptionService_1 = class Micros
158
422
  this.logger.log('✅ Full cleanup completed');
159
423
  return result;
160
424
  }
425
+ async renewSubscriptions() {
426
+ try {
427
+ const expiringSubscriptions = await this.webhookSubscriptionRepository.findSubscriptionsNeedingRenewal(24, { skipLocked: true });
428
+ if (expiringSubscriptions.length === 0) {
429
+ this.logger.debug("No subscriptions need renewal");
430
+ return;
431
+ }
432
+ this.logger.log(`Found ${String(expiringSubscriptions.length)} subscriptions that need renewal`);
433
+ for (const subscription of expiringSubscriptions) {
434
+ try {
435
+ await this.renewWebhookSubscription(subscription.subscriptionId, subscription.userId);
436
+ }
437
+ catch (error) {
438
+ this.logger.error(`Failed to renew subscription ${subscription.subscriptionId}:`, error);
439
+ }
440
+ }
441
+ }
442
+ catch (error) {
443
+ this.logger.error("Error in subscription renewal job:", error);
444
+ }
445
+ }
446
+ async verifySubscriptionHealth() {
447
+ const correlationId = `health-check-${Date.now()}`;
448
+ try {
449
+ const activeSubscriptions = await this.webhookSubscriptionRepository.findActiveSubscriptions();
450
+ if (activeSubscriptions.length === 0) {
451
+ this.logger.debug(`[${correlationId}] No active subscriptions to verify`);
452
+ return;
453
+ }
454
+ this.logger.log(`[${correlationId}] Verifying health of ${String(activeSubscriptions.length)} active subscriptions`);
455
+ let verified = 0;
456
+ let recreated = 0;
457
+ let staleDetected = 0;
458
+ let failed = 0;
459
+ for (const subscription of activeSubscriptions) {
460
+ try {
461
+ const accessToken = await this.microsoftAuthService.getUserAccessToken({
462
+ internalUserId: subscription.userId,
463
+ });
464
+ const response = await (0, outlook_api_executor_util_1.executeGraphApiCall)(() => axios_1.default.get(`${this.graphApiBaseUrl}/subscriptions/${subscription.subscriptionId}`, {
465
+ headers: {
466
+ Authorization: `Bearer ${accessToken}`,
467
+ "Prefer": 'IdType="ImmutableId"',
468
+ },
469
+ }), {
470
+ logger: this.logger,
471
+ resourceName: `verify subscription ${subscription.subscriptionId}`,
472
+ maxRetries: 2,
473
+ return404AsNull: true,
474
+ });
475
+ if (!response) {
476
+ this.logger.warn(`[${correlationId}] Subscription ${subscription.subscriptionId} not found at Microsoft. Attempting re-creation.`);
477
+ await this.webhookSubscriptionRepository.deactivateSubscription(subscription.subscriptionId);
478
+ try {
479
+ const externalUserId = await this.userIdConverter.internalToExternal(subscription.userId);
480
+ await this.createWebhookSubscription(externalUserId);
481
+ recreated++;
482
+ this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.SUBSCRIPTION_RECREATED, {
483
+ subscriptionId: subscription.subscriptionId,
484
+ userId: subscription.userId,
485
+ reason: 'health_check_404',
486
+ });
487
+ }
488
+ catch (recreateError) {
489
+ failed++;
490
+ this.logger.error(`[${correlationId}] Failed to re-create subscription for user ${String(subscription.userId)}: ${recreateError instanceof Error ? recreateError.message : 'Unknown error'}`);
491
+ this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.SUBSCRIPTION_RECREATION_FAILED, {
492
+ subscriptionId: subscription.subscriptionId,
493
+ userId: subscription.userId,
494
+ reason: 'health_check_404',
495
+ error: recreateError instanceof Error ? recreateError.message : 'Unknown error',
496
+ });
497
+ }
498
+ continue;
499
+ }
500
+ verified++;
501
+ if (response.data.expirationDateTime) {
502
+ const expiration = new Date(response.data.expirationDateTime);
503
+ const twelveHoursFromNow = new Date();
504
+ twelveHoursFromNow.setHours(twelveHoursFromNow.getHours() + 12);
505
+ if (expiration < twelveHoursFromNow) {
506
+ this.logger.log(`[${correlationId}] Subscription ${subscription.subscriptionId} expires within 12h. Forcing renewal.`);
507
+ await this.renewWebhookSubscription(subscription.subscriptionId, subscription.userId);
508
+ }
509
+ }
510
+ if (subscription.lastNotificationAt) {
511
+ const twentyFourHoursAgo = new Date();
512
+ twentyFourHoursAgo.setHours(twentyFourHoursAgo.getHours() - 24);
513
+ if (subscription.lastNotificationAt < twentyFourHoursAgo) {
514
+ this.logger.warn(`[${correlationId}] Subscription ${subscription.subscriptionId} has not received notifications since ${subscription.lastNotificationAt.toISOString()}. Emitting LIFECYCLE_MISSED for delta sync.`);
515
+ staleDetected++;
516
+ this.eventEmitter.emit(event_types_enum_1.OutlookEventTypes.LIFECYCLE_MISSED, {
517
+ subscriptionId: subscription.subscriptionId,
518
+ userId: subscription.userId,
519
+ reason: 'health_check_stale',
520
+ });
521
+ }
522
+ }
523
+ }
524
+ catch (error) {
525
+ failed++;
526
+ this.logger.error(`[${correlationId}] Health check failed for subscription ${subscription.subscriptionId}:`, error);
527
+ }
528
+ }
529
+ this.logger.log(`[${correlationId}] Health check complete: ${String(verified)} verified, ${String(recreated)} recreated, ${String(staleDetected)} stale-detected, ${String(failed)} failed`);
530
+ }
531
+ catch (error) {
532
+ this.logger.error(`[${correlationId}] Subscription health check job failed:`, error);
533
+ }
534
+ }
161
535
  };
162
536
  exports.MicrosoftSubscriptionService = MicrosoftSubscriptionService;
537
+ __decorate([
538
+ (0, schedule_1.Cron)(schedule_1.CronExpression.EVERY_HOUR),
539
+ __metadata("design:type", Function),
540
+ __metadata("design:paramtypes", []),
541
+ __metadata("design:returntype", Promise)
542
+ ], MicrosoftSubscriptionService.prototype, "renewSubscriptions", null);
543
+ __decorate([
544
+ (0, schedule_1.Cron)('0 */6 * * *'),
545
+ __metadata("design:type", Function),
546
+ __metadata("design:paramtypes", []),
547
+ __metadata("design:returntype", Promise)
548
+ ], MicrosoftSubscriptionService.prototype, "verifySubscriptionHealth", null);
163
549
  exports.MicrosoftSubscriptionService = MicrosoftSubscriptionService = MicrosoftSubscriptionService_1 = __decorate([
164
- (0, common_1.Injectable)()
550
+ (0, common_1.Injectable)(),
551
+ __param(0, (0, common_1.Inject)((0, common_1.forwardRef)(() => microsoft_auth_service_1.MicrosoftAuthService))),
552
+ __param(3, (0, common_1.Inject)(constants_1.MICROSOFT_CONFIG)),
553
+ __param(4, (0, typeorm_1.InjectRepository)(microsoft_user_entity_1.MicrosoftUser)),
554
+ __metadata("design:paramtypes", [microsoft_auth_service_1.MicrosoftAuthService,
555
+ outlook_webhook_subscription_repository_1.OutlookWebhookSubscriptionRepository,
556
+ event_emitter_1.EventEmitter2, Object, typeorm_2.Repository,
557
+ user_id_converter_service_1.UserIdConverterService])
165
558
  ], MicrosoftSubscriptionService);
166
559
  //# sourceMappingURL=microsoft-subscription.service.js.map