@rapidmx/mapi-plugin 1.0.0-beta.3 → 1.0.0-beta.4

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.
Files changed (154) hide show
  1. package/README.md +4 -4
  2. package/dist/lib/BaseMapiEmsmdbRoute.js +211 -36
  3. package/dist/lib/BaseMapiEmsmdbRoute.js.map +1 -1
  4. package/dist/lib/MapiSessionManager.js +404 -48
  5. package/dist/lib/MapiSessionManager.js.map +1 -1
  6. package/dist/lib/RegexPatternUtils.js +30 -0
  7. package/dist/lib/RegexPatternUtils.js.map +1 -0
  8. package/dist/lib/RopDispatcher.js +130 -19
  9. package/dist/lib/RopDispatcher.js.map +1 -1
  10. package/dist/lib/codec/AppointmentRecurrence.js +22 -21
  11. package/dist/lib/codec/AppointmentRecurrence.js.map +1 -1
  12. package/dist/lib/codec/BufferCursor.js +41 -12
  13. package/dist/lib/codec/BufferCursor.js.map +1 -1
  14. package/dist/lib/codec/GlobalObjectId.js +26 -20
  15. package/dist/lib/codec/GlobalObjectId.js.map +1 -1
  16. package/dist/lib/codec/MapiTimeZone.js +43 -10
  17. package/dist/lib/codec/MapiTimeZone.js.map +1 -1
  18. package/dist/lib/codec/PropertyValue.js +28 -2
  19. package/dist/lib/codec/PropertyValue.js.map +1 -1
  20. package/dist/lib/codec/RopBuffer.js +15 -3
  21. package/dist/lib/codec/RopBuffer.js.map +1 -1
  22. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +2 -1
  23. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -1
  24. package/dist/lib/nspi/NspiCodec.js +5 -5
  25. package/dist/lib/nspi/NspiCodec.js.map +1 -1
  26. package/dist/lib/nspi/NspiGetMatchesHandler.js +14 -14
  27. package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -1
  28. package/dist/lib/rop/AddressList.js +109 -0
  29. package/dist/lib/rop/AddressList.js.map +1 -0
  30. package/dist/lib/rop/CalendarEventTarget.js +7 -4
  31. package/dist/lib/rop/CalendarEventTarget.js.map +1 -1
  32. package/dist/lib/rop/ContactTarget.js +2 -6
  33. package/dist/lib/rop/ContactTarget.js.map +1 -1
  34. package/dist/lib/rop/ContentsTable.js +60 -0
  35. package/dist/lib/rop/ContentsTable.js.map +1 -0
  36. package/dist/lib/rop/ExecuteBudget.js +82 -0
  37. package/dist/lib/rop/ExecuteBudget.js.map +1 -0
  38. package/dist/lib/rop/FastTransferStream.js +99 -2
  39. package/dist/lib/rop/FastTransferStream.js.map +1 -1
  40. package/dist/lib/rop/FolderTarget.js +13 -6
  41. package/dist/lib/rop/FolderTarget.js.map +1 -1
  42. package/dist/lib/rop/HandleDataCache.js +412 -0
  43. package/dist/lib/rop/HandleDataCache.js.map +1 -0
  44. package/dist/lib/rop/MeetingMessageClassHandler.js +194 -48
  45. package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -1
  46. package/dist/lib/rop/MessageBodyStream.js +33 -7
  47. package/dist/lib/rop/MessageBodyStream.js.map +1 -1
  48. package/dist/lib/rop/MessageTarget.js +17 -4
  49. package/dist/lib/rop/MessageTarget.js.map +1 -1
  50. package/dist/lib/rop/NamedPropertyRegistry.js +8 -5
  51. package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -1
  52. package/dist/lib/rop/PropertyResolvers.js +3 -1
  53. package/dist/lib/rop/PropertyResolvers.js.map +1 -1
  54. package/dist/lib/rop/RepoPaging.js +54 -0
  55. package/dist/lib/rop/RepoPaging.js.map +1 -0
  56. package/dist/lib/rop/RestapiRules.js +52 -0
  57. package/dist/lib/rop/RestapiRules.js.map +1 -0
  58. package/dist/lib/rop/RopCreateMessageHandler.js +4 -2
  59. package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -1
  60. package/dist/lib/rop/RopDeleteFolderHandler.js +112 -77
  61. package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -1
  62. package/dist/lib/rop/RopDeleteMessagesHandler.js +17 -1
  63. package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -1
  64. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +14 -14
  65. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -1
  66. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +13 -14
  67. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -1
  68. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +33 -32
  69. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -1
  70. package/dist/lib/rop/RopGetContentsTableHandler.js +17 -38
  71. package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -1
  72. package/dist/lib/rop/RopGetHierarchyTableHandler.js +4 -2
  73. package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -1
  74. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +6 -8
  75. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -1
  76. package/dist/lib/rop/RopHandler.js +5 -1
  77. package/dist/lib/rop/RopHandler.js.map +1 -1
  78. package/dist/lib/rop/RopLogonHandler.js +5 -2
  79. package/dist/lib/rop/RopLogonHandler.js.map +1 -1
  80. package/dist/lib/rop/RopOpenFolderHandler.js +3 -1
  81. package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -1
  82. package/dist/lib/rop/RopOpenMessageHandler.js +3 -1
  83. package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -1
  84. package/dist/lib/rop/RopOpenStreamHandler.js +11 -8
  85. package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -1
  86. package/dist/lib/rop/RopQueryRowsHandler.js +31 -5
  87. package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -1
  88. package/dist/lib/rop/RopReadStreamHandler.js +22 -4
  89. package/dist/lib/rop/RopReadStreamHandler.js.map +1 -1
  90. package/dist/lib/rop/RopReleaseHandler.js +4 -1
  91. package/dist/lib/rop/RopReleaseHandler.js.map +1 -1
  92. package/dist/lib/rop/RopSaveChangesMessageHandler.js +66 -7
  93. package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -1
  94. package/dist/lib/rop/RopSetColumnsHandler.js +6 -8
  95. package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -1
  96. package/dist/lib/rop/RopSetPropertiesHandler.js +23 -12
  97. package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -1
  98. package/dist/lib/rop/RopSubmitMessageHandler.js +144 -120
  99. package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -1
  100. package/dist/lib/rop/RopWriteStreamHandler.js +37 -10
  101. package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -1
  102. package/dist/lib/rop/TaskTarget.js +2 -6
  103. package/dist/lib/rop/TaskTarget.js.map +1 -1
  104. package/dist/lib/rop/TransportSend.js +16 -0
  105. package/dist/lib/rop/TransportSend.js.map +1 -0
  106. package/dist/lib/sql/MapiEmsmdbRouteSQL.js +2 -1
  107. package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -1
  108. package/dist/types/BaseMapiEmsmdbRoute.d.ts +52 -2
  109. package/dist/types/MapiSessionManager.d.ts +218 -63
  110. package/dist/types/RegexPatternUtils.d.ts +14 -0
  111. package/dist/types/RopDispatcher.d.ts +47 -11
  112. package/dist/types/codec/BufferCursor.d.ts +14 -0
  113. package/dist/types/codec/GlobalObjectId.d.ts +9 -5
  114. package/dist/types/codec/PropertyValue.d.ts +10 -0
  115. package/dist/types/codec/RopBuffer.d.ts +7 -0
  116. package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +1 -0
  117. package/dist/types/nspi/NspiGetMatchesHandler.d.ts +2 -0
  118. package/dist/types/rop/AddressList.d.ts +48 -0
  119. package/dist/types/rop/CalendarEventTarget.d.ts +7 -3
  120. package/dist/types/rop/ContactTarget.d.ts +3 -3
  121. package/dist/types/rop/ContentsTable.d.ts +16 -0
  122. package/dist/types/rop/ExecuteBudget.d.ts +48 -0
  123. package/dist/types/rop/FastTransferStream.d.ts +41 -2
  124. package/dist/types/rop/FolderTarget.d.ts +3 -2
  125. package/dist/types/rop/HandleDataCache.d.ts +145 -0
  126. package/dist/types/rop/MeetingMessageClassHandler.d.ts +23 -29
  127. package/dist/types/rop/MessageBodyStream.d.ts +16 -7
  128. package/dist/types/rop/MessageTarget.d.ts +10 -3
  129. package/dist/types/rop/NamedPropertyRegistry.d.ts +6 -2
  130. package/dist/types/rop/PropertyResolvers.d.ts +1 -1
  131. package/dist/types/rop/RepoPaging.d.ts +30 -0
  132. package/dist/types/rop/RestapiRules.d.ts +32 -0
  133. package/dist/types/rop/RopCreateMessageHandler.d.ts +1 -0
  134. package/dist/types/rop/RopDeleteFolderHandler.d.ts +36 -21
  135. package/dist/types/rop/RopDeleteMessagesHandler.d.ts +7 -0
  136. package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +1 -0
  137. package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +1 -0
  138. package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +10 -11
  139. package/dist/types/rop/RopGetContentsTableHandler.d.ts +7 -13
  140. package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +1 -0
  141. package/dist/types/rop/RopHandler.d.ts +25 -1
  142. package/dist/types/rop/RopOpenFolderHandler.d.ts +1 -0
  143. package/dist/types/rop/RopOpenMessageHandler.d.ts +1 -0
  144. package/dist/types/rop/RopOpenStreamHandler.d.ts +1 -0
  145. package/dist/types/rop/RopQueryRowsHandler.d.ts +3 -0
  146. package/dist/types/rop/RopReadStreamHandler.d.ts +3 -1
  147. package/dist/types/rop/RopReleaseHandler.d.ts +1 -0
  148. package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +16 -1
  149. package/dist/types/rop/RopSubmitMessageHandler.d.ts +33 -23
  150. package/dist/types/rop/RopWriteStreamHandler.d.ts +18 -8
  151. package/dist/types/rop/TaskTarget.d.ts +3 -3
  152. package/dist/types/rop/TransportSend.d.ts +10 -0
  153. package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +1 -0
  154. package/package.json +3 -3
