@rapidmx/mapi-plugin 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.
Files changed (180) hide show
  1. package/LICENSE +382 -0
  2. package/README.md +60 -0
  3. package/dist/lib/BaseMapiEmsmdbRoute.js +297 -0
  4. package/dist/lib/BaseMapiEmsmdbRoute.js.map +1 -0
  5. package/dist/lib/BaseMapiNspiRoute.js +114 -0
  6. package/dist/lib/BaseMapiNspiRoute.js.map +1 -0
  7. package/dist/lib/MapiSessionManager.js +119 -0
  8. package/dist/lib/MapiSessionManager.js.map +1 -0
  9. package/dist/lib/RopDispatcher.js +34 -0
  10. package/dist/lib/RopDispatcher.js.map +1 -0
  11. package/dist/lib/codec/AppointmentRecurrence.js +314 -0
  12. package/dist/lib/codec/AppointmentRecurrence.js.map +1 -0
  13. package/dist/lib/codec/BufferCursor.js +213 -0
  14. package/dist/lib/codec/BufferCursor.js.map +1 -0
  15. package/dist/lib/codec/GlobalObjectId.js +92 -0
  16. package/dist/lib/codec/GlobalObjectId.js.map +1 -0
  17. package/dist/lib/codec/MapiGuid.js +41 -0
  18. package/dist/lib/codec/MapiGuid.js.map +1 -0
  19. package/dist/lib/codec/MapiTimeZone.js +93 -0
  20. package/dist/lib/codec/MapiTimeZone.js.map +1 -0
  21. package/dist/lib/codec/PropertyValue.js +214 -0
  22. package/dist/lib/codec/PropertyValue.js.map +1 -0
  23. package/dist/lib/codec/RopBuffer.js +26 -0
  24. package/dist/lib/codec/RopBuffer.js.map +1 -0
  25. package/dist/lib/codec/TypedString.js +54 -0
  26. package/dist/lib/codec/TypedString.js.map +1 -0
  27. package/dist/lib/index.js +99 -0
  28. package/dist/lib/index.js.map +1 -0
  29. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +84 -0
  30. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -0
  31. package/dist/lib/mongo/MapiNspiRouteMongo.js +33 -0
  32. package/dist/lib/mongo/MapiNspiRouteMongo.js.map +1 -0
  33. package/dist/lib/mongo/index.js +7 -0
  34. package/dist/lib/mongo/index.js.map +1 -0
  35. package/dist/lib/mongo.js +6 -0
  36. package/dist/lib/mongo.js.map +1 -0
  37. package/dist/lib/nspi/NspiBindHandler.js +54 -0
  38. package/dist/lib/nspi/NspiBindHandler.js.map +1 -0
  39. package/dist/lib/nspi/NspiCodec.js +106 -0
  40. package/dist/lib/nspi/NspiCodec.js.map +1 -0
  41. package/dist/lib/nspi/NspiGetMatchesHandler.js +142 -0
  42. package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -0
  43. package/dist/lib/rop/CalendarEventTarget.js +27 -0
  44. package/dist/lib/rop/CalendarEventTarget.js.map +1 -0
  45. package/dist/lib/rop/CalendarNamedProperties.js +57 -0
  46. package/dist/lib/rop/CalendarNamedProperties.js.map +1 -0
  47. package/dist/lib/rop/ContactTarget.js +23 -0
  48. package/dist/lib/rop/ContactTarget.js.map +1 -0
  49. package/dist/lib/rop/FastTransferStream.js +98 -0
  50. package/dist/lib/rop/FastTransferStream.js.map +1 -0
  51. package/dist/lib/rop/FolderTarget.js +111 -0
  52. package/dist/lib/rop/FolderTarget.js.map +1 -0
  53. package/dist/lib/rop/MeetingMessageClassHandler.js +95 -0
  54. package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -0
  55. package/dist/lib/rop/MessageBodyStream.js +42 -0
  56. package/dist/lib/rop/MessageBodyStream.js.map +1 -0
  57. package/dist/lib/rop/MessageTarget.js +44 -0
  58. package/dist/lib/rop/MessageTarget.js.map +1 -0
  59. package/dist/lib/rop/NamedPropertyRegistry.js +66 -0
  60. package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -0
  61. package/dist/lib/rop/PropertyResolvers.js +313 -0
  62. package/dist/lib/rop/PropertyResolvers.js.map +1 -0
  63. package/dist/lib/rop/RopCreateMessageHandler.js +53 -0
  64. package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -0
  65. package/dist/lib/rop/RopDeleteFolderHandler.js +133 -0
  66. package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -0
  67. package/dist/lib/rop/RopDeleteMessagesHandler.js +70 -0
  68. package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -0
  69. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +61 -0
  70. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -0
  71. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +61 -0
  72. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -0
  73. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +75 -0
  74. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -0
  75. package/dist/lib/rop/RopGetContentsTableHandler.js +76 -0
  76. package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -0
  77. package/dist/lib/rop/RopGetHierarchyTableHandler.js +40 -0
  78. package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -0
  79. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +55 -0
  80. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -0
  81. package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js +92 -0
  82. package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js.map +1 -0
  83. package/dist/lib/rop/RopHandler.js +2 -0
  84. package/dist/lib/rop/RopHandler.js.map +1 -0
  85. package/dist/lib/rop/RopLogonHandler.js +132 -0
  86. package/dist/lib/rop/RopLogonHandler.js.map +1 -0
  87. package/dist/lib/rop/RopOpenFolderHandler.js +46 -0
  88. package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -0
  89. package/dist/lib/rop/RopOpenMessageHandler.js +81 -0
  90. package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -0
  91. package/dist/lib/rop/RopOpenStreamHandler.js +81 -0
  92. package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -0
  93. package/dist/lib/rop/RopQueryRowsHandler.js +91 -0
  94. package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -0
  95. package/dist/lib/rop/RopReadStreamHandler.js +55 -0
  96. package/dist/lib/rop/RopReadStreamHandler.js.map +1 -0
  97. package/dist/lib/rop/RopReleaseHandler.js +20 -0
  98. package/dist/lib/rop/RopReleaseHandler.js.map +1 -0
  99. package/dist/lib/rop/RopSaveChangesMessageHandler.js +210 -0
  100. package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -0
  101. package/dist/lib/rop/RopSetColumnsHandler.js +52 -0
  102. package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -0
  103. package/dist/lib/rop/RopSetPropertiesHandler.js +162 -0
  104. package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -0
  105. package/dist/lib/rop/RopSubmitMessageHandler.js +314 -0
  106. package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -0
  107. package/dist/lib/rop/RopWriteStreamHandler.js +45 -0
  108. package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -0
  109. package/dist/lib/rop/TaskNamedProperties.js +29 -0
  110. package/dist/lib/rop/TaskNamedProperties.js.map +1 -0
  111. package/dist/lib/rop/TaskTarget.js +19 -0
  112. package/dist/lib/rop/TaskTarget.js.map +1 -0
  113. package/dist/lib/sql/MapiEmsmdbRouteSQL.js +84 -0
  114. package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -0
  115. package/dist/lib/sql/MapiNspiRouteSQL.js +33 -0
  116. package/dist/lib/sql/MapiNspiRouteSQL.js.map +1 -0
  117. package/dist/lib/sql/index.js +7 -0
  118. package/dist/lib/sql/index.js.map +1 -0
  119. package/dist/lib/sql.js +6 -0
  120. package/dist/lib/sql.js.map +1 -0
  121. package/dist/types/BaseMapiEmsmdbRoute.d.ts +82 -0
  122. package/dist/types/BaseMapiNspiRoute.d.ts +38 -0
  123. package/dist/types/MapiSessionManager.d.ts +130 -0
  124. package/dist/types/RopDispatcher.d.ts +17 -0
  125. package/dist/types/codec/AppointmentRecurrence.d.ts +14 -0
  126. package/dist/types/codec/BufferCursor.d.ts +78 -0
  127. package/dist/types/codec/GlobalObjectId.d.ts +11 -0
  128. package/dist/types/codec/MapiGuid.d.ts +6 -0
  129. package/dist/types/codec/MapiTimeZone.d.ts +7 -0
  130. package/dist/types/codec/PropertyValue.d.ts +77 -0
  131. package/dist/types/codec/RopBuffer.d.ts +25 -0
  132. package/dist/types/codec/TypedString.d.ts +17 -0
  133. package/dist/types/index.d.ts +94 -0
  134. package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +19 -0
  135. package/dist/types/mongo/MapiNspiRouteMongo.d.ts +13 -0
  136. package/dist/types/mongo/index.d.ts +2 -0
  137. package/dist/types/mongo.d.ts +1 -0
  138. package/dist/types/nspi/NspiBindHandler.d.ts +22 -0
  139. package/dist/types/nspi/NspiCodec.d.ts +59 -0
  140. package/dist/types/nspi/NspiGetMatchesHandler.d.ts +24 -0
  141. package/dist/types/rop/CalendarEventTarget.d.ts +29 -0
  142. package/dist/types/rop/CalendarNamedProperties.d.ts +37 -0
  143. package/dist/types/rop/ContactTarget.d.ts +29 -0
  144. package/dist/types/rop/FastTransferStream.d.ts +18 -0
  145. package/dist/types/rop/FolderTarget.d.ts +63 -0
  146. package/dist/types/rop/MeetingMessageClassHandler.d.ts +36 -0
  147. package/dist/types/rop/MessageBodyStream.d.ts +26 -0
  148. package/dist/types/rop/MessageTarget.d.ts +38 -0
  149. package/dist/types/rop/NamedPropertyRegistry.d.ts +46 -0
  150. package/dist/types/rop/PropertyResolvers.d.ts +60 -0
  151. package/dist/types/rop/RopCreateMessageHandler.d.ts +23 -0
  152. package/dist/types/rop/RopDeleteFolderHandler.d.ts +38 -0
  153. package/dist/types/rop/RopDeleteMessagesHandler.d.ts +31 -0
  154. package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +24 -0
  155. package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +24 -0
  156. package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +23 -0
  157. package/dist/types/rop/RopGetContentsTableHandler.d.ts +31 -0
  158. package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +17 -0
  159. package/dist/types/rop/RopGetPropertiesSpecificHandler.d.ts +23 -0
  160. package/dist/types/rop/RopGetPropertyIdsFromNamesHandler.d.ts +23 -0
  161. package/dist/types/rop/RopHandler.d.ts +67 -0
  162. package/dist/types/rop/RopLogonHandler.d.ts +31 -0
  163. package/dist/types/rop/RopOpenFolderHandler.d.ts +19 -0
  164. package/dist/types/rop/RopOpenMessageHandler.d.ts +27 -0
  165. package/dist/types/rop/RopOpenStreamHandler.d.ts +27 -0
  166. package/dist/types/rop/RopQueryRowsHandler.d.ts +36 -0
  167. package/dist/types/rop/RopReadStreamHandler.d.ts +18 -0
  168. package/dist/types/rop/RopReleaseHandler.d.ts +14 -0
  169. package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +44 -0
  170. package/dist/types/rop/RopSetColumnsHandler.d.ts +21 -0
  171. package/dist/types/rop/RopSetPropertiesHandler.d.ts +38 -0
  172. package/dist/types/rop/RopSubmitMessageHandler.d.ts +70 -0
  173. package/dist/types/rop/RopWriteStreamHandler.d.ts +21 -0
  174. package/dist/types/rop/TaskNamedProperties.d.ts +24 -0
  175. package/dist/types/rop/TaskTarget.d.ts +24 -0
  176. package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +19 -0
  177. package/dist/types/sql/MapiNspiRouteSQL.d.ts +13 -0
  178. package/dist/types/sql/index.d.ts +2 -0
  179. package/dist/types/sql.d.ts +1 -0
  180. package/package.json +104 -0
