@rapidmx/activesync-plugin 1.0.0-beta.2 → 1.0.0-beta.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.
- package/README.md +4 -4
- package/dist/lib/BaseDeviceSyncStateRoute.js +32 -0
- package/dist/lib/BaseDeviceSyncStateRoute.js.map +1 -1
- package/dist/lib/BaseEasRoute.js +91 -15
- package/dist/lib/BaseEasRoute.js.map +1 -1
- package/dist/lib/EasAuditLog.js +56 -0
- package/dist/lib/EasAuditLog.js.map +1 -0
- package/dist/lib/EasCollectionLease.js +199 -0
- package/dist/lib/EasCollectionLease.js.map +1 -0
- package/dist/lib/EasCollectionStore.js +102 -0
- package/dist/lib/EasCollectionStore.js.map +1 -0
- package/dist/lib/EasCollectionSync.js +294 -0
- package/dist/lib/EasCollectionSync.js.map +1 -0
- package/dist/lib/EasSyncKeyUtils.js +125 -62
- package/dist/lib/EasSyncKeyUtils.js.map +1 -1
- package/dist/lib/MessageMoveRules.js +100 -0
- package/dist/lib/MessageMoveRules.js.map +1 -0
- package/dist/lib/MimeHeaderUtils.js +395 -0
- package/dist/lib/MimeHeaderUtils.js.map +1 -0
- package/dist/lib/RegexPatternUtils.js +30 -0
- package/dist/lib/RegexPatternUtils.js.map +1 -0
- package/dist/lib/RestapiCompat.js +41 -0
- package/dist/lib/RestapiCompat.js.map +1 -0
- package/dist/lib/adapters/CalendarSyncAdapter.js +142 -33
- package/dist/lib/adapters/CalendarSyncAdapter.js.map +1 -1
- package/dist/lib/adapters/EmailSyncAdapter.js +114 -27
- package/dist/lib/adapters/EmailSyncAdapter.js.map +1 -1
- package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js +2 -1
- package/dist/lib/adapters/mongo/EmailSyncAdapterMongo.js.map +1 -1
- package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js +2 -1
- package/dist/lib/adapters/sql/EmailSyncAdapterSQL.js.map +1 -1
- package/dist/lib/codec/WbxmlDecoder.js +86 -34
- package/dist/lib/codec/WbxmlDecoder.js.map +1 -1
- package/dist/lib/codec/WbxmlEncoder.js +103 -22
- package/dist/lib/codec/WbxmlEncoder.js.map +1 -1
- package/dist/lib/commands/ComposeMailCommand.js +105 -31
- package/dist/lib/commands/ComposeMailCommand.js.map +1 -1
- package/dist/lib/commands/FolderSyncCommand.js +67 -27
- package/dist/lib/commands/FolderSyncCommand.js.map +1 -1
- package/dist/lib/commands/GetItemEstimateCommand.js +80 -59
- package/dist/lib/commands/GetItemEstimateCommand.js.map +1 -1
- package/dist/lib/commands/ItemOperationsCommand.js +219 -56
- package/dist/lib/commands/ItemOperationsCommand.js.map +1 -1
- package/dist/lib/commands/MeetingResponseCommand.js +212 -53
- package/dist/lib/commands/MeetingResponseCommand.js.map +1 -1
- package/dist/lib/commands/MoveItemsCommand.js +54 -21
- package/dist/lib/commands/MoveItemsCommand.js.map +1 -1
- package/dist/lib/commands/PingCommand.js +288 -56
- package/dist/lib/commands/PingCommand.js.map +1 -1
- package/dist/lib/commands/ProvisionCommand.js +34 -17
- package/dist/lib/commands/ProvisionCommand.js.map +1 -1
- package/dist/lib/commands/ResolveRecipientsCommand.js +43 -5
- package/dist/lib/commands/ResolveRecipientsCommand.js.map +1 -1
- package/dist/lib/commands/SearchCommand.js +92 -17
- package/dist/lib/commands/SearchCommand.js.map +1 -1
- package/dist/lib/commands/SettingsCommand.js +2 -1
- package/dist/lib/commands/SettingsCommand.js.map +1 -1
- package/dist/lib/commands/SmartForwardCommand.js +2 -1
- package/dist/lib/commands/SmartForwardCommand.js.map +1 -1
- package/dist/lib/commands/SmartReplyCommand.js +2 -1
- package/dist/lib/commands/SmartReplyCommand.js.map +1 -1
- package/dist/lib/commands/SyncCommand.js +481 -244
- package/dist/lib/commands/SyncCommand.js.map +1 -1
- package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js +6 -1
- package/dist/lib/commands/mongo/GetItemEstimateCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js +3 -1
- package/dist/lib/commands/mongo/ItemOperationsCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js +2 -1
- package/dist/lib/commands/mongo/MeetingResponseCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/PingCommandMongo.js +23 -0
- package/dist/lib/commands/mongo/PingCommandMongo.js.map +1 -0
- package/dist/lib/commands/mongo/SearchCommandMongo.js +3 -1
- package/dist/lib/commands/mongo/SearchCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/SendMailCommandMongo.js +2 -1
- package/dist/lib/commands/mongo/SendMailCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/SmartForwardCommandMongo.js +2 -1
- package/dist/lib/commands/mongo/SmartForwardCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/SmartReplyCommandMongo.js +2 -1
- package/dist/lib/commands/mongo/SmartReplyCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/SyncCommandMongo.js +7 -1
- package/dist/lib/commands/mongo/SyncCommandMongo.js.map +1 -1
- package/dist/lib/commands/mongo/index.js +1 -0
- package/dist/lib/commands/mongo/index.js.map +1 -1
- package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js +6 -1
- package/dist/lib/commands/sql/GetItemEstimateCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/ItemOperationsCommandSQL.js +3 -1
- package/dist/lib/commands/sql/ItemOperationsCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/MeetingResponseCommandSQL.js +2 -1
- package/dist/lib/commands/sql/MeetingResponseCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/PingCommandSQL.js +23 -0
- package/dist/lib/commands/sql/PingCommandSQL.js.map +1 -0
- package/dist/lib/commands/sql/SearchCommandSQL.js +3 -1
- package/dist/lib/commands/sql/SearchCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/SendMailCommandSQL.js +2 -1
- package/dist/lib/commands/sql/SendMailCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/SmartForwardCommandSQL.js +2 -1
- package/dist/lib/commands/sql/SmartForwardCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/SmartReplyCommandSQL.js +2 -1
- package/dist/lib/commands/sql/SmartReplyCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/SyncCommandSQL.js +7 -1
- package/dist/lib/commands/sql/SyncCommandSQL.js.map +1 -1
- package/dist/lib/commands/sql/index.js +1 -0
- package/dist/lib/commands/sql/index.js.map +1 -1
- package/dist/lib/index.js +5 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/jobs/EasDeviceStateCleanupJob.js +44 -2
- package/dist/lib/jobs/EasDeviceStateCleanupJob.js.map +1 -1
- package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js +4 -0
- package/dist/lib/jobs/mongo/EasDeviceStateCleanupJobMongo.js.map +1 -1
- package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js +9 -0
- package/dist/lib/jobs/sql/EasDeviceStateCleanupJobSQL.js.map +1 -1
- package/dist/lib/models/EasCollectionChunk.js +2 -0
- package/dist/lib/models/EasCollectionChunk.js.map +1 -0
- package/dist/lib/models/EasCollectionState.js +2 -0
- package/dist/lib/models/EasCollectionState.js.map +1 -0
- package/dist/lib/models/mongo/DeviceSyncStateMongo.js +7 -0
- package/dist/lib/models/mongo/DeviceSyncStateMongo.js.map +1 -1
- package/dist/lib/models/mongo/EasCollectionChunkMongo.js +83 -0
- package/dist/lib/models/mongo/EasCollectionChunkMongo.js.map +1 -0
- package/dist/lib/models/mongo/EasCollectionStateMongo.js +162 -0
- package/dist/lib/models/mongo/EasCollectionStateMongo.js.map +1 -0
- package/dist/lib/models/sql/DeviceSyncStateSQL.js +7 -0
- package/dist/lib/models/sql/DeviceSyncStateSQL.js.map +1 -1
- package/dist/lib/models/sql/EasCollectionChunkSQL.js +83 -0
- package/dist/lib/models/sql/EasCollectionChunkSQL.js.map +1 -0
- package/dist/lib/models/sql/EasCollectionStateSQL.js +162 -0
- package/dist/lib/models/sql/EasCollectionStateSQL.js.map +1 -0
- package/dist/lib/mongo/EasRouteMongo.js +2 -2
- package/dist/lib/mongo/EasRouteMongo.js.map +1 -1
- package/dist/lib/mongo.js +2 -0
- package/dist/lib/mongo.js.map +1 -1
- package/dist/lib/sql/EasRouteSQL.js +2 -2
- package/dist/lib/sql/EasRouteSQL.js.map +1 -1
- package/dist/lib/sql.js +2 -0
- package/dist/lib/sql.js.map +1 -1
- package/dist/types/BaseDeviceSyncStateRoute.d.ts +10 -0
- package/dist/types/BaseEasRoute.d.ts +15 -4
- package/dist/types/EasAuditLog.d.ts +47 -0
- package/dist/types/EasCollectionLease.d.ts +60 -0
- package/dist/types/EasCollectionStore.d.ts +51 -0
- package/dist/types/EasCollectionSync.d.ts +96 -0
- package/dist/types/EasCommandHandler.d.ts +7 -4
- package/dist/types/EasSyncKeyUtils.d.ts +73 -42
- package/dist/types/MessageMoveRules.d.ts +45 -0
- package/dist/types/MimeHeaderUtils.d.ts +73 -0
- package/dist/types/RegexPatternUtils.d.ts +14 -0
- package/dist/types/RestapiCompat.d.ts +24 -0
- package/dist/types/adapters/CalendarSyncAdapter.d.ts +47 -18
- package/dist/types/adapters/EasCollectionSyncAdapter.d.ts +18 -2
- package/dist/types/adapters/EmailSyncAdapter.d.ts +24 -7
- package/dist/types/adapters/mongo/EmailSyncAdapterMongo.d.ts +1 -0
- package/dist/types/adapters/sql/EmailSyncAdapterSQL.d.ts +1 -0
- package/dist/types/codec/WbxmlDecoder.d.ts +39 -0
- package/dist/types/codec/WbxmlEncoder.d.ts +36 -1
- package/dist/types/commands/ComposeMailCommand.d.ts +33 -15
- package/dist/types/commands/FolderSyncCommand.d.ts +4 -1
- package/dist/types/commands/GetItemEstimateCommand.d.ts +20 -15
- package/dist/types/commands/ItemOperationsCommand.d.ts +29 -4
- package/dist/types/commands/MeetingResponseCommand.d.ts +52 -13
- package/dist/types/commands/MoveItemsCommand.d.ts +13 -3
- package/dist/types/commands/PingCommand.d.ts +72 -14
- package/dist/types/commands/ProvisionCommand.d.ts +16 -11
- package/dist/types/commands/ResolveRecipientsCommand.d.ts +4 -0
- package/dist/types/commands/SearchCommand.d.ts +13 -1
- package/dist/types/commands/SyncCommand.d.ts +102 -62
- package/dist/types/commands/mongo/GetItemEstimateCommandMongo.d.ts +3 -0
- package/dist/types/commands/mongo/ItemOperationsCommandMongo.d.ts +2 -0
- package/dist/types/commands/mongo/MeetingResponseCommandMongo.d.ts +1 -0
- package/dist/types/commands/mongo/PingCommandMongo.d.ts +8 -0
- package/dist/types/commands/mongo/SearchCommandMongo.d.ts +2 -0
- package/dist/types/commands/mongo/SendMailCommandMongo.d.ts +1 -0
- package/dist/types/commands/mongo/SmartForwardCommandMongo.d.ts +1 -0
- package/dist/types/commands/mongo/SmartReplyCommandMongo.d.ts +1 -0
- package/dist/types/commands/mongo/SyncCommandMongo.d.ts +4 -0
- package/dist/types/commands/mongo/index.d.ts +1 -0
- package/dist/types/commands/sql/GetItemEstimateCommandSQL.d.ts +3 -0
- package/dist/types/commands/sql/ItemOperationsCommandSQL.d.ts +2 -0
- package/dist/types/commands/sql/MeetingResponseCommandSQL.d.ts +1 -0
- package/dist/types/commands/sql/PingCommandSQL.d.ts +8 -0
- package/dist/types/commands/sql/SearchCommandSQL.d.ts +2 -0
- package/dist/types/commands/sql/SendMailCommandSQL.d.ts +1 -0
- package/dist/types/commands/sql/SmartForwardCommandSQL.d.ts +1 -0
- package/dist/types/commands/sql/SmartReplyCommandSQL.d.ts +1 -0
- package/dist/types/commands/sql/SyncCommandSQL.d.ts +4 -0
- package/dist/types/commands/sql/index.d.ts +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/jobs/EasDeviceStateCleanupJob.d.ts +15 -0
- package/dist/types/jobs/mongo/EasDeviceStateCleanupJobMongo.d.ts +2 -0
- package/dist/types/jobs/sql/EasDeviceStateCleanupJobSQL.d.ts +4 -0
- package/dist/types/models/DeviceSyncState.d.ts +13 -2
- package/dist/types/models/EasCollectionChunk.d.ts +20 -0
- package/dist/types/models/EasCollectionState.d.ts +79 -0
- package/dist/types/models/mongo/DeviceSyncStateMongo.d.ts +1 -0
- package/dist/types/models/mongo/EasCollectionChunkMongo.d.ts +16 -0
- package/dist/types/models/mongo/EasCollectionStateMongo.d.ts +27 -0
- package/dist/types/models/sql/DeviceSyncStateSQL.d.ts +1 -0
- package/dist/types/models/sql/EasCollectionChunkSQL.d.ts +16 -0
- package/dist/types/models/sql/EasCollectionStateSQL.d.ts +27 -0
- package/dist/types/mongo.d.ts +2 -0
- package/dist/types/sql.d.ts +2 -0
- package/package.json +267 -238
|
@@ -11,35 +11,67 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
12
12
|
// SPDX-License-Identifier: MPL-2.0
|
|
13
13
|
///////////////////////////////////////////////////////////////////////////////
|
|
14
|
+
import * as crypto from "crypto";
|
|
15
|
+
import { simpleParser } from "mailparser";
|
|
14
16
|
import { ApiError, ObjectDecorators } from "@rapidrest/core";
|
|
15
|
-
import { ACLAction, ACLUtils, ApiErrorMessages, ApiErrors, RepoUtils } from "@rapidrest/service-core";
|
|
17
|
+
import { ACLAction, ACLUtils, ApiErrorMessages, ApiErrors, ModelUtils, RepoUtils } from "@rapidrest/service-core";
|
|
16
18
|
import { WbxmlCodePage } from "../codec/WbxmlCodePages.js";
|
|
17
|
-
import { childText, element, findChild, textElement } from "../codec/WbxmlElement.js";
|
|
18
|
-
import { AttendeeResponseStatus, RecoverableRepoUtils } from "@rapidmx/restapi";
|
|
19
|
-
|
|
19
|
+
import { childText, element, findChild, findChildren, textElement } from "../codec/WbxmlElement.js";
|
|
20
|
+
import { AttendeeResponseStatus, buildEventIcs, parseIcsEvent, RecoverableRepoUtils, } from "@rapidmx/restapi";
|
|
21
|
+
import { isOrganizedBy } from "../adapters/CalendarSyncAdapter.js";
|
|
22
|
+
import { asEntity, boundIndexedValue } from "../RestapiCompat.js";
|
|
23
|
+
const { Init, Inject, Logger } = ObjectDecorators;
|
|
20
24
|
/** MS-ASCMD `UserResponse`: 1=Accepted, 2=Tentatively accepted, 3=Declined. */
|
|
21
25
|
const USER_RESPONSE_STATUS = {
|
|
22
26
|
"1": AttendeeResponseStatus.ACCEPTED,
|
|
23
27
|
"2": AttendeeResponseStatus.TENTATIVE,
|
|
24
28
|
"3": AttendeeResponseStatus.DECLINED,
|
|
25
29
|
};
|
|
30
|
+
const USER_RESPONSE_LABEL = { "1": "Accepted", "2": "Tentative", "3": "Declined" };
|
|
26
31
|
const USER_RESPONSE_DECLINED = "3";
|
|
32
|
+
/** MS-ASCMD `MeetingResponse` `Result/Status` values this command reports. */
|
|
33
|
+
const STATUS_SUCCESS = "1";
|
|
34
|
+
const STATUS_INVALID_REQUEST = "2";
|
|
35
|
+
const STATUS_MAILBOX_ERROR = "3";
|
|
36
|
+
const STATUS_SERVER_ERROR = "4";
|
|
37
|
+
/** Most `Request` elements one `MeetingResponse` may carry. */
|
|
38
|
+
export const MAX_MEETING_RESPONSES = 100;
|
|
27
39
|
/**
|
|
28
|
-
* Handles EAS `MeetingResponse`: records the caller's own accept/tentative/decline response to
|
|
29
|
-
*
|
|
30
|
-
* exposes as `ServerId` elsewhere (Sync/FolderSync) - no separate lookup table is needed.
|
|
40
|
+
* Handles EAS `MeetingResponse`: records the caller's own accept/tentative/decline response to each meeting the
|
|
41
|
+
* request's `<Request>` elements name, each answered with its own `<Result>`.
|
|
31
42
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* meeting from the declining attendee's own calendar, leaving the organizer's and every other attendee's own
|
|
38
|
-
* copy untouched. Accept/Tentative still update `Attendee.responseStatus` in place. The response omits
|
|
39
|
-
* `CalendarId` for a decline either way, matching the spec's own convention, so a client relying on that
|
|
40
|
-
* signal isn't misled into thinking a new item was created.
|
|
43
|
+
* **`RequestId`** is either the `CalendarEvent.uid` (a response from the calendar) or the `Message.uid` of the
|
|
44
|
+
* meeting request in the Inbox (a response from the mail view - what most clients send). For a message, the
|
|
45
|
+
* caller needs `READ` on its folder; its `text/calendar` part's `UID` is then resolved to the caller's own copy of
|
|
46
|
+
* the event (`icalUid` within the caller's mailbox) - looked up bounded (`boundIndexedValue`, as restapi stores it) and
|
|
47
|
+
* exact-matched in memory, since the UID is sender-controlled text a query parser could read as an operator.
|
|
41
48
|
*
|
|
42
|
-
*
|
|
49
|
+
* **Someone else's calendar**: whether a copy is the organizer's is judged against the event's own mailbox, not the
|
|
50
|
+
* caller's. A response to an event in another mailbox (a delegate with `UPDATE` on it) is refused with Status 2 when
|
|
51
|
+
* that event is its owner's organizer copy - it can only ever be an attendee copy. Updates are version-checked on both
|
|
52
|
+
* backends (`asEntity`).
|
|
53
|
+
*
|
|
54
|
+
* **Effect**: the caller must be an attendee and have `UPDATE` on the event's folder. Accept/Tentative update
|
|
55
|
+
* the caller's `Attendee.responseStatus`. A decline removes the caller's own copy of the event (matching Exchange)
|
|
56
|
+
* when the caller also has `DELETE` on the folder, and otherwise just records the declined status - a delegate
|
|
57
|
+
* with edit-only rights can't delete. Each mailbox has its own event row, so neither touches the organizer's or
|
|
58
|
+
* any other attendee's copy. `CalendarId` is omitted for a removed event. Since the caller's copy is an attendee's copy
|
|
59
|
+
* of someone else's meeting, neither write may look like the organizer acting to restapi's `MeetingSchedulingJob`:
|
|
60
|
+
* a removed copy is stamped `cancelNoticeSentAt` first (no CANCEL mailed as the organizer), and an updated copy keeps
|
|
61
|
+
* `inviteSequenceSent` equal to its `sequence` (no REQUEST).
|
|
62
|
+
*
|
|
63
|
+
* **Reply to the organizer**: in protocol 16.x the client asks the server to notify the organizer with
|
|
64
|
+
* `SendResponse`; when it's present an iTIP `REPLY` (built with restapi's `buildEventIcs`, the same payload
|
|
65
|
+
* `BaseCalendarEventRoute.respond` sends) is mailed from the caller's attendee address to the organizer,
|
|
66
|
+
* and a transport that accepts none of it (or rejects the organizer) is reported as Status 4 - the response itself is
|
|
67
|
+
* already recorded, so a retry only re-sends the reply. Without it (14.x clients send their own reply via `SendMail`) nothing is mailed, so the organizer
|
|
68
|
+
* never receives two replies.
|
|
69
|
+
*
|
|
70
|
+
* Failures are per request: an unknown/unresolvable meeting, a meeting the caller may not respond to, or a
|
|
71
|
+
* malformed `Request` gets Status 2 (indistinguishable, so nothing about other mailboxes leaks); a failed write
|
|
72
|
+
* Status 3.
|
|
73
|
+
*
|
|
74
|
+
* `calendarEventClass`/`mailboxClass`/`messageClass` are supplied by the Mongo/SQL concrete subclasses.
|
|
43
75
|
*
|
|
44
76
|
* @author Jean-Philippe Steinmetz
|
|
45
77
|
*/
|
|
@@ -56,61 +88,188 @@ export class MeetingResponseCommand {
|
|
|
56
88
|
name: this.mailboxClass.name,
|
|
57
89
|
args: [this.mailboxClass],
|
|
58
90
|
});
|
|
91
|
+
this.messageRepo = await this._objectFactory.newInstance(RepoUtils, {
|
|
92
|
+
name: this.messageClass.name,
|
|
93
|
+
args: [this.messageClass],
|
|
94
|
+
});
|
|
59
95
|
}
|
|
60
96
|
async handle(ctx) {
|
|
61
|
-
if (!this.calendarEventRepo || !this.mailboxRepo) {
|
|
97
|
+
if (!this.calendarEventRepo || !this.mailboxRepo || !this.messageRepo) {
|
|
62
98
|
throw new ApiError(ApiErrors.INTERNAL_ERROR, 500, ApiErrorMessages.INTERNAL_ERROR);
|
|
63
99
|
}
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
100
|
+
const requestEls = ctx.request ? findChildren(ctx.request, "Request") : [];
|
|
101
|
+
if (requestEls.length === 0 || requestEls.length > MAX_MEETING_RESPONSES) {
|
|
66
102
|
throw new ApiError(ApiErrors.INVALID_REQUEST, 400, ApiErrorMessages.INVALID_REQUEST);
|
|
67
103
|
}
|
|
104
|
+
const mailbox = await this.mailboxRepo.findOne(ctx.mailboxUid, { ignoreACL: true });
|
|
105
|
+
if (!mailbox) {
|
|
106
|
+
throw new ApiError(ApiErrors.NOT_FOUND, 404, ApiErrorMessages.NOT_FOUND);
|
|
107
|
+
}
|
|
108
|
+
const results = [];
|
|
109
|
+
for (const requestEl of requestEls) {
|
|
110
|
+
results.push(await this.respond(ctx, mailbox, requestEl));
|
|
111
|
+
}
|
|
112
|
+
return element(WbxmlCodePage.MeetingResponse, "MeetingResponse", results);
|
|
113
|
+
}
|
|
114
|
+
result(requestId, status, calendarId) {
|
|
115
|
+
return element(WbxmlCodePage.MeetingResponse, "Result", [
|
|
116
|
+
...(requestId ? [textElement(WbxmlCodePage.MeetingResponse, "RequestId", requestId)] : []),
|
|
117
|
+
textElement(WbxmlCodePage.MeetingResponse, "Status", status),
|
|
118
|
+
...(calendarId ? [textElement(WbxmlCodePage.MeetingResponse, "CalendarId", calendarId)] : []),
|
|
119
|
+
]);
|
|
120
|
+
}
|
|
121
|
+
async respond(ctx, mailbox, requestEl) {
|
|
68
122
|
const userResponse = childText(requestEl, "UserResponse");
|
|
69
123
|
const requestId = childText(requestEl, "RequestId");
|
|
70
124
|
if (!userResponse || !requestId || !USER_RESPONSE_STATUS[userResponse]) {
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
const event = await this.calendarEventRepo.findOne(requestId, { ignoreACL: true });
|
|
74
|
-
if (!event) {
|
|
75
|
-
throw new ApiError(ApiErrors.NOT_FOUND, 404, ApiErrorMessages.NOT_FOUND);
|
|
76
|
-
}
|
|
77
|
-
if (!(await this.aclUtils.hasPermission(ctx.user, event.folderUid, ACLAction.UPDATE))) {
|
|
78
|
-
throw new ApiError(ApiErrors.AUTH_PERMISSION_FAILURE, 403, ApiErrorMessages.AUTH_PERMISSION_FAILURE);
|
|
125
|
+
return this.result(requestId, STATUS_INVALID_REQUEST);
|
|
79
126
|
}
|
|
80
|
-
const
|
|
81
|
-
if (!
|
|
82
|
-
|
|
127
|
+
const event = await this.resolveEvent(ctx, requestId);
|
|
128
|
+
if (!event || !(await this.aclUtils.hasPermission(ctx.user, event.folderUid, ACLAction.UPDATE))) {
|
|
129
|
+
return this.result(requestId, STATUS_INVALID_REQUEST);
|
|
83
130
|
}
|
|
84
|
-
const callerAddresses = new Set([mailbox.primarySmtpAddress
|
|
131
|
+
const callerAddresses = new Set([mailbox.primarySmtpAddress, ...(mailbox.aliasAddresses ?? [])].map((a) => a.toLowerCase()));
|
|
85
132
|
const attendeeIndex = event.attendees.findIndex((attendee) => callerAddresses.has(attendee.address.toLowerCase()));
|
|
86
133
|
if (attendeeIndex === -1) {
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
:
|
|
106
|
-
|
|
107
|
-
|
|
134
|
+
return this.result(requestId, STATUS_INVALID_REQUEST);
|
|
135
|
+
}
|
|
136
|
+
const updatedAttendee = { ...event.attendees[attendeeIndex], responseStatus: USER_RESPONSE_STATUS[userResponse] };
|
|
137
|
+
// Whose copy this is decides whether it's the organizer's: the event's own mailbox, which for a delegate
|
|
138
|
+
// responding in someone else's calendar is not the caller's. A delegate never responds on (and so never
|
|
139
|
+
// deletes, or re-invites from) the owner's organizer copy of a meeting.
|
|
140
|
+
const owner = event.mailboxUid === ctx.mailboxUid ? mailbox : await this.mailboxRepo.findOne(event.mailboxUid, { ignoreACL: true });
|
|
141
|
+
if (!owner) {
|
|
142
|
+
return this.result(requestId, STATUS_INVALID_REQUEST);
|
|
143
|
+
}
|
|
144
|
+
const attendeeCopy = !isOrganizedBy(event, owner);
|
|
145
|
+
if (!attendeeCopy && owner !== mailbox) {
|
|
146
|
+
return this.result(requestId, STATUS_INVALID_REQUEST);
|
|
147
|
+
}
|
|
148
|
+
let removed = false;
|
|
149
|
+
try {
|
|
150
|
+
if (userResponse === USER_RESPONSE_DECLINED && (await this.aclUtils.hasPermission(ctx.user, event.folderUid, ACLAction.DELETE))) {
|
|
151
|
+
if (attendeeCopy && event.cancelNoticeSentAt == null) {
|
|
152
|
+
await this.calendarEventRepo.update({ uid: event.uid, version: event.version, cancelNoticeSentAt: new Date() }, asEntity(this.calendarEventRepo, event), { ignoreACL: true, user: ctx.user });
|
|
153
|
+
}
|
|
154
|
+
await this.calendarEventRepo.delete(event.uid, { ignoreACL: true, user: ctx.user });
|
|
155
|
+
removed = true;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const attendees = event.attendees.map((attendee, i) => (i === attendeeIndex ? updatedAttendee : attendee));
|
|
159
|
+
const inviteSequence = attendeeCopy && event.inviteSequenceSent !== event.sequence ? { inviteSequenceSent: event.sequence ?? 0 } : {};
|
|
160
|
+
await this.calendarEventRepo.update({ uid: event.uid, version: event.version, attendees, ...inviteSequence }, asEntity(this.calendarEventRepo, event), { ignoreACL: true, user: ctx.user });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
this.logger?.warn(`MeetingResponseCommand: failed to record response to event ${event.uid}: ${err?.message}`);
|
|
165
|
+
return this.result(requestId, STATUS_MAILBOX_ERROR);
|
|
166
|
+
}
|
|
167
|
+
if (findChild(requestEl, "SendResponse") && !(await this.sendReply(mailbox, event, updatedAttendee, userResponse))) {
|
|
168
|
+
return this.result(requestId, STATUS_SERVER_ERROR, removed ? undefined : event.uid);
|
|
169
|
+
}
|
|
170
|
+
return this.result(requestId, STATUS_SUCCESS, removed ? undefined : event.uid);
|
|
171
|
+
}
|
|
172
|
+
/** Resolves `requestId` to the caller's event: an event uid directly, or a meeting request message's
|
|
173
|
+
* `text/calendar` `UID` looked up among the caller's own mailbox's events. */
|
|
174
|
+
async resolveEvent(ctx, requestId) {
|
|
175
|
+
const direct = await this.calendarEventRepo.findOne(requestId, { ignoreACL: true });
|
|
176
|
+
if (direct) {
|
|
177
|
+
return direct;
|
|
178
|
+
}
|
|
179
|
+
const message = await this.messageRepo.findOne(requestId, { ignoreACL: true });
|
|
180
|
+
if (!message || !(await this.aclUtils.hasPermission(ctx.user, message.folderUid, ACLAction.READ))) {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
const icalUid = await this.meetingUidOf(message);
|
|
184
|
+
if (!icalUid) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
// The UID is sender-controlled: looked up bounded (restapi stores `icalUid` through `boundIndexedValue()`) as a
|
|
188
|
+
// `ModelUtils.literal()`, and exact-matched in memory as restapi's `ScanQueueJob.findCalendarEventRows()` does -
|
|
189
|
+
// a UID like `ne(x)` must never be parsed as a query operator and select (and let a decline delete) a different
|
|
190
|
+
// meeting.
|
|
191
|
+
const key = boundIndexedValue(icalUid);
|
|
192
|
+
const events = (await this.calendarEventRepo.find({ mailboxUid: ctx.mailboxUid, icalUid: ModelUtils.literal(key), limit: 50 }, {
|
|
193
|
+
ignoreACL: true,
|
|
194
|
+
limit: 50,
|
|
195
|
+
})).filter((row) => row.icalUid === key && row.mailboxUid === ctx.mailboxUid);
|
|
196
|
+
// The series master (no `recurrenceId`) is what a response to the whole invitation applies to.
|
|
197
|
+
return events.find((candidate) => !candidate.recurrenceId) ?? events[0];
|
|
198
|
+
}
|
|
199
|
+
/** The iCalendar `UID` of a meeting request message's `text/calendar` part, if it has one. */
|
|
200
|
+
async meetingUidOf(message) {
|
|
201
|
+
try {
|
|
202
|
+
const parsed = await simpleParser(await this.blobStore.get(message.bodyBlobKey));
|
|
203
|
+
const calendarPart = parsed.attachments.find((part) => part.contentType === "text/calendar");
|
|
204
|
+
return calendarPart ? parseIcsEvent(calendarPart.content.toString("utf-8"))?.uid : undefined;
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
/** Mails an iTIP `REPLY` for `attendee`'s response to the event's organizer. Returns `false` (after logging) when
|
|
211
|
+
* the transport threw or didn't accept the message for the organizer - checked the way restapi's `sendOrThrow`
|
|
212
|
+
* does, since every bundled transport reports a relay failure through `TransportResult.rejected` rather than
|
|
213
|
+
* throwing. */
|
|
214
|
+
async sendReply(mailbox, event, attendee, userResponse) {
|
|
215
|
+
try {
|
|
216
|
+
const ics = buildEventIcs({ ...event, attendees: [attendee] }, "REPLY", { onlyAttendee: attendee });
|
|
217
|
+
const boundary = `eas-${crypto.randomUUID()}`;
|
|
218
|
+
const subject = `${USER_RESPONSE_LABEL[userResponse]}: ${event.title}`.replace(/[\r\n]+/g, " ");
|
|
219
|
+
const fromName = (mailbox.displayName ?? "").replace(/[\r\n"]+/g, " ");
|
|
220
|
+
const raw = [
|
|
221
|
+
`From: "${fromName}" <${attendee.address}>`,
|
|
222
|
+
`To: <${event.organizer.address}>`,
|
|
223
|
+
`Subject: ${subject}`,
|
|
224
|
+
`Date: ${new Date().toUTCString()}`,
|
|
225
|
+
`Message-ID: <${crypto.randomUUID()}@eas>`,
|
|
226
|
+
"MIME-Version: 1.0",
|
|
227
|
+
`Content-Type: multipart/alternative; boundary="${boundary}"`,
|
|
228
|
+
"",
|
|
229
|
+
`--${boundary}`,
|
|
230
|
+
"Content-Type: text/plain; charset=utf-8",
|
|
231
|
+
"",
|
|
232
|
+
`${attendee.displayName ?? attendee.address} has responded ${USER_RESPONSE_LABEL[userResponse].toLowerCase()} to: ${event.title}`,
|
|
233
|
+
`--${boundary}`,
|
|
234
|
+
'Content-Type: text/calendar; charset=utf-8; method=REPLY',
|
|
235
|
+
"",
|
|
236
|
+
ics,
|
|
237
|
+
`--${boundary}--`,
|
|
238
|
+
"",
|
|
239
|
+
].join("\r\n");
|
|
240
|
+
const result = await this.mailTransport.send({
|
|
241
|
+
raw: Buffer.from(raw, "utf-8"),
|
|
242
|
+
envelopeFrom: attendee.address,
|
|
243
|
+
envelopeTo: [event.organizer.address],
|
|
244
|
+
});
|
|
245
|
+
if (!result || (result.accepted ?? []).length === 0 || (result.rejected ?? []).length > 0) {
|
|
246
|
+
this.logger?.warn(`MeetingResponseCommand: the mail transport did not accept the iTIP REPLY for event ${event.uid}`);
|
|
247
|
+
return false;
|
|
248
|
+
}
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
this.logger?.warn(`MeetingResponseCommand: failed to send iTIP REPLY for event ${event.uid}: ${err?.message}`);
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
108
255
|
}
|
|
109
256
|
}
|
|
110
257
|
__decorate([
|
|
111
258
|
Inject(ACLUtils),
|
|
112
259
|
__metadata("design:type", ACLUtils)
|
|
113
260
|
], MeetingResponseCommand.prototype, "aclUtils", void 0);
|
|
261
|
+
__decorate([
|
|
262
|
+
Inject("BlobStore"),
|
|
263
|
+
__metadata("design:type", Object)
|
|
264
|
+
], MeetingResponseCommand.prototype, "blobStore", void 0);
|
|
265
|
+
__decorate([
|
|
266
|
+
Inject("MailTransport"),
|
|
267
|
+
__metadata("design:type", Object)
|
|
268
|
+
], MeetingResponseCommand.prototype, "mailTransport", void 0);
|
|
269
|
+
__decorate([
|
|
270
|
+
Logger,
|
|
271
|
+
__metadata("design:type", Object)
|
|
272
|
+
], MeetingResponseCommand.prototype, "logger", void 0);
|
|
114
273
|
__decorate([
|
|
115
274
|
Init,
|
|
116
275
|
__metadata("design:type", Function),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MeetingResponseCommand.js","sourceRoot":"","sources":["../../../src/commands/MeetingResponseCommand.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MeetingResponseCommand.js","sourceRoot":"","sources":["../../../src/commands/MeetingResponseCommand.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,25 +11,38 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
11
11
|
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
12
12
|
// SPDX-License-Identifier: MPL-2.0
|
|
13
13
|
///////////////////////////////////////////////////////////////////////////////
|
|
14
|
-
import { ObjectDecorators } from "@rapidrest/core";
|
|
15
|
-
import { ACLAction, ACLUtils, RepoUtils } from "@rapidrest/service-core";
|
|
14
|
+
import { ApiError, ObjectDecorators } from "@rapidrest/core";
|
|
15
|
+
import { ACLAction, ACLUtils, ApiErrors, RepoUtils } from "@rapidrest/service-core";
|
|
16
16
|
import { WbxmlCodePage } from "../codec/WbxmlCodePages.js";
|
|
17
17
|
import { childText, element, findChildren, textElement } from "../codec/WbxmlElement.js";
|
|
18
|
+
import { planMessageMove } from "../MessageMoveRules.js";
|
|
19
|
+
import { asEntity } from "../RestapiCompat.js";
|
|
18
20
|
const { Init, Inject } = ObjectDecorators;
|
|
19
|
-
/** [MS-ASCMD] `
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const STATUS_SUCCESS = "
|
|
24
|
-
const
|
|
21
|
+
/** [MS-ASCMD] `MoveItems` `Status` codes (section 2.2.3.177.10): `3` is success - not `1`, which means an invalid
|
|
22
|
+
* source. */
|
|
23
|
+
const STATUS_INVALID_SOURCE = "1";
|
|
24
|
+
const STATUS_INVALID_DESTINATION = "2";
|
|
25
|
+
const STATUS_SUCCESS = "3";
|
|
26
|
+
const STATUS_SAME_FOLDER = "4";
|
|
27
|
+
const STATUS_LOCKED = "7";
|
|
28
|
+
/** Most `Move` elements one `MoveItems` request may carry - more is rejected with HTTP 400. */
|
|
29
|
+
export const MAX_MOVES_PER_REQUEST = 500;
|
|
25
30
|
/**
|
|
26
31
|
* Handles the standalone EAS `MoveItems` command: moves one or more `Message`s between folders in the caller's
|
|
27
|
-
* own mailbox by `ServerId`/`uid`.
|
|
32
|
+
* own mailbox by `ServerId`/`uid`. A move never crosses mailboxes (the destination folder must belong to the
|
|
33
|
+
* message's own mailbox) and a request may carry at most `MAX_MOVES_PER_REQUEST` moves.
|
|
34
|
+
*
|
|
35
|
+
* Each move gets its own [MS-ASCMD] status: `3` success; `1` an unknown/unreadable message, or a `SrcFldId` that
|
|
36
|
+
* isn't where it lives (or can't be updated); `2` an unknown destination, one in another mailbox, one the caller
|
|
37
|
+
* can't create in, Outbox, or Drafts for a message that isn't already a draft (`MessageMoveRules.planMessageMove`);
|
|
38
|
+
* `4` source and destination are the same folder; `7` the update itself failed (e.g. a concurrent edit's version
|
|
39
|
+
* conflict - the update is version-checked on both backends), a send in flight, or the message already left Outbox as sent - one failing
|
|
40
|
+
* move never aborts the others. Moving a message out of Outbox cancels its scheduled send.
|
|
28
41
|
*
|
|
29
42
|
* **Pragmatic subset**: `Message` only - `Contacts`/`Calendar`/`Tasks` moves are rare in practice (unlike
|
|
30
43
|
* `Message`, whose Inbox-to-subfolder filing is a real, common client action) and would each need their own
|
|
31
|
-
* ACL/ownership verification path for comparatively little value; a client attempting one gets
|
|
32
|
-
* rather than being silently ignored. `DstMsgId` in the response is always the same `uid` as `SrcMsgId` - this
|
|
44
|
+
* ACL/ownership verification path for comparatively little value; a client attempting one gets Status 1 (its
|
|
45
|
+
* `SrcMsgId` isn't a message) rather than being silently ignored. `DstMsgId` in the response is always the same `uid` as `SrcMsgId` - this
|
|
33
46
|
* library never mints a new identifier on move, unlike a real Exchange server, which sometimes does.
|
|
34
47
|
*
|
|
35
48
|
* `messageClass`/`folderClass` are supplied by the Mongo/SQL concrete subclasses.
|
|
@@ -52,6 +65,9 @@ export class MoveItemsCommand {
|
|
|
52
65
|
}
|
|
53
66
|
async handle(ctx) {
|
|
54
67
|
const moveEls = ctx.request ? findChildren(ctx.request, "Move") : [];
|
|
68
|
+
if (moveEls.length > MAX_MOVES_PER_REQUEST) {
|
|
69
|
+
throw new ApiError(ApiErrors.INVALID_REQUEST, 400, `MoveItems supports at most ${MAX_MOVES_PER_REQUEST} Move elements per request.`);
|
|
70
|
+
}
|
|
55
71
|
const responses = [];
|
|
56
72
|
for (const moveEl of moveEls) {
|
|
57
73
|
responses.push(await this.moveOne(ctx, moveEl));
|
|
@@ -62,24 +78,41 @@ export class MoveItemsCommand {
|
|
|
62
78
|
const srcMsgId = childText(moveEl, "SrcMsgId");
|
|
63
79
|
const srcFldId = childText(moveEl, "SrcFldId");
|
|
64
80
|
const dstFldId = childText(moveEl, "DstFldId");
|
|
65
|
-
if (!srcMsgId || !srcFldId
|
|
66
|
-
return this.responseElement(srcMsgId,
|
|
81
|
+
if (!srcMsgId || !srcFldId) {
|
|
82
|
+
return this.responseElement(srcMsgId, STATUS_INVALID_SOURCE, undefined);
|
|
83
|
+
}
|
|
84
|
+
if (!dstFldId) {
|
|
85
|
+
return this.responseElement(srcMsgId, STATUS_INVALID_DESTINATION, undefined);
|
|
86
|
+
}
|
|
87
|
+
if (srcFldId === dstFldId) {
|
|
88
|
+
return this.responseElement(srcMsgId, STATUS_SAME_FOLDER, undefined);
|
|
67
89
|
}
|
|
68
90
|
const message = await this.messageRepo.findOne(srcMsgId, { ignoreACL: true });
|
|
69
91
|
// The client's claimed SrcFldId must match where the message actually lives - protects against a
|
|
70
92
|
// stale/mismatched client cache rather than trusting the claim outright.
|
|
71
|
-
if (!message || message.folderUid !== srcFldId) {
|
|
72
|
-
return this.responseElement(srcMsgId,
|
|
93
|
+
if (!message || message.folderUid !== srcFldId || !(await this.aclUtils.hasPermission(ctx.user, srcFldId, ACLAction.UPDATE))) {
|
|
94
|
+
return this.responseElement(srcMsgId, STATUS_INVALID_SOURCE, undefined);
|
|
73
95
|
}
|
|
74
|
-
if (!(await this.aclUtils.hasPermission(ctx.user,
|
|
75
|
-
|
|
76
|
-
return this.responseElement(srcMsgId, STATUS_FAILURE, undefined);
|
|
96
|
+
if (!(await this.aclUtils.hasPermission(ctx.user, dstFldId, ACLAction.CREATE))) {
|
|
97
|
+
return this.responseElement(srcMsgId, STATUS_INVALID_DESTINATION, undefined);
|
|
77
98
|
}
|
|
78
99
|
const destFolder = await this.folderRepo.findOne(dstFldId, { ignoreACL: true });
|
|
79
|
-
|
|
80
|
-
|
|
100
|
+
// A message never changes mailbox by moving: its `mailboxUid` (quota, retention, search scoping) must keep
|
|
101
|
+
// matching its folder's mailbox, so a destination in any other mailbox is refused.
|
|
102
|
+
if (!destFolder || destFolder.mailboxUid !== message.mailboxUid) {
|
|
103
|
+
return this.responseElement(srcMsgId, STATUS_INVALID_DESTINATION, undefined);
|
|
104
|
+
}
|
|
105
|
+
const sourceFolder = await this.folderRepo.findOne(message.folderUid, { ignoreACL: true });
|
|
106
|
+
const plan = planMessageMove(message, sourceFolder?.type, destFolder.type);
|
|
107
|
+
if (!plan.allowed) {
|
|
108
|
+
return this.responseElement(srcMsgId, plan.reason === "destination" ? STATUS_INVALID_DESTINATION : STATUS_LOCKED, undefined);
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
await this.messageRepo.update({ uid: message.uid, version: message.version, folderUid: dstFldId, ...plan.patch }, asEntity(this.messageRepo, message), { ignoreACL: true, user: ctx.user });
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return this.responseElement(srcMsgId, STATUS_LOCKED, undefined);
|
|
81
115
|
}
|
|
82
|
-
await this.messageRepo.update({ uid: message.uid, version: message.version, folderUid: dstFldId }, message, { ignoreACL: true, user: ctx.user });
|
|
83
116
|
return this.responseElement(srcMsgId, STATUS_SUCCESS, message.uid);
|
|
84
117
|
}
|
|
85
118
|
responseElement(srcMsgId, status, dstMsgId) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MoveItemsCommand.js","sourceRoot":"","sources":["../../../src/commands/MoveItemsCommand.ts"],"names":[],"mappings":";;;;;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"MoveItemsCommand.js","sourceRoot":"","sources":["../../../src/commands/MoveItemsCommand.ts"],"names":[],"mappings":";;;;;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAiB,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEnG,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAqB,MAAM,0BAA0B,CAAC;AAE5G,OAAO,EAAwB,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC;AAE1C;aACa;AACb,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAClC,MAAM,0BAA0B,GAAG,GAAG,CAAC;AACvC,MAAM,cAAc,GAAG,GAAG,CAAC;AAC3B,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,MAAM,aAAa,GAAG,GAAG,CAAC;AAE1B,+FAA+F;AAC/F,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAgB,gBAAgB;IAAtC;QACoB,YAAO,GAAG,WAAW,CAAC;IA+F1C,CAAC;IAhFgB,AAAN,KAAK,CAAC,IAAI;QACb,IAAI,CAAC,WAAW,GAAG,MAAM,IAAI,CAAC,cAAe,CAAC,WAAW,CAAC,SAAS,EAAE;YACjE,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI;YAC5B,IAAI,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC;SAC5B,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,GAAG,MAAM,IAAI,CAAC,cAAe,CAAC,WAAW,CAAC,SAAS,EAAE;YAChE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;YAC3B,IAAI,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC;SAC3B,CAAC,CAAC;IACP,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,GAAsB;QACtC,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,IAAI,OAAO,CAAC,MAAM,GAAG,qBAAqB,EAAE,CAAC;YACzC,MAAM,IAAI,QAAQ,CAAC,SAAS,CAAC,eAAe,EAAE,GAAG,EAAE,8BAA8B,qBAAqB,6BAA6B,CAAC,CAAC;QACzI,CAAC;QACD,MAAM,SAAS,GAAmB,EAAE,CAAC;QACrC,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC3B,SAAS,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;IAC/D,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,GAAsB,EAAE,MAAoB;QAC9D,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;QAC/C,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,qBAAqB,EAAE,SAAS,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,0BAA0B,EAAE,SAAS,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,kBAAkB,EAAE,SAAS,CAAC,CAAC;QACzE,CAAC;QAED,MAAM,OAAO,GAAwB,MAAM,IAAI,CAAC,WAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpG,iGAAiG;QACjG,yEAAyE;QACzE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,SAAS,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,QAAS,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YAC5H,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,qBAAqB,EAAE,SAAS,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,QAAS,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YAC9E,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,0BAA0B,EAAE,SAAS,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,UAAU,GAAuB,MAAM,IAAI,CAAC,UAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrG,2GAA2G;QAC3G,mFAAmF;QACnF,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,UAAU,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC;YAC9D,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,0BAA0B,EAAE,SAAS,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,YAAY,GAAuB,MAAM,IAAI,CAAC,UAAW,CAAC,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChH,MAAM,IAAI,GAAoB,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QAC5F,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC;QACjI,CAAC;QAED,IAAI,CAAC;YACD,MAAM,IAAI,CAAC,WAAY,CAAC,MAAM,CAC1B,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,OAAO,EAAG,OAAe,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,EAAS,EAClG,QAAQ,CAAC,IAAI,CAAC,WAAY,EAAE,OAAO,CAAC,EACpC,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,CACtC,CAAC;QACN,CAAC;QAAC,MAAM,CAAC;YACL,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IACvE,CAAC;IAEO,eAAe,CAAC,QAA4B,EAAE,MAAc,EAAE,QAA4B;QAC9F,OAAO,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE;YAC3C,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAC5E,WAAW,CAAC,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC;YACjD,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/E,CAAC,CAAC;IACP,CAAC;CACJ;AAnFW;IADP,MAAM,CAAC,QAAQ,CAAC;8BACE,QAAQ;kDAAC;AAGf;IADZ,IAAI;;;;4CAUJ"}
|