@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 @@
1
+ {"version":3,"file":"GlobalObjectId.js","sourceRoot":"","sources":["../../../src/codec/GlobalObjectId.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import { BufferWriter } from "./BufferCursor.js";
6
+ /**
7
+ * Encodes/decodes the 16-byte binary GUID layout `[MS-DTYP]`'s `GUID` structure defines and every MAPI wire
8
+ * structure that embeds a GUID (EntryIDs, `PidTagStoreRecordKey`, `PtypGuid` property values, property set
9
+ * IDs) uses: `Data1`/`Data2`/`Data3` in little-endian order, followed by `Data4`'s 8 bytes unchanged (the same
10
+ * order they appear in a standard textual GUID's last two hyphen-separated groups). This is distinct from a
11
+ * plain RFC 4122 UUID's all-big-endian textual byte order, so a generic UUID library's byte form can't be
12
+ * reused directly - hand-built here, same "no library, build the wire format precisely" precedent as the
13
+ * WBXML codec and the Autodiscover XML helpers.
14
+ *
15
+ * @author Jean-Philippe Steinmetz
16
+ */
17
+ const GUID_STRING_PATTERN = /^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i;
18
+ /** Encodes a standard hyphenated GUID/UUID string into its 16-byte MS wire form. */
19
+ export function encodeGuid(guid) {
20
+ const match = GUID_STRING_PATTERN.exec(guid);
21
+ if (!match) {
22
+ throw new Error(`Invalid GUID string: ${guid}`);
23
+ }
24
+ const [, data1, data2, data3, data4a, data4b] = match;
25
+ const writer = new BufferWriter();
26
+ writer.writeUInt32LE(parseInt(data1, 16));
27
+ writer.writeUInt16LE(parseInt(data2, 16));
28
+ writer.writeUInt16LE(parseInt(data3, 16));
29
+ writer.writeBytes(Buffer.from(data4a + data4b, "hex"));
30
+ return writer.toBuffer();
31
+ }
32
+ /** Decodes a 16-byte MS wire-form GUID (read from `reader`'s current position) into a standard hyphenated
33
+ * GUID/UUID string. */
34
+ export function decodeGuid(reader) {
35
+ const data1 = reader.readUInt32LE().toString(16).padStart(8, "0");
36
+ const data2 = reader.readUInt16LE().toString(16).padStart(4, "0");
37
+ const data3 = reader.readUInt16LE().toString(16).padStart(4, "0");
38
+ const data4 = reader.readBytes(8).toString("hex");
39
+ return `${data1}-${data2}-${data3}-${data4.slice(0, 4)}-${data4.slice(4)}`;
40
+ }
41
+ //# sourceMappingURL=MapiGuid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapiGuid.js","sourceRoot":"","sources":["../../../src/codec/MapiGuid.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAgB,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,MAAM,mBAAmB,GAAG,2EAA2E,CAAC;AAExG,oFAAoF;AACpF,MAAM,UAAU,UAAU,CAAC,IAAY;IACnC,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;IAEtD,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1C,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1C,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1C,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACvD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED;uBACuB;AACvB,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,OAAO,GAAG,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,93 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import { BufferWriter } from "./BufferCursor.js";
6
+ /**
7
+ * Encodes/decodes `CalendarEvent.timezone` (a plain IANA zone identifier) to/from `PidLidTimeZoneStruct`'s
8
+ * `TimeZoneStruct` BLOB (`[MS-OXOCAL]` §2.2.1.39, confirmed field-by-field this session, including a real
9
+ * worked example: `lBias(4,LONG)+lStandardBias(4,LONG)+lDaylightBias(4,LONG)+wStandardYear(2,WORD)+
10
+ * stStandardDate(16,SYSTEMTIME)+wDaylightYear(2,WORD)+stDaylightDate(16,SYSTEMTIME)` = 48 bytes total, all
11
+ * little-endian. `SYSTEMTIME` (`[MS-DTYP]`) is 8 `WORD` fields (`wYear`/`wMonth`/`wDayOfWeek`/`wDay`/`wHour`/
12
+ * `wMinute`/`wSecond`/`wMilliseconds`), 16 bytes.
13
+ *
14
+ * This is deliberately the older, simpler `TimeZoneStruct` - not the newer `TimeZoneDefinition`/
15
+ * `PidLidAppointmentTimeZoneDefinitionStartDisplay`, which additionally encodes named DST transition rules.
16
+ *
17
+ * **Pragmatic scope, matching the same limits `CalendarSyncAdapter` (EAS) already carries for timezones**:
18
+ * - `"UTC"` encodes as an all-zero struct (no bias, no DST) - the spec-legitimate representation of "no offset,
19
+ * no DST".
20
+ * - Any other IANA zone is approximated as a **fixed-offset** zone: `lBias` is derived from that zone's actual
21
+ * UTC offset at the given reference instant (via `Intl`), with `lStandardBias`/`lDaylightBias` always `0` and
22
+ * both `SYSTEMTIME` transition dates all-zero (`wMonth=0`, the spec's own documented way to say "this zone
23
+ * does not observe daylight saving time"). **This is wrong across a real DST boundary** for a zone that
24
+ * actually observes DST - a real client will show the correct offset only for occurrences near the reference
25
+ * instant used at encode time, not a spec violation but a real, documented fidelity gap.
26
+ * - Decoding a struct back into an IANA identifier is fundamentally lossy (a bias alone doesn't identify a
27
+ * unique zone name) - this codec resolves it to a synthetic-but-valid `Etc/GMT±N` IANA identifier (note the
28
+ * IANA `Etc/GMT` area's own sign convention is POSIX-inverted from common usage: `Etc/GMT+8` means UTC-8, not
29
+ * UTC+8) rounded to the nearest whole hour, since `Etc/GMT` zones only support integer-hour offsets - a further
30
+ * documented approximation for zones with a half-hour/quarter-hour offset (e.g. India, Nepal).
31
+ *
32
+ * @author Jean-Philippe Steinmetz
33
+ */
34
+ const SYSTEMTIME_FIELD_COUNT = 8;
35
+ function writeZeroTransitionBlock(writer) {
36
+ writer.writeUInt16LE(0); // wStandardYear / wDaylightYear
37
+ for (let i = 0; i < SYSTEMTIME_FIELD_COUNT; i++) {
38
+ writer.writeUInt16LE(0);
39
+ }
40
+ }
41
+ function skipTransitionBlock(reader) {
42
+ reader.readUInt16LE(); // wStandardYear / wDaylightYear
43
+ for (let i = 0; i < SYSTEMTIME_FIELD_COUNT; i++) {
44
+ reader.readUInt16LE();
45
+ }
46
+ }
47
+ /** The zone's UTC offset in minutes at instant `at` (standard convention: local minus UTC, e.g. `-480` for
48
+ * `America/Los_Angeles` in winter), read via `Intl`'s `shortOffset` formatting rather than hand-rolling a
49
+ * zone database. Throws the same way `Intl.DateTimeFormat` itself does for an unrecognized zone identifier. */
50
+ function utcOffsetMinutes(timezone, at) {
51
+ const formatter = new Intl.DateTimeFormat("en-US", { timeZone: timezone, timeZoneName: "shortOffset" });
52
+ // `formatToParts` always includes a "timeZoneName" part when `timeZoneName` is requested in the
53
+ // formatter's own options, so the non-null assertion below reflects a real `Intl` guarantee, not an
54
+ // unverified assumption.
55
+ const tzName = formatter.formatToParts(at).find((part) => part.type === "timeZoneName").value;
56
+ const match = /^GMT([+-])(\d+)(?::(\d+))?$/.exec(tzName);
57
+ if (!match) {
58
+ return 0; // Bare "GMT", i.e. UTC itself.
59
+ }
60
+ const sign = match[1] === "-" ? -1 : 1;
61
+ const hours = parseInt(match[2], 10);
62
+ const minutes = match[3] ? parseInt(match[3], 10) : 0;
63
+ return sign * (hours * 60 + minutes);
64
+ }
65
+ /** Encodes `timezone` (an IANA identifier, or `"UTC"`) into a 48-byte `TimeZoneStruct` BLOB, using `at` as the
66
+ * reference instant for resolving a non-UTC zone's current fixed offset. */
67
+ export function encodeTimeZoneStruct(timezone, at) {
68
+ const writer = new BufferWriter();
69
+ const bias = timezone === "UTC" ? 0 : -utcOffsetMinutes(timezone, at);
70
+ writer.writeInt32LE(bias); // lBias
71
+ writer.writeInt32LE(0); // lStandardBias - no DST modeled
72
+ writer.writeInt32LE(0); // lDaylightBias - no DST modeled
73
+ writeZeroTransitionBlock(writer); // wStandardYear + stStandardDate
74
+ writeZeroTransitionBlock(writer); // wDaylightYear + stDaylightDate
75
+ return writer.toBuffer();
76
+ }
77
+ /** Decodes a `TimeZoneStruct` BLOB (read from `reader`'s current position) into an approximate IANA zone
78
+ * identifier - see this file's own doc comment for the lossy `Etc/GMT±N` fallback's exact rounding rules. */
79
+ export function decodeTimeZoneStruct(reader) {
80
+ const bias = reader.readInt32LE();
81
+ reader.readInt32LE(); // lStandardBias - not reconstructable into a real DST rule, ignored
82
+ reader.readInt32LE(); // lDaylightBias - ditto
83
+ skipTransitionBlock(reader); // wStandardYear + stStandardDate
84
+ skipTransitionBlock(reader); // wDaylightYear + stDaylightDate
85
+ if (bias === 0) {
86
+ return "UTC";
87
+ }
88
+ const offsetMinutes = -bias;
89
+ const wholeHours = Math.round(offsetMinutes / 60);
90
+ const etcSign = wholeHours <= 0 ? "+" : "-";
91
+ return `Etc/GMT${etcSign}${Math.abs(wholeHours)}`;
92
+ }
93
+ //# sourceMappingURL=MapiTimeZone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapiTimeZone.js","sourceRoot":"","sources":["../../../src/codec/MapiTimeZone.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,214 @@
1
+ import { decodeGuid, encodeGuid } from "./MapiGuid.js";
2
+ /**
3
+ * The property-value system every meaningful ROP depends on (`RopGetPropertiesSpecific`/`RopSetProperties`,
4
+ * table row data in `RopQueryRows`, ...), per `[MS-OXCDATA]` §2.11. Only the property types this phase's
5
+ * planned ROP handlers actually need are implemented (`readPropertyValue`/`writePropertyValue` throw a clear
6
+ * error for anything else) - add more as a real handler needs them, not speculatively.
7
+ *
8
+ * Numeric values and member names (`Ptyp*`) are exactly as published in `[MS-OXCDATA]`'s "Property Data
9
+ * Types" table - the full `Ptyp`-prefixed spec names are used rather than shorter aliases (`String`,
10
+ * `Boolean`, ...) both for fidelity to the spec and because those shorter names collide with this project's
11
+ * lint config's `id-denylist` rule (which exists to stop primitive-wrapper-like names shadowing globals).
12
+ */
13
+ export var PropertyType;
14
+ (function (PropertyType) {
15
+ PropertyType[PropertyType["PtypNull"] = 1] = "PtypNull";
16
+ PropertyType[PropertyType["PtypInteger16"] = 2] = "PtypInteger16";
17
+ PropertyType[PropertyType["PtypInteger32"] = 3] = "PtypInteger32";
18
+ PropertyType[PropertyType["PtypFloating32"] = 4] = "PtypFloating32";
19
+ PropertyType[PropertyType["PtypFloating64"] = 5] = "PtypFloating64";
20
+ PropertyType[PropertyType["PtypBoolean"] = 11] = "PtypBoolean";
21
+ PropertyType[PropertyType["PtypInteger64"] = 20] = "PtypInteger64";
22
+ PropertyType[PropertyType["PtypString8"] = 30] = "PtypString8";
23
+ PropertyType[PropertyType["PtypString"] = 31] = "PtypString";
24
+ PropertyType[PropertyType["PtypTime"] = 64] = "PtypTime";
25
+ PropertyType[PropertyType["PtypGuid"] = 72] = "PtypGuid";
26
+ PropertyType[PropertyType["PtypBinary"] = 258] = "PtypBinary";
27
+ PropertyType[PropertyType["PtypMultipleInteger32"] = 4099] = "PtypMultipleInteger32";
28
+ PropertyType[PropertyType["PtypMultipleString8"] = 4126] = "PtypMultipleString8";
29
+ PropertyType[PropertyType["PtypMultipleString"] = 4127] = "PtypMultipleString";
30
+ PropertyType[PropertyType["PtypMultipleBinary"] = 4354] = "PtypMultipleBinary";
31
+ })(PropertyType || (PropertyType = {}));
32
+ /**
33
+ * `PropertyTag` structure (`[MS-OXCDATA]` §2.9): a 4-byte value with **`PropertyType` in the low-order 16
34
+ * bits and `PropertyId` in the high-order 16 bits** - confirmed against the spec's own bit-range description
35
+ * and cross-checked against the well-known real property-tag constant `PR_SUBJECT = 0x0037001F` (`PidTagSubject`
36
+ * = property ID `0x0037`, `PtypString` = type `0x001F`), which only decodes correctly with `PropertyType` as
37
+ * the low half. On the wire (little-endian), that means `PropertyType` is read/written first.
38
+ */
39
+ export function readPropertyTag(reader) {
40
+ const propertyType = reader.readUInt16LE();
41
+ const propertyId = reader.readUInt16LE();
42
+ return { propertyId, propertyType };
43
+ }
44
+ export function writePropertyTag(writer, tag) {
45
+ writer.writeUInt16LE(tag.propertyType);
46
+ writer.writeUInt16LE(tag.propertyId);
47
+ }
48
+ /** `TypedPropertyValue` structure (`[MS-OXCDATA]` §2.11.4): `PropertyType` (2 bytes) followed by the value
49
+ * itself, encoded per `readPropertyValue`/`writePropertyValue` below. */
50
+ export function readTypedPropertyValue(reader) {
51
+ const propertyType = reader.readUInt16LE();
52
+ const value = readPropertyValue(reader, propertyType);
53
+ return { propertyType, value };
54
+ }
55
+ export function writeTypedPropertyValue(writer, typed) {
56
+ writer.writeUInt16LE(typed.propertyType);
57
+ writePropertyValue(writer, typed.propertyType, typed.value);
58
+ }
59
+ /** `TaggedPropertyValue` structure (`[MS-OXCDATA]` §2.11.4, confirmed via `RopSetProperties`'s own request-buffer
60
+ * page): a full `PropertyTag` (4 bytes - `PropertyId` **and** `PropertyType`, unlike `TypedPropertyValue`'s bare
61
+ * `PropertyType`) followed by the value itself. Used where a property's identity can't be inferred from
62
+ * context (e.g. `RopSetProperties`, which sets an arbitrary, client-chosen set of properties in one call). */
63
+ export function readTaggedPropertyValue(reader) {
64
+ const tag = readPropertyTag(reader);
65
+ const value = readPropertyValue(reader, tag.propertyType);
66
+ return { propertyId: tag.propertyId, propertyType: tag.propertyType, value };
67
+ }
68
+ export function writeTaggedPropertyValue(writer, tagged) {
69
+ writePropertyTag(writer, { propertyId: tagged.propertyId, propertyType: tagged.propertyType });
70
+ writePropertyValue(writer, tagged.propertyType, tagged.value);
71
+ }
72
+ /**
73
+ * Reads a bare `PropertyValue` (`[MS-OXCDATA]` §2.11.2) of the given, already-known `type`. `PtypBinary`'s
74
+ * length prefix is 16 bits and every `PtypMultiple*`'s value count is 32 bits wide, per the spec's explicit
75
+ * "in the context of ROP buffers" sizing rule - the only context every planned caller of this function
76
+ * operates in (the wider 32-bit `PtypBinary` count only applies to extended rules / a specific MAPI/HTTP
77
+ * structure this library doesn't implement).
78
+ */
79
+ export function readPropertyValue(reader, type) {
80
+ switch (type) {
81
+ case PropertyType.PtypNull:
82
+ return 0;
83
+ case PropertyType.PtypInteger16:
84
+ return reader.readInt16LE();
85
+ case PropertyType.PtypInteger32:
86
+ return reader.readInt32LE();
87
+ case PropertyType.PtypFloating32:
88
+ return reader.readFloatLE();
89
+ case PropertyType.PtypFloating64:
90
+ return reader.readDoubleLE();
91
+ case PropertyType.PtypBoolean:
92
+ return reader.readUInt8() !== 0;
93
+ case PropertyType.PtypInteger64:
94
+ return reader.readBigInt64LE();
95
+ case PropertyType.PtypTime:
96
+ return filetimeToDate(reader.readBigUInt64LE());
97
+ case PropertyType.PtypGuid:
98
+ return decodeGuid(reader);
99
+ case PropertyType.PtypString:
100
+ return reader.readNullTerminatedUtf16LE();
101
+ case PropertyType.PtypString8:
102
+ return reader.readNullTerminatedString8();
103
+ case PropertyType.PtypBinary:
104
+ return reader.readBytes(reader.readUInt16LE());
105
+ case PropertyType.PtypMultipleInteger32:
106
+ return readCountedArray(reader, () => reader.readInt32LE());
107
+ case PropertyType.PtypMultipleString:
108
+ return readCountedArray(reader, () => reader.readNullTerminatedUtf16LE());
109
+ case PropertyType.PtypMultipleString8:
110
+ return readCountedArray(reader, () => reader.readNullTerminatedString8());
111
+ case PropertyType.PtypMultipleBinary:
112
+ return readCountedArray(reader, () => reader.readBytes(reader.readUInt16LE()));
113
+ default:
114
+ throw new Error(`PropertyValue: unsupported PropertyType 0x${type.toString(16)}`);
115
+ }
116
+ }
117
+ export function writePropertyValue(writer, type, value) {
118
+ switch (type) {
119
+ case PropertyType.PtypNull:
120
+ return;
121
+ case PropertyType.PtypInteger16:
122
+ writer.writeInt16LE(value);
123
+ return;
124
+ case PropertyType.PtypInteger32:
125
+ writer.writeInt32LE(value);
126
+ return;
127
+ case PropertyType.PtypFloating32:
128
+ writer.writeFloatLE(value);
129
+ return;
130
+ case PropertyType.PtypFloating64:
131
+ writer.writeDoubleLE(value);
132
+ return;
133
+ case PropertyType.PtypBoolean:
134
+ writer.writeUInt8(value ? 1 : 0);
135
+ return;
136
+ case PropertyType.PtypInteger64:
137
+ writer.writeBigInt64LE(value);
138
+ return;
139
+ case PropertyType.PtypTime:
140
+ writer.writeBigUInt64LE(dateToFiletime(value));
141
+ return;
142
+ case PropertyType.PtypGuid:
143
+ writer.writeBytes(encodeGuid(value));
144
+ return;
145
+ case PropertyType.PtypString:
146
+ writer.writeNullTerminatedUtf16LE(value);
147
+ return;
148
+ case PropertyType.PtypString8:
149
+ writer.writeNullTerminatedString8(value);
150
+ return;
151
+ case PropertyType.PtypBinary: {
152
+ const buf = value;
153
+ writer.writeUInt16LE(buf.length);
154
+ writer.writeBytes(buf);
155
+ return;
156
+ }
157
+ case PropertyType.PtypMultipleInteger32:
158
+ writeCountedArray(writer, value, (v) => writer.writeInt32LE(v));
159
+ return;
160
+ case PropertyType.PtypMultipleString:
161
+ writeCountedArray(writer, value, (v) => writer.writeNullTerminatedUtf16LE(v));
162
+ return;
163
+ case PropertyType.PtypMultipleString8:
164
+ writeCountedArray(writer, value, (v) => writer.writeNullTerminatedString8(v));
165
+ return;
166
+ case PropertyType.PtypMultipleBinary:
167
+ writeCountedArray(writer, value, (v) => {
168
+ writer.writeUInt16LE(v.length);
169
+ writer.writeBytes(v);
170
+ });
171
+ return;
172
+ default:
173
+ throw new Error(`PropertyValue: unsupported PropertyType 0x${type.toString(16)}`);
174
+ }
175
+ }
176
+ /** `count` is a fully client-controlled `uint32` (up to ~4.29 billion). Every element type this reads needs at
177
+ * least 1 byte on the wire, so a `count` exceeding the buffer's actual remaining bytes can never be genuine -
178
+ * rejecting it immediately, before looping at all, turns a client lying about the count into an instant, clear
179
+ * `RangeError` instead of a loop that runs until either the heap is exhausted or (for the two `PtypMultipleString*`
180
+ * variants specifically, whose element reader used to tolerate running past the buffer's end - see
181
+ * `BufferCursor.ts`'s own doc comment) it simply never terminates. Defense in depth alongside that fix, not a
182
+ * replacement for it - this also fails fast for a merely-oversized-but-technically-satisfiable count instead of
183
+ * allocating a huge array first. */
184
+ function readCountedArray(reader, readOne) {
185
+ const count = reader.readUInt32LE();
186
+ if (count > reader.remaining) {
187
+ throw new RangeError(`PropertyValue.readCountedArray(): element count ${count} exceeds the remaining buffer size (${reader.remaining}).`);
188
+ }
189
+ const values = [];
190
+ for (let i = 0; i < count; i++) {
191
+ values.push(readOne());
192
+ }
193
+ return values;
194
+ }
195
+ function writeCountedArray(writer, values, writeOne) {
196
+ writer.writeUInt32LE(values.length);
197
+ for (const value of values) {
198
+ writeOne(value);
199
+ }
200
+ }
201
+ /** 100-nanosecond intervals between the FILETIME epoch (1601-01-01T00:00:00Z) and the Unix epoch
202
+ * (1970-01-01T00:00:00Z) - `[MS-DTYP]`'s `FILETIME` structure, which `PtypTime` uses. */
203
+ const FILETIME_EPOCH_DIFF_100NS = 116444736000000000n;
204
+ /** Converts a `PtypTime` value (100-ns intervals since 1601-01-01) into a JS `Date`. Sub-millisecond
205
+ * precision is truncated - `Date` has no finer resolution, a real, bounded, documented gap. */
206
+ export function filetimeToDate(filetime) {
207
+ const millis = (filetime - FILETIME_EPOCH_DIFF_100NS) / 10000n;
208
+ return new Date(Number(millis));
209
+ }
210
+ /** Converts a JS `Date` into a `PtypTime` value (100-ns intervals since 1601-01-01). */
211
+ export function dateToFiletime(date) {
212
+ return BigInt(date.getTime()) * 10000n + FILETIME_EPOCH_DIFF_100NS;
213
+ }
214
+ //# sourceMappingURL=PropertyValue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PropertyValue.js","sourceRoot":"","sources":["../../../src/codec/PropertyValue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import { BufferReader, BufferWriter } from "./BufferCursor.js";
6
+ export function encodeRopBuffer(buf) {
7
+ const writer = new BufferWriter();
8
+ // RopSize covers itself (2 bytes) plus ropsList - the handle table isn't part of RopSize's count.
9
+ writer.writeUInt16LE(2 + buf.ropsList.length);
10
+ writer.writeBytes(buf.ropsList);
11
+ for (const handle of buf.handleTable) {
12
+ writer.writeUInt32LE(handle);
13
+ }
14
+ return writer.toBuffer();
15
+ }
16
+ export function decodeRopBuffer(buffer) {
17
+ const reader = new BufferReader(buffer);
18
+ const ropSize = reader.readUInt16LE();
19
+ const ropsList = reader.readBytes(ropSize - 2);
20
+ const handleTable = [];
21
+ while (reader.hasMore()) {
22
+ handleTable.push(reader.readUInt32LE());
23
+ }
24
+ return { ropsList, handleTable };
25
+ }
26
+ //# sourceMappingURL=RopBuffer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RopBuffer.js","sourceRoot":"","sources":["../../../src/codec/RopBuffer.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA0B/D,MAAM,UAAU,eAAe,CAAC,GAAc;IAC1C,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,kGAAkG;IAClG,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc;IAC1C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,OAAO,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACtB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACrC,CAAC"}
@@ -0,0 +1,54 @@
1
+ /** `TypedString` (`[MS-OXCDATA]` §2.11.7) `StringType` enumeration values. */
2
+ const STRING_TYPE_NONE = 0x00;
3
+ const STRING_TYPE_EMPTY = 0x01;
4
+ const STRING_TYPE_STRING8 = 0x02;
5
+ const STRING_TYPE_REDUCED_UNICODE = 0x03;
6
+ const STRING_TYPE_UNICODE = 0x04;
7
+ /**
8
+ * `TypedString` (`[MS-OXCDATA]` §2.11.7): a leading `StringType` byte followed by an optional string in the
9
+ * format that byte names - used by `RopOpenMessage`'s success response (`SubjectPrefix`/`NormalizedSubject`).
10
+ * `writeTypedString` never produces the "reduced Unicode" (`0x03`) form - that's purely a wire-size
11
+ * optimization real Exchange applies when every character happens to fit in one byte, not something a peer is
12
+ * ever required to send, so this codec always writes plain UTF-16LE (`0x04`) for non-empty strings. `undefined`
13
+ * writes as "no string" (`0x00`), matching a field the spec allows to be entirely absent (e.g. no subject
14
+ * prefix at all, as opposed to an empty one).
15
+ */
16
+ export function writeTypedString(writer, value) {
17
+ if (value === undefined) {
18
+ writer.writeUInt8(STRING_TYPE_NONE);
19
+ }
20
+ else if (value === "") {
21
+ writer.writeUInt8(STRING_TYPE_EMPTY);
22
+ }
23
+ else {
24
+ writer.writeUInt8(STRING_TYPE_UNICODE);
25
+ writer.writeNullTerminatedUtf16LE(value);
26
+ }
27
+ }
28
+ /** Reads a `TypedString`, supporting every `StringType` value a peer could legally send (`0x00`-`0x04`) even
29
+ * though `writeTypedString` only ever produces `0x00`/`0x01`/`0x04` itself - this side of the codec is only
30
+ * ever exercised in this library's own round-trip tests, since a real MAPI/HTTP client never sends a
31
+ * `TypedString` value to the server. Returns `undefined` for `StringType = 0x00` ("no string"), matching
32
+ * `writeTypedString`'s own `undefined` input. */
33
+ export function readTypedString(reader) {
34
+ const stringType = reader.readUInt8();
35
+ switch (stringType) {
36
+ case STRING_TYPE_NONE:
37
+ return undefined;
38
+ case STRING_TYPE_EMPTY:
39
+ return "";
40
+ case STRING_TYPE_STRING8:
41
+ return reader.readNullTerminatedString8();
42
+ case STRING_TYPE_REDUCED_UNICODE: {
43
+ let value = "";
44
+ for (let code = reader.readUInt8(); code !== 0; code = reader.readUInt8()) {
45
+ value += String.fromCharCode(code);
46
+ }
47
+ return value;
48
+ }
49
+ case STRING_TYPE_UNICODE:
50
+ default:
51
+ return reader.readNullTerminatedUtf16LE();
52
+ }
53
+ }
54
+ //# sourceMappingURL=TypedString.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TypedString.js","sourceRoot":"","sources":["../../../src/codec/TypedString.ts"],"names":[],"mappings":"AAMA,8EAA8E;AAC9E,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAC9B,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAC/B,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACjC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AACzC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAoB,EAAE,KAAyB;IAC5E,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;IACxC,CAAC;SAAM,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACtB,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACJ,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QACvC,MAAM,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;AACL,CAAC;AAED;;;;iDAIiD;AACjD,MAAM,UAAU,eAAe,CAAC,MAAoB;IAChD,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IACtC,QAAQ,UAAU,EAAE,CAAC;QACjB,KAAK,gBAAgB;YACjB,OAAO,SAAS,CAAC;QACrB,KAAK,iBAAiB;YAClB,OAAO,EAAE,CAAC;QACd,KAAK,mBAAmB;YACpB,OAAO,MAAM,CAAC,yBAAyB,EAAE,CAAC;QAC9C,KAAK,2BAA2B,CAAC,CAAC,CAAC;YAC/B,IAAI,KAAK,GAAG,EAAE,CAAC;YACf,KAAK,IAAI,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,EAAE,IAAI,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;gBACxE,KAAK,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,KAAK,mBAAmB,CAAC;QACzB;YACI,OAAO,MAAM,CAAC,yBAAyB,EAAE,CAAC;IAClD,CAAC;AACL,CAAC"}
@@ -0,0 +1,99 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * MAPI-over-HTTP protocol compatibility (Phase 3 of this library's roadmap): a hand-built ROP (Remote
7
+ * Operation) codec and buffer-framing layer (`[MS-OXCROPS]`), JWT-secured EMSMDB transport (`BaseMapiEmsmdbRoute`,
8
+ * reusing the framework's existing `@Auth(["jwt"])` strategy - no MAPI-specific auth code of its own), and a
9
+ * minimal NSPI address-book endpoint (`BaseMapiNspiRoute`) for GAL "search as you type" lookups.
10
+ *
11
+ * This module exports only the backend-agnostic surface: the wire-format codecs, the abstract route base
12
+ * classes, `MapiSessionManager`, the ROP dispatcher, and every ROP/NSPI handler class (each takes a generic
13
+ * `RopContext`/repo argument, not a concrete entity class, so none of them are backend-specific). The concrete
14
+ * Mongo/SQL classes a deployment actually instantiates (`MapiEmsmdbRouteMongo`/`SQL`,
15
+ * `MapiNspiRouteMongo`/`SQL`) are exported from this package's `./mongo`/`./sql` subpaths instead, alongside
16
+ * every other entity/route/job this library defines - see `src/eas/index.ts`'s identical doc comment for the
17
+ * same convention.
18
+ *
19
+ * A deployment mounts both MAPI endpoints with a trivial one-line subclass each, the same pattern
20
+ * `src/eas/index.ts`'s doc comment describes for `BaseEasRoute`:
21
+ * ```ts
22
+ * import { MapiEmsmdbRouteMongo, MapiNspiRouteMongo } from "@rapidrest/mail/mongo";
23
+ * import { RouteDecorators } from "@rapidrest/service-core";
24
+ * const { Route } = RouteDecorators;
25
+ *
26
+ * @Route("/mapi/emsmdb")
27
+ * export class MyMapiEmsmdbRoute extends MapiEmsmdbRouteMongo {}
28
+ *
29
+ * @Route("/mapi/nspi")
30
+ * export class MyMapiNspiRoute extends MapiNspiRouteMongo {}
31
+ * ```
32
+ * Real Outlook desktop locates both URLs via `@rapidrest/mail/autodiscover`'s Outlook/EXCH response
33
+ * (`BaseAutodiscoverRoute`'s `mapiUrl` property) - see that module's own doc comment.
34
+ *
35
+ * **Documented gaps in this pragmatic subset** (see the architecture plan's "MAPI over HTTP (Phase 3)" section
36
+ * for the full reasoning behind each):
37
+ * - Incremental sync (`RopFastTransferSourceCopyTo`/`CopyProperties`/`GetBuffer`) always builds a full,
38
+ * non-differential dump, not real IDSET-based ICS (`[MS-OXCFXICS]`) - a real client still works correctly
39
+ * against this, just less efficiently than byte-perfect ICS.
40
+ * - Calendar/meetings: no counter-proposals, meeting-forwarding, delegate scheduling, or resource-booking
41
+ * auto-accept; no DST-aware timezones (fixed-offset approximation only); no recurrence exceptions/modified
42
+ * instances; no Hijri/`MonthEnd` recurrence patterns.
43
+ * - No `RopModifyRecipients` - attendees/recipients are always added via the same `PidTagDisplayTo`/`Cc`
44
+ * pragmatic path used for ordinary mail.
45
+ * - No public-folder support, no delegate/shared-mailbox access, no rules/permissions/search-folder ROPs, no
46
+ * client-certificate enrollment.
47
+ * - Calendar named properties (location/recurrence/timezone/etc.) are excluded from FastTransfer streams -
48
+ * only the columns in `FastTransferStream.ts`'s `DEFAULT_*_COLUMNS` tables are included.
49
+ * - NSPI is limited to `Bind`/`Unbind`/`GetMatches` only - no row/name lookups beyond a single content-
50
+ * restriction search, no directory replication.
51
+ */
52
+ export * from "./codec/BufferCursor.js";
53
+ export * from "./codec/MapiGuid.js";
54
+ export * from "./codec/TypedString.js";
55
+ export * from "./codec/PropertyValue.js";
56
+ export * from "./codec/RopBuffer.js";
57
+ export * from "./codec/AppointmentRecurrence.js";
58
+ export * from "./codec/MapiTimeZone.js";
59
+ export * from "./codec/GlobalObjectId.js";
60
+ export * from "./RopDispatcher.js";
61
+ export * from "./MapiSessionManager.js";
62
+ export * from "./BaseMapiEmsmdbRoute.js";
63
+ export * from "./BaseMapiNspiRoute.js";
64
+ export * from "./rop/RopHandler.js";
65
+ export * from "./rop/FolderTarget.js";
66
+ export * from "./rop/MessageTarget.js";
67
+ export * from "./rop/CalendarEventTarget.js";
68
+ export * from "./rop/MessageBodyStream.js";
69
+ export * from "./rop/PropertyResolvers.js";
70
+ export * from "./rop/NamedPropertyRegistry.js";
71
+ export * from "./rop/CalendarNamedProperties.js";
72
+ export * from "./rop/FastTransferStream.js";
73
+ export * from "./rop/MeetingMessageClassHandler.js";
74
+ export * from "./rop/RopLogonHandler.js";
75
+ export * from "./rop/RopReleaseHandler.js";
76
+ export * from "./rop/RopOpenFolderHandler.js";
77
+ export * from "./rop/RopGetHierarchyTableHandler.js";
78
+ export * from "./rop/RopSetColumnsHandler.js";
79
+ export * from "./rop/RopQueryRowsHandler.js";
80
+ export * from "./rop/RopGetContentsTableHandler.js";
81
+ export * from "./rop/RopOpenMessageHandler.js";
82
+ export * from "./rop/RopGetPropertiesSpecificHandler.js";
83
+ export * from "./rop/RopOpenStreamHandler.js";
84
+ export * from "./rop/RopReadStreamHandler.js";
85
+ export * from "./rop/RopCreateMessageHandler.js";
86
+ export * from "./rop/RopSetPropertiesHandler.js";
87
+ export * from "./rop/RopWriteStreamHandler.js";
88
+ export * from "./rop/RopSaveChangesMessageHandler.js";
89
+ export * from "./rop/RopSubmitMessageHandler.js";
90
+ export * from "./rop/RopGetPropertyIdsFromNamesHandler.js";
91
+ export * from "./rop/RopDeleteMessagesHandler.js";
92
+ export * from "./rop/RopDeleteFolderHandler.js";
93
+ export * from "./rop/RopFastTransferSourceCopyToHandler.js";
94
+ export * from "./rop/RopFastTransferSourceCopyPropertiesHandler.js";
95
+ export * from "./rop/RopFastTransferSourceGetBufferHandler.js";
96
+ export * from "./nspi/NspiCodec.js";
97
+ export * from "./nspi/NspiBindHandler.js";
98
+ export * from "./nspi/NspiGetMatchesHandler.js";
99
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0CAA0C,CAAC;AACzD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uCAAuC,CAAC;AACtD,cAAc,kCAAkC,CAAC;AACjD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,qDAAqD,CAAC;AACpE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC"}