@@ -0,0 +1,84 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ ///////////////////////////////////////////////////////////////////////////////
8
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
9
+ // SPDX-License-Identifier: MPL-2.0
10
+ ///////////////////////////////////////////////////////////////////////////////
11
+ import { CalendarEventMongo, ContactMongo, FolderMongo, LabelMongo, MailboxMongo, MessageMongo, TaskMongo } from "@rapidmx/restapi/mongo";
12
+ import { BaseMapiEmsmdbRoute } from "../BaseMapiEmsmdbRoute.js";
13
+ import { RopLogonHandler } from "../rop/RopLogonHandler.js";
14
+ import { RopReleaseHandler } from "../rop/RopReleaseHandler.js";
15
+ import { RopOpenFolderHandler } from "../rop/RopOpenFolderHandler.js";
16
+ import { RopGetHierarchyTableHandler } from "../rop/RopGetHierarchyTableHandler.js";
17
+ import { RopGetContentsTableHandler } from "../rop/RopGetContentsTableHandler.js";
18
+ import { RopSetColumnsHandler } from "../rop/RopSetColumnsHandler.js";
19
+ import { RopQueryRowsHandler } from "../rop/RopQueryRowsHandler.js";
20
+ import { RopOpenMessageHandler } from "../rop/RopOpenMessageHandler.js";
21
+ import { RopGetPropertiesSpecificHandler } from "../rop/RopGetPropertiesSpecificHandler.js";
22
+ import { RopOpenStreamHandler } from "../rop/RopOpenStreamHandler.js";
23
+ import { RopReadStreamHandler } from "../rop/RopReadStreamHandler.js";
24
+ import { RopCreateMessageHandler } from "../rop/RopCreateMessageHandler.js";
25
+ import { RopSetPropertiesHandler } from "../rop/RopSetPropertiesHandler.js";
26
+ import { RopWriteStreamHandler } from "../rop/RopWriteStreamHandler.js";
27
+ import { RopSaveChangesMessageHandler } from "../rop/RopSaveChangesMessageHandler.js";
28
+ import { RopSubmitMessageHandler } from "../rop/RopSubmitMessageHandler.js";
29
+ import { RopGetPropertyIdsFromNamesHandler } from "../rop/RopGetPropertyIdsFromNamesHandler.js";
30
+ import { RopDeleteMessagesHandler } from "../rop/RopDeleteMessagesHandler.js";
31
+ import { RopDeleteFolderHandler } from "../rop/RopDeleteFolderHandler.js";
32
+ import { RopFastTransferSourceCopyToHandler } from "../rop/RopFastTransferSourceCopyToHandler.js";
33
+ import { RopFastTransferSourceCopyPropertiesHandler } from "../rop/RopFastTransferSourceCopyPropertiesHandler.js";
34
+ import { RopFastTransferSourceGetBufferHandler } from "../rop/RopFastTransferSourceGetBufferHandler.js";
35
+ import { RouteDecorators } from "@rapidrest/service-core";
36
+ const { Route } = RouteDecorators;
37
+ /**
38
+ * Mongo-backed concrete `BaseMapiEmsmdbRoute`, mounted at `/mapi/emsmdb`. Exported from this plugin's
39
+ * `./mongo` entry point, so the server host mounts it without a wrapper class of its
40
+ * own.
41
+ *
42
+ * @author Jean-Philippe Steinmetz
43
+ */
44
+ let MapiEmsmdbRouteMongo = class MapiEmsmdbRouteMongo extends BaseMapiEmsmdbRoute {
45
+ constructor() {
46
+ super(...arguments);
47
+ this.mailboxClass = MailboxMongo;
48
+ this.folderClass = FolderMongo;
49
+ this.messageClass = MessageMongo;
50
+ this.calendarEventClass = CalendarEventMongo;
51
+ this.contactClass = ContactMongo;
52
+ this.taskClass = TaskMongo;
53
+ this.labelClass = LabelMongo;
54
+ this.ropHandlerClasses = [
55
+ RopLogonHandler,
56
+ RopReleaseHandler,
57
+ RopOpenFolderHandler,
58
+ RopGetHierarchyTableHandler,
59
+ RopGetContentsTableHandler,
60
+ RopSetColumnsHandler,
61
+ RopQueryRowsHandler,
62
+ RopOpenMessageHandler,
63
+ RopGetPropertiesSpecificHandler,
64
+ RopOpenStreamHandler,
65
+ RopReadStreamHandler,
66
+ RopCreateMessageHandler,
67
+ RopSetPropertiesHandler,
68
+ RopWriteStreamHandler,
69
+ RopSaveChangesMessageHandler,
70
+ RopSubmitMessageHandler,
71
+ RopGetPropertyIdsFromNamesHandler,
72
+ RopDeleteMessagesHandler,
73
+ RopDeleteFolderHandler,
74
+ RopFastTransferSourceCopyToHandler,
75
+ RopFastTransferSourceCopyPropertiesHandler,
76
+ RopFastTransferSourceGetBufferHandler,
77
+ ];
78
+ }
79
+ };
80
+ MapiEmsmdbRouteMongo = __decorate([
81
+ Route("/mapi/emsmdb")
82
+ ], MapiEmsmdbRouteMongo);
83
+ export { MapiEmsmdbRouteMongo };
84
+ //# sourceMappingURL=MapiEmsmdbRouteMongo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapiEmsmdbRouteMongo.js","sourceRoot":"","sources":["../../../src/mongo/MapiEmsmdbRouteMongo.ts"],"names":[],"mappings":";;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC1I,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACpF,OAAO,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,iCAAiC,EAAE,MAAM,6CAA6C,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,kCAAkC,EAAE,MAAM,8CAA8C,CAAC;AAClG,OAAO,EAAE,0CAA0C,EAAE,MAAM,sDAAsD,CAAC;AAClH,OAAO,EAAE,qCAAqC,EAAE,MAAM,iDAAiD,CAAC;AACxG,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC;AAElC;;;;;;GAMG;AAEI,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,mBAAiC;IAApE;;QACO,iBAAY,GAAQ,YAAY,CAAC;QACjC,gBAAW,GAAQ,WAAW,CAAC;QAC/B,iBAAY,GAAQ,YAAY,CAAC;QACjC,uBAAkB,GAAQ,kBAAkB,CAAC;QAC7C,iBAAY,GAAQ,YAAY,CAAC;QACjC,cAAS,GAAQ,SAAS,CAAC;QAC3B,eAAU,GAAQ,UAAU,CAAC;QAC7B,sBAAiB,GAAU;YACjC,eAAe;YACf,iBAAiB;YACjB,oBAAoB;YACpB,2BAA2B;YAC3B,0BAA0B;YAC1B,oBAAoB;YACpB,mBAAmB;YACnB,qBAAqB;YACrB,+BAA+B;YAC/B,oBAAoB;YACpB,oBAAoB;YACpB,uBAAuB;YACvB,uBAAuB;YACvB,qBAAqB;YACrB,4BAA4B;YAC5B,uBAAuB;YACvB,iCAAiC;YACjC,wBAAwB;YACxB,sBAAsB;YACtB,kCAAkC;YAClC,0CAA0C;YAC1C,qCAAqC;SACxC,CAAC;IACN,CAAC;CAAA,CAAA;AAhCY,oBAAoB;IADhC,KAAK,CAAC,cAAc,CAAC;GACT,oBAAoB,CAgChC"}
@@ -0,0 +1,33 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ ///////////////////////////////////////////////////////////////////////////////
8
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
9
+ // SPDX-License-Identifier: MPL-2.0
10
+ ///////////////////////////////////////////////////////////////////////////////
11
+ import { ContactMongo, MailboxMongo } from "@rapidmx/restapi/mongo";
12
+ import { BaseMapiNspiRoute } from "../BaseMapiNspiRoute.js";
13
+ import { RouteDecorators } from "@rapidrest/service-core";
14
+ const { Route } = RouteDecorators;
15
+ /**
16
+ * Mongo-backed concrete `BaseMapiNspiRoute`, mounted at `/mapi/nspi`. Exported from this plugin's
17
+ * `./mongo` entry point, so the server host mounts it without a wrapper class of its
18
+ * own.
19
+ *
20
+ * @author Jean-Philippe Steinmetz
21
+ */
22
+ let MapiNspiRouteMongo = class MapiNspiRouteMongo extends BaseMapiNspiRoute {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.mailboxClass = MailboxMongo;
26
+ this.contactClass = ContactMongo;
27
+ }
28
+ };
29
+ MapiNspiRouteMongo = __decorate([
30
+ Route("/mapi/nspi")
31
+ ], MapiNspiRouteMongo);
32
+ export { MapiNspiRouteMongo };
33
+ //# sourceMappingURL=MapiNspiRouteMongo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapiNspiRouteMongo.js","sourceRoot":"","sources":["../../../src/mongo/MapiNspiRouteMongo.ts"],"names":[],"mappings":";;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC;AAElC;;;;;;GAMG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,iBAA+B;IAAhE;;QACO,iBAAY,GAAQ,YAAY,CAAC;QACjC,iBAAY,GAAQ,YAAY,CAAC;IAC/C,CAAC;CAAA,CAAA;AAHY,kBAAkB;IAD9B,KAAK,CAAC,YAAY,CAAC;GACP,kBAAkB,CAG9B"}
@@ -0,0 +1,7 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ export * from "./MapiEmsmdbRouteMongo.js";
6
+ export * from "./MapiNspiRouteMongo.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mongo/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yBAAyB,CAAC"}
@@ -0,0 +1,6 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ export * from "./mongo/index.js";
6
+ //# sourceMappingURL=mongo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo.js","sourceRoot":"","sources":["../../src/mongo.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,54 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import crypto from "crypto";
6
+ import { BufferWriter } from "../codec/BufferCursor.js";
7
+ import { encodeGuid } from "../codec/MapiGuid.js";
8
+ import { resolveCallerMailboxUid } from "@rapidmx/restapi";
9
+ /** `[MS-OXNSPI]` §2.2.1.2's own `MAPI_E_NOT_FOUND` error code, reused for "the caller has no mailbox in this
10
+ * deployment" - the one real failure mode `Bind` can hit in this pragmatic subset. */
11
+ const ERROR_NOT_FOUND = 0x8004010f;
12
+ /**
13
+ * `Bind`/`Unbind` request types (`[MS-OXCMAPIHTTP]` §2.2.5.1/§2.2.5.2, backed by `[MS-OXNSPI]`'s own `NspiBind`/
14
+ * `NspiUnbind` methods): establishes/tears down an NSPI Session Context, the address-book endpoint's own
15
+ * analog of EMSMDB's `Connect`/`Disconnect`.
16
+ *
17
+ * **No real session state is created or tracked** - a deliberate, documented simplification, not an oversight:
18
+ * every subsequent NSPI operation in this pragmatic subset (`GetMatches`) is independently `@Auth(["jwt"])`-
19
+ * protected and re-resolves the caller's own mailbox from that same JWT, exactly the way `RopLogon`/every ROP
20
+ * handler already does for EMSMDB - the real spec's `MapiContext`-equivalent session cookie exists mainly for
21
+ * multi-server-farm request affinity, not additional authentication, so this pragmatic subset mints an opaque,
22
+ * unvalidated cookie value purely for wire-format conformance and never checks it again. `HasState`/`State`
23
+ * (an optional `STAT` scoping the bind to one address-book container) is accepted but not decoded at all -
24
+ * this pragmatic subset has exactly one "container" (a mailbox's own `Contact` list) regardless.
25
+ *
26
+ * @author Jean-Philippe Steinmetz
27
+ */
28
+ export async function handleNspiBind(res, user, mailboxRepo) {
29
+ const mailboxUid = await resolveCallerMailboxUid(mailboxRepo, user);
30
+ if (!mailboxUid) {
31
+ const body = new BufferWriter();
32
+ body.writeUInt32LE(ERROR_NOT_FOUND); // StatusCode - MUST NOT be 0 on failure
33
+ body.writeUInt32LE(0); // AuxiliaryBufferSize
34
+ res.status(200).send(body.toBuffer());
35
+ return;
36
+ }
37
+ res.appendHeader("Set-Cookie", `NspiContext=${crypto.randomUUID()}`); // opaque, unvalidated - see class doc comment
38
+ const body = new BufferWriter();
39
+ body.writeUInt32LE(0); // StatusCode - success
40
+ body.writeUInt32LE(0); // ErrorCode - success
41
+ body.writeBytes(encodeGuid(crypto.randomUUID())); // ServerGuid - a fresh value per Bind is harmless, see class doc comment
42
+ body.writeUInt32LE(0); // AuxiliaryBufferSize
43
+ res.status(200).send(body.toBuffer());
44
+ }
45
+ /** `Unbind` never fails and has nothing to tear down - see `handleNspiBind`'s own doc comment for why no real
46
+ * session exists to release. */
47
+ export function handleNspiUnbind(res) {
48
+ const body = new BufferWriter();
49
+ body.writeUInt32LE(0); // StatusCode
50
+ body.writeUInt32LE(0); // ErrorCode
51
+ body.writeUInt32LE(0); // AuxiliaryBufferSize
52
+ res.status(200).send(body.toBuffer());
53
+ }
54
+ //# sourceMappingURL=NspiBindHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NspiBindHandler.js","sourceRoot":"","sources":["../../../src/nspi/NspiBindHandler.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAC;AAE3D;sFACsF;AACtF,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAiB,EAAE,IAAa,EAAE,WAA2B;IAC9F,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC,UAAU,EAAE,CAAC;QACd,MAAM,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;QAChC,IAAI,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC,CAAC,wCAAwC;QAC7E,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB;QAC7C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtC,OAAO;IACX,CAAC;IAED,GAAG,CAAC,YAAY,CAAC,YAAY,EAAE,eAAe,MAAM,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,8CAA8C;IAEpH,MAAM,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;IAChC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB;IAC9C,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB;IAC7C,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,yEAAyE;IAC3H,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB;IAC7C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED;gCACgC;AAChC,MAAM,UAAU,gBAAgB,CAAC,GAAiB;IAC9C,MAAM,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;IAChC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa;IACpC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY;IACnC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB;IAC7C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,106 @@
1
+ import { PropertyType, readPropertyTag, readTaggedPropertyValue, writePropertyTag, writePropertyValue, } from "../codec/PropertyValue.js";
2
+ export function readStat(reader) {
3
+ return {
4
+ sortType: reader.readUInt32LE(),
5
+ containerId: reader.readUInt32LE(),
6
+ currentRec: reader.readUInt32LE(),
7
+ delta: reader.readInt32LE(),
8
+ numPos: reader.readUInt32LE(),
9
+ totalRecs: reader.readUInt32LE(),
10
+ codePage: reader.readUInt32LE(),
11
+ templateLocale: reader.readUInt32LE(),
12
+ sortLocale: reader.readUInt32LE(),
13
+ };
14
+ }
15
+ export function writeStat(writer, stat) {
16
+ writer.writeUInt32LE(stat.sortType);
17
+ writer.writeUInt32LE(stat.containerId);
18
+ writer.writeUInt32LE(stat.currentRec);
19
+ writer.writeInt32LE(stat.delta);
20
+ writer.writeUInt32LE(stat.numPos);
21
+ writer.writeUInt32LE(stat.totalRecs);
22
+ writer.writeUInt32LE(stat.codePage);
23
+ writer.writeUInt32LE(stat.templateLocale);
24
+ writer.writeUInt32LE(stat.sortLocale);
25
+ }
26
+ /** A blank `STAT` (`SortType`/`ContainerID`/... all zero) - what this pragmatic subset always echoes back
27
+ * (in `Bind`'s optional acknowledgement and `GetMatches`' response) regardless of the caller's own request
28
+ * `STAT`, since no real per-container/locale state is tracked. */
29
+ export const BLANK_STAT = {
30
+ sortType: 0,
31
+ containerId: 0,
32
+ currentRec: 0,
33
+ delta: 0,
34
+ numPos: 0,
35
+ totalRecs: 0,
36
+ codePage: 0,
37
+ templateLocale: 0,
38
+ sortLocale: 0,
39
+ };
40
+ /** `LargePropertyTagArray` (`[MS-OXCMAPIHTTP]` §2.2.1.8): a 4-byte count followed by that many `PropertyTag`
41
+ * structures (`[MS-OXCDATA]` §2.9 - the same `PropertyType`-then-`PropertyId` encoding `PropertyValue.ts`'s own
42
+ * `readPropertyTag`/`writePropertyTag` already implement). */
43
+ export function readLargePropertyTagArray(reader) {
44
+ const count = reader.readUInt32LE();
45
+ const tags = [];
46
+ for (let i = 0; i < count; i++) {
47
+ tags.push(readPropertyTag(reader));
48
+ }
49
+ return tags;
50
+ }
51
+ export function writeLargePropertyTagArray(writer, tags) {
52
+ writer.writeUInt32LE(tags.length);
53
+ for (const tag of tags) {
54
+ writePropertyTag(writer, tag);
55
+ }
56
+ }
57
+ /** Writes one column's `AddressBookPropertyValue` (`[MS-OXCMAPIHTTP]` §2.2.1.1): a `PtypString`/`PtypString8`/
58
+ * `PtypBinary` value is preceded by a `HasValue` byte (always `0xFF`/`TRUE` in this pragmatic subset, which
59
+ * never reports a missing column value - the same "always emit a real value of the right type" principle
60
+ * `PropertyResolvers.defaultValueForType` already applies for EMSMDB); every other (fixed-size) type has no
61
+ * such prefix. `PtypMultiple*` columns (which need a `HasValue` byte per *element*, not just once) are never
62
+ * produced by this pragmatic subset's own fixed GAL column set and are intentionally not handled here. */
63
+ function writeAddressBookPropertyValue(writer, type, value) {
64
+ if (type === PropertyType.PtypString || type === PropertyType.PtypString8 || type === PropertyType.PtypBinary) {
65
+ writer.writeUInt8(0xff); // HasValue - always TRUE, see function doc comment
66
+ }
67
+ writePropertyValue(writer, type, value);
68
+ }
69
+ /** Writes one `AddressBookPropertyRow` (`[MS-OXCMAPIHTTP]` §2.2.1.7) - always `Flags=0x00` (every column
70
+ * value present without error), the exact `StandardPropertyRow`-equivalent choice `RopQueryRowsHandler`/
71
+ * `RopGetPropertiesSpecificHandler` already make for EMSMDB's own row encoding. */
72
+ export function writeAddressBookPropertyRow(writer, columns, values) {
73
+ writer.writeUInt8(0x00); // Flags - see function doc comment
74
+ columns.forEach((column, index) => writeAddressBookPropertyValue(writer, column.propertyType, values[index]));
75
+ }
76
+ /** Decodes a `Restriction` (`[MS-OXCDATA]` §2.12)'s leading `RestrictType` byte and, only for a
77
+ * `ContentRestriction`/`RES_CONTENT` (`0x03`) - the shape a real client's own GAL "search as you type" sends -
78
+ * extracts the plain string search term from its `TaggedValue` field.
79
+ *
80
+ * **Throws for any other restriction type** (`AND`/`OR`/`PropertyRestriction`/...) rather than degrading
81
+ * gracefully - unlike this pragmatic subset's usual "return a default instead of failing" stance elsewhere,
82
+ * a restriction's own byte length is type-dependent (12 different packet formats, several recursively nested),
83
+ * so once an unrecognized `RestrictType` is seen there is no safe way to know how many bytes to skip to reach
84
+ * the request body's own subsequent fields (`RowCount`/`Columns`/...) - silently returning `undefined` here
85
+ * would leave the reader mid-structure and corrupt every field decoded afterward. Throwing is the honest,
86
+ * safe choice for an input this narrow codec was never meant to parse, not a design gap.
87
+ *
88
+ * `FuzzyLevelLow`/`FuzzyLevelHigh` (exact/substring/prefix matching, case sensitivity) and the restriction's
89
+ * own target `PropertyTag` are decoded to advance the reader correctly but not honored - this pragmatic
90
+ * subset always does a case-insensitive substring match against its own fixed Contact field set regardless of
91
+ * which property or fuzzy level the client's restriction actually named. */
92
+ export function extractContentRestrictionSearchTerm(reader) {
93
+ const restrictType = reader.readUInt8();
94
+ if (restrictType !== 0x03) {
95
+ throw new Error(`NspiCodec: unsupported restriction type 0x${restrictType.toString(16)} (only ContentRestriction/RES_CONTENT is supported)`);
96
+ }
97
+ reader.readUInt16LE(); // FuzzyLevelLow - not honored, see function doc comment
98
+ reader.readUInt16LE(); // FuzzyLevelHigh - not honored, see function doc comment
99
+ readPropertyTag(reader); // PropertyTag (the restriction's own target column) - not honored
100
+ const tagged = readTaggedPropertyValue(reader);
101
+ if (typeof tagged.value !== "string") {
102
+ throw new Error("NspiCodec: ContentRestriction's TaggedValue was not a string.");
103
+ }
104
+ return tagged.value;
105
+ }
106
+ //# sourceMappingURL=NspiCodec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NspiCodec.js","sourceRoot":"","sources":["../../../src/nspi/NspiCodec.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,142 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import { StringUtils } from "@rapidrest/core";
6
+ import { BufferReader, BufferWriter } from "../codec/BufferCursor.js";
7
+ import { PropertyType } from "../codec/PropertyValue.js";
8
+ import { defaultValueForType } from "../rop/PropertyResolvers.js";
9
+ import { BLANK_STAT, extractContentRestrictionSearchTerm, readLargePropertyTagArray, readStat, writeAddressBookPropertyRow, writeLargePropertyTagArray, writeStat, } from "./NspiCodec.js";
10
+ /** `PidTagDisplayName`/`PidTagEmailAddress` - the small default column set this pragmatic subset returns when
11
+ * a client's `GetMatches` request omits its own `Columns` field, mirroring EAS's own GAL result shape
12
+ * (`SearchCommand.ts`'s `DisplayName`/`EmailAddress`). */
13
+ const PID_TAG_DISPLAY_NAME = 0x3001;
14
+ const PID_TAG_EMAIL_ADDRESS = 0x3003;
15
+ const DEFAULT_COLUMNS = [
16
+ { propertyId: PID_TAG_DISPLAY_NAME, propertyType: PropertyType.PtypString },
17
+ { propertyId: PID_TAG_EMAIL_ADDRESS, propertyType: PropertyType.PtypString },
18
+ ];
19
+ /** A small, non-cryptographic FNV-1a 32-bit hash of a `Contact.uid`, used as that contact's `MinimalEntryID`
20
+ * in a `GetMatches` response. Deterministic per `uid` but not persisted or globally coordinated - acceptable
21
+ * here since no other operation in this pragmatic subset ever looks a `MinimalEntryID` back up (`NspiGetProps`/
22
+ * `NspiQueryRows`/... are out of scope), so nothing depends on it staying stable beyond a single response. */
23
+ function minimalEntryIdFor(uid) {
24
+ let hash = 0x811c9dc5;
25
+ for (let i = 0; i < uid.length; i++) {
26
+ hash ^= uid.charCodeAt(i);
27
+ hash = Math.imul(hash, 0x01000193);
28
+ }
29
+ return hash >>> 0;
30
+ }
31
+ function valueForColumn(contact, column) {
32
+ switch (column.propertyId) {
33
+ case PID_TAG_DISPLAY_NAME:
34
+ return contact.displayName;
35
+ case PID_TAG_EMAIL_ADDRESS:
36
+ // Optional-chained on `emails` itself, not just its first element - a Contact predating this field
37
+ // (or otherwise missing it) would throw on a bare `contact.emails[0]` before the `?.` on `.address`
38
+ // ever gets a chance to help.
39
+ return contact.emails?.[0]?.address ?? "";
40
+ default:
41
+ return defaultValueForType(column.propertyType);
42
+ }
43
+ }
44
+ /** Finds every `Contact` in `mailboxUid` matching `searchTerm` (a case-insensitive substring match against
45
+ * `displayName`/`givenName`/`surname`/`company`, queried per-field and merged in memory - the same two-backend
46
+ * workaround `SearchCommand.ts` already established for its own identical `$or`-is-Mongo-only /
47
+ * `ILike()`-needs-wrapping gaps) - or every `Contact` in the mailbox at all when `searchTerm` is `undefined`
48
+ * (no filter was supplied, or (`extractContentRestrictionSearchTerm`'s own contract) the filter was already
49
+ * known-good by the time this is called).
50
+ *
51
+ * Uses `RepoUtils`'s `regex(...)` operator (`@rapidrest/service-core` ^2.0), not `like(...)`: `like()` compiles
52
+ * a **glob** pattern (`*`/`?` as wildcards), which would require wrapping the term in `*...*` to get a substring
53
+ * match and would still treat a literal `*`/`?` in the search term itself as a wildcard (glob syntax has no
54
+ * escape for those two characters). `regex()` takes a real, already-anchoring-free regular expression compiled
55
+ * case-insensitively on both backends (`$regex`/`~*`/`REGEXP`), so escaping the term with `StringUtils
56
+ * .escapeRegExp` here gives a genuine literal-substring match with no residual wildcard ambiguity. `regex()`
57
+ * patterns are also independently validated by the framework itself (`ModelUtils.isUnsafeRegexPattern`) against
58
+ * catastrophic-backtracking shapes, but that guard is for patterns a caller assembles from parts; escaping the
59
+ * entire term with `escapeRegExp` before it ever reaches here already prevents any of those shapes from forming
60
+ * in the first place, since no unescaped metacharacter survives. */
61
+ async function findMatchingContacts(mailboxUid, contactRepo, searchTerm) {
62
+ if (!searchTerm) {
63
+ return contactRepo.find({ mailboxUid }, { ignoreACL: true });
64
+ }
65
+ const pattern = StringUtils.escapeRegExp(searchTerm);
66
+ const perField = await Promise.all(["displayName", "givenName", "surname", "company"].map((field) => contactRepo.find({ mailboxUid, [field]: `regex(${pattern})` }, { ignoreACL: true })));
67
+ const byUid = new Map();
68
+ for (const contact of perField.flat()) {
69
+ byUid.set(contact.uid, contact);
70
+ }
71
+ return Array.from(byUid.values()).sort((a, b) => a.displayName.localeCompare(b.displayName));
72
+ }
73
+ /**
74
+ * `GetMatches` request type (`[MS-OXCMAPIHTTP]` §2.2.5.5, backed by `[MS-OXNSPI]`'s own `NspiGetMatches`
75
+ * method): searches the GAL (this library's `Contact` records, the same source of truth EAS's own `Search`
76
+ * command already uses) for entries matching the client's restriction, returning up to `RowCount` matches as
77
+ * `AddressBookPropertyRow`s. This is the real operation behind a client's own address-book "search as you
78
+ * type" UI - the closest real NSPI equivalent to this plan's own "minimal prefix/substring lookups" scope.
79
+ *
80
+ * `HasState`/`State` (an input `STAT` scoping the search and reporting position) and `HasMinimalIds`/
81
+ * `MinimalIds` (an "Explicit Table" restricting the search to a caller-supplied candidate set) are decoded to
82
+ * advance the reader correctly but not honored - this pragmatic subset always searches the caller's entire
83
+ * Contact list fresh on every call (no real per-container/table state, see `NspiBindHandler.ts`'s own doc
84
+ * comment for the same reasoning applied to `Bind`). `HasFilter`'s `Filter` is decoded via
85
+ * `NspiCodec.extractContentRestrictionSearchTerm` - see that function's own doc comment for why an
86
+ * unsupported restriction type throws rather than degrading. `HasPropertyName` (an alternate open-by-named-
87
+ * property addressing mode) is decoded to advance the reader correctly but never itself used to select a
88
+ * search field.
89
+ *
90
+ * The response's own `State` is always `BLANK_STAT` (with `TotalRecs` set to the real match count) - no real
91
+ * per-container `STAT` is tracked, matching this pragmatic subset's stated scope.
92
+ *
93
+ * @author Jean-Philippe Steinmetz
94
+ */
95
+ export async function handleNspiGetMatches(req, res, mailboxUid, contactRepo) {
96
+ const reader = new BufferReader(req.rawBody ?? Buffer.alloc(0));
97
+ reader.readUInt32LE(); // Reserved
98
+ if (reader.readUInt8()) {
99
+ readStat(reader); // State - not honored, see function doc comment
100
+ }
101
+ if (reader.readUInt8()) {
102
+ // MinimalIds (an Explicit Table) - not honored, see function doc comment
103
+ const minimalIdCount = reader.readUInt32LE();
104
+ for (let i = 0; i < minimalIdCount; i++) {
105
+ reader.readUInt32LE();
106
+ }
107
+ }
108
+ reader.readUInt32LE(); // InterfaceOptionFlags - reserved, always 0
109
+ const searchTerm = reader.readUInt8() ? extractContentRestrictionSearchTerm(reader) : undefined;
110
+ if (reader.readUInt8()) {
111
+ reader.readBytes(16); // PropertyNameGuid - not honored, see function doc comment
112
+ reader.readUInt32LE(); // PropertyNameId
113
+ }
114
+ const rowCount = reader.readUInt32LE();
115
+ const columns = reader.readUInt8() ? readLargePropertyTagArray(reader) : DEFAULT_COLUMNS;
116
+ // AuxiliaryBufferSize/AuxiliaryBuffer intentionally left unread - no auxiliary-payload support.
117
+ const matches = await findMatchingContacts(mailboxUid, contactRepo, searchTerm);
118
+ const page = matches.slice(0, rowCount);
119
+ const body = new BufferWriter();
120
+ body.writeUInt32LE(0); // StatusCode - success
121
+ body.writeUInt32LE(0); // ErrorCode - success
122
+ body.writeUInt8(1); // HasState
123
+ writeStat(body, { ...BLANK_STAT, totalRecs: matches.length });
124
+ body.writeUInt8(page.length > 0 ? 1 : 0); // HasMinimalIds
125
+ if (page.length > 0) {
126
+ body.writeUInt32LE(page.length);
127
+ for (const contact of page) {
128
+ body.writeUInt32LE(minimalEntryIdFor(contact.uid));
129
+ }
130
+ }
131
+ body.writeUInt8(page.length > 0 ? 1 : 0); // HasColumnsAndRows
132
+ if (page.length > 0) {
133
+ writeLargePropertyTagArray(body, columns);
134
+ body.writeUInt32LE(page.length);
135
+ for (const contact of page) {
136
+ writeAddressBookPropertyRow(body, columns, columns.map((column) => valueForColumn(contact, column)));
137
+ }
138
+ }
139
+ body.writeUInt32LE(0); // AuxiliaryBufferSize
140
+ res.status(200).send(body.toBuffer());
141
+ }
142
+ //# sourceMappingURL=NspiGetMatchesHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NspiGetMatchesHandler.js","sourceRoot":"","sources":["../../../src/nspi/NspiGetMatchesHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { BusyStatus } from "@rapidmx/restapi";
2
+ /** Degrades to empty-looking values for a `"calendarEvent:<uid>"` target whose real `CalendarEvent` has since
3
+ * vanished (soft-deleted or otherwise) - the same "don't fail the whole ROP over one stale row" principle
4
+ * `MessageTarget.resolveMessageInfo`/`FolderTarget.resolveFolderInfo` already apply. */
5
+ export async function resolveCalendarEventInfo(target, calendarEventRepo) {
6
+ const uid = target.slice("calendarEvent:".length);
7
+ const event = await calendarEventRepo.findOne(uid, { ignoreACL: true });
8
+ return {
9
+ title: event?.title ?? "",
10
+ location: event?.location,
11
+ startDate: event?.startDate ?? new Date(0),
12
+ endDate: event?.endDate ?? new Date(0),
13
+ timezone: event?.timezone ?? "UTC",
14
+ busyStatus: event?.busyStatus ?? BusyStatus.BUSY,
15
+ recurrenceRule: event?.recurrenceRule,
16
+ reminderMinutesBeforeStart: event?.reminderMinutesBeforeStart,
17
+ organizerAddress: event?.organizer?.address ?? "",
18
+ attendees: event?.attendees ?? [],
19
+ };
20
+ }
21
+ /** Resolves the calendar events directly in `folderUid`, as `"calendarEvent:<uid>"` target strings, for
22
+ * `RopGetContentsTable` against a `CALENDAR`-type folder. */
23
+ export async function resolveFolderCalendarEvents(folderUid, calendarEventRepo) {
24
+ const events = await calendarEventRepo.find({ folderUid }, { ignoreACL: true });
25
+ return events.map((e) => `calendarEvent:${e.uid}`);
26
+ }
27
+ //# sourceMappingURL=CalendarEventTarget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CalendarEventTarget.js","sourceRoot":"","sources":["../../../src/rop/CalendarEventTarget.ts"],"names":[],"mappings":"AAKA,OAAO,EAAY,UAAU,EAAiC,MAAM,kBAAkB,CAAC;AAuBvF;;wFAEwF;AACxF,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAAC,MAAc,EAAE,iBAAiC;IAC5F,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,KAAK,GAA8B,MAAM,iBAAiB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnG,OAAO;QACH,KAAK,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE;QACzB,QAAQ,EAAE,KAAK,EAAE,QAAQ;QACzB,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC;QAC1C,OAAO,EAAE,KAAK,EAAE,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC;QACtC,QAAQ,EAAE,KAAK,EAAE,QAAQ,IAAI,KAAK;QAClC,UAAU,EAAE,KAAK,EAAE,UAAU,IAAI,UAAU,CAAC,IAAI;QAChD,cAAc,EAAE,KAAK,EAAE,cAAc;QACrC,0BAA0B,EAAE,KAAK,EAAE,0BAA0B;QAC7D,gBAAgB,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,IAAI,EAAE;QACjD,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE;KACpC,CAAC;AACN,CAAC;AAED;6DAC6D;AAC7D,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,SAAiB,EAAE,iBAAiC;IAClG,MAAM,MAAM,GAAoB,MAAM,iBAAiB,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACjG,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,57 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import { AttendeeResponseStatus, BusyStatus } from "@rapidmx/restapi";
6
+ /**
7
+ * The Calendar named-property identity table (`(PropertySet GUID, LID)` pairs) this pragmatic subset supports,
8
+ * per `[MS-OXPROPS]` - each pinned against its own MS-OXPROPS page (not invented), shared by `PropertyResolvers.ts`
9
+ * (the read side: `calendarEventValueFor`) and `RopSaveChangesMessageHandler.ts` (the write side: decoding a
10
+ * draft's accumulated `RopSetProperties` values back into a real `CalendarEvent`) so both directions of this
11
+ * mapping stay in exactly one place. See the architecture plan's "Calendar support" section for the full table.
12
+ */
13
+ export const PSETID_APPOINTMENT = "00062002-0000-0000-c000-000000000046";
14
+ export const PSETID_COMMON = "00062008-0000-0000-c000-000000000046";
15
+ export const PSETID_MEETING = "6ed8da90-450b-101b-98da-00aa003f1305";
16
+ export const LID_LOCATION = 0x8208;
17
+ export const LID_APPOINTMENT_START_WHOLE = 0x820d;
18
+ export const LID_APPOINTMENT_END_WHOLE = 0x820e;
19
+ export const LID_BUSY_STATUS = 0x8205;
20
+ export const LID_RECURRING = 0x8223;
21
+ export const LID_REMINDER_SET = 0x8503;
22
+ export const LID_REMINDER_DELTA = 0x8501;
23
+ export const LID_RESPONSE_STATUS = 0x8218;
24
+ export const LID_APPOINTMENT_RECUR = 0x8216;
25
+ export const LID_TIME_ZONE_STRUCT = 0x8233;
26
+ /** `PidLidGlobalObjectId` (`PSETID_Meeting`) - see `GlobalObjectId.ts` for the BLOB it carries and
27
+ * `MeetingMessageClassHandler.ts` for how a meeting response's own copy of it is correlated back to the
28
+ * original `CalendarEvent`. */
29
+ export const LID_GLOBAL_OBJECT_ID = 0x00000003;
30
+ /** `PidLidBusyStatus`'s wire values (`[MS-OXOCAL]` §2.2.1.2, confirmed this session) - a different numbering
31
+ * than `CalendarSyncAdapter`'s own `BUSY_STATUS_CODES` table for the unrelated MS-ASCAL `BusyStatus` field.
32
+ * `olWorkingElsewhere` (0x00000004) has no equivalent in this library's own `BusyStatus` enum - never produced,
33
+ * and decoded (via `BUSY_STATUS_FROM_CODE`) with a fallback to `BUSY`, a documented, harmless approximation. */
34
+ export const BUSY_STATUS_CODES = {
35
+ [BusyStatus.FREE]: 0,
36
+ [BusyStatus.TENTATIVE]: 1,
37
+ [BusyStatus.BUSY]: 2,
38
+ [BusyStatus.OUT_OF_OFFICE]: 3,
39
+ };
40
+ export const BUSY_STATUS_FROM_CODE = {
41
+ 0: BusyStatus.FREE,
42
+ 1: BusyStatus.TENTATIVE,
43
+ 2: BusyStatus.BUSY,
44
+ 3: BusyStatus.OUT_OF_OFFICE,
45
+ };
46
+ /** `PidLidResponseStatus`'s wire values (`[MS-OXOCAL]` §2.2.1.11, confirmed this session) for the caller's own
47
+ * attendee record. `respOrganized` (0x00000001) is returned when the caller *is* the organizer - not a value
48
+ * `AttendeeResponseStatus` itself has a case for, since that enum only models an attendee's own response. */
49
+ export const RESPONSE_STATUS_CODES = {
50
+ [AttendeeResponseStatus.NEEDS_ACTION]: 5, // respNotResponded
51
+ [AttendeeResponseStatus.TENTATIVE]: 2, // respTentative
52
+ [AttendeeResponseStatus.ACCEPTED]: 3, // respAccepted
53
+ [AttendeeResponseStatus.DECLINED]: 4, // respDeclined
54
+ };
55
+ export const RESPONSE_STATUS_ORGANIZED = 1; // respOrganized
56
+ export const RESPONSE_STATUS_NONE = 0; // respNone
57
+ //# sourceMappingURL=CalendarNamedProperties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CalendarNamedProperties.js","sourceRoot":"","sources":["../../../src/rop/CalendarNamedProperties.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,sBAAsB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEtE;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,sCAAsC,CAAC;AACzE,MAAM,CAAC,MAAM,aAAa,GAAG,sCAAsC,CAAC;AACpE,MAAM,CAAC,MAAM,cAAc,GAAG,sCAAsC,CAAC;AAErE,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,CAAC;AACnC,MAAM,CAAC,MAAM,2BAA2B,GAAG,MAAM,CAAC;AAClD,MAAM,CAAC,MAAM,yBAAyB,GAAG,MAAM,CAAC;AAChD,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AACtC,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC;AACpC,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAC1C,MAAM,CAAC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAC5C,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAE3C;;+BAE+B;AAC/B,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAE/C;;;gHAGgH;AAChH,MAAM,CAAC,MAAM,iBAAiB,GAA+B;IACzD,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;IACpB,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;IACzB,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;IACpB,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;CAChC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAA+B;IAC7D,CAAC,EAAE,UAAU,CAAC,IAAI;IAClB,CAAC,EAAE,UAAU,CAAC,SAAS;IACvB,CAAC,EAAE,UAAU,CAAC,IAAI;IAClB,CAAC,EAAE,UAAU,CAAC,aAAa;CAC9B,CAAC;AAEF;;6GAE6G;AAC7G,MAAM,CAAC,MAAM,qBAAqB,GAA2C;IACzE,CAAC,sBAAsB,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,mBAAmB;IAC7D,CAAC,sBAAsB,CAAC,SAAS,CAAC,EAAE,CAAC,EAAE,gBAAgB;IACvD,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,eAAe;IACrD,CAAC,sBAAsB,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,eAAe;CACxD,CAAC;AACF,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,CAAC,gBAAgB;AAC5D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,CAAC,WAAW"}
@@ -0,0 +1,23 @@
1
+ /** Degrades to empty-looking values for a `"contact:<uid>"` target whose real `Contact` has since vanished
2
+ * (soft-deleted or otherwise) - the same "don't fail the whole ROP over one stale row" principle
3
+ * `MessageTarget.resolveMessageInfo`/`CalendarEventTarget.resolveCalendarEventInfo` already apply. */
4
+ export async function resolveContactInfo(target, contactRepo) {
5
+ const uid = target.slice("contact:".length);
6
+ const contact = await contactRepo.findOne(uid, { ignoreACL: true });
7
+ return {
8
+ displayName: contact?.displayName ?? "",
9
+ givenName: contact?.givenName,
10
+ surname: contact?.surname,
11
+ email: contact?.emails?.[0]?.address,
12
+ businessPhone: contact?.phones?.[0]?.phoneNumber,
13
+ companyName: contact?.company,
14
+ jobTitle: contact?.jobTitle,
15
+ };
16
+ }
17
+ /** Resolves the contacts directly in `folderUid`, as `"contact:<uid>"` target strings, for
18
+ * `RopGetContentsTable` against a `CONTACTS`-type folder. */
19
+ export async function resolveFolderContacts(folderUid, contactRepo) {
20
+ const contacts = await contactRepo.find({ folderUid }, { ignoreACL: true });
21
+ return contacts.map((c) => `contact:${c.uid}`);
22
+ }
23
+ //# sourceMappingURL=ContactTarget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ContactTarget.js","sourceRoot":"","sources":["../../../src/rop/ContactTarget.ts"],"names":[],"mappings":"AA6BA;;sGAEsG;AACtG,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,WAA2B;IAChF,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAwB,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzF,OAAO;QACH,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,EAAE;QACvC,SAAS,EAAE,OAAO,EAAE,SAAS;QAC7B,OAAO,EAAE,OAAO,EAAE,OAAO;QACzB,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO;QACpC,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW;QAChD,WAAW,EAAE,OAAO,EAAE,OAAO;QAC7B,QAAQ,EAAE,OAAO,EAAE,QAAQ;KAC9B,CAAC;AACN,CAAC;AAED;6DAC6D;AAC7D,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,SAAiB,EAAE,WAA2B;IACtF,MAAM,QAAQ,GAAc,MAAM,WAAW,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvF,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AACnD,CAAC"}