@rapidmx/mapi-plugin 1.0.0-beta.10
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/LICENSE +382 -0
- package/README.md +60 -0
- package/dist/lib/BaseMapiEmsmdbRoute.js +489 -0
- package/dist/lib/BaseMapiEmsmdbRoute.js.map +1 -0
- package/dist/lib/BaseMapiNspiRoute.js +114 -0
- package/dist/lib/BaseMapiNspiRoute.js.map +1 -0
- package/dist/lib/MapiSessionManager.js +475 -0
- package/dist/lib/MapiSessionManager.js.map +1 -0
- package/dist/lib/RegexPatternUtils.js +30 -0
- package/dist/lib/RegexPatternUtils.js.map +1 -0
- package/dist/lib/RopDispatcher.js +145 -0
- package/dist/lib/RopDispatcher.js.map +1 -0
- package/dist/lib/codec/AppointmentRecurrence.js +315 -0
- package/dist/lib/codec/AppointmentRecurrence.js.map +1 -0
- package/dist/lib/codec/BufferCursor.js +242 -0
- package/dist/lib/codec/BufferCursor.js.map +1 -0
- package/dist/lib/codec/GlobalObjectId.js +98 -0
- package/dist/lib/codec/GlobalObjectId.js.map +1 -0
- package/dist/lib/codec/MapiGuid.js +41 -0
- package/dist/lib/codec/MapiGuid.js.map +1 -0
- package/dist/lib/codec/MapiTimeZone.js +126 -0
- package/dist/lib/codec/MapiTimeZone.js.map +1 -0
- package/dist/lib/codec/PropertyValue.js +240 -0
- package/dist/lib/codec/PropertyValue.js.map +1 -0
- package/dist/lib/codec/RopBuffer.js +38 -0
- package/dist/lib/codec/RopBuffer.js.map +1 -0
- package/dist/lib/codec/TypedString.js +54 -0
- package/dist/lib/codec/TypedString.js.map +1 -0
- package/dist/lib/index.js +99 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +85 -0
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -0
- package/dist/lib/mongo/MapiNspiRouteMongo.js +33 -0
- package/dist/lib/mongo/MapiNspiRouteMongo.js.map +1 -0
- package/dist/lib/mongo/index.js +7 -0
- package/dist/lib/mongo/index.js.map +1 -0
- package/dist/lib/mongo.js +6 -0
- package/dist/lib/mongo.js.map +1 -0
- package/dist/lib/nspi/NspiBindHandler.js +54 -0
- package/dist/lib/nspi/NspiBindHandler.js.map +1 -0
- package/dist/lib/nspi/NspiCodec.js +106 -0
- package/dist/lib/nspi/NspiCodec.js.map +1 -0
- package/dist/lib/nspi/NspiGetMatchesHandler.js +142 -0
- package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -0
- package/dist/lib/rop/AddressList.js +114 -0
- package/dist/lib/rop/AddressList.js.map +1 -0
- package/dist/lib/rop/CalendarEventTarget.js +30 -0
- package/dist/lib/rop/CalendarEventTarget.js.map +1 -0
- package/dist/lib/rop/CalendarNamedProperties.js +57 -0
- package/dist/lib/rop/CalendarNamedProperties.js.map +1 -0
- package/dist/lib/rop/ContactTarget.js +19 -0
- package/dist/lib/rop/ContactTarget.js.map +1 -0
- package/dist/lib/rop/ContentsTable.js +60 -0
- package/dist/lib/rop/ContentsTable.js.map +1 -0
- package/dist/lib/rop/ExecuteBudget.js +82 -0
- package/dist/lib/rop/ExecuteBudget.js.map +1 -0
- package/dist/lib/rop/FastTransferStream.js +195 -0
- package/dist/lib/rop/FastTransferStream.js.map +1 -0
- package/dist/lib/rop/FolderTarget.js +118 -0
- package/dist/lib/rop/FolderTarget.js.map +1 -0
- package/dist/lib/rop/HandleDataCache.js +412 -0
- package/dist/lib/rop/HandleDataCache.js.map +1 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js +241 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -0
- package/dist/lib/rop/MessageBodyStream.js +68 -0
- package/dist/lib/rop/MessageBodyStream.js.map +1 -0
- package/dist/lib/rop/MessageTarget.js +57 -0
- package/dist/lib/rop/MessageTarget.js.map +1 -0
- package/dist/lib/rop/NamedPropertyRegistry.js +69 -0
- package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -0
- package/dist/lib/rop/PropertyResolvers.js +353 -0
- package/dist/lib/rop/PropertyResolvers.js.map +1 -0
- package/dist/lib/rop/RepoPaging.js +54 -0
- package/dist/lib/rop/RepoPaging.js.map +1 -0
- package/dist/lib/rop/RestapiRules.js +52 -0
- package/dist/lib/rop/RestapiRules.js.map +1 -0
- package/dist/lib/rop/RopCreateMessageHandler.js +55 -0
- package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js +174 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteMessagesHandler.js +110 -0
- package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +61 -0
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +60 -0
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +76 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js +55 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js +42 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +56 -0
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -0
- package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js +92 -0
- package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js.map +1 -0
- package/dist/lib/rop/RopHandler.js +6 -0
- package/dist/lib/rop/RopHandler.js.map +1 -0
- package/dist/lib/rop/RopLogonHandler.js +135 -0
- package/dist/lib/rop/RopLogonHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenFolderHandler.js +48 -0
- package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenMessageHandler.js +83 -0
- package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenStreamHandler.js +84 -0
- package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopQueryRowsHandler.js +120 -0
- package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -0
- package/dist/lib/rop/RopReadStreamHandler.js +73 -0
- package/dist/lib/rop/RopReadStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopReleaseHandler.js +23 -0
- package/dist/lib/rop/RopReleaseHandler.js.map +1 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js +269 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopSetColumnsHandler.js +50 -0
- package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js +173 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js +342 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopWriteStreamHandler.js +72 -0
- package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -0
- package/dist/lib/rop/TaskNamedProperties.js +29 -0
- package/dist/lib/rop/TaskNamedProperties.js.map +1 -0
- package/dist/lib/rop/TaskTarget.js +15 -0
- package/dist/lib/rop/TaskTarget.js.map +1 -0
- package/dist/lib/rop/TransportSend.js +16 -0
- package/dist/lib/rop/TransportSend.js.map +1 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js +85 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -0
- package/dist/lib/sql/MapiNspiRouteSQL.js +33 -0
- package/dist/lib/sql/MapiNspiRouteSQL.js.map +1 -0
- package/dist/lib/sql/index.js +7 -0
- package/dist/lib/sql/index.js.map +1 -0
- package/dist/lib/sql.js +6 -0
- package/dist/lib/sql.js.map +1 -0
- package/dist/types/BaseMapiEmsmdbRoute.d.ts +139 -0
- package/dist/types/BaseMapiNspiRoute.d.ts +38 -0
- package/dist/types/MapiSessionManager.d.ts +285 -0
- package/dist/types/RegexPatternUtils.d.ts +14 -0
- package/dist/types/RopDispatcher.d.ts +53 -0
- package/dist/types/codec/AppointmentRecurrence.d.ts +14 -0
- package/dist/types/codec/BufferCursor.d.ts +92 -0
- package/dist/types/codec/GlobalObjectId.d.ts +15 -0
- package/dist/types/codec/MapiGuid.d.ts +6 -0
- package/dist/types/codec/MapiTimeZone.d.ts +7 -0
- package/dist/types/codec/PropertyValue.d.ts +87 -0
- package/dist/types/codec/RopBuffer.d.ts +32 -0
- package/dist/types/codec/TypedString.d.ts +17 -0
- package/dist/types/index.d.ts +94 -0
- package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +20 -0
- package/dist/types/mongo/MapiNspiRouteMongo.d.ts +13 -0
- package/dist/types/mongo/index.d.ts +2 -0
- package/dist/types/mongo.d.ts +1 -0
- package/dist/types/nspi/NspiBindHandler.d.ts +22 -0
- package/dist/types/nspi/NspiCodec.d.ts +59 -0
- package/dist/types/nspi/NspiGetMatchesHandler.d.ts +26 -0
- package/dist/types/rop/AddressList.d.ts +48 -0
- package/dist/types/rop/CalendarEventTarget.d.ts +33 -0
- package/dist/types/rop/CalendarNamedProperties.d.ts +37 -0
- package/dist/types/rop/ContactTarget.d.ts +29 -0
- package/dist/types/rop/ContentsTable.d.ts +16 -0
- package/dist/types/rop/ExecuteBudget.d.ts +48 -0
- package/dist/types/rop/FastTransferStream.d.ts +57 -0
- package/dist/types/rop/FolderTarget.d.ts +64 -0
- package/dist/types/rop/HandleDataCache.d.ts +145 -0
- package/dist/types/rop/MeetingMessageClassHandler.d.ts +30 -0
- package/dist/types/rop/MessageBodyStream.d.ts +35 -0
- package/dist/types/rop/MessageTarget.d.ts +45 -0
- package/dist/types/rop/NamedPropertyRegistry.d.ts +50 -0
- package/dist/types/rop/PropertyResolvers.d.ts +86 -0
- package/dist/types/rop/RepoPaging.d.ts +30 -0
- package/dist/types/rop/RestapiRules.d.ts +32 -0
- package/dist/types/rop/RopCreateMessageHandler.d.ts +24 -0
- package/dist/types/rop/RopDeleteFolderHandler.d.ts +53 -0
- package/dist/types/rop/RopDeleteMessagesHandler.d.ts +43 -0
- package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +25 -0
- package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +25 -0
- package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +22 -0
- package/dist/types/rop/RopGetContentsTableHandler.d.ts +25 -0
- package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +18 -0
- package/dist/types/rop/RopGetPropertiesSpecificHandler.d.ts +26 -0
- package/dist/types/rop/RopGetPropertyIdsFromNamesHandler.d.ts +23 -0
- package/dist/types/rop/RopHandler.d.ts +106 -0
- package/dist/types/rop/RopLogonHandler.d.ts +31 -0
- package/dist/types/rop/RopOpenFolderHandler.d.ts +20 -0
- package/dist/types/rop/RopOpenMessageHandler.d.ts +28 -0
- package/dist/types/rop/RopOpenStreamHandler.d.ts +28 -0
- package/dist/types/rop/RopQueryRowsHandler.d.ts +43 -0
- package/dist/types/rop/RopReadStreamHandler.d.ts +20 -0
- package/dist/types/rop/RopReleaseHandler.d.ts +15 -0
- package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +59 -0
- package/dist/types/rop/RopSetColumnsHandler.d.ts +21 -0
- package/dist/types/rop/RopSetPropertiesHandler.d.ts +38 -0
- package/dist/types/rop/RopSubmitMessageHandler.d.ts +80 -0
- package/dist/types/rop/RopWriteStreamHandler.d.ts +31 -0
- package/dist/types/rop/TaskNamedProperties.d.ts +24 -0
- package/dist/types/rop/TaskTarget.d.ts +24 -0
- package/dist/types/rop/TransportSend.d.ts +10 -0
- package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +20 -0
- package/dist/types/sql/MapiNspiRouteSQL.d.ts +13 -0
- package/dist/types/sql/index.d.ts +2 -0
- package/dist/types/sql.d.ts +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { FolderType } from "@rapidmx/restapi";
|
|
2
|
+
import { CALENDAR_EVENT_SORT } from "./CalendarEventTarget.js";
|
|
3
|
+
import { CONTACT_SORT } from "./ContactTarget.js";
|
|
4
|
+
import { MESSAGE_SORT } from "./MessageTarget.js";
|
|
5
|
+
import { findWindow } from "./RepoPaging.js";
|
|
6
|
+
import { TASK_SORT } from "./TaskTarget.js";
|
|
7
|
+
const SORT_BY_KIND = {
|
|
8
|
+
message: MESSAGE_SORT,
|
|
9
|
+
calendarEvent: CALENDAR_EVENT_SORT,
|
|
10
|
+
contact: CONTACT_SORT,
|
|
11
|
+
task: TASK_SORT,
|
|
12
|
+
};
|
|
13
|
+
/** Which repo a folder's items live in, decided by the folder's own `type`: a `Contact`/`Task`/`CalendarEvent` is
|
|
14
|
+
* its own entity, never a `Message` row. */
|
|
15
|
+
export async function resolveContentsKind(folderUid, context) {
|
|
16
|
+
context.budget?.chargeQueries();
|
|
17
|
+
const folder = await context.folderRepo.findOne(folderUid, { ignoreACL: true });
|
|
18
|
+
switch (folder?.type) {
|
|
19
|
+
case FolderType.CALENDAR:
|
|
20
|
+
return "calendarEvent";
|
|
21
|
+
case FolderType.CONTACTS:
|
|
22
|
+
return "contact";
|
|
23
|
+
case FolderType.TASKS:
|
|
24
|
+
return "task";
|
|
25
|
+
default:
|
|
26
|
+
return "message";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function repoFor(kind, context) {
|
|
30
|
+
switch (kind) {
|
|
31
|
+
case "calendarEvent":
|
|
32
|
+
return context.calendarEventRepo;
|
|
33
|
+
case "contact":
|
|
34
|
+
return context.contactRepo;
|
|
35
|
+
case "task":
|
|
36
|
+
return context.taskRepo;
|
|
37
|
+
default:
|
|
38
|
+
return context.messageRepo;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The `"<kind>:<uid>"` row targets at positions `[start, start + count)` of a contents table (a `"folder:<uid>"`
|
|
43
|
+
* table with `contentsKind` set), read straight from the database in a fixed, stable order. A context without the
|
|
44
|
+
* matching optional repo yields no rows.
|
|
45
|
+
*
|
|
46
|
+
* Reading a window per `RopQueryRows` instead of snapshotting every row at `RopGetContentsTable` time keeps session
|
|
47
|
+
* state small and makes no folder too large to page through. The trade-off is that a message added or removed
|
|
48
|
+
* between two `RopQueryRows` calls can shift the rows that follow.
|
|
49
|
+
*/
|
|
50
|
+
export async function resolveContentsWindow(context, table, start, count) {
|
|
51
|
+
const kind = table.contentsKind;
|
|
52
|
+
const repo = repoFor(kind, context);
|
|
53
|
+
if (!repo) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
const folderUid = table.entityUid.slice("folder:".length);
|
|
57
|
+
const rows = await findWindow(repo, { folderUid, mailboxUid: context.mailboxUid }, SORT_BY_KIND[kind], start, count, context.budget);
|
|
58
|
+
return rows.map((row) => `${kind}:${row.uid}`);
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=ContentsTable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ContentsTable.js","sourceRoot":"","sources":["../../../src/rop/ContentsTable.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAe,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAiB,MAAM,iBAAiB,CAAC;AAE5D,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,YAAY,GAAmC;IACjD,OAAO,EAAE,YAAY;IACrB,aAAa,EAAE,mBAAmB;IAClC,OAAO,EAAE,YAAY;IACrB,IAAI,EAAE,SAAS;CAClB,CAAC;AAEF;4CAC4C;AAC5C,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,SAAiB,EAAE,OAAmB;IAC5E,OAAO,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC;IAChC,MAAM,MAAM,GAAuB,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACpG,QAAQ,MAAM,EAAE,IAAI,EAAE,CAAC;QACnB,KAAK,UAAU,CAAC,QAAQ;YACpB,OAAO,eAAe,CAAC;QAC3B,KAAK,UAAU,CAAC,QAAQ;YACpB,OAAO,SAAS,CAAC;QACrB,KAAK,UAAU,CAAC,KAAK;YACjB,OAAO,MAAM,CAAC;QAClB;YACI,OAAO,SAAS,CAAC;IACzB,CAAC;AACL,CAAC;AAED,SAAS,OAAO,CAAC,IAAkB,EAAE,OAAmB;IACpD,QAAQ,IAAI,EAAE,CAAC;QACX,KAAK,eAAe;YAChB,OAAO,OAAO,CAAC,iBAAiB,CAAC;QACrC,KAAK,SAAS;YACV,OAAO,OAAO,CAAC,WAAW,CAAC;QAC/B,KAAK,MAAM;YACP,OAAO,OAAO,CAAC,QAAQ,CAAC;QAC5B;YACI,OAAO,OAAO,CAAC,WAAW,CAAC;IACnC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,OAAmB,EAAE,KAAuB,EAAE,KAAa,EAAE,KAAa;IAClH,MAAM,IAAI,GAAiB,KAAK,CAAC,YAAa,CAAC;IAC/C,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,EAAE,CAAC;IACd,CAAC;IACD,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAsB,MAAM,UAAU,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACxJ,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;AACnD,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/** The most rows (items or folders) whose properties one `Execute` resolves, across all of its ROPs. */
|
|
6
|
+
export const MAX_ROWS_RESOLVED_PER_EXECUTE = 20000;
|
|
7
|
+
/** The most bytes one `Execute` builds or parses (FastTransfer streams and message bodies), across all of its ROPs. */
|
|
8
|
+
export const MAX_BYTES_BUILT_PER_EXECUTE = 64 * 1024 * 1024;
|
|
9
|
+
/** The most database queries (paged reads, table lookups, deletes) one `Execute` runs through the budgeted paths. */
|
|
10
|
+
export const MAX_QUERIES_PER_EXECUTE = 20000;
|
|
11
|
+
/** The most rows one `Execute` reads back from paged queries (folder lists, folder walks, item lists). */
|
|
12
|
+
export const MAX_ROWS_FETCHED_PER_EXECUTE = 100000;
|
|
13
|
+
/** The most `RopSubmitMessage`s one `Execute` runs. Each one can relay mail, so a request can't repeat it 1024 times. */
|
|
14
|
+
export const MAX_SUBMITS_PER_EXECUTE = 16;
|
|
15
|
+
/** Thrown when an `Execute` has used up its `ExecuteBudget`. The ROP that hit it fails; see `RopDispatcher`. */
|
|
16
|
+
export class WorkBudgetExceededError extends Error {
|
|
17
|
+
constructor(what) {
|
|
18
|
+
super(`Execute: the per-request ${what} budget is exhausted.`);
|
|
19
|
+
this.name = "WorkBudgetExceededError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The work one `Execute` may do. Limits on ROP count and per-ROP sizes alone still let one request chain many
|
|
24
|
+
* expensive ROPs (a dozen 10000-row FastTransfer dumps, the same large body parsed by several streams, or a thousand
|
|
25
|
+
* hierarchy tables or folder walks), so rows resolved, bytes built, queries run, rows fetched and submits are counted
|
|
26
|
+
* across the whole request. Every charge happens before the work it pays for. Also dedupes message body parses within
|
|
27
|
+
* the request (`bodies`).
|
|
28
|
+
*/
|
|
29
|
+
export class ExecuteBudget {
|
|
30
|
+
constructor(maxRows = MAX_ROWS_RESOLVED_PER_EXECUTE, maxBytes = MAX_BYTES_BUILT_PER_EXECUTE, limits = {}) {
|
|
31
|
+
/** Message uid -> its decoded body, so opening the same body twice in one request parses it once. */
|
|
32
|
+
this.bodies = new Map();
|
|
33
|
+
this.rowsRemaining = maxRows;
|
|
34
|
+
this.bytesRemaining = maxBytes;
|
|
35
|
+
this.queriesRemaining = limits.maxQueries ?? MAX_QUERIES_PER_EXECUTE;
|
|
36
|
+
this.fetchedRowsRemaining = limits.maxFetchedRows ?? MAX_ROWS_FETCHED_PER_EXECUTE;
|
|
37
|
+
this.submitsRemaining = limits.maxSubmits ?? MAX_SUBMITS_PER_EXECUTE;
|
|
38
|
+
}
|
|
39
|
+
/** Uses `count` rows of the budget, throwing `WorkBudgetExceededError` once it is exhausted. */
|
|
40
|
+
chargeRows(count = 1) {
|
|
41
|
+
this.rowsRemaining -= count;
|
|
42
|
+
if (this.rowsRemaining < 0) {
|
|
43
|
+
throw new WorkBudgetExceededError("row");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Uses `count` bytes of the budget, throwing `WorkBudgetExceededError` once it is exhausted. */
|
|
47
|
+
chargeBytes(count) {
|
|
48
|
+
this.bytesRemaining -= count;
|
|
49
|
+
if (this.bytesRemaining < 0) {
|
|
50
|
+
throw new WorkBudgetExceededError("byte");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Throws `WorkBudgetExceededError` when no bytes are left, so work that can't be sized up front (fetching a blob)
|
|
54
|
+
* isn't started at all. */
|
|
55
|
+
assertBytesLeft() {
|
|
56
|
+
if (this.bytesRemaining <= 0) {
|
|
57
|
+
throw new WorkBudgetExceededError("byte");
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Uses `count` queries of the budget. Called before running them. */
|
|
61
|
+
chargeQueries(count = 1) {
|
|
62
|
+
this.queriesRemaining -= count;
|
|
63
|
+
if (this.queriesRemaining < 0) {
|
|
64
|
+
throw new WorkBudgetExceededError("query");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/** Uses `count` fetched rows of the budget. */
|
|
68
|
+
chargeFetchedRows(count) {
|
|
69
|
+
this.fetchedRowsRemaining -= count;
|
|
70
|
+
if (this.fetchedRowsRemaining < 0) {
|
|
71
|
+
throw new WorkBudgetExceededError("fetched row");
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/** Uses one submit of the budget. */
|
|
75
|
+
chargeSubmit() {
|
|
76
|
+
this.submitsRemaining -= 1;
|
|
77
|
+
if (this.submitsRemaining < 0) {
|
|
78
|
+
throw new WorkBudgetExceededError("submit");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=ExecuteBudget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExecuteBudget.js","sourceRoot":"","sources":["../../../src/rop/ExecuteBudget.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAE/E,wGAAwG;AACxG,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAK,CAAC;AAEnD,uHAAuH;AACvH,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAE5D,qHAAqH;AACrH,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAE7C,0GAA0G;AAC1G,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC;AAEnD,yHAAyH;AACzH,MAAM,CAAC,MAAM,uBAAuB,GAAG,EAAE,CAAC;AAE1C,gHAAgH;AAChH,MAAM,OAAO,uBAAwB,SAAQ,KAAK;IAC9C,YAAmB,IAAY;QAC3B,KAAK,CAAC,4BAA4B,IAAI,uBAAuB,CAAC,CAAC;QAC/D,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IAC1C,CAAC;CACJ;AAED;;;;;;GAMG;AACH,MAAM,OAAO,aAAa;IAStB,YACI,UAAkB,6BAA6B,EAC/C,WAAmB,2BAA2B,EAC9C,SAAgF,EAAE;QANtF,qGAAqG;QACrF,WAAM,GAAG,IAAI,GAAG,EAA2B,CAAC;QAOxD,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;QAC7B,IAAI,CAAC,cAAc,GAAG,QAAQ,CAAC;QAC/B,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,UAAU,IAAI,uBAAuB,CAAC;QACrE,IAAI,CAAC,oBAAoB,GAAG,MAAM,CAAC,cAAc,IAAI,4BAA4B,CAAC;QAClF,IAAI,CAAC,gBAAgB,GAAG,MAAM,CAAC,UAAU,IAAI,uBAAuB,CAAC;IACzE,CAAC;IAED,gGAAgG;IACzF,UAAU,CAAC,KAAK,GAAG,CAAC;QACvB,IAAI,CAAC,aAAa,IAAI,KAAK,CAAC;QAC5B,IAAI,IAAI,CAAC,aAAa,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,uBAAuB,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC;IACL,CAAC;IAED,iGAAiG;IAC1F,WAAW,CAAC,KAAa;QAC5B,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC;QAC7B,IAAI,IAAI,CAAC,cAAc,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC;IAED;+BAC2B;IACpB,eAAe;QAClB,IAAI,IAAI,CAAC,cAAc,IAAI,CAAC,EAAE,CAAC;YAC3B,MAAM,IAAI,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAC9C,CAAC;IACL,CAAC;IAED,sEAAsE;IAC/D,aAAa,CAAC,KAAK,GAAG,CAAC;QAC1B,IAAI,CAAC,gBAAgB,IAAI,KAAK,CAAC;QAC/B,IAAI,IAAI,CAAC,gBAAgB,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC;IACL,CAAC;IAED,+CAA+C;IACxC,iBAAiB,CAAC,KAAa;QAClC,IAAI,CAAC,oBAAoB,IAAI,KAAK,CAAC;QACnC,IAAI,IAAI,CAAC,oBAAoB,GAAG,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,uBAAuB,CAAC,aAAa,CAAC,CAAC;QACrD,CAAC;IACL,CAAC;IAED,qCAAqC;IAC9B,YAAY;QACf,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC3B,IAAI,IAAI,CAAC,gBAAgB,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QAChD,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { FolderType } from "@rapidmx/restapi";
|
|
6
|
+
import { BufferWriter } from "../codec/BufferCursor.js";
|
|
7
|
+
import { PropertyType, writeTaggedPropertyValue } from "../codec/PropertyValue.js";
|
|
8
|
+
import { assignHandle, releaseHandle } from "../MapiSessionManager.js";
|
|
9
|
+
import { resolveFolderCalendarEvents } from "./CalendarEventTarget.js";
|
|
10
|
+
import { handleDataKey, handleDataOwners } from "./HandleDataCache.js";
|
|
11
|
+
import { resolveFolderMessages } from "./MessageTarget.js";
|
|
12
|
+
import { resolvePropertyValues } from "./PropertyResolvers.js";
|
|
13
|
+
import { handleDataStoreOf } from "./RopHandler.js";
|
|
14
|
+
/**
|
|
15
|
+
* Builds the `FastTransfer` binary stream (`[MS-OXCFXICS]` §2.2.4) `RopFastTransferSourceCopyTo`/
|
|
16
|
+
* `CopyProperties` hand off to `RopFastTransferSourceGetBuffer` for paging out, per this pragmatic subset's own
|
|
17
|
+
* "ICS" scope (see the architecture plan's "Incremental sync" row): a **full, non-differential** dump of the
|
|
18
|
+
* target's current live state, built eagerly and stored whole on the output handle - not the real, much larger
|
|
19
|
+
* `contentsSync`/`hierarchySync` grammar (`IncrSyncChg`/`IncrSyncDel`/`IncrSyncStateBegin` markers), which
|
|
20
|
+
* requires a persisted per-device ICS state object (an `IDSET` baseline) this pragmatic subset doesn't
|
|
21
|
+
* implement. A real client that asks for an incremental sync here simply gets a full re-list every time and
|
|
22
|
+
* reconciles by diffing against its own local cache - spec-legitimate client behavior, just more state
|
|
23
|
+
* re-fetched per sync than a byte-perfect ICS server would send, exactly the tradeoff the plan accepts.
|
|
24
|
+
*
|
|
25
|
+
* Only the plain `PidTag*` properties this pragmatic subset already resolves via `PropertyResolvers.ts` are
|
|
26
|
+
* ever included - a Calendar item's own named properties (start/end/location/recurrence/...) are **not**
|
|
27
|
+
* included in the stream (only `PidTagSubject`), a deliberate scope cut: a client wanting those already has to
|
|
28
|
+
* `RopOpenMessage`+`RopGetPropertiesSpecific` the item directly (the same "just re-fetches more state" tradeoff
|
|
29
|
+
* applied one level deeper). No recipients/attachments/subfolders are emitted either - `messageChildren` is
|
|
30
|
+
* always empty and `Level` (whether to recurse into subfolders) is not honored, matching this pragmatic
|
|
31
|
+
* subset's existing "no `RopModifyRecipients`" and folder-hierarchy-is-flat-per-call precedents elsewhere.
|
|
32
|
+
*
|
|
33
|
+
* @author Jean-Philippe Steinmetz
|
|
34
|
+
*/
|
|
35
|
+
/** FastTransfer markers (`[MS-OXCFXICS]` §2.2.4.1.4, confirmed this session) - only the four this pragmatic
|
|
36
|
+
* subset's flat, non-differential dump ever needs. */
|
|
37
|
+
const MARKER_START_TOP_FLD = 0x40090003;
|
|
38
|
+
const MARKER_END_FOLDER = 0x400b0003;
|
|
39
|
+
const MARKER_START_MESSAGE = 0x400c0003;
|
|
40
|
+
const MARKER_END_MESSAGE = 0x400d0003;
|
|
41
|
+
/** The well-known columns this pragmatic subset includes by default when the caller (`RopFastTransferSourceCopyTo`)
|
|
42
|
+
* didn't supply an explicit include list - the same small "what a real client needs" sets `PropertyResolvers.ts`
|
|
43
|
+
* already defines its own defaults around. */
|
|
44
|
+
const DEFAULT_FOLDER_COLUMNS = [
|
|
45
|
+
{ propertyId: 0x3001, propertyType: PropertyType.PtypString }, // PidTagDisplayName
|
|
46
|
+
{ propertyId: 0x3602, propertyType: PropertyType.PtypInteger32 }, // PidTagContentCount
|
|
47
|
+
{ propertyId: 0x3603, propertyType: PropertyType.PtypInteger32 }, // PidTagContentUnreadCount
|
|
48
|
+
];
|
|
49
|
+
const DEFAULT_MESSAGE_COLUMNS = [
|
|
50
|
+
{ propertyId: 0x0037, propertyType: PropertyType.PtypString }, // PidTagSubject
|
|
51
|
+
{ propertyId: 0x0e07, propertyType: PropertyType.PtypInteger32 }, // PidTagMessageFlags
|
|
52
|
+
{ propertyId: 0x0e1b, propertyType: PropertyType.PtypBoolean }, // PidTagHasAttachments
|
|
53
|
+
{ propertyId: 0x0e06, propertyType: PropertyType.PtypTime }, // PidTagMessageDeliveryTime
|
|
54
|
+
];
|
|
55
|
+
/** A calendar item's named properties are deliberately excluded from the stream (see class doc comment) -
|
|
56
|
+
* `PidTagSubject` is the only column emitted for one. */
|
|
57
|
+
const DEFAULT_CALENDAR_COLUMNS = [{ propertyId: 0x0037, propertyType: PropertyType.PtypString }];
|
|
58
|
+
async function writePropList(writer, target, columns, context) {
|
|
59
|
+
const values = await resolvePropertyValues(target, columns, context);
|
|
60
|
+
columns.forEach((column, index) => writeTaggedPropertyValue(writer, { propertyId: column.propertyId, propertyType: column.propertyType, value: values[index] }));
|
|
61
|
+
}
|
|
62
|
+
function filterExcluded(columns, excludePropertyIds) {
|
|
63
|
+
return columns.filter((column) => !excludePropertyIds.has(column.propertyId));
|
|
64
|
+
}
|
|
65
|
+
/** The largest FastTransfer stream built for one handle; a larger source fails with `MAPI_E_TOO_BIG`. */
|
|
66
|
+
export const MAX_FAST_TRANSFER_BYTES = 32 * 1024 * 1024;
|
|
67
|
+
/** How long a built stream is kept for paging out. A client pages a stream out right after opening it; one that
|
|
68
|
+
* leaves it longer than this has to open the transfer again. */
|
|
69
|
+
export const FAST_TRANSFER_TTL_SECONDS = 10 * 60;
|
|
70
|
+
/** Thrown while building a stream that has grown past its byte limit. */
|
|
71
|
+
export class FastTransferTooBigError extends Error {
|
|
72
|
+
constructor() {
|
|
73
|
+
super("FastTransfer: the stream is larger than MAX_FAST_TRANSFER_BYTES.");
|
|
74
|
+
this.name = "FastTransferTooBigError";
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Builds the complete FastTransfer stream for `handle` (a `"folder"` or `"message"` Server object). `columns`,
|
|
79
|
+
* when given (a `RopFastTransferSourceCopyProperties` explicit include list), replaces every default column set
|
|
80
|
+
* uniformly at both folder- and message-level; `excludePropertyIds` (a `RopFastTransferSourceCopyTo` exclude
|
|
81
|
+
* list) is only ever applied to this pragmatic subset's own default columns, per the same reasoning.
|
|
82
|
+
*
|
|
83
|
+
* The size is checked after every item, so a huge folder stops being built as soon as it passes `maxBytes`
|
|
84
|
+
* (`FastTransferTooBigError`) instead of being fully built first. Every item resolved and the finished stream's bytes
|
|
85
|
+
* count against the request's `ExecuteBudget` when there is one.
|
|
86
|
+
*/
|
|
87
|
+
export async function buildFastTransferStream(handle, context, options = {}) {
|
|
88
|
+
const writer = new BufferWriter();
|
|
89
|
+
const exclude = options.excludePropertyIds ?? new Set();
|
|
90
|
+
const maxBytes = options.maxBytes ?? MAX_FAST_TRANSFER_BYTES;
|
|
91
|
+
const checkSize = () => {
|
|
92
|
+
if (writer.length > maxBytes) {
|
|
93
|
+
throw new FastTransferTooBigError();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
if (handle.type === "folder") {
|
|
97
|
+
const folderColumns = options.columns ?? filterExcluded(DEFAULT_FOLDER_COLUMNS, exclude);
|
|
98
|
+
writer.writeUInt32LE(MARKER_START_TOP_FLD);
|
|
99
|
+
await writePropList(writer, handle.entityUid, folderColumns, context);
|
|
100
|
+
if (handle.entityUid.startsWith("folder:")) {
|
|
101
|
+
const folderUid = handle.entityUid.slice("folder:".length);
|
|
102
|
+
const folder = await context.folderRepo.findOne(folderUid, { ignoreACL: true });
|
|
103
|
+
const isCalendar = folder?.type === FolderType.CALENDAR;
|
|
104
|
+
const rows = isCalendar
|
|
105
|
+
? await resolveFolderCalendarEvents(folderUid, context.calendarEventRepo, context.budget)
|
|
106
|
+
: await resolveFolderMessages(folderUid, context.messageRepo, context.budget);
|
|
107
|
+
const messageColumns = options.columns ?? filterExcluded(isCalendar ? DEFAULT_CALENDAR_COLUMNS : DEFAULT_MESSAGE_COLUMNS, exclude);
|
|
108
|
+
for (const row of rows) {
|
|
109
|
+
writer.writeUInt32LE(MARKER_START_MESSAGE);
|
|
110
|
+
await writePropList(writer, row, messageColumns, context);
|
|
111
|
+
writer.writeUInt32LE(MARKER_END_MESSAGE);
|
|
112
|
+
checkSize();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
writer.writeUInt32LE(MARKER_END_FOLDER);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const isCalendar = handle.entityUid.startsWith("calendarEvent:");
|
|
119
|
+
const columns = options.columns ?? filterExcluded(isCalendar ? DEFAULT_CALENDAR_COLUMNS : DEFAULT_MESSAGE_COLUMNS, exclude);
|
|
120
|
+
await writePropList(writer, handle.entityUid, columns, context);
|
|
121
|
+
}
|
|
122
|
+
checkSize();
|
|
123
|
+
context.budget?.chargeBytes(writer.length);
|
|
124
|
+
return writer.toBuffer();
|
|
125
|
+
}
|
|
126
|
+
/** Builds a `"fastTransfer"` handle's stream from what the handle records about its source, or `undefined` when it
|
|
127
|
+
* is larger than `MAX_FAST_TRANSFER_BYTES`. */
|
|
128
|
+
async function rebuildFastTransferStream(transfer, context) {
|
|
129
|
+
try {
|
|
130
|
+
return await buildFastTransferStream({ type: transfer.transferSourceType, entityUid: transfer.entityUid }, context, {
|
|
131
|
+
columns: transfer.transferColumns,
|
|
132
|
+
excludePropertyIds: new Set(transfer.transferExcludeIds ?? []),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
if (err instanceof FastTransferTooBigError) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
throw err;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The built stream for the `"fastTransfer"` handle at `handleIndex`, from the shared `HandleDataStore` (Redis when
|
|
144
|
+
* configured, so any replica can page it out).
|
|
145
|
+
*
|
|
146
|
+
* When the stream is gone (expired, evicted, or built by a replica without shared storage), it is rebuilt only if
|
|
147
|
+
* nothing has been paged out yet. Part-way through, a rebuild could differ from what the client already has (items
|
|
148
|
+
* added or changed since), and continuing at the old offset would hand it bytes from a different stream, so that
|
|
149
|
+
* case reports `"lost"` and the client restarts the transfer. A rebuild is held to `MAX_FAST_TRANSFER_BYTES` like
|
|
150
|
+
* the original build, and storing it to the session's and user's handle data quota (`handleDataOwners`); either
|
|
151
|
+
* failing reports `"tooBig"`.
|
|
152
|
+
*/
|
|
153
|
+
export async function loadFastTransferBuffer(context, handleIndex, transfer) {
|
|
154
|
+
const store = handleDataStoreOf(context);
|
|
155
|
+
const key = handleDataKey(context.session.uid, handleIndex, transfer.generation);
|
|
156
|
+
const stored = await store.get(key);
|
|
157
|
+
if (stored) {
|
|
158
|
+
return stored;
|
|
159
|
+
}
|
|
160
|
+
if ((transfer.transferPosition ?? 0) > 0) {
|
|
161
|
+
return "lost";
|
|
162
|
+
}
|
|
163
|
+
const buffer = await rebuildFastTransferStream(transfer, context);
|
|
164
|
+
if (!buffer || !(await store.set(key, buffer, FAST_TRANSFER_TTL_SECONDS, handleDataOwners(context.session.uid, context.session.userUid)))) {
|
|
165
|
+
return "tooBig";
|
|
166
|
+
}
|
|
167
|
+
return buffer;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Shared by `RopFastTransferSourceCopyTo`/`CopyProperties`: builds the stream for `source`, and on success stores a
|
|
171
|
+
* `"fastTransfer"` handle at `outputHandleIndex` with the stream in the `HandleDataStore`. Returns `false`, storing
|
|
172
|
+
* nothing, when the stream exceeds `MAX_FAST_TRANSFER_BYTES` or the session's or user's handle data quota
|
|
173
|
+
* (`handleDataOwners`) has no room for it.
|
|
174
|
+
*/
|
|
175
|
+
export async function openFastTransferHandle(context, outputHandleIndex, source, options) {
|
|
176
|
+
const transfer = {
|
|
177
|
+
type: "fastTransfer",
|
|
178
|
+
entityUid: source.entityUid,
|
|
179
|
+
transferSourceType: source.type === "folder" ? "folder" : "message",
|
|
180
|
+
transferColumns: options.columns,
|
|
181
|
+
transferExcludeIds: options.excludePropertyIds,
|
|
182
|
+
transferPosition: 0,
|
|
183
|
+
};
|
|
184
|
+
const buffer = await rebuildFastTransferStream(transfer, context);
|
|
185
|
+
if (!buffer) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
assignHandle(context.session, outputHandleIndex, transfer);
|
|
189
|
+
const stored = await handleDataStoreOf(context).set(handleDataKey(context.session.uid, outputHandleIndex, transfer.generation), buffer, FAST_TRANSFER_TTL_SECONDS, handleDataOwners(context.session.uid, context.session.userUid));
|
|
190
|
+
if (!stored) {
|
|
191
|
+
releaseHandle(context.session, outputHandleIndex);
|
|
192
|
+
}
|
|
193
|
+
return stored;
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=FastTransferStream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FastTransferStream.js","sourceRoot":"","sources":["../../../src/rop/FastTransferStream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { findAllCapped, MAX_COLLECTION_ROWS } from "./RepoPaging.js";
|
|
2
|
+
/** Every folder in `mailboxUid` (up to `MAX_COLLECTION_ROWS`), by name. Paged explicitly: a bare `find()` stops at
|
|
3
|
+
* the repo's 100-row default, which silently dropped folders from hierarchy tables in larger mailboxes. Each page is
|
|
4
|
+
* charged to `budget` before it is read. */
|
|
5
|
+
async function findMailboxFolders(mailboxUid, folderRepo, budget) {
|
|
6
|
+
return (await findAllCapped(folderRepo, { mailboxUid }, { name: "ASC", uid: "ASC" }, MAX_COLLECTION_ROWS, budget)).items;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Shared helpers for resolving the `"virtual:<name>"`/`"folder:<uid>"` target strings `RopLogonHandler`
|
|
10
|
+
* assigns to FIDs (see its own doc comment) into real folder data - used by `RopOpenFolderHandler` and
|
|
11
|
+
* `RopGetHierarchyTableHandler`.
|
|
12
|
+
*/
|
|
13
|
+
/** Display names for the virtual (no real backing `Folder`) special folders - see `RopLogonHandler`'s own
|
|
14
|
+
* doc comment for why these don't have real rows in this data model. */
|
|
15
|
+
const VIRTUAL_DISPLAY_NAMES = {
|
|
16
|
+
root: "Root",
|
|
17
|
+
deferredAction: "Deferred Action",
|
|
18
|
+
spoolerQueue: "Spooler Queue",
|
|
19
|
+
ipmSubtree: "Top of Information Store",
|
|
20
|
+
commonViews: "Common Views",
|
|
21
|
+
schedule: "Schedule",
|
|
22
|
+
search: "Finder",
|
|
23
|
+
views: "Views",
|
|
24
|
+
shortcuts: "Shortcuts",
|
|
25
|
+
};
|
|
26
|
+
/** Resolves a target string into the display data a folder-table row needs. A `"folder:<uid>"` target whose
|
|
27
|
+
* `Folder` has since been deleted (soft-deleted or otherwise vanished) degrades to empty-looking values rather
|
|
28
|
+
* than throwing - the row simply won't be interesting to a client, not a reason to fail the whole ROP. */
|
|
29
|
+
export async function resolveFolderInfo(mailboxUid, target, folderRepo, cache, budget) {
|
|
30
|
+
if (target.startsWith("folder:")) {
|
|
31
|
+
const uid = target.slice("folder:".length);
|
|
32
|
+
const folder = await folderRepo.findOne(uid, { ignoreACL: true });
|
|
33
|
+
const hasChildren = (await resolveFolderChildren(mailboxUid, target, folderRepo, cache, budget)).length > 0;
|
|
34
|
+
return {
|
|
35
|
+
displayName: folder?.name ?? "",
|
|
36
|
+
unreadCount: folder?.unreadCount ?? 0,
|
|
37
|
+
totalCount: folder?.totalCount ?? 0,
|
|
38
|
+
hasChildren,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
const name = target.slice("virtual:".length);
|
|
42
|
+
const hasChildren = (await resolveFolderChildren(mailboxUid, target, folderRepo, cache, budget)).length > 0;
|
|
43
|
+
return { displayName: VIRTUAL_DISPLAY_NAMES[name] ?? name, unreadCount: 0, totalCount: 0, hasChildren };
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Resolves the direct children of `target`, as an array of the same target-string format, for
|
|
47
|
+
* `RopGetHierarchyTable`. Only `"virtual:root"`/`"virtual:ipmSubtree"` (this mailbox's top-level real
|
|
48
|
+
* folders - both collapse to the same "top of the visible tree" concept in this pragmatic subset, see
|
|
49
|
+
* `RopLogonHandler`'s own doc comment) and a real folder (its own real children) have any children at all;
|
|
50
|
+
* every other virtual folder (Deferred Action, Spooler Queue, ...) is permanently empty, since this data
|
|
51
|
+
* model has no concept of nesting anything under them.
|
|
52
|
+
*
|
|
53
|
+
* Filters an already-fetched full folder list in application code rather than querying by
|
|
54
|
+
* `parentFolderUid: undefined` directly - query-DSL semantics for "field is unset" aren't reliably consistent
|
|
55
|
+
* across backends (the exact kind of gap this project's own testing philosophy has caught before, e.g. `$or`
|
|
56
|
+
* being Mongo-only), so filtering a fetched array sidesteps the question entirely rather than risking it.
|
|
57
|
+
* The comparison itself uses `== null` (matching both `null` and `undefined`), not `=== undefined` - a
|
|
58
|
+
* top-level folder's unset `parentFolderUid` round-trips as genuine `undefined` from Mongo but as `null` from
|
|
59
|
+
* a SQL `nullable` column, a real, previously-confirmed cross-backend discrepancy in this codebase (caught by
|
|
60
|
+
* this exact test against a real SQLite-backed server, not assumed).
|
|
61
|
+
*
|
|
62
|
+
* **`cache`**: without it, this fetches every folder in the mailbox on every call - fine for the single call
|
|
63
|
+
* `RopGetHierarchyTableHandler` makes to build a table, but `resolveFolderInfo` also calls this once per row
|
|
64
|
+
* just to compute `hasChildren`, and a table page can hold many rows. A caller resolving a whole page (
|
|
65
|
+
* `RopQueryRowsHandler`/`RopGetPropertiesSpecificHandler`) passes one shared cache object through every call in
|
|
66
|
+
* that batch so the full list is fetched at most once per batch instead of once per row - see
|
|
67
|
+
* `FolderResolutionCache`'s own doc comment for why this isn't session state.
|
|
68
|
+
*/
|
|
69
|
+
export async function resolveFolderChildren(mailboxUid, target, folderRepo, cache, budget) {
|
|
70
|
+
const isTopLevel = target === "virtual:root" || target === "virtual:ipmSubtree";
|
|
71
|
+
let parentFolderUid;
|
|
72
|
+
if (isTopLevel) {
|
|
73
|
+
parentFolderUid = undefined;
|
|
74
|
+
}
|
|
75
|
+
else if (target.startsWith("folder:")) {
|
|
76
|
+
parentFolderUid = target.slice("folder:".length);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
let allFolders;
|
|
82
|
+
if (cache) {
|
|
83
|
+
cache.allFolders ?? (cache.allFolders = await findMailboxFolders(mailboxUid, folderRepo, budget));
|
|
84
|
+
allFolders = cache.allFolders;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
allFolders = await findMailboxFolders(mailboxUid, folderRepo, budget);
|
|
88
|
+
}
|
|
89
|
+
return allFolders
|
|
90
|
+
.filter((f) => (isTopLevel ? f.parentFolderUid == null : f.parentFolderUid === parentFolderUid))
|
|
91
|
+
.map((f) => `folder:${f.uid}`);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Returns `target`'s existing FID if `RopLogon` or an earlier `RopGetHierarchyTable` row already assigned
|
|
95
|
+
* one, otherwise assigns and remembers the next free small integer FID. This is what lets a client
|
|
96
|
+
* `RopOpenFolder` a child folder it only ever learned about via a `RopQueryRows` row's `PidTagFolderId`
|
|
97
|
+
* column - without this, only the 13 `RopLogon`-time special folders could ever be opened.
|
|
98
|
+
*
|
|
99
|
+
* Backed by `session.folderTargetIds` (target -> FID) and `session.nextFolderId`, an O(1) reverse index/counter
|
|
100
|
+
* pair rather than a linear scan of `session.folderIds` plus a `Math.max(...spread)` over its keys - both real
|
|
101
|
+
* costs, not just theoretical ones: `folderTargetIds` only ever grows for a session's lifetime as a client
|
|
102
|
+
* browses more of a mailbox's folder tree, so the old scan-per-lookup approach was quadratic across a session
|
|
103
|
+
* that opens many folders, and `Math.max` spreading an unbounded array as call arguments risked a stack
|
|
104
|
+
* overflow past V8's argument-count limit on a mailbox with enough folders. `RopLogonHandler` keeps
|
|
105
|
+
* `folderTargetIds`/`nextFolderId` in sync with `folderIds` for the 13 special folders it assigns directly,
|
|
106
|
+
* rather than going through this function, since it assigns all 13 as one batch up front.
|
|
107
|
+
*/
|
|
108
|
+
export function assignOrGetFid(session, target) {
|
|
109
|
+
const existing = session.folderTargetIds[target];
|
|
110
|
+
if (existing !== undefined) {
|
|
111
|
+
return existing;
|
|
112
|
+
}
|
|
113
|
+
const fid = session.nextFolderId++;
|
|
114
|
+
session.folderIds[String(fid)] = target;
|
|
115
|
+
session.folderTargetIds[target] = fid;
|
|
116
|
+
return fid;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=FolderTarget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FolderTarget.js","sourceRoot":"","sources":["../../../src/rop/FolderTarget.ts"],"names":[],"mappings":"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"}
|