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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +4 -4
  2. package/dist/lib/BaseMapiEmsmdbRoute.js +229 -37
  3. package/dist/lib/BaseMapiEmsmdbRoute.js.map +1 -1
  4. package/dist/lib/MapiSessionManager.js +404 -48
  5. package/dist/lib/MapiSessionManager.js.map +1 -1
  6. package/dist/lib/RegexPatternUtils.js +30 -0
  7. package/dist/lib/RegexPatternUtils.js.map +1 -0
  8. package/dist/lib/RopDispatcher.js +130 -19
  9. package/dist/lib/RopDispatcher.js.map +1 -1
  10. package/dist/lib/codec/AppointmentRecurrence.js +22 -21
  11. package/dist/lib/codec/AppointmentRecurrence.js.map +1 -1
  12. package/dist/lib/codec/BufferCursor.js +41 -12
  13. package/dist/lib/codec/BufferCursor.js.map +1 -1
  14. package/dist/lib/codec/GlobalObjectId.js +26 -20
  15. package/dist/lib/codec/GlobalObjectId.js.map +1 -1
  16. package/dist/lib/codec/MapiTimeZone.js +43 -10
  17. package/dist/lib/codec/MapiTimeZone.js.map +1 -1
  18. package/dist/lib/codec/PropertyValue.js +28 -2
  19. package/dist/lib/codec/PropertyValue.js.map +1 -1
  20. package/dist/lib/codec/RopBuffer.js +15 -3
  21. package/dist/lib/codec/RopBuffer.js.map +1 -1
  22. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +2 -1
  23. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -1
  24. package/dist/lib/nspi/NspiCodec.js +5 -5
  25. package/dist/lib/nspi/NspiCodec.js.map +1 -1
  26. package/dist/lib/nspi/NspiGetMatchesHandler.js +14 -14
  27. package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -1
  28. package/dist/lib/rop/AddressList.js +109 -0
  29. package/dist/lib/rop/AddressList.js.map +1 -0
  30. package/dist/lib/rop/CalendarEventTarget.js +7 -4
  31. package/dist/lib/rop/CalendarEventTarget.js.map +1 -1
  32. package/dist/lib/rop/ContactTarget.js +2 -6
  33. package/dist/lib/rop/ContactTarget.js.map +1 -1
  34. package/dist/lib/rop/ContentsTable.js +60 -0
  35. package/dist/lib/rop/ContentsTable.js.map +1 -0
  36. package/dist/lib/rop/ExecuteBudget.js +82 -0
  37. package/dist/lib/rop/ExecuteBudget.js.map +1 -0
  38. package/dist/lib/rop/FastTransferStream.js +99 -2
  39. package/dist/lib/rop/FastTransferStream.js.map +1 -1
  40. package/dist/lib/rop/FolderTarget.js +13 -6
  41. package/dist/lib/rop/FolderTarget.js.map +1 -1
  42. package/dist/lib/rop/HandleDataCache.js +412 -0
  43. package/dist/lib/rop/HandleDataCache.js.map +1 -0
  44. package/dist/lib/rop/MeetingMessageClassHandler.js +194 -48
  45. package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -1
  46. package/dist/lib/rop/MessageBodyStream.js +33 -7
  47. package/dist/lib/rop/MessageBodyStream.js.map +1 -1
  48. package/dist/lib/rop/MessageTarget.js +17 -4
  49. package/dist/lib/rop/MessageTarget.js.map +1 -1
  50. package/dist/lib/rop/NamedPropertyRegistry.js +8 -5
  51. package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -1
  52. package/dist/lib/rop/PropertyResolvers.js +3 -1
  53. package/dist/lib/rop/PropertyResolvers.js.map +1 -1
  54. package/dist/lib/rop/RepoPaging.js +54 -0
  55. package/dist/lib/rop/RepoPaging.js.map +1 -0
  56. package/dist/lib/rop/RestapiRules.js +52 -0
  57. package/dist/lib/rop/RestapiRules.js.map +1 -0
  58. package/dist/lib/rop/RopCreateMessageHandler.js +4 -2
  59. package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -1
  60. package/dist/lib/rop/RopDeleteFolderHandler.js +118 -77
  61. package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -1
  62. package/dist/lib/rop/RopDeleteMessagesHandler.js +26 -1
  63. package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -1
  64. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +14 -14
  65. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -1
  66. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +13 -14
  67. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -1
  68. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +33 -32
  69. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -1
  70. package/dist/lib/rop/RopGetContentsTableHandler.js +17 -38
  71. package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -1
  72. package/dist/lib/rop/RopGetHierarchyTableHandler.js +4 -2
  73. package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -1
  74. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +6 -8
  75. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -1
  76. package/dist/lib/rop/RopHandler.js +5 -1
  77. package/dist/lib/rop/RopHandler.js.map +1 -1
  78. package/dist/lib/rop/RopLogonHandler.js +5 -2
  79. package/dist/lib/rop/RopLogonHandler.js.map +1 -1
  80. package/dist/lib/rop/RopOpenFolderHandler.js +3 -1
  81. package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -1
  82. package/dist/lib/rop/RopOpenMessageHandler.js +3 -1
  83. package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -1
  84. package/dist/lib/rop/RopOpenStreamHandler.js +11 -8
  85. package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -1
  86. package/dist/lib/rop/RopQueryRowsHandler.js +31 -5
  87. package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -1
  88. package/dist/lib/rop/RopReadStreamHandler.js +22 -4
  89. package/dist/lib/rop/RopReadStreamHandler.js.map +1 -1
  90. package/dist/lib/rop/RopReleaseHandler.js +4 -1
  91. package/dist/lib/rop/RopReleaseHandler.js.map +1 -1
  92. package/dist/lib/rop/RopSaveChangesMessageHandler.js +66 -7
  93. package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -1
  94. package/dist/lib/rop/RopSetColumnsHandler.js +6 -8
  95. package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -1
  96. package/dist/lib/rop/RopSetPropertiesHandler.js +23 -12
  97. package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -1
  98. package/dist/lib/rop/RopSubmitMessageHandler.js +148 -120
  99. package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -1
  100. package/dist/lib/rop/RopWriteStreamHandler.js +37 -10
  101. package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -1
  102. package/dist/lib/rop/TaskTarget.js +2 -6
  103. package/dist/lib/rop/TaskTarget.js.map +1 -1
  104. package/dist/lib/rop/TransportSend.js +16 -0
  105. package/dist/lib/rop/TransportSend.js.map +1 -0
  106. package/dist/lib/sql/MapiEmsmdbRouteSQL.js +2 -1
  107. package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -1
  108. package/dist/types/BaseMapiEmsmdbRoute.d.ts +59 -2
  109. package/dist/types/MapiSessionManager.d.ts +218 -63
  110. package/dist/types/RegexPatternUtils.d.ts +14 -0
  111. package/dist/types/RopDispatcher.d.ts +47 -11
  112. package/dist/types/codec/BufferCursor.d.ts +14 -0
  113. package/dist/types/codec/GlobalObjectId.d.ts +9 -5
  114. package/dist/types/codec/PropertyValue.d.ts +10 -0
  115. package/dist/types/codec/RopBuffer.d.ts +7 -0
  116. package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +1 -0
  117. package/dist/types/nspi/NspiGetMatchesHandler.d.ts +2 -0
  118. package/dist/types/rop/AddressList.d.ts +48 -0
  119. package/dist/types/rop/CalendarEventTarget.d.ts +7 -3
  120. package/dist/types/rop/ContactTarget.d.ts +3 -3
  121. package/dist/types/rop/ContentsTable.d.ts +16 -0
  122. package/dist/types/rop/ExecuteBudget.d.ts +48 -0
  123. package/dist/types/rop/FastTransferStream.d.ts +41 -2
  124. package/dist/types/rop/FolderTarget.d.ts +3 -2
  125. package/dist/types/rop/HandleDataCache.d.ts +145 -0
  126. package/dist/types/rop/MeetingMessageClassHandler.d.ts +23 -29
  127. package/dist/types/rop/MessageBodyStream.d.ts +16 -7
  128. package/dist/types/rop/MessageTarget.d.ts +10 -3
  129. package/dist/types/rop/NamedPropertyRegistry.d.ts +6 -2
  130. package/dist/types/rop/PropertyResolvers.d.ts +1 -1
  131. package/dist/types/rop/RepoPaging.d.ts +30 -0
  132. package/dist/types/rop/RestapiRules.d.ts +32 -0
  133. package/dist/types/rop/RopCreateMessageHandler.d.ts +1 -0
  134. package/dist/types/rop/RopDeleteFolderHandler.d.ts +36 -21
  135. package/dist/types/rop/RopDeleteMessagesHandler.d.ts +7 -0
  136. package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +1 -0
  137. package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +1 -0
  138. package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +10 -11
  139. package/dist/types/rop/RopGetContentsTableHandler.d.ts +7 -13
  140. package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +1 -0
  141. package/dist/types/rop/RopHandler.d.ts +40 -1
  142. package/dist/types/rop/RopOpenFolderHandler.d.ts +1 -0
  143. package/dist/types/rop/RopOpenMessageHandler.d.ts +1 -0
  144. package/dist/types/rop/RopOpenStreamHandler.d.ts +1 -0
  145. package/dist/types/rop/RopQueryRowsHandler.d.ts +3 -0
  146. package/dist/types/rop/RopReadStreamHandler.d.ts +3 -1
  147. package/dist/types/rop/RopReleaseHandler.d.ts +1 -0
  148. package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +16 -1
  149. package/dist/types/rop/RopSubmitMessageHandler.d.ts +33 -23
  150. package/dist/types/rop/RopWriteStreamHandler.d.ts +18 -8
  151. package/dist/types/rop/TaskTarget.d.ts +3 -3
  152. package/dist/types/rop/TransportSend.d.ts +10 -0
  153. package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +1 -0
  154. package/package.json +3 -3