@@ -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"}
@@ -5,9 +5,12 @@
5
5
  import { FolderType } from "@rapidmx/restapi";
6
6
  import { BufferWriter } from "../codec/BufferCursor.js";
7
7
  import { PropertyType, writeTaggedPropertyValue } from "../codec/PropertyValue.js";
8
+ import { assignHandle, releaseHandle } from "../MapiSessionManager.js";
8
9
  import { resolveFolderCalendarEvents } from "./CalendarEventTarget.js";
10
+ import { handleDataKey, handleDataOwners } from "./HandleDataCache.js";
9
11
  import { resolveFolderMessages } from "./MessageTarget.js";
10
12
  import { resolvePropertyValues } from "./PropertyResolvers.js";
13
+ import { handleDataStoreOf } from "./RopHandler.js";
11
14
  /**
12
15
  * Builds the `FastTransfer` binary stream (`[MS-OXCFXICS]` §2.2.4) `RopFastTransferSourceCopyTo`/
13
16
  * `CopyProperties` hand off to `RopFastTransferSourceGetBuffer` for paging out, per this pragmatic subset's own
@@ -59,15 +62,37 @@ async function writePropList(writer, target, columns, context) {
59
62
  function filterExcluded(columns, excludePropertyIds) {
60
63
  return columns.filter((column) => !excludePropertyIds.has(column.propertyId));
61
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
+ }
62
77
  /**
63
78
  * Builds the complete FastTransfer stream for `handle` (a `"folder"` or `"message"` Server object). `columns`,
64
79
  * when given (a `RopFastTransferSourceCopyProperties` explicit include list), replaces every default column set
65
80
  * uniformly at both folder- and message-level; `excludePropertyIds` (a `RopFastTransferSourceCopyTo` exclude
66
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.
67
86
  */
