@rapidmx/mapi-plugin 1.0.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/LICENSE +382 -0
  2. package/README.md +60 -0
  3. package/dist/lib/BaseMapiEmsmdbRoute.js +489 -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 +475 -0
  8. package/dist/lib/MapiSessionManager.js.map +1 -0
  9. package/dist/lib/RegexPatternUtils.js +30 -0
  10. package/dist/lib/RegexPatternUtils.js.map +1 -0
  11. package/dist/lib/RopDispatcher.js +145 -0
  12. package/dist/lib/RopDispatcher.js.map +1 -0
  13. package/dist/lib/codec/AppointmentRecurrence.js +315 -0
  14. package/dist/lib/codec/AppointmentRecurrence.js.map +1 -0
  15. package/dist/lib/codec/BufferCursor.js +242 -0
  16. package/dist/lib/codec/BufferCursor.js.map +1 -0
  17. package/dist/lib/codec/GlobalObjectId.js +98 -0
  18. package/dist/lib/codec/GlobalObjectId.js.map +1 -0
  19. package/dist/lib/codec/MapiGuid.js +41 -0
  20. package/dist/lib/codec/MapiGuid.js.map +1 -0
  21. package/dist/lib/codec/MapiTimeZone.js +126 -0
  22. package/dist/lib/codec/MapiTimeZone.js.map +1 -0
  23. package/dist/lib/codec/PropertyValue.js +240 -0
  24. package/dist/lib/codec/PropertyValue.js.map +1 -0
  25. package/dist/lib/codec/RopBuffer.js +38 -0
  26. package/dist/lib/codec/RopBuffer.js.map +1 -0
  27. package/dist/lib/codec/TypedString.js +54 -0
  28. package/dist/lib/codec/TypedString.js.map +1 -0
  29. package/dist/lib/index.js +99 -0
  30. package/dist/lib/index.js.map +1 -0
  31. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +85 -0
  32. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -0
  33. package/dist/lib/mongo/MapiNspiRouteMongo.js +33 -0
  34. package/dist/lib/mongo/MapiNspiRouteMongo.js.map +1 -0
  35. package/dist/lib/mongo/index.js +7 -0
  36. package/dist/lib/mongo/index.js.map +1 -0
  37. package/dist/lib/mongo.js +6 -0
  38. package/dist/lib/mongo.js.map +1 -0
  39. package/dist/lib/nspi/NspiBindHandler.js +54 -0
  40. package/dist/lib/nspi/NspiBindHandler.js.map +1 -0
  41. package/dist/lib/nspi/NspiCodec.js +106 -0
  42. package/dist/lib/nspi/NspiCodec.js.map +1 -0
  43. package/dist/lib/nspi/NspiGetMatchesHandler.js +142 -0
  44. package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -0
  45. package/dist/lib/rop/AddressList.js +114 -0
  46. package/dist/lib/rop/AddressList.js.map +1 -0
  47. package/dist/lib/rop/CalendarEventTarget.js +30 -0
  48. package/dist/lib/rop/CalendarEventTarget.js.map +1 -0
  49. package/dist/lib/rop/CalendarNamedProperties.js +57 -0
  50. package/dist/lib/rop/CalendarNamedProperties.js.map +1 -0
  51. package/dist/lib/rop/ContactTarget.js +19 -0
  52. package/dist/lib/rop/ContactTarget.js.map +1 -0
  53. package/dist/lib/rop/ContentsTable.js +60 -0
  54. package/dist/lib/rop/ContentsTable.js.map +1 -0
  55. package/dist/lib/rop/ExecuteBudget.js +82 -0
  56. package/dist/lib/rop/ExecuteBudget.js.map +1 -0
  57. package/dist/lib/rop/FastTransferStream.js +195 -0
  58. package/dist/lib/rop/FastTransferStream.js.map +1 -0
  59. package/dist/lib/rop/FolderTarget.js +118 -0
  60. package/dist/lib/rop/FolderTarget.js.map +1 -0
  61. package/dist/lib/rop/HandleDataCache.js +412 -0
  62. package/dist/lib/rop/HandleDataCache.js.map +1 -0
  63. package/dist/lib/rop/MeetingMessageClassHandler.js +241 -0
  64. package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -0
  65. package/dist/lib/rop/MessageBodyStream.js +68 -0
  66. package/dist/lib/rop/MessageBodyStream.js.map +1 -0
  67. package/dist/lib/rop/MessageTarget.js +57 -0
  68. package/dist/lib/rop/MessageTarget.js.map +1 -0
  69. package/dist/lib/rop/NamedPropertyRegistry.js +69 -0
  70. package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -0
  71. package/dist/lib/rop/PropertyResolvers.js +353 -0
  72. package/dist/lib/rop/PropertyResolvers.js.map +1 -0
  73. package/dist/lib/rop/RepoPaging.js +54 -0
  74. package/dist/lib/rop/RepoPaging.js.map +1 -0
  75. package/dist/lib/rop/RestapiRules.js +52 -0
  76. package/dist/lib/rop/RestapiRules.js.map +1 -0
  77. package/dist/lib/rop/RopCreateMessageHandler.js +55 -0
  78. package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -0
  79. package/dist/lib/rop/RopDeleteFolderHandler.js +174 -0
  80. package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -0
  81. package/dist/lib/rop/RopDeleteMessagesHandler.js +110 -0
  82. package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -0
  83. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +61 -0
  84. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -0
  85. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +60 -0
  86. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -0
  87. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +76 -0
  88. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -0
  89. package/dist/lib/rop/RopGetContentsTableHandler.js +55 -0
  90. package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -0
  91. package/dist/lib/rop/RopGetHierarchyTableHandler.js +42 -0
  92. package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -0
  93. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +56 -0
  94. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -0
  95. package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js +92 -0
  96. package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js.map +1 -0
  97. package/dist/lib/rop/RopHandler.js +6 -0
  98. package/dist/lib/rop/RopHandler.js.map +1 -0
  99. package/dist/lib/rop/RopLogonHandler.js +135 -0
  100. package/dist/lib/rop/RopLogonHandler.js.map +1 -0
  101. package/dist/lib/rop/RopOpenFolderHandler.js +48 -0
  102. package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -0
  103. package/dist/lib/rop/RopOpenMessageHandler.js +83 -0
  104. package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -0
  105. package/dist/lib/rop/RopOpenStreamHandler.js +84 -0
  106. package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -0
  107. package/dist/lib/rop/RopQueryRowsHandler.js +120 -0
  108. package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -0
  109. package/dist/lib/rop/RopReadStreamHandler.js +73 -0
  110. package/dist/lib/rop/RopReadStreamHandler.js.map +1 -0
  111. package/dist/lib/rop/RopReleaseHandler.js +23 -0
  112. package/dist/lib/rop/RopReleaseHandler.js.map +1 -0
  113. package/dist/lib/rop/RopSaveChangesMessageHandler.js +269 -0
  114. package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -0
  115. package/dist/lib/rop/RopSetColumnsHandler.js +50 -0
  116. package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -0
  117. package/dist/lib/rop/RopSetPropertiesHandler.js +173 -0
  118. package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -0
  119. package/dist/lib/rop/RopSubmitMessageHandler.js +342 -0
  120. package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -0
  121. package/dist/lib/rop/RopWriteStreamHandler.js +72 -0
  122. package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -0
  123. package/dist/lib/rop/TaskNamedProperties.js +29 -0
  124. package/dist/lib/rop/TaskNamedProperties.js.map +1 -0
  125. package/dist/lib/rop/TaskTarget.js +15 -0
  126. package/dist/lib/rop/TaskTarget.js.map +1 -0
  127. package/dist/lib/rop/TransportSend.js +16 -0
  128. package/dist/lib/rop/TransportSend.js.map +1 -0
  129. package/dist/lib/sql/MapiEmsmdbRouteSQL.js +85 -0
  130. package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -0
  131. package/dist/lib/sql/MapiNspiRouteSQL.js +33 -0
  132. package/dist/lib/sql/MapiNspiRouteSQL.js.map +1 -0
  133. package/dist/lib/sql/index.js +7 -0
  134. package/dist/lib/sql/index.js.map +1 -0
  135. package/dist/lib/sql.js +6 -0
  136. package/dist/lib/sql.js.map +1 -0
  137. package/dist/types/BaseMapiEmsmdbRoute.d.ts +139 -0
  138. package/dist/types/BaseMapiNspiRoute.d.ts +38 -0
  139. package/dist/types/MapiSessionManager.d.ts +285 -0
  140. package/dist/types/RegexPatternUtils.d.ts +14 -0
  141. package/dist/types/RopDispatcher.d.ts +53 -0
  142. package/dist/types/codec/AppointmentRecurrence.d.ts +14 -0
  143. package/dist/types/codec/BufferCursor.d.ts +92 -0
  144. package/dist/types/codec/GlobalObjectId.d.ts +15 -0
  145. package/dist/types/codec/MapiGuid.d.ts +6 -0
  146. package/dist/types/codec/MapiTimeZone.d.ts +7 -0
  147. package/dist/types/codec/PropertyValue.d.ts +87 -0
  148. package/dist/types/codec/RopBuffer.d.ts +32 -0
  149. package/dist/types/codec/TypedString.d.ts +17 -0
  150. package/dist/types/index.d.ts +94 -0
  151. package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +20 -0
  152. package/dist/types/mongo/MapiNspiRouteMongo.d.ts +13 -0
  153. package/dist/types/mongo/index.d.ts +2 -0
  154. package/dist/types/mongo.d.ts +1 -0
  155. package/dist/types/nspi/NspiBindHandler.d.ts +22 -0
  156. package/dist/types/nspi/NspiCodec.d.ts +59 -0
  157. package/dist/types/nspi/NspiGetMatchesHandler.d.ts +26 -0
  158. package/dist/types/rop/AddressList.d.ts +48 -0
  159. package/dist/types/rop/CalendarEventTarget.d.ts +33 -0
  160. package/dist/types/rop/CalendarNamedProperties.d.ts +37 -0
  161. package/dist/types/rop/ContactTarget.d.ts +29 -0
  162. package/dist/types/rop/ContentsTable.d.ts +16 -0
  163. package/dist/types/rop/ExecuteBudget.d.ts +48 -0
  164. package/dist/types/rop/FastTransferStream.d.ts +57 -0
  165. package/dist/types/rop/FolderTarget.d.ts +64 -0
  166. package/dist/types/rop/HandleDataCache.d.ts +145 -0
  167. package/dist/types/rop/MeetingMessageClassHandler.d.ts +30 -0
  168. package/dist/types/rop/MessageBodyStream.d.ts +35 -0
  169. package/dist/types/rop/MessageTarget.d.ts +45 -0
  170. package/dist/types/rop/NamedPropertyRegistry.d.ts +50 -0
  171. package/dist/types/rop/PropertyResolvers.d.ts +86 -0
  172. package/dist/types/rop/RepoPaging.d.ts +30 -0
  173. package/dist/types/rop/RestapiRules.d.ts +32 -0
  174. package/dist/types/rop/RopCreateMessageHandler.d.ts +24 -0
  175. package/dist/types/rop/RopDeleteFolderHandler.d.ts +53 -0
  176. package/dist/types/rop/RopDeleteMessagesHandler.d.ts +43 -0
  177. package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +25 -0
  178. package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +25 -0
  179. package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +22 -0
  180. package/dist/types/rop/RopGetContentsTableHandler.d.ts +25 -0
  181. package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +18 -0
  182. package/dist/types/rop/RopGetPropertiesSpecificHandler.d.ts +26 -0
  183. package/dist/types/rop/RopGetPropertyIdsFromNamesHandler.d.ts +23 -0
  184. package/dist/types/rop/RopHandler.d.ts +106 -0
  185. package/dist/types/rop/RopLogonHandler.d.ts +31 -0
  186. package/dist/types/rop/RopOpenFolderHandler.d.ts +20 -0
  187. package/dist/types/rop/RopOpenMessageHandler.d.ts +28 -0
  188. package/dist/types/rop/RopOpenStreamHandler.d.ts +28 -0
  189. package/dist/types/rop/RopQueryRowsHandler.d.ts +43 -0
  190. package/dist/types/rop/RopReadStreamHandler.d.ts +20 -0
  191. package/dist/types/rop/RopReleaseHandler.d.ts +15 -0
  192. package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +59 -0
  193. package/dist/types/rop/RopSetColumnsHandler.d.ts +21 -0
  194. package/dist/types/rop/RopSetPropertiesHandler.d.ts +38 -0
  195. package/dist/types/rop/RopSubmitMessageHandler.d.ts +80 -0
  196. package/dist/types/rop/RopWriteStreamHandler.d.ts +31 -0
  197. package/dist/types/rop/TaskNamedProperties.d.ts +24 -0
  198. package/dist/types/rop/TaskTarget.d.ts +24 -0
  199. package/dist/types/rop/TransportSend.d.ts +10 -0
  200. package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +20 -0
  201. package/dist/types/sql/MapiNspiRouteSQL.d.ts +13 -0
  202. package/dist/types/sql/index.d.ts +2 -0
  203. package/dist/types/sql.d.ts +1 -0
  204. package/package.json +104 -0
