@checkfirst/nestjs-outlook
Version:
An opinionated NestJS module for Microsoft Outlook integration that provides easy access to Microsoft Graph API for emails, calendars, and more.
165 lines • 10.1 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __asyncValues = (this && this.__asyncValues) || function (o) {
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
};
var RecurrenceService_1;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RecurrenceService = void 0;
const common_1 = require("@nestjs/common");
const calendar_service_1 = require("./calendar.service");
let RecurrenceService = RecurrenceService_1 = class RecurrenceService {
constructor(calendarService) {
this.calendarService = calendarService;
this.logger = new common_1.Logger(RecurrenceService_1.name);
}
processEvent(event) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
const eventType = (_a = event.type) !== null && _a !== void 0 ? _a : 'singleInstance';
const processed = {
externalId: (_b = event.id) !== null && _b !== void 0 ? _b : '',
eventType,
start: {
dateTime: (_d = (_c = event.start) === null || _c === void 0 ? void 0 : _c.dateTime) !== null && _d !== void 0 ? _d : '',
timeZone: (_f = (_e = event.start) === null || _e === void 0 ? void 0 : _e.timeZone) !== null && _f !== void 0 ? _f : '',
},
end: {
dateTime: (_h = (_g = event.end) === null || _g === void 0 ? void 0 : _g.dateTime) !== null && _h !== void 0 ? _h : '',
timeZone: (_k = (_j = event.end) === null || _j === void 0 ? void 0 : _j.timeZone) !== null && _k !== void 0 ? _k : '',
},
subject: (_l = event.subject) !== null && _l !== void 0 ? _l : '',
bodyPreview: (_m = event.bodyPreview) !== null && _m !== void 0 ? _m : '',
location: (_p = (_o = event.location) === null || _o === void 0 ? void 0 : _o.displayName) !== null && _p !== void 0 ? _p : undefined,
showAs: (_q = event.showAs) !== null && _q !== void 0 ? _q : undefined,
changeKey: (_r = event.changeKey) !== null && _r !== void 0 ? _r : undefined,
seriesMasterId: (_s = event.seriesMasterId) !== null && _s !== void 0 ? _s : undefined,
transactionId: (_t = event.transactionId) !== null && _t !== void 0 ? _t : undefined,
};
if (eventType === 'seriesMaster' && event.recurrence) {
processed.recurrenceRule = this.extractRecurrenceRule(event.recurrence);
}
if (eventType === 'exception' && event.originalStart) {
processed.originalStart = {
dateTime: event.originalStart,
timeZone: (_w = (_u = event.originalStartTimeZone) !== null && _u !== void 0 ? _u : (_v = event.start) === null || _v === void 0 ? void 0 : _v.timeZone) !== null && _w !== void 0 ? _w : '',
};
}
return processed;
}
async expandRecurringSeries(seriesMasterId, externalUserId, options) {
var _a, e_1, _b, _c;
this.logger.log(`[expandRecurringSeries] Expanding series ${seriesMasterId} for user ${externalUserId}`);
const masterEvents = await this.calendarService.getEventsBatch([seriesMasterId], externalUserId);
if (masterEvents.length === 0) {
throw new Error(`Series master ${seriesMasterId} not found in Outlook for user ${externalUserId}`);
}
const seriesMaster = this.processEvent(masterEvents[0]);
const expansionWindow = this.calculateExpansionWindow(seriesMaster.recurrenceRule, options === null || options === void 0 ? void 0 : options.existingWindowEnd);
this.logger.log(`[expandRecurringSeries] Window: ${expansionWindow.startDate.toISOString()} → ${expansionWindow.endDate.toISOString()}`);
const instances = [];
try {
for (var _d = true, _e = __asyncValues(this.calendarService.getRecurringEventInstances(seriesMasterId, externalUserId, {
startDate: expansionWindow.startDate,
endDate: expansionWindow.endDate,
batchSize: 100,
})), _f; _f = await _e.next(), _a = _f.done, !_a; _d = true) {
_c = _f.value;
_d = false;
const batch = _c;
for (const event of batch) {
instances.push(this.processEvent(event));
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (!_d && !_a && (_b = _e.return)) await _b.call(_e);
}
finally { if (e_1) throw e_1.error; }
}
this.logger.log(`[expandRecurringSeries] Fetched ${instances.length} instances for series ${seriesMasterId}`);
const staleExternalIds = (options === null || options === void 0 ? void 0 : options.existingExternalIds)
? this.detectStaleOccurrences(instances.map((i) => i.externalId), options.existingExternalIds)
: [];
if (staleExternalIds.length > 0) {
this.logger.log(`[expandRecurringSeries] Detected ${staleExternalIds.length} stale occurrences`);
}
return {
seriesMaster,
instances,
expansionWindow,
staleExternalIds,
};
}
calculateExpansionWindow(recurrenceRule, existingWindowEnd) {
const now = new Date();
const startDate = new Date(now);
startDate.setMonth(startDate.getMonth() - 1);
let endDate;
if ((recurrenceRule === null || recurrenceRule === void 0 ? void 0 : recurrenceRule.range.type) === 'endDate' &&
recurrenceRule.range.endDate) {
const seriesEnd = new Date(recurrenceRule.range.endDate);
const maxEnd = new Date(now);
maxEnd.setFullYear(maxEnd.getFullYear() + 5);
endDate = seriesEnd < maxEnd ? seriesEnd : maxEnd;
}
else if (existingWindowEnd) {
endDate = new Date(existingWindowEnd);
endDate.setMonth(endDate.getMonth() + 6);
}
else {
endDate = new Date(now);
endDate.setMonth(endDate.getMonth() + 6);
}
return { startDate, endDate };
}
detectStaleOccurrences(fetchedExternalIds, existingExternalIds) {
const fetchedSet = new Set(fetchedExternalIds);
return existingExternalIds.filter((id) => !fetchedSet.has(id));
}
isSeriesMaster(event) {
return event.type === 'seriesMaster' || event.recurrence != null;
}
extractRecurrenceRule(recurrence) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
const pattern = recurrence.pattern;
const range = recurrence.range;
return {
pattern: {
type: (_a = pattern === null || pattern === void 0 ? void 0 : pattern.type) !== null && _a !== void 0 ? _a : 'daily',
interval: (_b = pattern === null || pattern === void 0 ? void 0 : pattern.interval) !== null && _b !== void 0 ? _b : 1,
daysOfWeek: (_c = pattern === null || pattern === void 0 ? void 0 : pattern.daysOfWeek) !== null && _c !== void 0 ? _c : undefined,
dayOfMonth: (_d = pattern === null || pattern === void 0 ? void 0 : pattern.dayOfMonth) !== null && _d !== void 0 ? _d : undefined,
month: (_e = pattern === null || pattern === void 0 ? void 0 : pattern.month) !== null && _e !== void 0 ? _e : undefined,
firstDayOfWeek: (_f = pattern === null || pattern === void 0 ? void 0 : pattern.firstDayOfWeek) !== null && _f !== void 0 ? _f : undefined,
index: (_g = pattern === null || pattern === void 0 ? void 0 : pattern.index) !== null && _g !== void 0 ? _g : undefined,
},
range: {
type: (_h = range === null || range === void 0 ? void 0 : range.type) !== null && _h !== void 0 ? _h : 'noEnd',
startDate: (_j = range === null || range === void 0 ? void 0 : range.startDate) !== null && _j !== void 0 ? _j : '',
endDate: (_k = range === null || range === void 0 ? void 0 : range.endDate) !== null && _k !== void 0 ? _k : undefined,
numberOfOccurrences: (_l = range === null || range === void 0 ? void 0 : range.numberOfOccurrences) !== null && _l !== void 0 ? _l : undefined,
recurrenceTimeZone: (_m = range === null || range === void 0 ? void 0 : range.recurrenceTimeZone) !== null && _m !== void 0 ? _m : undefined,
},
};
}
};
exports.RecurrenceService = RecurrenceService;
exports.RecurrenceService = RecurrenceService = RecurrenceService_1 = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [calendar_service_1.CalendarService])
], RecurrenceService);
//# sourceMappingURL=recurrence.service.js.map