@dv4resi/dvss-backend-module-calendar-im 0.0.10 → 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 +4 -0
- package/dist/index.js +97 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -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
|
@@ -4050,11 +4050,43 @@ function graphEventsToInstances(response) {
|
|
|
4050
4050
|
startDateLabel: graph.start.dateTime.slice(0, 10),
|
|
4051
4051
|
seriesId: graph.seriesMasterId,
|
|
4052
4052
|
iCalUId: graph.iCalUId,
|
|
4053
|
+
uid: graph.uid,
|
|
4054
|
+
instanceKind: graph.type ? GRAPH_TYPE_TO_INSTANCE_KIND[graph.type] : void 0,
|
|
4053
4055
|
transactionId: graph.transactionId,
|
|
4054
4056
|
subject: graph.subject
|
|
4055
4057
|
}));
|
|
4056
4058
|
}
|
|
4057
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");
|
|
4058
4090
|
function toGraphDateTime(dateLabel, timeLabel, isFullDay) {
|
|
4059
4091
|
if (isFullDay || !timeLabel) {
|
|
4060
4092
|
return `${dateLabel}T00:00:00`;
|
|
@@ -4084,6 +4116,10 @@ function _ts_metadata23(k, v) {
|
|
|
4084
4116
|
}
|
|
4085
4117
|
__name(_ts_metadata23, "_ts_metadata");
|
|
4086
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";
|
|
4087
4123
|
exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService extends BaseCalendarBookingManagement {
|
|
4088
4124
|
static {
|
|
4089
4125
|
__name(this, "MicrosoftCalendarBookingService");
|
|
@@ -4112,7 +4148,7 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4112
4148
|
targetMailbox: mailboxEmail
|
|
4113
4149
|
})
|
|
4114
4150
|
}, integration, loggedInUserId);
|
|
4115
|
-
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);
|
|
4116
4152
|
const ref = graphEventToRef(graphEvent, {
|
|
4117
4153
|
organizerUserEmail: this.organizerUserMailbox(organizerEmail),
|
|
4118
4154
|
resourceId: roomEmail,
|
|
@@ -4146,7 +4182,7 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4146
4182
|
targetMailbox: mailboxEmail
|
|
4147
4183
|
})
|
|
4148
4184
|
}, integration, loggedInUserId);
|
|
4149
|
-
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);
|
|
4150
4186
|
const ref = graphEventToRef(graphEvent, {
|
|
4151
4187
|
organizerUserEmail: this.organizerUserMailbox(request.organizerUserEmail),
|
|
4152
4188
|
resourceId: request.resourceEmail,
|
|
@@ -4268,18 +4304,15 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4268
4304
|
try {
|
|
4269
4305
|
const mailboxEmail = this.pickMailbox(request.organizerUserEmail, request.resourceEmail);
|
|
4270
4306
|
this.assertMailbox(mailboxEmail);
|
|
4271
|
-
const
|
|
4272
|
-
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);
|
|
4273
4308
|
this.logger.info(loggedInUserId, this.getEvents.name, this.fileName, "List Microsoft Graph calendar events", {
|
|
4274
4309
|
mailboxEmail,
|
|
4275
4310
|
path: url,
|
|
4276
|
-
hasTimeWindow:
|
|
4311
|
+
hasTimeWindow: Boolean(request.startDateLabel && request.endDateLabel)
|
|
4312
|
+
});
|
|
4313
|
+
const events = graphEventsToInstances({
|
|
4314
|
+
value: await this.listAllEvents(url, request.timeZone, integration, loggedInUserId)
|
|
4277
4315
|
});
|
|
4278
|
-
const response = await this.microsoftApiClient.apiCall({
|
|
4279
|
-
apiMethod: HTTP_METHOD.GET,
|
|
4280
|
-
url
|
|
4281
|
-
}, integration, loggedInUserId);
|
|
4282
|
-
const events = graphEventsToInstances(response);
|
|
4283
4316
|
this.logger.info(loggedInUserId, this.getEvents.name, this.fileName, "Listed Microsoft Graph calendar events", {
|
|
4284
4317
|
mailboxEmail,
|
|
4285
4318
|
count: events.length
|
|
@@ -4302,17 +4335,15 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4302
4335
|
const mailboxEmail = this.pickMailbox(request.organizerUserEmail, request.resourceEmail);
|
|
4303
4336
|
this.assertMailbox(mailboxEmail);
|
|
4304
4337
|
this.assertEventId(request.seriesEventId);
|
|
4305
|
-
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));
|
|
4306
4339
|
this.logger.info(loggedInUserId, this.getEventInstances.name, this.fileName, "List Microsoft Graph series instances", {
|
|
4307
4340
|
mailboxEmail,
|
|
4308
4341
|
seriesEventId: request.seriesEventId,
|
|
4309
4342
|
path: url
|
|
4310
4343
|
});
|
|
4311
|
-
const
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
}, integration, loggedInUserId);
|
|
4315
|
-
const events = graphEventsToInstances(response);
|
|
4344
|
+
const events = graphEventsToInstances({
|
|
4345
|
+
value: await this.listAllEvents(url, request.timeZone, integration, loggedInUserId)
|
|
4346
|
+
});
|
|
4316
4347
|
this.logger.info(loggedInUserId, this.getEventInstances.name, this.fileName, "Listed Microsoft Graph series instances", {
|
|
4317
4348
|
mailboxEmail,
|
|
4318
4349
|
seriesEventId: request.seriesEventId,
|
|
@@ -4417,14 +4448,14 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4417
4448
|
* created/updated and cancels it via the existing DELETE path. Best-effort per date — a
|
|
4418
4449
|
* date that can't be resolved is reported `excluded: false`, not thrown.
|
|
4419
4450
|
*/
|
|
4420
|
-
async resolveSkipDatesIfAny(seriesId, dates, mailboxEmail, organizerUserEmail, integration, loggedInUserId) {
|
|
4451
|
+
async resolveSkipDatesIfAny(seriesId, dates, mailboxEmail, organizerUserEmail, timeZone, integration, loggedInUserId) {
|
|
4421
4452
|
if (!dates?.length) {
|
|
4422
4453
|
return void 0;
|
|
4423
4454
|
}
|
|
4424
4455
|
const results = [];
|
|
4425
4456
|
for (const date of dates) {
|
|
4426
4457
|
try {
|
|
4427
|
-
const instanceId = await this.findOccurrenceInstanceId(seriesId, date, mailboxEmail, integration, loggedInUserId);
|
|
4458
|
+
const instanceId = await this.findOccurrenceInstanceId(seriesId, date, mailboxEmail, timeZone, integration, loggedInUserId);
|
|
4428
4459
|
if (!instanceId) {
|
|
4429
4460
|
this.logger.warn(loggedInUserId, this.resolveSkipDatesIfAny.name, this.fileName, "Could not resolve skip-date occurrence", {
|
|
4430
4461
|
seriesId,
|
|
@@ -4462,12 +4493,54 @@ exports.MicrosoftCalendarBookingService = class MicrosoftCalendarBookingService
|
|
|
4462
4493
|
}
|
|
4463
4494
|
return results;
|
|
4464
4495
|
}
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
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;
|
|
4471
4544
|
}
|
|
4472
4545
|
/** Mailbox the Graph call targets: the organizing user if known, else the room. */
|
|
4473
4546
|
pickMailbox(organizerEmail, roomEmail) {
|