68
87
  export async function buildFastTransferStream(handle, context, options = {}) {
69
88
  const writer = new BufferWriter();
70
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
+ };
71
96
  if (handle.type === "folder") {
72
97
  const folderColumns = options.columns ?? filterExcluded(DEFAULT_FOLDER_COLUMNS, exclude);
73
98
  writer.writeUInt32LE(MARKER_START_TOP_FLD);
@@ -77,13 +102,14 @@ export async function buildFastTransferStream(handle, context, options = {}) {
77
102
  const folder = await context.folderRepo.findOne(folderUid, { ignoreACL: true });
78
103
  const isCalendar = folder?.type === FolderType.CALENDAR;
79
104
  const rows = isCalendar
80
- ? await resolveFolderCalendarEvents(folderUid, context.calendarEventRepo)
81
- : await resolveFolderMessages(folderUid, context.messageRepo);
105
+ ? await resolveFolderCalendarEvents(folderUid, context.calendarEventRepo, context.budget)
106
+ : await resolveFolderMessages(folderUid, context.messageRepo, context.budget);
82
107
  const messageColumns = options.columns ?? filterExcluded(isCalendar ? DEFAULT_CALENDAR_COLUMNS : DEFAULT_MESSAGE_COLUMNS, exclude);
83
108
  for (const row of rows) {
84
109
  writer.writeUInt32LE(MARKER_START_MESSAGE);
85
110
  await writePropList(writer, row, messageColumns, context);
86
111
  writer.writeUInt32LE(MARKER_END_MESSAGE);
112
+ checkSize();
87
113
  }
88
114
  }
89
115
  writer.writeUInt32LE(MARKER_END_FOLDER);
@@ -93,6 +119,77 @@ export async function buildFastTransferStream(handle, context, options = {}) {
93
119
  const columns = options.columns ?? filterExcluded(isCalendar ? DEFAULT_CALENDAR_COLUMNS : DEFAULT_MESSAGE_COLUMNS, exclude);
94
120
  await writePropList(writer, handle.entityUid, columns, context);
95
121
  }
122
+ checkSize();
123
+ context.budget?.chargeBytes(writer.length);
96
124
  return writer.toBuffer();
97
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
+ }
98
195
  //# sourceMappingURL=FastTransferStream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FastTransferStream.js","sourceRoot":"","sources":["../../../src/rop/FastTransferStream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FastTransferStream.js","sourceRoot":"","sources":["../../../src/rop/FastTransferStream.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,10 @@
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
+ }
1
8
  /**
2
9
  * Shared helpers for resolving the `"virtual:<name>"`/`"folder:<uid>"` target strings `RopLogonHandler`
3
10
  * assigns to FIDs (see its own doc comment) into real folder data - used by `RopOpenFolderHandler` and
@@ -19,11 +26,11 @@ const VIRTUAL_DISPLAY_NAMES = {
19
26
  /** Resolves a target string into the display data a folder-table row needs. A `"folder:<uid>"` target whose
20
27
  * `Folder` has since been deleted (soft-deleted or otherwise vanished) degrades to empty-looking values rather
21
28
  * than throwing - the row simply won't be interesting to a client, not a reason to fail the whole ROP. */