@@ -0,0 +1,242 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * A small positional cursor over a `Buffer`, shared by every MAPI codec in this package (`MapiGuid`,
7
+ * `PropertyValue`, `RopBuffer`, and every individual ROP handler's own request/response encoding). Unlike
8
+ * WBXML's self-describing tag stream, MAPI's wire structures are fixed/variable-length binary records with no
9
+ * generic "read until end tag" mechanism, so every codec needs the same little-endian primitive reads/writes
10
+ * with automatic offset advancement - reimplementing that per file would be pure repetition across the dozens
11
+ * of ROP handlers this phase's plan calls for, unlike EAS's WBXML codec, which only needed one such reader.
12
+ *
13
+ * Underlying `Buffer` methods already bounds-check and throw `RangeError` on overflow/truncation for every
14
+ * fixed-width primitive read - a malformed or truncated ROP buffer legitimately failing loudly is the correct
15
+ * behavior, not something to swallow here. `readBytes`/`readNullTerminatedUtf16LE`/`readNullTerminatedString8`
16
+ * are the three exceptions: `Buffer.subarray` silently clamps instead of throwing, and a null-terminated scan
17
+ * has no fixed width to bounds-check against `Buffer` methods at all, so those three enforce the same
18
+ * "malformed/truncated input throws" contract explicitly below instead of relying on it happening for free.
19
+ *
20
+ * @author Jean-Philippe Steinmetz
21
+ */
22
+ /**
23
+ * A request that can't be decoded: truncated, or carrying a value (such as an unknown property type) whose wire
24
+ * size can't be determined. `RopDispatcher` answers the whole `Execute` with a 400 for one of these, since the bytes
25
+ * of every later ROP can no longer be located.
26
+ */
27
+ export class DecodeError extends RangeError {
28
+ constructor(message) {
29
+ super(message);
30
+ this.name = "DecodeError";
31
+ }
32
+ }
33
+ export class BufferReader {
34
+ constructor(buffer, offset = 0) {
35
+ this.buffer = buffer;
36
+ this.offset = offset;
37
+ }
38
+ get position() {
39
+ return this.offset;
40
+ }
41
+ get remaining() {
42
+ return this.buffer.length - this.offset;
43
+ }
44
+ hasMore() {
45
+ return this.offset < this.buffer.length;
46
+ }
47
+ /** Moves to `position` (backwards or forwards). Throws a `RangeError` for a position outside the buffer. */
48
+ seek(position) {
49
+ if (position < 0 || position > this.buffer.length) {
50
+ throw new RangeError(`BufferReader.seek(${position}): out of range (buffer length ${this.buffer.length}).`);
51
+ }
52
+ this.offset = position;
53
+ }
54
+ readUInt8() {
55
+ const value = this.buffer.readUInt8(this.offset);
56
+ this.offset += 1;
57
+ return value;
58
+ }
59
+ readInt16LE() {
60
+ const value = this.buffer.readInt16LE(this.offset);
61
+ this.offset += 2;
62
+ return value;
63
+ }
64
+ readUInt16LE() {
65
+ const value = this.buffer.readUInt16LE(this.offset);
66
+ this.offset += 2;
67
+ return value;
68
+ }
69
+ readInt32LE() {
70
+ const value = this.buffer.readInt32LE(this.offset);
71
+ this.offset += 4;
72
+ return value;
73
+ }
74
+ readUInt32LE() {
75
+ const value = this.buffer.readUInt32LE(this.offset);
76
+ this.offset += 4;
77
+ return value;
78
+ }
79
+ readFloatLE() {
80
+ const value = this.buffer.readFloatLE(this.offset);
81
+ this.offset += 4;
82
+ return value;
83
+ }
84
+ readDoubleLE() {
85
+ const value = this.buffer.readDoubleLE(this.offset);
86
+ this.offset += 8;
87
+ return value;
88
+ }
89
+ readBigInt64LE() {
90
+ const value = this.buffer.readBigInt64LE(this.offset);
91
+ this.offset += 8;
92
+ return value;
93
+ }
94
+ readBigUInt64LE() {
95
+ const value = this.buffer.readBigUInt64LE(this.offset);
96
+ this.offset += 8;
97
+ return value;
98
+ }
99
+ /** Unlike every fixed-width `readXxxLE` above, `Buffer.prototype.subarray` never throws - an out-of-range
100
+ * `length` (negative, or reaching past the buffer's end) silently clamps instead, which would otherwise let
101
+ * a malformed/truncated ROP buffer produce garbage-but-not-erroring reads (a negative `length` even rewinds
102
+ * `offset` backwards) instead of failing loudly the way this class's own doc comment promises. Explicitly
103
+ * bounds-checked here for that reason. */
104
+ readBytes(length) {
105
+ if (length < 0 || this.offset + length > this.buffer.length) {
106
+ throw new RangeError(`BufferReader.readBytes(${length}): out of range at offset ${this.offset} (buffer length ${this.buffer.length}).`);
107
+ }
108
+ const value = this.buffer.subarray(this.offset, this.offset + length);
109
+ this.offset += length;
110
+ return value;
111
+ }
112
+ /** Reads a UTF-16LE string up to (and consuming) its terminating `0x0000` code unit - `PtypString`'s wire
113
+ * encoding. Scans on 2-byte boundaries, since a null code unit's low/high byte pair can't be mistaken for
114
+ * one half of a non-null UTF-16 code unit at an odd offset the way a naive single-byte scan could.
115
+ *
116
+ * Throws if no terminator is found before running out of buffer, rather than silently returning whatever
117
+ * content preceded the truncation and leaving `offset` past the buffer's actual end - a truncated/malformed
118
+ * string is exactly the kind of input this class's own doc comment says should fail loudly. This also
119
+ * closes a real DoS: `PropertyValue.ts`'s `readCountedArray` loops a client-controlled element count with
120
+ * no independent cap, trusting each element's own reader to terminate the loop early against a too-small
121
+ * buffer the way every fixed-width reader already does - without this, `PtypMultipleString`'s
122
+ * `readNullTerminatedUtf16LE` calls kept silently returning `""` past the buffer's end forever instead. */
123
+ readNullTerminatedUtf16LE() {
124
+ let end = this.offset;
125
+ while (end + 1 < this.buffer.length && !(this.buffer[end] === 0 && this.buffer[end + 1] === 0)) {
126
+ end += 2;
127
+ }
128
+ if (end + 1 >= this.buffer.length) {
129
+ throw new RangeError("BufferReader.readNullTerminatedUtf16LE(): no null terminator found before the end of the buffer.");
130
+ }
131
+ const value = this.buffer.toString("utf16le", this.offset, end);
132
+ this.offset = end + 2;
133
+ return value;
134
+ }
135
+ /** Reads a single-byte-terminated 8-bit string (`PtypString8`'s wire encoding). Multibyte string content
136
+ * itself is treated as UTF-8, a pragmatic choice documented in `PropertyValue.ts` rather than the
137
+ * "externally specified encoding" the spec leaves open-ended.
138
+ *
139
+ * Throws if no terminator is found before running out of buffer - see `readNullTerminatedUtf16LE`'s own
140
+ * doc comment for why (identical reasoning, including the `readCountedArray` DoS this closes). */
141
+ readNullTerminatedString8() {
142
+ let end = this.offset;
143
+ while (end < this.buffer.length && this.buffer[end] !== 0) {
144
+ end += 1;
145
+ }
146
+ if (end >= this.buffer.length) {
147
+ throw new RangeError("BufferReader.readNullTerminatedString8(): no null terminator found before the end of the buffer.");
148
+ }
149
+ const value = this.buffer.toString("utf-8", this.offset, end);
150
+ this.offset = end + 1;
151
+ return value;
152
+ }
153
+ }
154
+ /** The write-side counterpart to `BufferReader`, accumulating chunks and concatenating once via `toBuffer()` -
155
+ * the same "array of pieces, `Buffer.concat` once at the end" idiom `WbxmlEncoder` already uses for its own
156
+ * byte-array accumulator, adapted for multi-byte little-endian fields instead of single bytes. */
157
+ export class BufferWriter {
158
+ constructor() {
159
+ this.chunks = [];
160
+ this.byteLength = 0;
161
+ }
162
+ /** The number of bytes written so far. */
163
+ get length() {
164
+ return this.byteLength;
165
+ }
166
+ push(...buffers) {
167
+ for (const buffer of buffers) {
168
+ this.chunks.push(buffer);
169
+ this.byteLength += buffer.length;
170
+ }
171
+ }
172
+ writeUInt8(value) {
173
+ const buf = Buffer.alloc(1);
174
+ buf.writeUInt8(value, 0);
175
+ this.push(buf);
176
+ return this;
177
+ }
178
+ writeInt16LE(value) {
179
+ const buf = Buffer.alloc(2);
180
+ buf.writeInt16LE(value, 0);
181
+ this.push(buf);
182
+ return this;
183
+ }
184
+ writeUInt16LE(value) {
185
+ const buf = Buffer.alloc(2);
186
+ buf.writeUInt16LE(value, 0);
187
+ this.push(buf);
188
+ return this;
189
+ }
190
+ writeInt32LE(value) {
191
+ const buf = Buffer.alloc(4);
192
+ buf.writeInt32LE(value, 0);
193
+ this.push(buf);
194
+ return this;
195
+ }
196
+ writeUInt32LE(value) {
197
+ const buf = Buffer.alloc(4);
198
+ buf.writeUInt32LE(value, 0);
199
+ this.push(buf);
200
+ return this;
201
+ }
202
+ writeFloatLE(value) {
203
+ const buf = Buffer.alloc(4);
204
+ buf.writeFloatLE(value, 0);
205
+ this.push(buf);
206
+ return this;
207
+ }
208
+ writeDoubleLE(value) {
209
+ const buf = Buffer.alloc(8);
210
+ buf.writeDoubleLE(value, 0);
211
+ this.push(buf);
212
+ return this;
213
+ }
214
+ writeBigInt64LE(value) {
215
+ const buf = Buffer.alloc(8);
216
+ buf.writeBigInt64LE(value, 0);
217
+ this.push(buf);
218
+ return this;
219
+ }
220
+ writeBigUInt64LE(value) {
221
+ const buf = Buffer.alloc(8);
222
+ buf.writeBigUInt64LE(value, 0);
223
+ this.push(buf);
224
+ return this;
225
+ }
226
+ writeBytes(value) {
227
+ this.push(value);
228
+ return this;
229
+ }
230
+ writeNullTerminatedUtf16LE(value) {
231
+ this.push(Buffer.from(value, "utf16le"), Buffer.from([0x00, 0x00]));
232
+ return this;
233
+ }
234
+ writeNullTerminatedString8(value) {
235
+ this.push(Buffer.from(value, "utf-8"), Buffer.from([0x00]));
236
+ return this;
237
+ }
238
+ toBuffer() {
239
+ return Buffer.concat(this.chunks);
240
+ }
241
+ }
242
+ //# sourceMappingURL=BufferCursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BufferCursor.js","sourceRoot":"","sources":["../../../src/codec/BufferCursor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
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
+ import { dateToFiletime } from "./PropertyValue.js";
7
+ /**
8
+ * Encodes/decodes `CalendarEvent.icalUid` to/from the `GlobalObjectId` BLOB carried by `PidLidGlobalObjectId`
9
+ * (`[MS-OXOCAL]` §2.2.1.27, confirmed field-by-field this session): `ByteArrayID(16, a fixed spec constant)
10
+ * +YH(1)+YL(1)+M(1)+D(1)+CreationTime(8,FILETIME)+X(8,reserved,zero)+Size(4)+Data(variable, Size bytes)` - 40
11
+ * fixed header bytes followed by `Data`.
12
+ *
13
+ * **This server never actually embeds a `GlobalObjectId` in the invites it sends** - `RopSubmitMessageHandler
14
+ * .submitAppointment()`'s invite is a plain RFC 5546 `METHOD:REQUEST` iCalendar attachment relayed over SMTP,
15
+ * not a native MAPI Store object a real client reads `PidLidGlobalObjectId` off of directly; that iCalendar
16
+ * only ever carries a plain `UID:` line. A real Outlook client receiving it therefore always *synthesizes* its
17
+ * own `PidLidGlobalObjectId` from that bare iCalendar UID, using the `VCALID` form both `[MS-ASEMAIL]` §2.2.2.37
18
+ * and the equivalent `[MS-OXCICAL]` UID-conversion algorithm document: `Data` = the 8-byte ASCII marker
19
+ * `"vCal-Uid"`, then a 4-byte version (`01 00 00 00`), then the UID's own bytes, then one trailing `NUL` -
20
+ * **not** the bare UID bytes this codec originally assumed. `decodeGlobalObjectId` recognizes and unwraps this
21
+ * form (falling back to the hex form below only when the `vCal-Uid` marker isn't present, i.e. an
22
+ * `OutlookID` - a native-Exchange-generated `GlobalObjectId`, decoded to the hex form `[MS-OXCICAL]` gives its
23
+ * iCalendar UID). `encodeGlobalObjectId` now builds the same `VCALID` shape, both so
24
+ * a round trip through this codec models the real wire form and because `MeetingMessageClassHandler.test.ts`'s
25
+ * own test doubles need a realistic fixture to encode.
26
+ *
27
+ * **Pragmatic scope**: `YH`/`YL`/`M`/`D` (set when a `GlobalObjectId` identifies a single occurrence of a recurring
28
+ * series) are always encoded as `0` ("not an exception"); `globalObjectIdInstanceDate` reads them from a client's
29
+ * meeting response.
30
+ * `PidLidCleanGlobalObjectId` (the sibling property real Outlook also sets, identical structure but with
31
+ * `YH`/`YL`/`M`/`D` always zeroed) is therefore byte-identical to this codec's own output and needs no separate
32
+ * implementation - the same value serves both properties.
33
+ *
34
+ * @author Jean-Philippe Steinmetz
35
+ */
36
+ /** `ByteArrayID` (`[MS-OXOCAL]` §2.2.1.27): a fixed 16-byte constant identifying this BLOB as a `GlobalObjectId`
37
+ * - the spec's own exact required byte sequence, not invented. */
38
+ const BYTE_ARRAY_ID = Buffer.from([0x04, 0x00, 0x00, 0x00, 0x82, 0x00, 0xe0, 0x00, 0x74, 0xc5, 0xb7, 0x10, 0x1a, 0x82, 0xe0, 0x08]);
39
+ /** `VCALID`'s own fixed 8-byte ASCII marker (`[MS-ASEMAIL]` §2.2.2.37's `VCALSTRING`) identifying `Data` as a
40
+ * `"vCal-Uid"`-wrapped UID rather than a native `OutlookID`'s raw bytes. */
41
+ const VCAL_MARKER = Buffer.from("vCal-Uid", "ascii");
42
+ /** `VCALID`'s own fixed 4-byte `VERSION` field - always this exact literal byte sequence, not a real version
43
+ * negotiated at runtime. */
44
+ const VCAL_VERSION = Buffer.from([0x01, 0x00, 0x00, 0x00]);
45
+ /** A `VCALID`'s minimum possible `Data` length: `VCAL_MARKER` (8) + `VCAL_VERSION` (4) + a zero-length UID (0)
46
+ * + the trailing `NUL` (1). */
47
+ const VCAL_MIN_DATA_LENGTH = VCAL_MARKER.length + VCAL_VERSION.length + 1;
48
+ /** Encodes `icalUid` into a `GlobalObjectId` BLOB in the `VCALID` form a real client synthesizes from a plain
49
+ * iCalendar UID (see this file's own doc comment for why that's the form that matters here), using `at` as the
50
+ * `CreationTime`. */
51
+ export function encodeGlobalObjectId(icalUid, at) {
52
+ const data = Buffer.concat([VCAL_MARKER, VCAL_VERSION, Buffer.from(icalUid, "utf-8"), Buffer.from([0x00])]);
53
+ const writer = new BufferWriter();
54
+ writer.writeBytes(BYTE_ARRAY_ID);
55
+ writer.writeUInt8(0); // YH - not an exception, see class doc comment
56
+ writer.writeUInt8(0); // YL
57
+ writer.writeUInt8(0); // M
58
+ writer.writeUInt8(0); // D
59
+ writer.writeBigUInt64LE(dateToFiletime(at)); // CreationTime
60
+ writer.writeBytes(Buffer.alloc(8)); // X - reserved, MUST be zero
61
+ writer.writeUInt32LE(data.length); // Size
62
+ writer.writeBytes(data);
63
+ return writer.toBuffer();
64
+ }
65
+ /** Decodes a `GlobalObjectId` BLOB (read from `reader`'s current position) back into the `icalUid` it stands for.
66
+ * A `VCALID` (see this file's own doc comment) yields the UID it wraps. Anything else is a native `OutlookID`,
67
+ * whose `Data` is binary, not text: per `[MS-OXCICAL]`'s UID conversion, the iCalendar UID of such an object is the
68
+ * uppercase hex of the whole `GlobalObjectId` with the instance date (`YH`/`YL`/`M`/`D`, bytes 16-19) zeroed, so
69
+ * that is what is returned (compare it case-insensitively). Throws if `ByteArrayID` doesn't match the spec's own
70
+ * fixed constant - a real, spec-mandated identity check, not an invented restriction. */
71
+ export function decodeGlobalObjectId(reader) {
72
+ const byteArrayId = reader.readBytes(16);
73
+ if (!byteArrayId.equals(BYTE_ARRAY_ID)) {
74
+ throw new Error("GlobalObjectId: ByteArrayID did not match the required [MS-OXOCAL] constant.");
75
+ }
76
+ reader.readBytes(4); // YH/YL/M/D
77
+ const creationTimeAndReserved = reader.readBytes(16); // CreationTime + X
78
+ const sizeBytes = reader.readBytes(4);
79
+ const size = sizeBytes.readUInt32LE(0);
80
+ const data = reader.readBytes(size);
81
+ const isVCalId = size >= VCAL_MIN_DATA_LENGTH && data.subarray(0, 8).equals(VCAL_MARKER) && data.subarray(8, 12).equals(VCAL_VERSION);
82
+ if (isVCalId) {
83
+ // Strip the marker+version prefix and the trailing NUL, per [MS-ASEMAIL]'s own UID-length formula
84
+ // (BYTECOUNT minus the marker minus the version minus 1 byte for the NUL).
85
+ return data.subarray(12, data.length - 1).toString("utf-8");
86
+ }
87
+ return Buffer.concat([byteArrayId, Buffer.alloc(4), creationTimeAndReserved, sizeBytes, data]).toString("hex").toUpperCase();
88
+ }
89
+ /** The `YYYY-MM-DD` occurrence date a `GlobalObjectId` names (`YH`/`YL`/`M`/`D`), or `undefined` when it names the
90
+ * whole series (a zero year). `globalObjectId` must already have decoded successfully. */
91
+ export function globalObjectIdInstanceDate(globalObjectId) {
92
+ const year = (globalObjectId[16] << 8) | globalObjectId[17];
93
+ if (year === 0) {
94
+ return undefined;
95
+ }
96
+ return `${String(year).padStart(4, "0")}-${String(globalObjectId[18]).padStart(2, "0")}-${String(globalObjectId[19]).padStart(2, "0")}`;
97
+ }
98
+ //# sourceMappingURL=GlobalObjectId.js.map
@@ -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,126 @@
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 a whole-hour offset to a synthetic-but-valid `Etc/GMT±N` IANA identifier
28
+ * (note the IANA `Etc/GMT` area's own sign convention is POSIX-inverted from common usage: `Etc/GMT+8` means UTC-8,
29
+ * not UTC+8). A half-hour/quarter-hour offset keeps its minutes: it maps to a real DST-less zone with that offset
30
+ * (e.g. `Asia/Kolkata`, `Asia/Kathmandu`) or otherwise to a fixed-offset identifier like `"-03:30"`. An offset
31
+ * outside UTC-12..UTC+14 decodes as `"UTC"`.
32
+ * - Encoding a zone `Intl` doesn't recognize falls back to UTC instead of throwing.
33
+ *
34
+ * @author Jean-Philippe Steinmetz
35
+ */
36
+ const SYSTEMTIME_FIELD_COUNT = 8;
37
+ function writeZeroTransitionBlock(writer) {
38
+ writer.writeUInt16LE(0); // wStandardYear / wDaylightYear
39
+ for (let i = 0; i < SYSTEMTIME_FIELD_COUNT; i++) {
40
+ writer.writeUInt16LE(0);
41
+ }
42
+ }
43
+ function skipTransitionBlock(reader) {
44
+ reader.readUInt16LE(); // wStandardYear / wDaylightYear
45
+ for (let i = 0; i < SYSTEMTIME_FIELD_COUNT; i++) {
46
+ reader.readUInt16LE();
47
+ }
48
+ }
49
+ /** The zone's UTC offset in minutes at instant `at` (standard convention: local minus UTC, e.g. `-480` for
50
+ * `America/Los_Angeles` in winter), read via `Intl`'s `shortOffset` formatting rather than hand-rolling a
51
+ * zone database. Throws the same way `Intl.DateTimeFormat` itself does for an unrecognized zone identifier. */
52
+ function utcOffsetMinutes(timezone, at) {
53
+ const formatter = new Intl.DateTimeFormat("en-US", { timeZone: timezone, timeZoneName: "shortOffset" });
54
+ // `formatToParts` always includes a "timeZoneName" part when `timeZoneName` is requested in the
55
+ // formatter's own options, so the non-null assertion below reflects a real `Intl` guarantee, not an
56
+ // unverified assumption.
57
+ const tzName = formatter.formatToParts(at).find((part) => part.type === "timeZoneName").value;
58
+ const match = /^GMT([+-])(\d+)(?::(\d+))?$/.exec(tzName);
59
+ if (!match) {
60
+ return 0; // Bare "GMT", i.e. UTC itself.
61
+ }
62
+ const sign = match[1] === "-" ? -1 : 1;
63
+ const hours = parseInt(match[2], 10);
64
+ const minutes = match[3] ? parseInt(match[3], 10) : 0;
65
+ return sign * (hours * 60 + minutes);
66
+ }
67
+ /** Encodes `timezone` (an IANA identifier, or `"UTC"`) into a 48-byte `TimeZoneStruct` BLOB, using `at` as the
68
+ * reference instant for resolving a non-UTC zone's current fixed offset. */
69
+ export function encodeTimeZoneStruct(timezone, at) {
70
+ const writer = new BufferWriter();
71
+ let bias = 0;
72
+ try {
73
+ bias = timezone === "UTC" ? 0 : -utcOffsetMinutes(timezone, at);
74
+ }
75
+ catch {
76
+ // An identifier Intl doesn't recognize (e.g. stored by another client) is sent as UTC rather than failing
77
+ // the whole property read.
78
+ bias = 0;
79
+ }
80
+ writer.writeInt32LE(bias); // lBias
81
+ writer.writeInt32LE(0); // lStandardBias - no DST modeled
82
+ writer.writeInt32LE(0); // lDaylightBias - no DST modeled
83
+ writeZeroTransitionBlock(writer); // wStandardYear + stStandardDate
84
+ writeZeroTransitionBlock(writer); // wDaylightYear + stDaylightDate
85
+ return writer.toBuffer();
86
+ }
87
+ /** Decodes a `TimeZoneStruct` BLOB (read from `reader`'s current position) into an approximate IANA zone
88
+ * identifier - see this file's own doc comment for the lossy `Etc/GMT±N` fallback's exact rounding rules. */
89
+ export function decodeTimeZoneStruct(reader) {
90
+ const bias = reader.readInt32LE();
91
+ reader.readInt32LE(); // lStandardBias - not reconstructable into a real DST rule, ignored
92
+ reader.readInt32LE(); // lDaylightBias - ditto
93
+ skipTransitionBlock(reader); // wStandardYear + stStandardDate
94
+ skipTransitionBlock(reader); // wDaylightYear + stDaylightDate
95
+ const offsetMinutes = -bias;
96
+ // No real zone is further than UTC-12/UTC+14; anything else is garbage and treated as UTC.
97
+ if (offsetMinutes === 0 || offsetMinutes < -12 * 60 || offsetMinutes > 14 * 60) {
98
+ return "UTC";
99
+ }
100
+ if (offsetMinutes % 60 === 0) {
101
+ const hours = offsetMinutes / 60;
102
+ return `Etc/GMT${hours < 0 ? "+" : "-"}${Math.abs(hours)}`;
103
+ }
104
+ return FRACTIONAL_OFFSET_ZONES[offsetMinutes] ?? formatFixedOffset(offsetMinutes);
105
+ }
106
+ /** Real zones with a non-whole-hour offset and no daylight saving, so the zone matches a DST-less
107
+ * `TimeZoneStruct` all year. */
108
+ const FRACTIONAL_OFFSET_ZONES = {
109
+ [-570]: "Pacific/Marquesas",
110
+ 210: "Asia/Tehran",
111
+ 270: "Asia/Kabul",
112
+ 330: "Asia/Kolkata",
113
+ 345: "Asia/Kathmandu",
114
+ 390: "Asia/Yangon",
115
+ 525: "Australia/Eucla",
116
+ 570: "Australia/Darwin",
117
+ };
118
+ /** A fixed-offset identifier such as `"-03:30"`, which `Intl.DateTimeFormat` accepts as a `timeZone`. Used for a
119
+ * minute-precision offset with no matching DST-less zone, instead of rounding it to a whole hour. */
120
+ function formatFixedOffset(offsetMinutes) {
121
+ const magnitude = Math.abs(offsetMinutes);
122
+ const hours = String(Math.floor(magnitude / 60)).padStart(2, "0");
123
+ const minutes = String(magnitude % 60).padStart(2, "0");
124
+ return `${offsetMinutes < 0 ? "-" : "+"}${hours}:${minutes}`;
125
+ }
126
+ //# 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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"}