@dv4resi/dvss-backend-module-calendar-im 0.0.9 → 0.0.11
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.
- package/dist/index.d.ts +6 -2
- package/dist/index.js +106 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1750,10 +1750,10 @@ interface IEventSyncMetadata {
|
|
|
1750
1750
|
createdBy?: 'DVSS' | 'PROVIDER';
|
|
1751
1751
|
syncVersion?: number;
|
|
1752
1752
|
lastSyncTimestamp?: string;
|
|
1753
|
-
|
|
1753
|
+
organizerEventId?: string;
|
|
1754
1754
|
syncType?: 'SINGLE' | 'RECURRING_SERIES' | 'CUSTOM_DATES';
|
|
1755
1755
|
externalSeriesId?: string;
|
|
1756
|
-
|
|
1756
|
+
organizerEventIds?: {
|
|
1757
1757
|
date: string;
|
|
1758
1758
|
eventId: string;
|
|
1759
1759
|
}[];
|
|
@@ -1835,6 +1835,8 @@ interface IBookingEventInstance {
|
|
|
1835
1835
|
startDateLabel: string;
|
|
1836
1836
|
seriesId?: string;
|
|
1837
1837
|
iCalUId?: string;
|
|
1838
|
+
uid?: string;
|
|
1839
|
+
instanceKind?: EVENT_INSTANCE_KIND;
|
|
1838
1840
|
transactionId?: string;
|
|
1839
1841
|
subject?: string;
|
|
1840
1842
|
}
|
|
@@ -2423,6 +2425,7 @@ interface IMicrosoftGraphEvent {
|
|
|
2423
2425
|
seriesMasterId?: string;
|
|
2424
2426
|
transactionId?: string;
|
|
2425
2427
|
iCalUId?: string;
|
|
2428
|
+
uid?: string;
|
|
2426
2429
|
recurrence?: IMicrosoftGraphRecurrence;
|
|
2427
2430
|
attendees?: IMicrosoftGraphAttendee[];
|
|
2428
2431
|
organizer?: {
|
|
@@ -2565,6 +2568,7 @@ declare class MicrosoftCalendarBookingService extends BaseCalendarBookingManagem
|
|
|
2565
2568
|
private deleteGraphEvent;
|
|
2566
2569
|
private resolveSkipDatesIfAny;
|
|
2567
2570
|
private findOccurrenceInstanceId;
|
|
2571
|
+
private listAllEvents;
|
|
2568
2572
|
private pickMailbox;
|
|
2569
2573
|
private organizerUserMailbox;
|
|
2570
2574
|
private assertMailbox;
|
package/dist/index.js
CHANGED
|
@@ -4023,18 +4023,25 @@ function scheduleToGraphRecurrence(schedule, window) {
|
|
|
4023
4023
|
}
|
|
4024
4024
|
__name(scheduleToGraphRecurrence, "scheduleToGraphRecurrence");
|
|
4025
4025
|
function graphEventToRef(graph, options) {
|
|
4026
|
-
|
|
4026
|
+
const result = {
|
|
4027
4027
|
id: graph.id,
|
|
4028
4028
|
seriesId: graph.seriesMasterId,
|
|
4029
4029
|
instanceKind: graph.type ? GRAPH_TYPE_TO_INSTANCE_KIND[graph.type] : void 0,
|
|
4030
4030
|
syncMetadata: omitUndefined({
|
|
4031
4031
|
...options?.syncMetadata,
|
|
4032
|
-
|
|
4032
|
+
organizerEventId: graph.id ?? options?.syncMetadata?.organizerEventId,
|
|
4033
4033
|
organizerUserEmail: options?.organizerUserEmail ?? options?.syncMetadata?.organizerUserEmail,
|
|
4034
4034
|
resourceId: options?.resourceId ?? options?.syncMetadata?.resourceId,
|
|
4035
4035
|
excludedDateResults: options?.excludedDateResults ?? options?.syncMetadata?.excludedDateResults
|
|
4036
4036
|
})
|
|
4037
4037
|
};
|
|
4038
|
+
if (graph.iCalUId !== void 0) {
|
|
4039
|
+
result.iCalUId = graph.iCalUId;
|
|
4040
|
+
result.providerPayload = {
|
|
4041
|
+
iCalUId: graph.iCalUId
|
|
4042
|
+
};
|
|
4043
|
+
}
|
|
4044
|
+
return result;
|
|
4038
4045
|
}
|
|
4039
4046
|
__name(graphEventToRef, "graphEventToRef");
|
|
4040
4047
|
function graphEventsToInstances(response) {
|
|
@@ -4043,11 +4050,43 @@ function graphEventsToInstances(response) {
|
|
|
4043
4050
|
startDateLabel: graph.start.dateTime.slice(0, 10),
|
|
4044
4051
|
seriesId: graph.seriesMasterId,
|
|
4045
4052
|
iCalUId: graph.iCalUId,
|
|
4053
|
+
uid: graph.uid,
|
|
4054
|
+
instanceKind: graph.type ? GRAPH_TYPE_TO_INSTANCE_KIND[graph.type] : void 0,
|
|
4046
4055
|
transactionId: graph.transactionId,
|
|
4047
4056
|
subject: graph.subject
|
|
4048
4057
|
}));
|
|
4049
4058
|
}
|
|
4050
4059
|
__name(graphEventsToInstances, "graphEventsToInstances");
|
|
4060
|
+
function toGraphWindowDateTime(dateLabel, timeLabel, timeZone) {
|
|
4061
|
+
const local = `${dateLabel}T${timeLabel}`;
|
|
4062
|
+
const offset = timeZone ? timeZoneOffset(local, timeZone) : void 0;
|
|
4063
|
+
return offset ? `${local}${offset}` : local;
|
|
4064
|
+
}
|
|
4065
|
+
__name(toGraphWindowDateTime, "toGraphWindowDateTime");
|
|
4066
|
+
function timeZoneOffset(local, timeZone) {
|
|
4067
|
+
try {
|
|
4068
|
+
const zoneName = new Intl.DateTimeFormat("en-US", {
|
|
4069
|
+
timeZone,
|
|
4070
|
+
timeZoneName: "longOffset"
|
|
4071
|
+
}).formatToParts(/* @__PURE__ */ new Date(`${local}Z`)).find((part) => part.type === "timeZoneName")?.value;
|
|
4072
|
+
const match = zoneName ? /^GMT(?<offset>[+-]\d{2}:\d{2})?$/.exec(zoneName) : void 0;
|
|
4073
|
+
if (!match) {
|
|
4074
|
+
return void 0;
|
|
4075
|
+
}
|
|
4076
|
+
return match.groups?.offset ?? "+00:00";
|
|
4077
|
+
} catch {
|
|
4078
|
+
return void 0;
|
|
4079
|
+
}
|
|
4080
|
+
}
|
|
4081
|
+
__name(timeZoneOffset, "timeZoneOffset");
|
|
4082
|
+
function toGraphRelativeUrl(link) {
|
|
4083
|
+
if (!link) {
|
|
4084
|
+
return void 0;
|
|
4085
|
+
}
|
|
4086
|
+
const parsed = new URL(link);
|
|
4087
|
+
return `${parsed.pathname.replace(/^\/(?:v1\.0|beta)(?=\/)/, "")}${parsed.search}`;
|
|
4088
|
+
}
|
|
4089
|
+
__name(toGraphRelativeUrl, "toGraphRelativeUrl");
|
|
4051
4090
|
function toGraphDateTime(dateLabel, timeLabel, isFullDay) {
|
|
4052
4091
|
if (isFullDay || !timeLabel) {
|
|
4053
4092
|
return `${dateLabel}T00:00:00`;
|
|
@@ -4077,6 +4116,10 @@ function _ts_metadata23(k, v) {
|
|
|
4077
4116
|
}
|
|
4078
4117
|
__name(_ts_metadata23, "_ts_metadata");
|
|
4079
4118
|
var GRAPH_BATCH_MAX_SIZE = 20;
|
|
4119
|
+
var GRAPH_LIST_PAGE_SIZE = 100;
|
|
4120
|
+
var GRAPH_LIST_MAX_PAGES = 50;
|
|
4121
|
+
var WINDOW_START_TIME = "00:00:00";
|
|
4122
|
+
var WINDOW_END_TIME = "23:59:59";
|
|
4080
4123
|
exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService extends BaseCalendarBookingManagement {
|
|
4081
4124
|
static {
|
|
4082
4125
|
__name(this, "MicrosoftCalendarBookingService");
|
|
@@ -4105,7 +4148,7 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4105
4148
|
targetMailbox: mailboxEmail
|
|
4106
4149
|
})
|
|
4107
4150
|
}, integration, loggedInUserId);
|
|
4108
|
-
const excludedDateResults = await this.resolveSkipDatesIfAny(graphEvent.id, request.event.schedule?.skipDates, mailboxEmail, this.organizerUserMailbox(organizerEmail), integration, loggedInUserId);
|
|
4151
|
+
const excludedDateResults = await this.resolveSkipDatesIfAny(graphEvent.id, request.event.schedule?.skipDates, mailboxEmail, this.organizerUserMailbox(organizerEmail), request.event.timeZone, integration, loggedInUserId);
|
|
4109
4152
|
const ref = graphEventToRef(graphEvent, {
|
|
4110
4153
|
organizerUserEmail: this.organizerUserMailbox(organizerEmail),
|
|
4111
4154
|
resourceId: roomEmail,
|
|
@@ -4139,7 +4182,7 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4139
4182
|
targetMailbox: mailboxEmail
|
|
4140
4183
|
})
|
|
4141
4184
|
}, integration, loggedInUserId);
|
|
4142
|
-
const excludedDateResults = await this.resolveSkipDatesIfAny(graphEvent.id ?? request.eventId, request.event.schedule?.skipDates, mailboxEmail, this.organizerUserMailbox(request.organizerUserEmail), integration, loggedInUserId);
|
|
4185
|
+
const excludedDateResults = await this.resolveSkipDatesIfAny(graphEvent.id ?? request.eventId, request.event.schedule?.skipDates, mailboxEmail, this.organizerUserMailbox(request.organizerUserEmail), request.event.timeZone, integration, loggedInUserId);
|
|
4143
4186
|
const ref = graphEventToRef(graphEvent, {
|
|
4144
4187
|
organizerUserEmail: this.organizerUserMailbox(request.organizerUserEmail),
|
|
4145
4188
|
resourceId: request.resourceEmail,
|
|
@@ -4261,18 +4304,15 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4261
4304
|
try {
|
|
4262
4305
|
const mailboxEmail = this.pickMailbox(request.organizerUserEmail, request.resourceEmail);
|
|
4263
4306
|
this.assertMailbox(mailboxEmail);
|
|
4264
|
-
const
|
|
4265
|
-
const url = hasWindow ? MICROSOFT_GRAPH_PATHS.userCalendarView(mailboxEmail, `${request.startDateLabel}T00:00:00`, `${request.endDateLabel}T23:59:59`) : MICROSOFT_GRAPH_PATHS.userCalendarEvents(mailboxEmail);
|
|
4307
|
+
const url = request.startDateLabel && request.endDateLabel ? MICROSOFT_GRAPH_PATHS.userCalendarView(mailboxEmail, toGraphWindowDateTime(request.startDateLabel, WINDOW_START_TIME, request.timeZone), toGraphWindowDateTime(request.endDateLabel, WINDOW_END_TIME, request.timeZone)) : MICROSOFT_GRAPH_PATHS.userCalendarEvents(mailboxEmail);
|
|
4266
4308
|
this.logger.info(loggedInUserId, this.getEvents.name, this.fileName, "List Microsoft Graph calendar events", {
|
|
4267
4309
|
mailboxEmail,
|
|
4268
4310
|
path: url,
|
|
4269
|
-
hasTimeWindow:
|
|
4311
|
+
hasTimeWindow: Boolean(request.startDateLabel && request.endDateLabel)
|
|
4312
|
+
});
|
|
4313
|
+
const events = graphEventsToInstances({
|
|
4314
|
+
value: await this.listAllEvents(url, request.timeZone, integration, loggedInUserId)
|
|
4270
4315
|
});
|
|
4271
|
-
const response = await this.microsoftApiClient.apiCall({
|
|
4272
|
-
apiMethod: HTTP_METHOD.GET,
|
|
4273
|
-
url
|
|
4274
|
-
}, integration, loggedInUserId);
|
|
4275
|
-
const events = graphEventsToInstances(response);
|
|
4276
4316
|
this.logger.info(loggedInUserId, this.getEvents.name, this.fileName, "Listed Microsoft Graph calendar events", {
|
|
4277
4317
|
mailboxEmail,
|
|
4278
4318
|
count: events.length
|
|
@@ -4295,17 +4335,15 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4295
4335
|
const mailboxEmail = this.pickMailbox(request.organizerUserEmail, request.resourceEmail);
|
|
4296
4336
|
this.assertMailbox(mailboxEmail);
|
|
4297
4337
|
this.assertEventId(request.seriesEventId);
|
|
4298
|
-
const url = MICROSOFT_GRAPH_PATHS.userCalendarEventInstances(mailboxEmail, request.seriesEventId,
|
|
4338
|
+
const url = MICROSOFT_GRAPH_PATHS.userCalendarEventInstances(mailboxEmail, request.seriesEventId, toGraphWindowDateTime(request.startDateLabel, WINDOW_START_TIME, request.timeZone), toGraphWindowDateTime(request.endDateLabel, WINDOW_END_TIME, request.timeZone));
|
|
4299
4339
|
this.logger.info(loggedInUserId, this.getEventInstances.name, this.fileName, "List Microsoft Graph series instances", {
|
|
4300
4340
|
mailboxEmail,
|
|
4301
4341
|
seriesEventId: request.seriesEventId,
|
|
4302
4342
|
path: url
|
|
4303
4343
|
});
|
|
4304
|
-
const
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
}, integration, loggedInUserId);
|
|
4308
|
-
const events = graphEventsToInstances(response);
|
|
4344
|
+
const events = graphEventsToInstances({
|
|
4345
|
+
value: await this.listAllEvents(url, request.timeZone, integration, loggedInUserId)
|
|
4346
|
+
});
|
|
4309
4347
|
this.logger.info(loggedInUserId, this.getEventInstances.name, this.fileName, "Listed Microsoft Graph series instances", {
|
|
4310
4348
|
mailboxEmail,
|
|
4311
4349
|
seriesEventId: request.seriesEventId,
|
|
@@ -4410,14 +4448,14 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4410
4448
|
* created/updated and cancels it via the existing DELETE path. Best-effort per date — a
|
|
4411
4449
|
* date that can't be resolved is reported `excluded: false`, not thrown.
|
|
4412
4450
|
*/
|
|
4413
|
-
async resolveSkipDatesIfAny(seriesId, dates, mailboxEmail, organizerUserEmail, integration, loggedInUserId) {
|
|
4451
|
+
async resolveSkipDatesIfAny(seriesId, dates, mailboxEmail, organizerUserEmail, timeZone, integration, loggedInUserId) {
|
|
4414
4452
|
if (!dates?.length) {
|
|
4415
4453
|
return void 0;
|
|
4416
4454
|
}
|
|
4417
4455
|
const results = [];
|
|
4418
4456
|
for (const date of dates) {
|
|
4419
4457
|
try {
|
|
4420
|
-
const instanceId = await this.findOccurrenceInstanceId(seriesId, date, mailboxEmail, integration, loggedInUserId);
|
|
4458
|
+
const instanceId = await this.findOccurrenceInstanceId(seriesId, date, mailboxEmail, timeZone, integration, loggedInUserId);
|
|
4421
4459
|
if (!instanceId) {
|
|
4422
4460
|
this.logger.warn(loggedInUserId, this.resolveSkipDatesIfAny.name, this.fileName, "Could not resolve skip-date occurrence", {
|
|
4423
4461
|
seriesId,
|
|
@@ -4455,12 +4493,54 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4455
4493
|
}
|
|
4456
4494
|
return results;
|
|
4457
4495
|
}
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4496
|
+
/**
|
|
4497
|
+
* The series' own instance on `date`. Lists the series' instances rather than the mailbox's
|
|
4498
|
+
* whole calendarView, so a busy day can't push the occurrence off the returned page.
|
|
4499
|
+
*/
|
|
4500
|
+
async findOccurrenceInstanceId(seriesId, date, mailboxEmail, timeZone, integration, loggedInUserId) {
|
|
4501
|
+
if (!seriesId) {
|
|
4502
|
+
return void 0;
|
|
4503
|
+
}
|
|
4504
|
+
const instances = await this.listAllEvents(MICROSOFT_GRAPH_PATHS.userCalendarEventInstances(mailboxEmail, seriesId, toGraphWindowDateTime(date, WINDOW_START_TIME, timeZone), toGraphWindowDateTime(date, WINDOW_END_TIME, timeZone)), timeZone, integration, loggedInUserId);
|
|
4505
|
+
return instances.find((occurrence) => occurrence.seriesMasterId === seriesId)?.id;
|
|
4506
|
+
}
|
|
4507
|
+
/**
|
|
4508
|
+
* GETs a Graph event listing and follows `@odata.nextLink` until the last page.
|
|
4509
|
+
*
|
|
4510
|
+
* Graph pages calendarView/instances listings (10 events by default), so reading only the first
|
|
4511
|
+
* page silently drops every event past it — on a busy organizer mailbox that is the very series
|
|
4512
|
+
* being looked up. `Prefer: outlook.timezone` makes Graph return `start`/`end` in the property's
|
|
4513
|
+
* zone, so the date labels cut from them are local dates rather than UTC ones.
|
|
4514
|
+
* @param url - The first page's path (calendarView / instances / events)
|
|
4515
|
+
* @param timeZone - IANA zone to return event times in; UTC when absent
|
|
4516
|
+
*/
|
|
4517
|
+
async listAllEvents(url, timeZone, integration, loggedInUserId) {
|
|
4518
|
+
const headers = timeZone ? {
|
|
4519
|
+
Prefer: `outlook.timezone="${timeZone}"`
|
|
4520
|
+
} : void 0;
|
|
4521
|
+
const events = [];
|
|
4522
|
+
let nextUrl = `${url}${url.includes("?") ? "&" : "?"}$top=${GRAPH_LIST_PAGE_SIZE}`;
|
|
4523
|
+
let pageCount = 0;
|
|
4524
|
+
while (nextUrl && pageCount < GRAPH_LIST_MAX_PAGES) {
|
|
4525
|
+
const response = await this.microsoftApiClient.apiCall({
|
|
4526
|
+
apiMethod: HTTP_METHOD.GET,
|
|
4527
|
+
url: nextUrl,
|
|
4528
|
+
...headers ? {
|
|
4529
|
+
headers
|
|
4530
|
+
} : {}
|
|
4531
|
+
}, integration, loggedInUserId);
|
|
4532
|
+
events.push(...response.value ?? []);
|
|
4533
|
+
nextUrl = toGraphRelativeUrl(response["@odata.nextLink"]);
|
|
4534
|
+
pageCount += 1;
|
|
4535
|
+
}
|
|
4536
|
+
if (nextUrl) {
|
|
4537
|
+
this.logger.warn(loggedInUserId, this.listAllEvents.name, this.fileName, "Stopped following Graph pages at the page limit; listing truncated", {
|
|
4538
|
+
url,
|
|
4539
|
+
pageCount,
|
|
4540
|
+
eventCount: events.length
|
|
4541
|
+
});
|
|
4542
|
+
}
|
|
4543
|
+
return events;
|
|
4464
4544
|
}
|
|
4465
4545
|
/** Mailbox the Graph call targets: the organizing user if known, else the room. */
|
|
4466
4546
|
pickMailbox(organizerEmail, roomEmail) {
|