@@ -4,14 +4,28 @@
4
4
  ///////////////////////////////////////////////////////////////////////////////
5
5
  import * as crypto from "crypto";
6
6
  import MailComposer from "nodemailer/lib/mail-composer/index.js";
7
+ import { ApiErrors } from "@rapidrest/service-core";
7
8
  import { findOrCreateWellKnownFolder, FolderType, MessageImportance, RecipientType, scanAndRelay, } from "@rapidmx/restapi";
9
+ import { MAX_RECIPIENTS_PER_MESSAGE, parseRecipientList, resolveRecipientList } from "./AddressList.js";
10
+ import { handleDataOwners, writeStreamKey } from "./HandleDataCache.js";
8
11
  import { submitMeetingResponse } from "./MeetingMessageClassHandler.js";
12
+ import { handleDataStoreOf } from "./RopHandler.js";
13
+ import { readWriteStream } from "./RopWriteStreamHandler.js";
14
+ import { asEntity, isInvitePending } from "./RestapiRules.js";
9
15
  const ROP_ID_SUBMIT_MESSAGE = 0x32;
10
16
  /** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for both "the referenced handle isn't a draft
11
17
  * message" and "the draft has no resolvable recipients/sender" - the same constant reused throughout this
12
18
  * pragmatic subset as a generic "can't do this" signal, not a claim of exact per-condition `[MS-OXCRPC]`
13
19
  * return-value-table parity. */
14
20
  const ERROR_INVALID_OBJECT = 0x80070005;
21
+ /** `MAPI_E_INVALID_PARAMETER`: the draft has no recipients, a recipient that isn't a usable address, or no sender. */
22
+ const ERROR_INVALID_PARAMETER = 0x80070057;
23
+ /** `MAPI_E_NOT_FOUND`: a recipient given only by display name matches no single contact of the caller's. */
24
+ const ERROR_NOT_FOUND = 0x8004010f;
25
+ /** `MAPI_E_TOO_BIG`: more than `MAX_RECIPIENTS_PER_MESSAGE` recipients. */
26
+ const ERROR_TOO_BIG = 0x80040305;
27
+ /** `MAPI_E_CALL_FAILED`: the body written through `RopWriteStream` can no longer be reassembled (its chunks expired). */
28
+ const ERROR_CALL_FAILED = 0x80004005;
15
29
  // The same well-known property IDs RopSetPropertiesHandler tracks - duplicated here (rather than imported)
16
30
  // since importing them would only save a handful of literals; see that file for the real documentation of what