22
- export async function resolveFolderInfo(mailboxUid, target, folderRepo, cache) {
29
+ export async function resolveFolderInfo(mailboxUid, target, folderRepo, cache, budget) {
23
30
  if (target.startsWith("folder:")) {
24
31
  const uid = target.slice("folder:".length);
25
32
  const folder = await folderRepo.findOne(uid, { ignoreACL: true });
26
- const hasChildren = (await resolveFolderChildren(mailboxUid, target, folderRepo, cache)).length > 0;
33
+ const hasChildren = (await resolveFolderChildren(mailboxUid, target, folderRepo, cache, budget)).length > 0;
27
34
  return {
28
35
  displayName: folder?.name ?? "",
29
36
  unreadCount: folder?.unreadCount ?? 0,
@@ -32,7 +39,7 @@ export async function resolveFolderInfo(mailboxUid, target, folderRepo, cache) {
32
39
  };
33
40
  }
34
41
  const name = target.slice("virtual:".length);
35
- const hasChildren = (await resolveFolderChildren(mailboxUid, target, folderRepo, cache)).length > 0;
42
+ const hasChildren = (await resolveFolderChildren(mailboxUid, target, folderRepo, cache, budget)).length > 0;
36
43
  return { displayName: VIRTUAL_DISPLAY_NAMES[name] ?? name, unreadCount: 0, totalCount: 0, hasChildren };
37
44
  }
38
45
  /**
@@ -59,7 +66,7 @@ export async function resolveFolderInfo(mailboxUid, target, folderRepo, cache) {
59
66
  * that batch so the full list is fetched at most once per batch instead of once per row - see
60
67
  * `FolderResolutionCache`'s own doc comment for why this isn't session state.
61
68
  */
62
- export async function resolveFolderChildren(mailboxUid, target, folderRepo, cache) {
69
+ export async function resolveFolderChildren(mailboxUid, target, folderRepo, cache, budget) {
63
70
  const isTopLevel = target === "virtual:root" || target === "virtual:ipmSubtree";
64
71
  let parentFolderUid;
65
72
  if (isTopLevel) {
@@ -73,11 +80,11 @@ export async function resolveFolderChildren(mailboxUid, target, folderRepo, cach
73
80
  }
74
81
  let allFolders;
75
82
  if (cache) {
76
- cache.allFolders ?? (cache.allFolders = await folderRepo.find({ mailboxUid }, { ignoreACL: true }));
83
+ cache.allFolders ?? (cache.allFolders = await findMailboxFolders(mailboxUid, folderRepo, budget));
77
84
  allFolders = cache.allFolders;
78
85
  }
79
86
  else {
80
- allFolders = await folderRepo.find({ mailboxUid }, { ignoreACL: true });
87
+ allFolders = await findMailboxFolders(mailboxUid, folderRepo, budget);
81
88
  }
82
89
  return allFolders
83
90
  .filter((f) => (isTopLevel ? f.parentFolderUid == null : f.parentFolderUid === parentFolderUid))
@@ -1 +1 @@
1
- {"version":3,"file":"FolderTarget.js","sourceRoot":"","sources":["../../../src/rop/FolderTarget.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FolderTarget.js","sourceRoot":"","sources":["../../../src/rop/FolderTarget.ts"],"names":[],"mappings":"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"}