@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,80 @@
1
+ import type { BufferReader, BufferWriter } from "../codec/BufferCursor.js";
2
+ import { type RopContext, type RopHandler } from "./RopHandler.js";
3
+ export { isPlainEmailAddress, parseAddressList } from "./AddressList.js";
4
+ /**
5
+ * `RopSubmitMessage` (`[MS-OXOMSG]`/`[MS-OXCROPS]`): sends a composed message - the actual trigger point for
6
+ * this pragmatic subset's compose/send pipeline, since `RopSaveChangesMessage` itself does no real persistence
7
+ * (see its own doc comment). Builds a raw MIME buffer from whatever `RopSetProperties`/`RopWriteStream` calls
8
+ * accumulated on the draft handle (`Subject`, the `PidTagBody` stream or an inline `PidTagBody` property, and
9
+ * addressing - see below), via `nodemailer`'s `MailComposer` (already a dependency, used elsewhere in this
10
+ * library only to *send*, not build, MIME - this is its first use purely as a RFC 5322 serializer), then calls
11
+ * the exact same `scanAndRelay()` scan-then-relay pipeline `BaseMessageRoute.send()`/EAS's `ComposeMailCommand`
12
+ * already share, and persists a Sent Items copy (mirroring `ComposeMailCommand`'s own always-committed Sent
13
+ * Items behavior for MAPI submission specifically, since - unlike EAS's optional `SaveInSentItems` - a MAPI
14
+ * `RopSubmitMessage` call has no "don't keep a copy" option to honor).
15
+ *
16
+ * **Known, deliberate limitation - no `RopModifyRecipients` support**: real recipient rows (`[MS-OXCMSG]`
17
+ * §2.2.3.2, each with its own `PidTagEmailAddress`/`PidTagRecipientType`) are a substantial structure this
18
+ * pragmatic subset's ROP coverage doesn't include. Instead, addressing is read from `PidTagDisplayTo`/
19
+ * `DisplayCc`/`DisplayBcc` - the same semicolon-separated "cached recipient display string" properties real
20
+ * Outlook *also* always sets via `RopSetProperties` alongside `RopModifyRecipients` (as a display-only
21
+ * convenience cache). Entries are separated by `;` and parsed with nodemailer's `addressparser`, so both bare
22
+ * addresses and resolved `Name <address>` forms work. A client that resolved a name against an address book may
23
+ * write the display name alone; that is looked up among the caller's own contacts (see `resolveRecipientList`), and
24
+ * a name matching no single contact fails the submit with `MAPI_E_NOT_FOUND`. It is still **not** a substitute for
25
+ * real recipient rows (there is no recipient table to fall back on), so the whole send is refused rather than sent to
26
+ * fewer people than the user addressed. A malformed recipient fails with `MAPI_E_INVALID_PARAMETER`.
27
+ *
28
+ * `SubmitFlags` (`PreprocessOnly`, ...) is decoded to advance past it correctly but not honored - this
29
+ * pragmatic subset has no transport-agent preprocessing distinction to vary by flag.
30
+ *
31
+ * **`PidTagDeferredSendTime`** ("Do not deliver before"), if set to a future time via `RopSetProperties`,
32
+ * parks the message in Outbox with `Message.scheduledSendTime` set instead of relaying immediately - mirroring
33
+ * `BaseMessageRoute.send()`'s own identical branch - for `ScheduledSendJob` to relay later via this same
34
+ * `scanAndRelay()` pipeline. **`PidTagReadReceiptRequested`**, if `true`, attaches a real
35
+ * `Disposition-Notification-To` header (see `util/ReceiptUtils.ts`) and is recorded on the persisted message's
36
+ * own `requestReceipt` field - honored only when the client explicitly sets it, not this mailbox's
37
+ * `alwaysRequestReceiptInternal`/`External` defaults (those apply to the REST/webmail compose path only).
38
+ *
39
+ * **Once per draft.** A mail or meeting-response draft is marked `submitted` as soon as a submit gets past the handle
40
+ * check, whatever the outcome, and a submitted draft can't be submitted again (`MAPI_E_INVALID_OBJECT`) or changed by
41
+ * `RopSetProperties`/`RopWriteStream`; its write-stream chunks are deleted once read. Each `Execute` runs at most
42
+ * `MAX_SUBMITS_PER_EXECUTE` submits, and a message may have at most `MAX_RECIPIENTS_PER_MESSAGE` recipients
43
+ * (`MAPI_E_TOO_BIG`), counted before any display name is looked up.
44
+ *
45
+ * **Calendar branches**: a draft whose `PidTagMessageClass` starts with `"IPM.Appointment"` is routed to
46
+ * `submitAppointment()` instead of the mail path below - see that method's own doc comment. One starting with
47
+ * `"IPM.Schedule.Meeting.Resp."` (an attendee's own accept/decline/tentative response to a meeting this server
48
+ * previously invited them to) is routed to `MeetingMessageClassHandler.submitMeetingResponse()` instead - see
49
+ * that function's own doc comment.
50
+ *
51
+ * @author Jean-Philippe Steinmetz
52
+ */
53
+ export declare class RopSubmitMessageHandler implements RopHandler {
54
+ readonly ropId = 50;
55
+ handle(reader: BufferReader, writer: BufferWriter, context: RopContext): Promise<void>;
56
+ /**
57
+ * Submits a Calendar item. The appointment itself is already persisted (`RopSaveChangesMessageHandler` writes the
58
+ * real `CalendarEvent` row at Save time, unlike a mail draft, which stays purely in-session until Submit), so there
59
+ * is nothing left to store and nothing is sent from here.
60
+ *
61
+ * **Invites are restapi's `MeetingSchedulingJob`'s job.** That job sends an iTIP `REQUEST` for every
62
+ * organizer-owned event whose `inviteSequenceSent` differs from its `sequence`, claiming each revision with a
63
+ * versioned update before sending and building the invite with restapi's own `buildEventIcs` (so a recurring
64
+ * meeting's invite carries its `RRULE` and exceptions). Saving stamps `inviteSequenceSent = sequence`, so a meeting
65
+ * that is only saved ("Save & Close", or "save changes but don't send") invites no one. Submitting clears the stamp
66
+ * (`inviteSequenceSent: null`) with a versioned update, which makes the job send the current revision exactly once.
67
+ * - A revision that is already waiting for the job (submitted and not yet sent, or never stamped) is left alone, so
68
+ * submitting it again before the job runs doesn't cause a second invite.
69
+ * - The update is versioned (`asEntity`). The job only ever claims a waiting revision, so a conflict here comes from
70
+ * some other edit (an attendee's reply updating the row, a REST edit); the row is read again and the check repeated,
71
+ * up to `MAX_INVITE_REQUEST_ATTEMPTS` times, after which the ROP fails (`MAPI_E_CALL_FAILED`).
72
+ * - Submitting a revision the job has already sent sends it again: the client asked to send.
73
+ *
74
+ * Only the organizer's own copy may be submitted (an attendee's copy of someone else's meeting answers
75
+ * `MAPI_E_INVALID_OBJECT`, as before, and nothing is changed).
76
+ */
77
+ private submitAppointment;
78
+ }
79
+ /** How many times `requestInvites` re-reads a row whose versioned update lost to another edit before giving up. */
80
+ export declare const MAX_INVITE_REQUEST_ATTEMPTS = 3;
@@ -0,0 +1,31 @@
1
+ import type { BufferReader, BufferWriter } from "../codec/BufferCursor.js";
2
+ import type { MapiObjectHandle } from "../MapiSessionManager.js";
3
+ import { type RopContext, type RopHandler } from "./RopHandler.js";
4
+ /** The largest body a write stream accumulates. */
5
+ export declare const MAX_WRITE_STREAM_BYTES: number;
6
+ /** How long a write stream's chunks are kept after its last write - the session's own idle lifetime. */
7
+ export declare const WRITE_STREAM_TTL_SECONDS: number;
8
+ export { writeStreamKey } from "./HandleDataCache.js";
9
+ /**
10
+ * `RopWriteStream` (`[MS-OXCPRPT]`/`[MS-OXCROPS]`): writes bytes to a stream opened in `ReadWrite`/`Create`
11
+ * mode (`RopOpenStreamHandler`'s write-mode branch - the only kind of writable stream this pragmatic subset
12
+ * ever produces, always a `RopCreateMessage` draft's `PidTagBody`). Each write is stored as a chunk keyed by its
13
+ * offset in the `HandleDataStore` (Redis when configured), not in the session: only `writeSize` is session state.
14
+ * Keying by offset makes a retried write (after a request whose session save lost a conflict) replace its chunk
15
+ * instead of appending it twice. Up to `MAX_WRITE_STREAM_BYTES`; a write past that fails with `MAPI_E_TOO_BIG` and
16
+ * nothing is stored, as it is when the session's or user's handle data quota (`handleDataOwners`) is used up. A stream
17
+ * whose draft has already been submitted takes no more writes. `RopSubmitMessageHandler` reassembles the body (`readWriteStream`) once composing is complete.
18
+ *
19
+ * Like `RopReadStream`, `[MS-OXCROPS]` documents only one combined response-buffer shape for this ROP (no
20
+ * separate Success/Failure pages) - `WrittenSize` is always present, `0` standing in for the failure case.
21
+ *
22
+ * @author Jean-Philippe Steinmetz
23
+ */
24
+ export declare class RopWriteStreamHandler implements RopHandler {
25
+ readonly ropId = 45;
26
+ readonly failureTailBytes = 2;
27
+ handle(reader: BufferReader, writer: BufferWriter, context: RopContext): Promise<void>;
28
+ }
29
+ /** The bytes written so far to the write stream `stream` at `handleIndex`, or `undefined` when they can no longer be
30
+ * reassembled (a chunk expired or was evicted). */
31
+ export declare function readWriteStream(context: RopContext, handleIndex: number, stream: MapiObjectHandle): Promise<Buffer | undefined>;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The Task named-property identity table (`(PropertySet GUID, LID)` pairs) this pragmatic subset supports, per
3
+ * `[MS-OXPROPS]`/`[MS-OXOTASK]` - the exact `CalendarNamedProperties.ts` precedent, adapted for `PSETID_Task`,
4
+ * shared by `PropertyResolvers.ts` (the read side: `taskValueFor`). Read-only in this pass - see
5
+ * `TaskTarget.ts`'s own doc comment for why there's no write-side (`RopSetProperties`/`RopSaveChangesMessage`)
6
+ * counterpart yet.
7
+ */
8
+ export declare const PSETID_TASK = "00062003-0000-0000-c000-000000000046";
9
+ /** `PidLidTaskStatus` (`PT_LONG`) - `[MS-OXOTASK]` §2.2.2.1.5's own `olTaskNotStarted`(0)/`olTaskInProgress`(1)/
10
+ * `olTaskComplete`(2)/`olTaskWaiting`(3)/`olTaskDeferred`(4) values. This data model's `Task.completed` is a
11
+ * plain boolean with no in-progress/waiting/deferred distinction, so only `olTaskNotStarted`/`olTaskComplete`
12
+ * are ever produced - a documented, harmless approximation, the same category as `CalendarNamedProperties.ts`'s
13
+ * own `olWorkingElsewhere` gap. */
14
+ export declare const LID_TASK_STATUS = 33025;
15
+ export declare const TASK_STATUS_NOT_STARTED = 0;
16
+ export declare const TASK_STATUS_COMPLETE = 2;
17
+ /** `PidLidPercentComplete` (`PT_R8`, `[MS-OXOTASK]` §2.2.2.1.6) - `0.0`-`1.0`. No partial-progress tracking in
18
+ * this data model either, so this is always `1.0` (complete) or `0.0` (not started), mirroring
19
+ * `LID_TASK_STATUS`'s own two-value approximation. */
20
+ export declare const LID_PERCENT_COMPLETE = 33026;
21
+ /** `PidLidTaskDueDate` (`PT_SYSTIME`, `[MS-OXOTASK]` §2.2.2.2.4). */
22
+ export declare const LID_TASK_DUE_DATE = 33029;
23
+ /** `PidLidTaskComplete` (`PT_BOOLEAN`, `[MS-OXOTASK]` §2.2.2.1.9) - maps directly to `Task.completed`. */
24
+ export declare const LID_TASK_COMPLETE = 33052;
@@ -0,0 +1,24 @@
1
+ import type { RepoUtils } from "@rapidrest/service-core";
2
+ import type { RepoSort } from "./RepoPaging.js";
3
+ /**
4
+ * The `RopGetContentsTable`/`RopOpenMessage` analog of `MessageTarget.ts`, for a `Folder` of type `TASKS`:
5
+ * resolves a `"task:<uid>"` row/handle target into the display data a task-item row or an opened task's
6
+ * properties need. A `Task` is addressed by MID exactly the same way a `Message`/`CalendarEvent`/`Contact` is -
7
+ * `MessageTarget.assignOrGetMid`/`session.messageIds` are reused as-is, so this file adds no MID-registry code
8
+ * of its own.
9
+ *
10
+ * Read-only in this pragmatic subset - a client checking off a task (`RopSetProperties`/`RopSaveChangesMessage`
11
+ * against a `"task:"` handle) is a documented gap, same as Contacts (see `ContactTarget.ts`'s own note); the
12
+ * REST API's own `PUT`/`PATCH` `/tasks/:id` remains the way to mutate a `Task` today.
13
+ */
14
+ export interface TaskTargetInfo {
15
+ title: string;
16
+ completed: boolean;
17
+ dueDate?: Date;
18
+ }
19
+ /** Degrades to empty-looking values for a `"task:<uid>"` target whose real `Task` has since vanished
20
+ * (soft-deleted or otherwise) - the same "don't fail the whole ROP over one stale row" principle
21
+ * `MessageTarget.resolveMessageInfo`/`ContactTarget.resolveContactInfo` already apply. */
22
+ export declare function resolveTaskInfo(target: string, taskRepo: RepoUtils<any>): Promise<TaskTargetInfo>;
23
+ /** The order a `TASKS` folder's contents table lists tasks in (see `ContentsTable.ts`). */
24
+ export declare const TASK_SORT: RepoSort;
@@ -0,0 +1,10 @@
1
+ import type { MailTransport, OutboundMessage, TransportResult } from "@rapidmx/restapi";
2
+ /**
3
+ * Sends `message` and throws unless the transport accepted it for at least one recipient and rejected none.
4
+ *
5
+ * The same rule as restapi's own `sendOrThrow()` (`transport/TransportResultUtils.ts`), which isn't exported from
6
+ * the `@rapidmx/restapi` package root, so it can't be imported here; keep the two in sync. Every bundled transport
7
+ * reports a failed relay through `TransportResult.rejected` rather than throwing, so a bare `send()` would treat a
8
+ * rejected message as sent.
9
+ */
10
+ export declare function sendOrThrow(transport: MailTransport, message: OutboundMessage): Promise<TransportResult>;
@@ -0,0 +1,20 @@
1
+ import { MailboxSQL } from "@rapidmx/restapi/sql";
2
+ import { BaseMapiEmsmdbRoute } from "../BaseMapiEmsmdbRoute.js";
3
+ /**
4
+ * SQL-backed concrete `BaseMapiEmsmdbRoute`, mounted at `/mapi/emsmdb`. Exported from this plugin's
5
+ * `./sql` entry point, so the server host mounts it without a wrapper class of its
6
+ * own.
7
+ *
8
+ * @author Jean-Philippe Steinmetz
9
+ */
10
+ export declare class MapiEmsmdbRouteSQL extends BaseMapiEmsmdbRoute<MailboxSQL> {
11
+ protected mailboxClass: any;
12
+ protected folderClass: any;
13
+ protected messageClass: any;
14
+ protected calendarEventClass: any;
15
+ protected contactClass: any;
16
+ protected taskClass: any;
17
+ protected labelClass: any;
18
+ protected auditLogClass: any;
19
+ protected ropHandlerClasses: any[];
20
+ }
@@ -0,0 +1,13 @@
1
+ import { MailboxSQL } from "@rapidmx/restapi/sql";
2
+ import { BaseMapiNspiRoute } from "../BaseMapiNspiRoute.js";
3
+ /**
4
+ * SQL-backed concrete `BaseMapiNspiRoute`, mounted at `/mapi/nspi`. Exported from this plugin's
5
+ * `./sql` entry point, so the server host mounts it without a wrapper class of its
6
+ * own.
7
+ *
8
+ * @author Jean-Philippe Steinmetz
9
+ */
10
+ export declare class MapiNspiRouteSQL extends BaseMapiNspiRoute<MailboxSQL> {
11
+ protected mailboxClass: any;
12
+ protected contactClass: any;
13
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./MapiEmsmdbRouteSQL.js";
2
+ export * from "./MapiNspiRouteSQL.js";
@@ -0,0 +1 @@
1
+ export * from "./sql/index.js";
package/package.json ADDED
@@ -0,0 +1,104 @@
1
+ {
2
+ "name": "@rapidmx/mapi-plugin",
3
+ "version": "1.0.0-beta.10",
4
+ "description": "A RapidMX plugin that provides MAPI over HTTP protocol support.",
5
+ "repository": "https://github.com/rapidmx/mapi-plugin.git",
6
+ "author": "RapidREST <rapidrests@gmail.com>",
7
+ "license": "MPL-2.0",
8
+ "contributors": [
9
+ "Jean-Philippe Steinmetz"
10
+ ],
11
+ "scripts": {
12
+ "build": "yarn lint && rimraf dist && tsc",
13
+ "lint": "eslint ./src ./test",
14
+ "local-audit": "yarn install && yarn npm audit -A -R \"$@\"",
15
+ "checkup": "yarn dlx @yarnpkg/doctor \"$@\"",
16
+ "dependency-check": "yarn dlx depcheck \"$@\"",
17
+ "report-coverage": "cat ./coverage/lcov.info | coveralls",
18
+ "test": "vitest run",
19
+ "test:prod": "npm run lint && vitest run --coverage",
20
+ "test:watch": "vitest",
21
+ "release": "npx @rapidrest/cli release",
22
+ "prepublish": "yarn build"
23
+ },
24
+ "peerDependencies": {
25
+ "@rapidmx/restapi": "0.x",
26
+ "@rapidrest/core": "5.x",
27
+ "@rapidrest/service-core": "2.x"
28
+ },
29
+ "dependencies": {
30
+ "mailparser": "^3.9.23",
31
+ "nodemailer": "^10.0.1"
32
+ },
33
+ "devDependencies": {
34
+ "@rapidmx/restapi": "^0.22.1",
35
+ "@rapidrest/core": "^6.0.0",
36
+ "@rapidrest/service-core": "^2.3.0",
37
+ "@swc/core": "^1.16.2",
38
+ "@types/mailparser": "^3.4.6",
39
+ "@types/nconf": "^0.10.7",
40
+ "@types/node": "^26.5.0",
41
+ "@types/nodemailer": "^8.0.1",
42
+ "@typescript-eslint/eslint-plugin": "^8.70.0",
43
+ "@typescript-eslint/parser": "^8.70.0",
44
+ "@vitest/coverage-v8": "^5.0.0",
45
+ "better-sqlite3": "^13.0.3",
46
+ "eslint": "^10.10.0",
47
+ "eslint-config-prettier": "^10.1.8",
48
+ "eslint-plugin-import": "^2.32.0",
49
+ "eslint-plugin-jsdoc": "^64.3.6",
50
+ "globals": "^17.12.0",
51
+ "lodash-es": "^4.18.1",
52
+ "mongodb": "^7.6.0",
53
+ "mongodb-memory-server": "^11.2.0",
54
+ "nconf": "^0.13.0",
55
+ "openapi3-ts": "^4.6.1",
56
+ "prom-client": "^15.1.3",
57
+ "redis": "^6.2.1",
58
+ "reflect-metadata": "^0.2.2",
59
+ "rimraf": "^6.1.3",
60
+ "ts-node": "^10.9.2",
61
+ "tsx": "^4.23.13",
62
+ "typeorm": "^1.1.1",
63
+ "typescript": "^6.0.3",
64
+ "unplugin-swc": "^1.6.0",
65
+ "vite": "^8.2.2",
66
+ "vitest": "^5.0.0",
67
+ "winston": "^3.19.0"
68
+ },
69
+ "packageManager": "yarn@4.5.3",
70
+ "engines": {
71
+ "node": ">=24.0.0"
72
+ },
73
+ "publishConfig": {
74
+ "registry": "https://registry.npmjs.org/"
75
+ },
76
+ "type": "module",
77
+ "main": "dist/lib/index.js",
78
+ "exports": {
79
+ ".": {
80
+ "import": "./dist/lib/index.js",
81
+ "types": "./dist/types/index.d.ts"
82
+ },
83
+ "./mongo": {
84
+ "import": "./dist/lib/mongo.js",
85
+ "types": "./dist/types/mongo.d.ts"
86
+ },
87
+ "./sql": {
88
+ "import": "./dist/lib/sql.js",
89
+ "types": "./dist/types/sql.d.ts"
90
+ }
91
+ },
92
+ "typings": "dist/types/index.d.ts",
93
+ "files": [
94
+ "dist"
95
+ ],
96
+ "rapidmx": {
97
+ "plugin": {
98
+ "apiVersion": 1,
99
+ "displayName": "MAPI over HTTP",
100
+ "description": "Lets Outlook for Windows connect with the MAPI/HTTP protocol (served at /mapi/emsmdb and /mapi/nspi).",
101
+ "settings": []
102
+ }
103
+ }
104
+ }