17
31
  // each means.
@@ -31,18 +45,12 @@ const MESSAGE_CLASS_APPOINTMENT_PREFIX = "IPM.Appointment";
31
45
  * through `MeetingMessageClassHandler.submitMeetingResponse()` instead of every other path here - see that
32
46
  * function's own doc comment. */
33
47
  const MESSAGE_CLASS_MEETING_RESPONSE_PREFIX = "IPM.Schedule.Meeting.Resp.";
34
- /** Splits a `PidTagDisplayTo`/`Cc`/`Bcc`-style string on the semicolons real Outlook separates recipients
35
- * with (also tolerating commas, in case a client or test harness uses that convention instead), trimming and
36
- * dropping empty entries. Exported since `RopSaveChangesMessageHandler.ts` reads the same accumulated
37
- * `PidTagDisplayTo`/`Cc` draft properties to build a Calendar item's attendee list. */
38
- export function parseAddressList(value) {
39
- if (!value) {
40
- return [];
41
- }
42
- return value
43
- .split(/[;,]/)
44
- .map((s) => s.trim())
45
- .filter((s) => s.length > 0);
48
+ // Re-exported for existing importers; the implementation lives in AddressList.ts.
49
+ export { isPlainEmailAddress, parseAddressList } from "./AddressList.js";
50
+ function writeResult(writer, inputHandleIndex, returnValue) {
51
+ writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
52
+ writer.writeUInt8(inputHandleIndex);
53
+ writer.writeUInt32LE(returnValue);
46
54
  }
47
55
  /**
48
56
  * `RopSubmitMessage` (`[MS-OXOMSG]`/`[MS-OXCROPS]`): sends a composed message - the actual trigger point for
@@ -61,12 +69,12 @@ export function parseAddressList(value) {
61
69
  * pragmatic subset's ROP coverage doesn't include. Instead, addressing is read from `PidTagDisplayTo`/
62
70
  * `DisplayCc`/`DisplayBcc` - the same semicolon-separated "cached recipient display string" properties real
63
71
  * Outlook *also* always sets via `RopSetProperties` alongside `RopModifyRecipients` (as a display-only
64
- * convenience cache). This works correctly for the common case of composing to bare, unresolved email
65
- * addresses (nothing to resolve to a distinct display name) - the case this library's own integration tests
66
- * exercise - but is **not** a substitute for real recipient rows: a client that resolves typed names against an
67
- * address book before submitting would populate these fields with display names, not addresses, and this
68
- * pragmatic subset has no way to recover a real SMTP address from a bare display name. Documented here rather
69
- * than silently producing wrong addressing.
72
+ * convenience cache). Entries are separated by `;` and parsed with nodemailer's `addressparser`, so both bare
73
+ * addresses and resolved `Name <address>` forms work. A client that resolved a name against an address book may
74
+ * write the display name alone; that is looked up among the caller's own contacts (see `resolveRecipientList`), and
75
+ * a name matching no single contact fails the submit with `MAPI_E_NOT_FOUND`. It is still **not** a substitute for
76
+ * real recipient rows (there is no recipient table to fall back on), so the whole send is refused rather than sent to
77
+ * fewer people than the user addressed. A malformed recipient fails with `MAPI_E_INVALID_PARAMETER`.
70
78
  *
71
79
  * `SubmitFlags` (`PreprocessOnly`, ...) is decoded to advance past it correctly but not honored - this
72
80
  * pragmatic subset has no transport-agent preprocessing distinction to vary by flag.
@@ -79,6 +87,12 @@ export function parseAddressList(value) {
79
87
  * own `requestReceipt` field - honored only when the client explicitly sets it, not this mailbox's
80
88
  * `alwaysRequestReceiptInternal`/`External` defaults (those apply to the REST/webmail compose path only).
81
89
  *
90
+ * **Once per draft.** A mail or meeting-response draft is marked `submitted` as soon as a submit gets past the handle
91
+ * check, whatever the outcome, and a submitted draft can't be submitted again (`MAPI_E_INVALID_OBJECT`) or changed by
92
+ * `RopSetProperties`/`RopWriteStream`; its write-stream chunks are deleted once read. Each `Execute` runs at most
93
+ * `MAX_SUBMITS_PER_EXECUTE` submits, and a message may have at most `MAX_RECIPIENTS_PER_MESSAGE` recipients
94
+ * (`MAPI_E_TOO_BIG`), counted before any display name is looked up.
95
+ *
82
96
  * **Calendar branches**: a draft whose `PidTagMessageClass` starts with `"IPM.Appointment"` is routed to
83
97
  * `submitAppointment()` instead of the mail path below - see that method's own doc comment. One starting with
84
98
  * `"IPM.Schedule.Meeting.Resp."` (an attendee's own accept/decline/tentative response to a meeting this server
@@ -96,39 +110,53 @@ export class RopSubmitMessageHandler {
96
110
  const inputHandleIndex = reader.readUInt8();
97
111
  reader.readUInt8(); // SubmitFlags - see class doc comment
98
112
  const handle = context.session.handles[inputHandleIndex];
99
- if (!handle || handle.type !== "message") {
113
+ if (!handle || handle.type !== "message" || handle.submitted) {
100
114
  writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
101
115
  writer.writeUInt8(inputHandleIndex);
102
116
  writer.writeUInt32LE(ERROR_INVALID_OBJECT);
103
117
  return;
104
118
  }
119
+ context.budget?.chargeSubmit();
105
120
  const properties = handle.draftProperties ?? {};
106
121
  const messageClass = properties[String(PID_TAG_MESSAGE_CLASS)] ?? "IPM.Note";
107
122
  if (messageClass.startsWith(MESSAGE_CLASS_APPOINTMENT_PREFIX)) {
108
123
  await this.submitAppointment(handle, context, writer, inputHandleIndex);
109
124
  return;
110
125
  }
126
+ // From here on the draft is used up by this attempt, whatever its outcome, so it can't be sent again.
127
+ handle.submitted = true;
111
128
  if (messageClass.startsWith(MESSAGE_CLASS_MEETING_RESPONSE_PREFIX)) {
112
- await submitMeetingResponse(messageClass, properties, context);
113
- writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
114
- writer.writeUInt8(inputHandleIndex);
115
- writer.writeUInt32LE(0); // ReturnValue - success, see MeetingMessageClassHandler's own doc comment
116
- // on why every failure mode there is a silent no-op rather than surfaced here.
129
+ writeResult(writer, inputHandleIndex, await submitMeetingResponse(messageClass, properties, context));
117
130
  return;
118
131
  }
119
- const to = parseAddressList(properties[String(PID_TAG_DISPLAY_TO)]);
120
- const cc = parseAddressList(properties[String(PID_TAG_DISPLAY_CC)]);
121
- const bcc = parseAddressList(properties[String(PID_TAG_DISPLAY_BCC)]);
132
+ const recipientCount = [PID_TAG_DISPLAY_TO, PID_TAG_DISPLAY_CC, PID_TAG_DISPLAY_BCC].reduce((count, propertyId) => count + parseRecipientList(properties[String(propertyId)]).length, 0);
133
+ if (recipientCount > MAX_RECIPIENTS_PER_MESSAGE) {
134
+ writeResult(writer, inputHandleIndex, ERROR_TOO_BIG);
135
+ return;
136
+ }
137
+ const resolutions = [
138
+ await resolveRecipientList(properties[String(PID_TAG_DISPLAY_TO)], context),
139
+ await resolveRecipientList(properties[String(PID_TAG_DISPLAY_CC)], context),
140
+ await resolveRecipientList(properties[String(PID_TAG_DISPLAY_BCC)], context),
141
+ ];
142
+ const [to, cc, bcc] = resolutions.map((resolution) => resolution.recipients);
122
143
  const mailbox = await context.mailboxRepo.findOne(context.mailboxUid, { ignoreACL: true });
123
144
  const envelopeFrom = mailbox?.primarySmtpAddress;
124
- if (!envelopeFrom || to.length + cc.length + bcc.length === 0) {
125
- writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
126
- writer.writeUInt8(inputHandleIndex);
127
- writer.writeUInt32LE(ERROR_INVALID_OBJECT);
145
+ // Refuse the whole send over one malformed or unresolvable recipient rather than silently dropping it.
146
+ if (!envelopeFrom || to.length + cc.length + bcc.length === 0 || resolutions.some((resolution) => resolution.invalid.length > 0)) {
147
+ writeResult(writer, inputHandleIndex, ERROR_INVALID_PARAMETER);
148
+ return;
149
+ }
150
+ if (resolutions.some((resolution) => resolution.unresolved.length > 0)) {
151
+ writeResult(writer, inputHandleIndex, ERROR_NOT_FOUND);
128
152
  return;
129
153
  }
130
154
  const subject = properties[String(PID_TAG_SUBJECT)] ?? "";
131
- const bodyText = resolveDraftBody(context, inputHandleIndex, properties);
155
+ const bodyText = await resolveDraftBody(context, inputHandleIndex, properties);
156
+ if (bodyText === undefined) {
157
+ writeResult(writer, inputHandleIndex, ERROR_CALL_FAILED);
158
+ return;
159
+ }
132
160
  const requestReceipt = properties[String(PID_TAG_READ_RECEIPT_REQUESTED)] === "true";
133
161
  // "Do not deliver before" - a real Outlook compose option, tracked as a plain ISO-8601 string by
134
162
  // RopSetPropertiesHandler.stringifyValue()'s PtypTime encoding.
@@ -137,9 +165,9 @@ export class RopSubmitMessageHandler {
137
165
  const isDeferred = deferredSendTime !== undefined && deferredSendTime.getTime() > Date.now();
138
166
  const raw = await new MailComposer({
139
167
  from: envelopeFrom,
140
- to,
141
- cc,
142
- bcc,
168
+ to: to.map(mailAddress),
169
+ cc: cc.map(mailAddress),
170
+ bcc: bcc.map(mailAddress),
143
171
  subject,
144
172
  text: bodyText,
145
173
  // A real Disposition-Notification-To request, mirroring BaseMessageRoute.send()'s own explicit
@@ -151,12 +179,12 @@ export class RopSubmitMessageHandler {
151
179
  })
152
180
  .compile()
153
181
  .build();
154
- const envelopeTo = [...to, ...cc, ...bcc];
182
+ const envelopeTo = [...to, ...cc, ...bcc].map((recipient) => recipient.address);
155
183
  const bodyBlobKey = `bodies/${crypto.randomUUID()}`;
156
184
  const recipients = [
157
- ...to.map((address) => ({ address, type: RecipientType.TO })),
158
- ...cc.map((address) => ({ address, type: RecipientType.CC })),
159
- ...bcc.map((address) => ({ address, type: RecipientType.BCC })),
185
+ ...to.map((recipient) => storedRecipient(recipient, RecipientType.TO)),
186
+ ...cc.map((recipient) => storedRecipient(recipient, RecipientType.CC)),
187
+ ...bcc.map((recipient) => storedRecipient(recipient, RecipientType.BCC)),
160
188
  ];
161
189
  if (isDeferred) {
162
190
  // Mirrors BaseMessageRoute.send()'s own scheduledSendTime branch: park the message in Outbox,
@@ -182,25 +210,31 @@ export class RopSubmitMessageHandler {
182
210
  scheduledSendTime: deferredSendTime,
183
211
  requestReceipt,
184
212
  }), { ignoreACL: true });
213
+ // Adding a message to a folder always bumps its sync key too - see `refreshFolderCounts()`'s own doc comment.
214
+ await context.notifyFolderCounts?.([outbox.uid], { bumpSyncKey: true });
185
215
  writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
186
216
  writer.writeUInt8(inputHandleIndex);
187
217
  writer.writeUInt32LE(0); // ReturnValue - success
188
218
  return;
189
219
  }
190
- const { sanitizedHtmlBlobKey } = await scanAndRelay(raw, envelopeFrom, envelopeTo, context.scanPipeline, context.mailTransport, context.blobStore);
191
- await context.blobStore.put(bodyBlobKey, raw, { contentType: "message/rfc822" });
220
+ const relayed = await scanAndRelay(raw, envelopeFrom, envelopeTo, context.scanPipeline, context.mailTransport, context.blobStore);
221
+ // The Sent Items copy stores exactly what was relayed: scanAndRelay may have added a Message-ID header, and
222
+ // that header's value (plus the thread it derived) is what recipients' copies carry and what recall targets.
223
+ await context.blobStore.put(bodyBlobKey, relayed.raw, { contentType: "message/rfc822" });
192
224
  const sentFolder = await findOrCreateWellKnownFolder(context.folderRepo, context.folderClass, context.mailboxUid, FolderType.SENT_ITEMS);
193
225
  await context.messageRepo.create(new context.messageClass({
194
226
  folderUid: sentFolder.uid,
195
227
  mailboxUid: context.mailboxUid,
196
- messageId: `${crypto.randomUUID()}@mapi`,
228
+ messageId: relayed.messageId,
229
+ conversationId: relayed.conversationId,
230
+ encrypted: relayed.encrypted,
197
231
  subject,
198
232
  from: { address: envelopeFrom, type: RecipientType.TO },
199
233
  recipients,
200
234
  sentDate: new Date(),
201
235
  receivedDate: new Date(),
202
236
  bodyBlobKey,
203
- sanitizedHtmlBlobKey,
237
+ sanitizedHtmlBlobKey: relayed.sanitizedHtmlBlobKey,
204
238
  bodyPreview: bodyText.slice(0, 200),
205
239
  flags: { read: true, flagged: false, answered: false, forwarded: false },
206
240
  importance: MessageImportance.NORMAL,
@@ -208,105 +242,99 @@ export class RopSubmitMessageHandler {
208
242
  hasAttachments: false,
209
243
  requestReceipt,
210
244
  }), { ignoreACL: true });
245
+ // Adding a message to a folder always bumps its sync key too - see `refreshFolderCounts()`'s own doc comment.
246
+ await context.notifyFolderCounts?.([sentFolder.uid], { bumpSyncKey: true });
211
247
  writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
212
248
  writer.writeUInt8(inputHandleIndex);
213
249
  writer.writeUInt32LE(0); // ReturnValue - success
214
250
  }
215
251
  /**
216
- * Submits a Calendar item. The appointment itself is already persisted (`RopSaveChangesMessageHandler`
217
- * writes the real `CalendarEvent` row at Save time, unlike a mail draft, which stays purely in-session until
218
- * Submit) - this method's only job is notifying attendees, if any were set (via `PidTagDisplayTo`/`Cc`,
219
- * decoded into `CalendarEvent.attendees` at Save time). No attendees means no invite to send (e.g. a private,
220
- * non-meeting appointment) - a well-formed success response either way, since the appointment already exists.
252
+ * Submits a Calendar item. The appointment itself is already persisted (`RopSaveChangesMessageHandler` writes the
253
+ * real `CalendarEvent` row at Save time, unlike a mail draft, which stays purely in-session until Submit), so there
254
+ * is nothing left to store and nothing is sent from here.
221
255
  *
222
- * Unlike ordinary mail, there is no separate "Sent Items copy" to create - the appointment's durable copy
223
- * *is* the `CalendarEvent` row already sitting in the organizer's own Calendar folder.
256
+ * **Invites are restapi's `MeetingSchedulingJob`'s job.** That job sends an iTIP `REQUEST` for every
257
+ * organizer-owned event whose `inviteSequenceSent` differs from its `sequence`, claiming each revision with a
258
+ * versioned update before sending and building the invite with restapi's own `buildEventIcs` (so a recurring
259
+ * meeting's invite carries its `RRULE` and exceptions). Saving stamps `inviteSequenceSent = sequence`, so a meeting
260
+ * that is only saved ("Save & Close", or "save changes but don't send") invites no one. Submitting clears the stamp
261
+ * (`inviteSequenceSent: null`) with a versioned update, which makes the job send the current revision exactly once.
262
+ * - A revision that is already waiting for the job (submitted and not yet sent, or never stamped) is left alone, so
263
+ * submitting it again before the job runs doesn't cause a second invite.
264
+ * - The update is versioned (`asEntity`). The job only ever claims a waiting revision, so a conflict here comes from
265
+ * some other edit (an attendee's reply updating the row, a REST edit); the row is read again and the check repeated,
266
+ * up to `MAX_INVITE_REQUEST_ATTEMPTS` times, after which the ROP fails (`MAPI_E_CALL_FAILED`).
267
+ * - Submitting a revision the job has already sent sends it again: the client asked to send.
224
268
  *
225
- * The invite itself is a minimal iCalendar (`RFC 5545`) `VEVENT` with `METHOD:REQUEST` (`RFC 5546`),
226
- * attached via `nodemailer`'s own `MailComposer` `icalEvent` option (which produces both a `text/calendar;
227
- * method=REQUEST` MIME alternative and an `.ics` attachment - the standard dual form real invite emails use)
228
- * - reusing the identical `scanAndRelay()` pipeline the mail path above already calls.
269
+ * Only the organizer's own copy may be submitted (an attendee's copy of someone else's meeting answers
270
+ * `MAPI_E_INVALID_OBJECT`, as before, and nothing is changed).
229
271
  */
230
272
  async submitAppointment(handle, context, writer, inputHandleIndex) {
231
273
  const uid = handle.entityUid.startsWith("calendarEvent:") ? handle.entityUid.slice("calendarEvent:".length) : undefined;
232
274
  const event = uid ? await context.calendarEventRepo.findOne(uid, { ignoreACL: true }) : undefined;
233
- if (!event) {
234
- writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
235
- writer.writeUInt8(inputHandleIndex);
236
- writer.writeUInt32LE(ERROR_INVALID_OBJECT);
275
+ const mailbox = event?.mailboxUid === context.mailboxUid ? await context.mailboxRepo.findOne(context.mailboxUid, { ignoreACL: true }) : undefined;
276
+ const callerAddresses = mailbox ? [mailbox.primarySmtpAddress, ...(mailbox.aliasAddresses ?? [])].map((a) => a.toLowerCase()) : [];
277
+ const isOrganizer = !!event && callerAddresses.includes((event.organizer?.address ?? "").toLowerCase());
278
+ if (!isOrganizer) {
279
+ writeResult(writer, inputHandleIndex, ERROR_INVALID_OBJECT);
237
280
  return;
238
281
  }
239
- if (event.attendees.length > 0) {
240
- const mailbox = await context.mailboxRepo.findOne(context.mailboxUid, { ignoreACL: true });
241
- const envelopeFrom = mailbox?.primarySmtpAddress;
242
- if (envelopeFrom) {
243
- const attendeeAddresses = event.attendees.map((attendee) => attendee.address);
244
- const ics = buildMeetingRequestIcs(event, envelopeFrom);
245
- const raw = await new MailComposer({
246
- from: envelopeFrom,
247
- to: attendeeAddresses,
248
- subject: event.title,
249
- text: `You have been invited to: ${event.title}`,
250
- icalEvent: { method: "REQUEST", content: ics },
251
- })
252
- .compile()
253
- .build();
254
- await scanAndRelay(raw, envelopeFrom, attendeeAddresses, context.scanPipeline, context.mailTransport, context.blobStore);
282
+ writeResult(writer, inputHandleIndex, (await requestInvites(context, uid, event)) ? 0 : ERROR_NOT_FOUND);
283
+ }
284
+ }
285
+ /** How many times `requestInvites` re-reads a row whose versioned update lost to another edit before giving up. */
286
+ export const MAX_INVITE_REQUEST_ATTEMPTS = 3;
287
+ /** Makes restapi's `MeetingSchedulingJob` send invites for the organizer copy `event`'s current revision (see
288
+ * `submitAppointment`). `false` when the row disappeared meanwhile. */
289
+ async function requestInvites(context, uid, event) {
290
+ let row = event;
291
+ for (let attempt = 0; attempt < MAX_INVITE_REQUEST_ATTEMPTS; attempt++) {
292
+ if (!row) {
293
+ return false;
294
+ }
295
+ if (isInvitePending(row)) {
296
+ return true;
297
+ }
298
+ try {
299
+ await context.calendarEventRepo.update({ uid: row.uid, version: row.version, inviteSequenceSent: null }, asEntity(context.calendarEventRepo, row), { ignoreACL: true });
300
+ return true;
301
+ }
302
+ catch (err) {
303
+ if (err?.code !== ApiErrors.INVALID_OBJECT_VERSION) {
304
+ throw err;
255
305
  }
306
+ row = await context.calendarEventRepo.findOne(uid, { ignoreACL: true });
256
307
  }
257
- writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
258
- writer.writeUInt8(inputHandleIndex);
259
- writer.writeUInt32LE(0); // ReturnValue - success
260
308
  }
309
+ throw new Error("RopSubmitMessage: the meeting kept changing while its invites were requested.");
261
310
  }
262
- /** `YYYYMMDDTHHMMSSZ` - the `RFC 5545` "form 2" (UTC) `DATE-TIME` format every field below uses. */
263
- function formatIcsDateUtc(date) {
264
- return date.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z";
311
+ /** A recipient as nodemailer's `MailComposer` takes it: a display name only when there is one. */
312
+ function mailAddress(recipient) {
313
+ return recipient.name ? { name: recipient.name, address: recipient.address } : recipient.address;
265
314
  }
266
- /** Escapes the `RFC 5545` §3.3.11 `TEXT` value special characters (backslash, semicolon, comma, newline) - the
267
- * only value types this minimal builder ever emits unescaped text into (`SUMMARY`/`LOCATION`). */
268
- function escapeIcsText(value) {
269
- return value.replace(/\\/g, "\\\\").replace(/;/g, "\\;").replace(/,/g, "\\,").replace(/\r?\n/g, "\\n");
270
- }
271
- /**
272
- * Builds a minimal `RFC 5545`/`RFC 5546` `METHOD:REQUEST` iCalendar document for `event`. Deliberately not a
273
- * general-purpose iCalendar writer (see `AutodiscoverXml.ts`'s own doc comment for the same "hand-build just
274
- * the fields this pass needs" precedent) - no `RRULE` (recurring meeting invites are a documented gap, same as
275
- * this pragmatic subset's other recurrence-adjacent limitations), no line-folding at the 75-octet boundary
276
- * `RFC 5545` §3.1 technically requires (every field emitted here is short enough in practice that folding would
277
- * never trigger), no `VTIMEZONE` block (times are always emitted as UTC `Z`-suffixed values instead).
278
- */
279
- function buildMeetingRequestIcs(event, organizerAddress) {
280
- const lines = [
281
- "BEGIN:VCALENDAR",
282
- "PRODID:-//RapidREST//Mail//EN",
283
- "VERSION:2.0",
284
- "METHOD:REQUEST",
285
- "BEGIN:VEVENT",
286
- `UID:${event.icalUid}`,
287
- `SEQUENCE:${event.sequence}`,
288
- `DTSTAMP:${formatIcsDateUtc(new Date())}`,
289
- `DTSTART:${formatIcsDateUtc(event.startDate)}`,
290
- `DTEND:${formatIcsDateUtc(event.endDate)}`,
291
- `SUMMARY:${escapeIcsText(event.title)}`,
292
- ...(event.location ? [`LOCATION:${escapeIcsText(event.location)}`] : []),
293
- `ORGANIZER:mailto:${organizerAddress}`,
294
- ...event.attendees.map((attendee) => `ATTENDEE;RSVP=TRUE:mailto:${attendee.address}`),
295
- "STATUS:CONFIRMED",
296
- "END:VEVENT",
297
- "END:VCALENDAR",
298
- ];
299
- return lines.join("\r\n");
315
+ /** A recipient as the Sent Items copy stores it. */
316
+ function storedRecipient(recipient, type) {
317
+ return { address: recipient.address, ...(recipient.name ? { displayName: recipient.name } : {}), type };
300
318
  }
301
319
  /** Prefers a `RopWriteStream`-accumulated body (the real path a large body takes) over an inline `PidTagBody`
302
320
  * set directly via `RopSetProperties` (only realistic for a short body small enough to set inline) - see
303
321
  * `RopOpenStreamHandler`'s write-mode branch for how `writeTargetHandleIndex` links a stream handle back to the
304
- * draft message handle it was opened against. */
305
- function resolveDraftBody(context, messageHandleIndex, properties) {
306
- for (const candidate of Object.values(context.session.handles)) {
307
- if (candidate.type === "stream" && candidate.writeTargetHandleIndex === messageHandleIndex && candidate.writeBufferBase64) {
308
- const raw = Buffer.from(candidate.writeBufferBase64, "base64");
309
- return raw.toString("utf16le").replace(/\0+$/, "");
322
+ * draft message handle it was opened against. The generation must match too, so a stream left over from an
323
+ * earlier message at the same handle index never supplies this message's body. `undefined` when the stream's
324
+ * chunks can no longer be reassembled - sending a truncated body would be worse than failing. */
325
+ async function resolveDraftBody(context, messageHandleIndex, properties) {
326
+ const generation = context.session.handles[messageHandleIndex].generation;
327
+ for (const [index, candidate] of Object.entries(context.session.handles)) {
328
+ if (candidate.type === "stream" &&
329
+ candidate.writeTargetHandleIndex === messageHandleIndex &&
330
+ candidate.writeTargetGeneration === generation &&
331
+ candidate.writeSize) {
332
+ const raw = await readWriteStream(context, Number(index), candidate);
333
+ // The chunks are only needed for this one submit; best effort, they expire anyway.
334
+ await handleDataStoreOf(context)
335
+ .delete(writeStreamKey(context.session.uid, Number(index), candidate.generation), handleDataOwners(context.session.uid, context.session.userUid))
336
+ .catch(() => undefined);
337
+ return raw?.toString("utf16le").replace(/\0+$/, "");
310
338
  }
311
339
  }
312
340
  return properties[String(PID_TAG_BODY)] ?? "";
@@ -1 +1 @@
1
- {"version":3,"file":"RopSubmitMessageHandler.js","sourceRoot":"","sources":["../../../src/rop/RopSubmitMessageHandler.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"RopSubmitMessageHandler.js","sourceRoot":"","sources":["../../../src/rop/RopSubmitMessageHandler.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,26 @@
1
+ import { handleDataOwners, writeStreamKey } from "./HandleDataCache.js";
2
+ import { handleDataStoreOf } from "./RopHandler.js";
1
3
  const ROP_ID_WRITE_STREAM = 0x2d;
2
4
  /** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a write-mode
3
5
  * stream (or doesn't exist)" - the same constant `RopReadStreamHandler` uses for its own analogous check. */
4
6
  const ERROR_INVALID_OBJECT = 0x80070005;
7
+ /** `MAPI_E_TOO_BIG`, for a write that would take the stream past `MAX_WRITE_STREAM_BYTES`. */
8
+ const ERROR_TOO_BIG = 0x80040305;
9
+ /** The largest body a write stream accumulates. */
10
+ export const MAX_WRITE_STREAM_BYTES = 4 * 1024 * 1024;
11
+ /** How long a write stream's chunks are kept after its last write - the session's own idle lifetime. */
12
+ export const WRITE_STREAM_TTL_SECONDS = 15 * 60;
13
+ // Re-exported for existing importers; the key lives next to the other handle data keys.
14
+ export { writeStreamKey } from "./HandleDataCache.js";
5
15
  /**
6
16
  * `RopWriteStream` (`[MS-OXCPRPT]`/`[MS-OXCROPS]`): writes bytes to a stream opened in `ReadWrite`/`Create`
7
17
  * mode (`RopOpenStreamHandler`'s write-mode branch - the only kind of writable stream this pragmatic subset
8
- * ever produces, always a `RopCreateMessage` draft's `PidTagBody`). Accumulates `Data` into the stream handle's
9
- * `writeBufferBase64` field, decode-concat-reencode each call rather than a naive string concatenation of
10
- * per-call base64 chunks - base64 is not concatenation-safe (a chunk's padding only belongs at the true end of
11
- * the data), so reassembling the real bytes requires decoding what's accumulated so far, appending the new raw
12
- * bytes, and re-encoding the whole thing. `RopSaveChangesMessageHandler`/`RopSubmitMessageHandler` decode this
13
- * buffer back to the final body text once composing is complete.
18
+ * ever produces, always a `RopCreateMessage` draft's `PidTagBody`). Each write is stored as a chunk keyed by its
19
+ * offset in the `HandleDataStore` (Redis when configured), not in the session: only `writeSize` is session state.
20
+ * Keying by offset makes a retried write (after a request whose session save lost a conflict) replace its chunk
21
+ * instead of appending it twice. Up to `MAX_WRITE_STREAM_BYTES`; a write past that fails with `MAPI_E_TOO_BIG` and
22
+ * nothing is stored, as it is when the session's or user's handle data quota (`handleDataOwners`) is used up. A stream
23
+ * whose draft has already been submitted takes no more writes. `RopSubmitMessageHandler` reassembles the body (`readWriteStream`) once composing is complete.
14
24
  *
15
25
  * Like `RopReadStream`, `[MS-OXCROPS]` documents only one combined response-buffer shape for this ROP (no
16
26
  * separate Success/Failure pages) - `WrittenSize` is always present, `0` standing in for the failure case.
@@ -20,26 +30,43 @@ const ERROR_INVALID_OBJECT = 0x80070005;
20
30
  export class RopWriteStreamHandler {
21
31
  constructor() {
22
32
  this.ropId = ROP_ID_WRITE_STREAM;
33
+ this.failureTailBytes = 2; // DataSize/WrittenSize
23
34
  }
24
- handle(reader, writer, context) {
35
+ async handle(reader, writer, context) {
25
36
  reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
26
37
  const inputHandleIndex = reader.readUInt8();
27
38
  const dataSize = reader.readUInt16LE();
28
39
  const data = reader.readBytes(dataSize);
29
40
  const handle = context.session.handles[inputHandleIndex];
30
- if (!handle || handle.type !== "stream" || handle.writeTargetHandleIndex === undefined) {
41
+ const target = handle?.writeTargetHandleIndex !== undefined ? context.session.handles[handle.writeTargetHandleIndex] : undefined;
42
+ if (!handle || handle.type !== "stream" || handle.writeTargetHandleIndex === undefined || target?.submitted) {
31
43
  writer.writeUInt8(ROP_ID_WRITE_STREAM);
32
44
  writer.writeUInt8(inputHandleIndex);
33
45
  writer.writeUInt32LE(ERROR_INVALID_OBJECT);
34
46
  writer.writeUInt16LE(0); // WrittenSize - see class doc comment on why this is still written on failure
35
47
  return;
36
48
  }
37
- const existing = handle.writeBufferBase64 ? Buffer.from(handle.writeBufferBase64, "base64") : Buffer.alloc(0);
38
- handle.writeBufferBase64 = Buffer.concat([existing, data]).toString("base64");
49
+ const existingSize = handle.writeSize ?? 0;
50
+ const stored = existingSize + data.length <= MAX_WRITE_STREAM_BYTES &&
51
+ (data.length === 0 ||
52
+ (await handleDataStoreOf(context).putChunk(writeStreamKey(context.session.uid, inputHandleIndex, handle.generation), existingSize, data, WRITE_STREAM_TTL_SECONDS, handleDataOwners(context.session.uid, context.session.userUid))));
53
+ if (!stored) {
54
+ writer.writeUInt8(ROP_ID_WRITE_STREAM);
55
+ writer.writeUInt8(inputHandleIndex);
56
+ writer.writeUInt32LE(ERROR_TOO_BIG);
57
+ writer.writeUInt16LE(0); // WrittenSize
58
+ return;
59
+ }
60
+ handle.writeSize = existingSize + data.length;
39
61
  writer.writeUInt8(ROP_ID_WRITE_STREAM);
40
62
  writer.writeUInt8(inputHandleIndex);
41
63
  writer.writeUInt32LE(0); // ReturnValue - success
42
64
  writer.writeUInt16LE(data.length); // WrittenSize
43
65
  }
44
66
  }
67
+ /** The bytes written so far to the write stream `stream` at `handleIndex`, or `undefined` when they can no longer be
68
+ * reassembled (a chunk expired or was evicted). */
69
+ export async function readWriteStream(context, handleIndex, stream) {
70
+ return handleDataStoreOf(context).readChunks(writeStreamKey(context.session.uid, handleIndex, stream.generation), stream.writeSize ?? 0);
71
+ }
45
72
  //# sourceMappingURL=RopWriteStreamHandler.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RopWriteStreamHandler.js","sourceRoot":"","sources":["../../../src/rop/RopWriteStreamHandler.ts"],"names":[],"mappings":"AAOA,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;6GAC6G;AAC7G,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,qBAAqB;IAAlC;QACoB,UAAK,GAAG,mBAAmB,CAAC;IAyBhD,CAAC;IAvBU,MAAM,CAAC,MAAoB,EAAE,MAAoB,EAAE,OAAmB;QACzE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,uFAAuF;QAC3G,MAAM,gBAAgB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACpD,MAAM,QAAQ,GAAW,MAAM,CAAC,YAAY,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAW,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,sBAAsB,KAAK,SAAS,EAAE,CAAC;YACrF,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;YACvC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACpC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,8EAA8E;YACvG,OAAO;QACX,CAAC;QAED,MAAM,QAAQ,GAAW,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACtH,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE9E,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QACvC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc;IACrD,CAAC;CACJ"}
1
+ {"version":3,"file":"RopWriteStreamHandler.js","sourceRoot":"","sources":["../../../src/rop/RopWriteStreamHandler.ts"],"names":[],"mappings":"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"}
@@ -10,10 +10,6 @@ export async function resolveTaskInfo(target, taskRepo) {
10
10
  dueDate: task?.dueDate,
11
11
  };
12
12
  }
13
- /** Resolves the tasks directly in `folderUid`, as `"task:<uid>"` target strings, for `RopGetContentsTable`
14
- * against a `TASKS`-type folder. */
15
- export async function resolveFolderTasks(folderUid, taskRepo) {
16
- const tasks = await taskRepo.find({ folderUid }, { ignoreACL: true });
17
- return tasks.map((t) => `task:${t.uid}`);
18
- }
13
+ /** The order a `TASKS` folder's contents table lists tasks in (see `ContentsTable.ts`). */
14
+ export const TASK_SORT = { title: "ASC", uid: "ASC" };
19
15
  //# sourceMappingURL=TaskTarget.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"TaskTarget.js","sourceRoot":"","sources":["../../../src/rop/TaskTarget.ts"],"names":[],"mappings":"AAwBA;;0FAE0F;AAC1F,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc,EAAE,QAAwB;IAC1E,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,IAAI,GAAqB,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,OAAO;QACH,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;QACxB,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,KAAK;QACnC,OAAO,EAAE,IAAI,EAAE,OAAO;KACzB,CAAC;AACN,CAAC;AAED;oCACoC;AACpC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAiB,EAAE,QAAwB;IAChF,MAAM,KAAK,GAAW,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9E,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AAC7C,CAAC"}
1
+ {"version":3,"file":"TaskTarget.js","sourceRoot":"","sources":["../../../src/rop/TaskTarget.ts"],"names":[],"mappings":"AAyBA;;0FAE0F;AAC1F,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc,EAAE,QAAwB;IAC1E,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,IAAI,GAAqB,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,OAAO;QACH,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;QACxB,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,KAAK;QACnC,OAAO,EAAE,IAAI,EAAE,OAAO;KACzB,CAAC;AACN,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,MAAM,SAAS,GAAa,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Sends `message` and throws unless the transport accepted it for at least one recipient and rejected none.
3
+ *
4
+ * The same rule as restapi's own `sendOrThrow()` (`transport/TransportResultUtils.ts`), which isn't exported from
5
+ * the `@rapidmx/restapi` package root, so it can't be imported here; keep the two in sync. Every bundled transport
6
+ * reports a failed relay through `TransportResult.rejected` rather than throwing, so a bare `send()` would treat a
7
+ * rejected message as sent.
8
+ */
9
+ export async function sendOrThrow(transport, message) {
10
+ const result = await transport.send(message);
11
+ if (!result || (result.accepted ?? []).length === 0 || (result.rejected ?? []).length > 0) {
12
+ throw new Error(`The mail transport did not accept the message (rejected: ${(result?.rejected ?? []).length}).`);
13
+ }
14
+ return result;
15
+ }
16
+ //# sourceMappingURL=TransportSend.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TransportSend.js","sourceRoot":"","sources":["../../../src/rop/TransportSend.ts"],"names":[],"mappings":"AAMA;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,SAAwB,EAAE,OAAwB;IAChF,MAAM,MAAM,GAAgC,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1E,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxF,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC;IACrH,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC"}