@mcp-z/mcp-outlook 1.0.0

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 (300) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/bin/server.js +5 -0
  4. package/dist/cjs/constants.d.cts +10 -0
  5. package/dist/cjs/constants.d.ts +10 -0
  6. package/dist/cjs/constants.js +35 -0
  7. package/dist/cjs/constants.js.map +1 -0
  8. package/dist/cjs/email/composition/outlook-message-builder.d.cts +36 -0
  9. package/dist/cjs/email/composition/outlook-message-builder.d.ts +36 -0
  10. package/dist/cjs/email/composition/outlook-message-builder.js +56 -0
  11. package/dist/cjs/email/composition/outlook-message-builder.js.map +1 -0
  12. package/dist/cjs/email/messages/messages.d.cts +7 -0
  13. package/dist/cjs/email/messages/messages.d.ts +7 -0
  14. package/dist/cjs/email/messages/messages.js +61 -0
  15. package/dist/cjs/email/messages/messages.js.map +1 -0
  16. package/dist/cjs/email/parsing/header-parsing.d.cts +18 -0
  17. package/dist/cjs/email/parsing/header-parsing.d.ts +18 -0
  18. package/dist/cjs/email/parsing/header-parsing.js +42 -0
  19. package/dist/cjs/email/parsing/header-parsing.js.map +1 -0
  20. package/dist/cjs/email/parsing/message-extraction.d.cts +4 -0
  21. package/dist/cjs/email/parsing/message-extraction.d.ts +4 -0
  22. package/dist/cjs/email/parsing/message-extraction.js +192 -0
  23. package/dist/cjs/email/parsing/message-extraction.js.map +1 -0
  24. package/dist/cjs/email/parsing/message-mapping.d.cts +21 -0
  25. package/dist/cjs/email/parsing/message-mapping.d.ts +21 -0
  26. package/dist/cjs/email/parsing/message-mapping.js +47 -0
  27. package/dist/cjs/email/parsing/message-mapping.js.map +1 -0
  28. package/dist/cjs/email/querying/execute-query.d.cts +20 -0
  29. package/dist/cjs/email/querying/execute-query.d.ts +20 -0
  30. package/dist/cjs/email/querying/execute-query.js +268 -0
  31. package/dist/cjs/email/querying/execute-query.js.map +1 -0
  32. package/dist/cjs/email/querying/query-builder.d.cts +32 -0
  33. package/dist/cjs/email/querying/query-builder.d.ts +32 -0
  34. package/dist/cjs/email/querying/query-builder.js +528 -0
  35. package/dist/cjs/email/querying/query-builder.js.map +1 -0
  36. package/dist/cjs/email/querying/search-execution.d.cts +24 -0
  37. package/dist/cjs/email/querying/search-execution.d.ts +24 -0
  38. package/dist/cjs/email/querying/search-execution.js +261 -0
  39. package/dist/cjs/email/querying/search-execution.js.map +1 -0
  40. package/dist/cjs/index.d.cts +8 -0
  41. package/dist/cjs/index.d.ts +8 -0
  42. package/dist/cjs/index.js +314 -0
  43. package/dist/cjs/index.js.map +1 -0
  44. package/dist/cjs/lib/create-store.d.cts +2 -0
  45. package/dist/cjs/lib/create-store.d.ts +2 -0
  46. package/dist/cjs/lib/create-store.js +166 -0
  47. package/dist/cjs/lib/create-store.js.map +1 -0
  48. package/dist/cjs/lib/messages-to-row.d.cts +39 -0
  49. package/dist/cjs/lib/messages-to-row.d.ts +39 -0
  50. package/dist/cjs/lib/messages-to-row.js +177 -0
  51. package/dist/cjs/lib/messages-to-row.js.map +1 -0
  52. package/dist/cjs/lib/outlook/index.d.cts +7 -0
  53. package/dist/cjs/lib/outlook/index.d.ts +7 -0
  54. package/dist/cjs/lib/outlook/index.js +56 -0
  55. package/dist/cjs/lib/outlook/index.js.map +1 -0
  56. package/dist/cjs/lib/outlook/types.d.cts +22 -0
  57. package/dist/cjs/lib/outlook/types.d.ts +22 -0
  58. package/dist/cjs/lib/outlook/types.js +6 -0
  59. package/dist/cjs/lib/outlook/types.js.map +1 -0
  60. package/dist/cjs/mcp/index.d.cts +3 -0
  61. package/dist/cjs/mcp/index.d.ts +3 -0
  62. package/dist/cjs/mcp/index.js +66 -0
  63. package/dist/cjs/mcp/index.js.map +1 -0
  64. package/dist/cjs/mcp/prompts/draft-email.d.cts +30 -0
  65. package/dist/cjs/mcp/prompts/draft-email.d.ts +30 -0
  66. package/dist/cjs/mcp/prompts/draft-email.js +184 -0
  67. package/dist/cjs/mcp/prompts/draft-email.js.map +1 -0
  68. package/dist/cjs/mcp/prompts/index.d.cts +2 -0
  69. package/dist/cjs/mcp/prompts/index.d.ts +2 -0
  70. package/dist/cjs/mcp/prompts/index.js +26 -0
  71. package/dist/cjs/mcp/prompts/index.js.map +1 -0
  72. package/dist/cjs/mcp/prompts/query-syntax.d.cts +19 -0
  73. package/dist/cjs/mcp/prompts/query-syntax.d.ts +19 -0
  74. package/dist/cjs/mcp/prompts/query-syntax.js +169 -0
  75. package/dist/cjs/mcp/prompts/query-syntax.js.map +1 -0
  76. package/dist/cjs/mcp/resources/email.d.cts +11 -0
  77. package/dist/cjs/mcp/resources/email.d.ts +11 -0
  78. package/dist/cjs/mcp/resources/email.js +233 -0
  79. package/dist/cjs/mcp/resources/email.js.map +1 -0
  80. package/dist/cjs/mcp/resources/index.d.cts +1 -0
  81. package/dist/cjs/mcp/resources/index.d.ts +1 -0
  82. package/dist/cjs/mcp/resources/index.js +17 -0
  83. package/dist/cjs/mcp/resources/index.js.map +1 -0
  84. package/dist/cjs/mcp/tools/categories-list.d.cts +96 -0
  85. package/dist/cjs/mcp/tools/categories-list.d.ts +96 -0
  86. package/dist/cjs/mcp/tools/categories-list.js +252 -0
  87. package/dist/cjs/mcp/tools/categories-list.js.map +1 -0
  88. package/dist/cjs/mcp/tools/index.d.cts +11 -0
  89. package/dist/cjs/mcp/tools/index.d.ts +11 -0
  90. package/dist/cjs/mcp/tools/index.js +62 -0
  91. package/dist/cjs/mcp/tools/index.js.map +1 -0
  92. package/dist/cjs/mcp/tools/label-add.d.cts +44 -0
  93. package/dist/cjs/mcp/tools/label-add.d.ts +44 -0
  94. package/dist/cjs/mcp/tools/label-add.js +249 -0
  95. package/dist/cjs/mcp/tools/label-add.js.map +1 -0
  96. package/dist/cjs/mcp/tools/label-delete.d.cts +54 -0
  97. package/dist/cjs/mcp/tools/label-delete.d.ts +54 -0
  98. package/dist/cjs/mcp/tools/label-delete.js +497 -0
  99. package/dist/cjs/mcp/tools/label-delete.js.map +1 -0
  100. package/dist/cjs/mcp/tools/labels-list.d.cts +96 -0
  101. package/dist/cjs/mcp/tools/labels-list.d.ts +96 -0
  102. package/dist/cjs/mcp/tools/labels-list.js +252 -0
  103. package/dist/cjs/mcp/tools/labels-list.js.map +1 -0
  104. package/dist/cjs/mcp/tools/message-get.d.cts +110 -0
  105. package/dist/cjs/mcp/tools/message-get.d.ts +110 -0
  106. package/dist/cjs/mcp/tools/message-get.js +289 -0
  107. package/dist/cjs/mcp/tools/message-get.js.map +1 -0
  108. package/dist/cjs/mcp/tools/message-mark-read.d.cts +42 -0
  109. package/dist/cjs/mcp/tools/message-mark-read.d.ts +42 -0
  110. package/dist/cjs/mcp/tools/message-mark-read.js +254 -0
  111. package/dist/cjs/mcp/tools/message-mark-read.js.map +1 -0
  112. package/dist/cjs/mcp/tools/message-move-to-trash.d.cts +54 -0
  113. package/dist/cjs/mcp/tools/message-move-to-trash.d.ts +54 -0
  114. package/dist/cjs/mcp/tools/message-move-to-trash.js +460 -0
  115. package/dist/cjs/mcp/tools/message-move-to-trash.js.map +1 -0
  116. package/dist/cjs/mcp/tools/message-respond.d.cts +52 -0
  117. package/dist/cjs/mcp/tools/message-respond.d.ts +52 -0
  118. package/dist/cjs/mcp/tools/message-respond.js +263 -0
  119. package/dist/cjs/mcp/tools/message-respond.js.map +1 -0
  120. package/dist/cjs/mcp/tools/message-search.d.cts +138 -0
  121. package/dist/cjs/mcp/tools/message-search.d.ts +138 -0
  122. package/dist/cjs/mcp/tools/message-search.js +408 -0
  123. package/dist/cjs/mcp/tools/message-search.js.map +1 -0
  124. package/dist/cjs/mcp/tools/message-send.d.cts +66 -0
  125. package/dist/cjs/mcp/tools/message-send.d.ts +66 -0
  126. package/dist/cjs/mcp/tools/message-send.js +298 -0
  127. package/dist/cjs/mcp/tools/message-send.js.map +1 -0
  128. package/dist/cjs/mcp/tools/messages-export-csv.d.cts +72 -0
  129. package/dist/cjs/mcp/tools/messages-export-csv.d.ts +72 -0
  130. package/dist/cjs/mcp/tools/messages-export-csv.js +540 -0
  131. package/dist/cjs/mcp/tools/messages-export-csv.js.map +1 -0
  132. package/dist/cjs/package.json +1 -0
  133. package/dist/cjs/schemas/index.d.cts +2 -0
  134. package/dist/cjs/schemas/index.d.ts +2 -0
  135. package/dist/cjs/schemas/index.js +20 -0
  136. package/dist/cjs/schemas/index.js.map +1 -0
  137. package/dist/cjs/schemas/outlook-query-schema.d.cts +53 -0
  138. package/dist/cjs/schemas/outlook-query-schema.d.ts +53 -0
  139. package/dist/cjs/schemas/outlook-query-schema.js +115 -0
  140. package/dist/cjs/schemas/outlook-query-schema.js.map +1 -0
  141. package/dist/cjs/schemas/outlook-validation.d.cts +428 -0
  142. package/dist/cjs/schemas/outlook-validation.d.ts +428 -0
  143. package/dist/cjs/schemas/outlook-validation.js +420 -0
  144. package/dist/cjs/schemas/outlook-validation.js.map +1 -0
  145. package/dist/cjs/setup/config.d.cts +50 -0
  146. package/dist/cjs/setup/config.d.ts +50 -0
  147. package/dist/cjs/setup/config.js +217 -0
  148. package/dist/cjs/setup/config.js.map +1 -0
  149. package/dist/cjs/setup/http.d.cts +8 -0
  150. package/dist/cjs/setup/http.d.ts +8 -0
  151. package/dist/cjs/setup/http.js +267 -0
  152. package/dist/cjs/setup/http.js.map +1 -0
  153. package/dist/cjs/setup/index.d.cts +5 -0
  154. package/dist/cjs/setup/index.d.ts +5 -0
  155. package/dist/cjs/setup/index.js +46 -0
  156. package/dist/cjs/setup/index.js.map +1 -0
  157. package/dist/cjs/setup/oauth-microsoft.d.cts +43 -0
  158. package/dist/cjs/setup/oauth-microsoft.d.ts +43 -0
  159. package/dist/cjs/setup/oauth-microsoft.js +366 -0
  160. package/dist/cjs/setup/oauth-microsoft.js.map +1 -0
  161. package/dist/cjs/setup/runtime.d.cts +11 -0
  162. package/dist/cjs/setup/runtime.d.ts +11 -0
  163. package/dist/cjs/setup/runtime.js +489 -0
  164. package/dist/cjs/setup/runtime.js.map +1 -0
  165. package/dist/cjs/setup/stdio.d.cts +7 -0
  166. package/dist/cjs/setup/stdio.d.ts +7 -0
  167. package/dist/cjs/setup/stdio.js +239 -0
  168. package/dist/cjs/setup/stdio.js.map +1 -0
  169. package/dist/cjs/types.d.cts +54 -0
  170. package/dist/cjs/types.d.ts +54 -0
  171. package/dist/cjs/types.js +5 -0
  172. package/dist/cjs/types.js.map +1 -0
  173. package/dist/esm/constants.d.ts +10 -0
  174. package/dist/esm/constants.js +13 -0
  175. package/dist/esm/constants.js.map +1 -0
  176. package/dist/esm/email/composition/outlook-message-builder.d.ts +36 -0
  177. package/dist/esm/email/composition/outlook-message-builder.js +46 -0
  178. package/dist/esm/email/composition/outlook-message-builder.js.map +1 -0
  179. package/dist/esm/email/messages/messages.d.ts +7 -0
  180. package/dist/esm/email/messages/messages.js +42 -0
  181. package/dist/esm/email/messages/messages.js.map +1 -0
  182. package/dist/esm/email/parsing/header-parsing.d.ts +18 -0
  183. package/dist/esm/email/parsing/header-parsing.js +18 -0
  184. package/dist/esm/email/parsing/header-parsing.js.map +1 -0
  185. package/dist/esm/email/parsing/message-extraction.d.ts +4 -0
  186. package/dist/esm/email/parsing/message-extraction.js +26 -0
  187. package/dist/esm/email/parsing/message-extraction.js.map +1 -0
  188. package/dist/esm/email/parsing/message-mapping.d.ts +21 -0
  189. package/dist/esm/email/parsing/message-mapping.js +35 -0
  190. package/dist/esm/email/parsing/message-mapping.js.map +1 -0
  191. package/dist/esm/email/querying/execute-query.d.ts +20 -0
  192. package/dist/esm/email/querying/execute-query.js +48 -0
  193. package/dist/esm/email/querying/execute-query.js.map +1 -0
  194. package/dist/esm/email/querying/query-builder.d.ts +32 -0
  195. package/dist/esm/email/querying/query-builder.js +424 -0
  196. package/dist/esm/email/querying/query-builder.js.map +1 -0
  197. package/dist/esm/email/querying/search-execution.d.ts +24 -0
  198. package/dist/esm/email/querying/search-execution.js +96 -0
  199. package/dist/esm/email/querying/search-execution.js.map +1 -0
  200. package/dist/esm/index.d.ts +8 -0
  201. package/dist/esm/index.js +34 -0
  202. package/dist/esm/index.js.map +1 -0
  203. package/dist/esm/lib/create-store.d.ts +2 -0
  204. package/dist/esm/lib/create-store.js +6 -0
  205. package/dist/esm/lib/create-store.js.map +1 -0
  206. package/dist/esm/lib/messages-to-row.d.ts +39 -0
  207. package/dist/esm/lib/messages-to-row.js +141 -0
  208. package/dist/esm/lib/messages-to-row.js.map +1 -0
  209. package/dist/esm/lib/outlook/index.d.ts +7 -0
  210. package/dist/esm/lib/outlook/index.js +7 -0
  211. package/dist/esm/lib/outlook/index.js.map +1 -0
  212. package/dist/esm/lib/outlook/types.d.ts +22 -0
  213. package/dist/esm/lib/outlook/types.js +2 -0
  214. package/dist/esm/lib/outlook/types.js.map +1 -0
  215. package/dist/esm/mcp/index.d.ts +3 -0
  216. package/dist/esm/mcp/index.js +6 -0
  217. package/dist/esm/mcp/index.js.map +1 -0
  218. package/dist/esm/mcp/prompts/draft-email.d.ts +30 -0
  219. package/dist/esm/mcp/prompts/draft-email.js +37 -0
  220. package/dist/esm/mcp/prompts/draft-email.js.map +1 -0
  221. package/dist/esm/mcp/prompts/index.d.ts +2 -0
  222. package/dist/esm/mcp/prompts/index.js +2 -0
  223. package/dist/esm/mcp/prompts/index.js.map +1 -0
  224. package/dist/esm/mcp/prompts/query-syntax.d.ts +19 -0
  225. package/dist/esm/mcp/prompts/query-syntax.js +75 -0
  226. package/dist/esm/mcp/prompts/query-syntax.js.map +1 -0
  227. package/dist/esm/mcp/resources/email.d.ts +11 -0
  228. package/dist/esm/mcp/resources/email.js +69 -0
  229. package/dist/esm/mcp/resources/email.js.map +1 -0
  230. package/dist/esm/mcp/resources/index.d.ts +1 -0
  231. package/dist/esm/mcp/resources/index.js +1 -0
  232. package/dist/esm/mcp/resources/index.js.map +1 -0
  233. package/dist/esm/mcp/tools/categories-list.d.ts +96 -0
  234. package/dist/esm/mcp/tools/categories-list.js +78 -0
  235. package/dist/esm/mcp/tools/categories-list.js.map +1 -0
  236. package/dist/esm/mcp/tools/index.d.ts +11 -0
  237. package/dist/esm/mcp/tools/index.js +11 -0
  238. package/dist/esm/mcp/tools/index.js.map +1 -0
  239. package/dist/esm/mcp/tools/label-add.d.ts +44 -0
  240. package/dist/esm/mcp/tools/label-add.js +75 -0
  241. package/dist/esm/mcp/tools/label-add.js.map +1 -0
  242. package/dist/esm/mcp/tools/label-delete.d.ts +54 -0
  243. package/dist/esm/mcp/tools/label-delete.js +166 -0
  244. package/dist/esm/mcp/tools/label-delete.js.map +1 -0
  245. package/dist/esm/mcp/tools/labels-list.d.ts +96 -0
  246. package/dist/esm/mcp/tools/labels-list.js +78 -0
  247. package/dist/esm/mcp/tools/labels-list.js.map +1 -0
  248. package/dist/esm/mcp/tools/message-get.d.ts +110 -0
  249. package/dist/esm/mcp/tools/message-get.js +117 -0
  250. package/dist/esm/mcp/tools/message-get.js.map +1 -0
  251. package/dist/esm/mcp/tools/message-mark-read.d.ts +42 -0
  252. package/dist/esm/mcp/tools/message-mark-read.js +80 -0
  253. package/dist/esm/mcp/tools/message-mark-read.js.map +1 -0
  254. package/dist/esm/mcp/tools/message-move-to-trash.d.ts +54 -0
  255. package/dist/esm/mcp/tools/message-move-to-trash.js +177 -0
  256. package/dist/esm/mcp/tools/message-move-to-trash.js.map +1 -0
  257. package/dist/esm/mcp/tools/message-respond.d.ts +52 -0
  258. package/dist/esm/mcp/tools/message-respond.js +89 -0
  259. package/dist/esm/mcp/tools/message-respond.js.map +1 -0
  260. package/dist/esm/mcp/tools/message-search.d.ts +138 -0
  261. package/dist/esm/mcp/tools/message-search.js +184 -0
  262. package/dist/esm/mcp/tools/message-search.js.map +1 -0
  263. package/dist/esm/mcp/tools/message-send.d.ts +66 -0
  264. package/dist/esm/mcp/tools/message-send.js +111 -0
  265. package/dist/esm/mcp/tools/message-send.js.map +1 -0
  266. package/dist/esm/mcp/tools/messages-export-csv.d.ts +72 -0
  267. package/dist/esm/mcp/tools/messages-export-csv.js +273 -0
  268. package/dist/esm/mcp/tools/messages-export-csv.js.map +1 -0
  269. package/dist/esm/package.json +1 -0
  270. package/dist/esm/schemas/index.d.ts +2 -0
  271. package/dist/esm/schemas/index.js +2 -0
  272. package/dist/esm/schemas/index.js.map +1 -0
  273. package/dist/esm/schemas/outlook-query-schema.d.ts +53 -0
  274. package/dist/esm/schemas/outlook-query-schema.js +63 -0
  275. package/dist/esm/schemas/outlook-query-schema.js.map +1 -0
  276. package/dist/esm/schemas/outlook-validation.d.ts +428 -0
  277. package/dist/esm/schemas/outlook-validation.js +388 -0
  278. package/dist/esm/schemas/outlook-validation.js.map +1 -0
  279. package/dist/esm/setup/config.d.ts +50 -0
  280. package/dist/esm/setup/config.js +180 -0
  281. package/dist/esm/setup/config.js.map +1 -0
  282. package/dist/esm/setup/http.d.ts +8 -0
  283. package/dist/esm/setup/http.js +61 -0
  284. package/dist/esm/setup/http.js.map +1 -0
  285. package/dist/esm/setup/index.d.ts +5 -0
  286. package/dist/esm/setup/index.js +5 -0
  287. package/dist/esm/setup/index.js.map +1 -0
  288. package/dist/esm/setup/oauth-microsoft.d.ts +43 -0
  289. package/dist/esm/setup/oauth-microsoft.js +169 -0
  290. package/dist/esm/setup/oauth-microsoft.js.map +1 -0
  291. package/dist/esm/setup/runtime.d.ts +11 -0
  292. package/dist/esm/setup/runtime.js +115 -0
  293. package/dist/esm/setup/runtime.js.map +1 -0
  294. package/dist/esm/setup/stdio.d.ts +7 -0
  295. package/dist/esm/setup/stdio.js +38 -0
  296. package/dist/esm/setup/stdio.js.map +1 -0
  297. package/dist/esm/types.d.ts +54 -0
  298. package/dist/esm/types.js +1 -0
  299. package/dist/esm/types.js.map +1 -0
  300. package/package.json +111 -0
@@ -0,0 +1,21 @@
1
+ import type { OutlookMessage } from '../../lib/outlook/types.js';
2
+ export interface NormalizedAddress {
3
+ address?: string | undefined;
4
+ name?: string | undefined;
5
+ }
6
+ export interface NormalizedMessage {
7
+ id: string;
8
+ threadId?: string;
9
+ date?: string;
10
+ subject?: string;
11
+ from?: NormalizedAddress;
12
+ to?: string[];
13
+ cc?: string[];
14
+ bcc?: string[];
15
+ snippet?: string;
16
+ labels?: string[];
17
+ body?: string;
18
+ }
19
+ export declare function mapOutlookMessage(msg: OutlookMessage, opts?: {
20
+ preferHtml?: boolean;
21
+ }): NormalizedMessage;
@@ -0,0 +1,35 @@
1
+ import { stripHtml, normalizeDateToISO as toIsoUtc } from '@mcp-z/email';
2
+ import { extractEmailsFromRecipients } from './header-parsing.js';
3
+ export function mapOutlookMessage(msg, opts = {}) {
4
+ var _ref, _ref1, _msg_id, _toIsoUtc, _msg_toRecipients, _msg_ccRecipients, _msg_bccRecipients;
5
+ var _msg_from, _msg_body, _msg_body1;
6
+ const fromAddr = (_msg_from = msg.from) === null || _msg_from === void 0 ? void 0 : _msg_from.emailAddress;
7
+ const bodyContent = (_ref = (_msg_body = msg.body) === null || _msg_body === void 0 ? void 0 : _msg_body.content) !== null && _ref !== void 0 ? _ref : '';
8
+ const bodyType = String((_ref1 = (_msg_body1 = msg.body) === null || _msg_body1 === void 0 ? void 0 : _msg_body1.contentType) !== null && _ref1 !== void 0 ? _ref1 : '').toLowerCase();
9
+ let body;
10
+ if (bodyContent) {
11
+ if (opts.preferHtml && bodyType === 'html') body = stripHtml(bodyContent);
12
+ else body = bodyType === 'html' ? stripHtml(bodyContent) : String(bodyContent);
13
+ }
14
+ const out = {
15
+ id: (_msg_id = msg.id) !== null && _msg_id !== void 0 ? _msg_id : ''
16
+ };
17
+ if (msg.conversationId) out.threadId = String(msg.conversationId);
18
+ if (msg.receivedDateTime) out.date = (_toIsoUtc = toIsoUtc(msg.receivedDateTime)) !== null && _toIsoUtc !== void 0 ? _toIsoUtc : String(msg.receivedDateTime);
19
+ if (msg.subject) out.subject = String(msg.subject);
20
+ const fromObj = fromAddr ? {
21
+ address: fromAddr.address || undefined,
22
+ name: fromAddr.name || undefined
23
+ } : undefined;
24
+ if (fromObj && (fromObj.address || fromObj.name)) out.from = fromObj;
25
+ const toList = extractEmailsFromRecipients((_msg_toRecipients = msg.toRecipients) !== null && _msg_toRecipients !== void 0 ? _msg_toRecipients : []);
26
+ if (Array.isArray(toList) && toList.length) out.to = toList;
27
+ const ccList = extractEmailsFromRecipients((_msg_ccRecipients = msg.ccRecipients) !== null && _msg_ccRecipients !== void 0 ? _msg_ccRecipients : []);
28
+ if (Array.isArray(ccList) && ccList.length) out.cc = ccList;
29
+ const bccList = extractEmailsFromRecipients((_msg_bccRecipients = msg.bccRecipients) !== null && _msg_bccRecipients !== void 0 ? _msg_bccRecipients : []);
30
+ if (Array.isArray(bccList) && bccList.length) out.bcc = bccList;
31
+ if (msg.bodyPreview) out.snippet = String(msg.bodyPreview);
32
+ if (Array.isArray(msg.categories) && msg.categories.length) out.labels = msg.categories.map(String);
33
+ if (body) out.body = body;
34
+ return out;
35
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/servers/mcp-outlook/src/email/parsing/message-mapping.ts"],"sourcesContent":["import { stripHtml, normalizeDateToISO as toIsoUtc } from '@mcp-z/email';\nimport type { OutlookMessage } from '../../lib/outlook/types.js';\nimport { extractEmailsFromRecipients } from './header-parsing.js';\n\nexport interface NormalizedAddress {\n address?: string | undefined;\n name?: string | undefined;\n}\nexport interface NormalizedMessage {\n id: string;\n threadId?: string;\n date?: string;\n subject?: string;\n from?: NormalizedAddress;\n to?: string[];\n cc?: string[];\n bcc?: string[];\n snippet?: string;\n labels?: string[];\n body?: string;\n}\n\nexport function mapOutlookMessage(msg: OutlookMessage, opts: { preferHtml?: boolean } = {}): NormalizedMessage {\n const fromAddr = msg.from?.emailAddress;\n const bodyContent = msg.body?.content ?? '';\n const bodyType = String(msg.body?.contentType ?? '').toLowerCase();\n\n let body: string | undefined;\n if (bodyContent) {\n if (opts.preferHtml && bodyType === 'html') body = stripHtml(bodyContent);\n else body = bodyType === 'html' ? stripHtml(bodyContent) : String(bodyContent);\n }\n\n const out: NormalizedMessage = { id: msg.id ?? '' };\n\n if (msg.conversationId) out.threadId = String(msg.conversationId);\n if (msg.receivedDateTime) out.date = toIsoUtc(msg.receivedDateTime) ?? String(msg.receivedDateTime);\n if (msg.subject) out.subject = String(msg.subject);\n\n const fromObj = fromAddr ? { address: fromAddr.address || undefined, name: fromAddr.name || undefined } : undefined;\n if (fromObj && (fromObj.address || fromObj.name)) out.from = fromObj;\n\n const toList = extractEmailsFromRecipients(msg.toRecipients ?? []);\n if (Array.isArray(toList) && toList.length) out.to = toList;\n\n const ccList = extractEmailsFromRecipients(msg.ccRecipients ?? []);\n if (Array.isArray(ccList) && ccList.length) out.cc = ccList;\n\n const bccList = extractEmailsFromRecipients(msg.bccRecipients ?? []);\n if (Array.isArray(bccList) && bccList.length) out.bcc = bccList;\n\n if (msg.bodyPreview) out.snippet = String(msg.bodyPreview);\n if (Array.isArray(msg.categories) && msg.categories.length) out.labels = msg.categories.map(String);\n if (body) out.body = body;\n\n return out;\n}\n"],"names":["stripHtml","normalizeDateToISO","toIsoUtc","extractEmailsFromRecipients","mapOutlookMessage","msg","opts","fromAddr","from","emailAddress","bodyContent","body","content","bodyType","String","contentType","toLowerCase","preferHtml","out","id","conversationId","threadId","receivedDateTime","date","subject","fromObj","address","undefined","name","toList","toRecipients","Array","isArray","length","to","ccList","ccRecipients","cc","bccList","bccRecipients","bcc","bodyPreview","snippet","categories","labels","map"],"mappings":"AAAA,SAASA,SAAS,EAAEC,sBAAsBC,QAAQ,QAAQ,eAAe;AAEzE,SAASC,2BAA2B,QAAQ,sBAAsB;AAoBlE,OAAO,SAASC,kBAAkBC,GAAmB,EAAEC,OAAiC,CAAC,CAAC;qBAWnDD,SAGAH,WAMMG,mBAGAA,mBAGCA;QAzB3BA,WACGA,WACIA;IAFxB,MAAME,YAAWF,YAAAA,IAAIG,IAAI,cAARH,gCAAAA,UAAUI,YAAY;IACvC,MAAMC,uBAAcL,YAAAA,IAAIM,IAAI,cAARN,gCAAAA,UAAUO,OAAO,uCAAI;IACzC,MAAMC,WAAWC,iBAAOT,aAAAA,IAAIM,IAAI,cAARN,iCAAAA,WAAUU,WAAW,yCAAI,IAAIC,WAAW;IAEhE,IAAIL;IACJ,IAAID,aAAa;QACf,IAAIJ,KAAKW,UAAU,IAAIJ,aAAa,QAAQF,OAAOX,UAAUU;aACxDC,OAAOE,aAAa,SAASb,UAAUU,eAAeI,OAAOJ;IACpE;IAEA,MAAMQ,MAAyB;QAAEC,EAAE,GAAEd,UAAAA,IAAIc,EAAE,cAANd,qBAAAA,UAAU;IAAG;IAElD,IAAIA,IAAIe,cAAc,EAAEF,IAAIG,QAAQ,GAAGP,OAAOT,IAAIe,cAAc;IAChE,IAAIf,IAAIiB,gBAAgB,EAAEJ,IAAIK,IAAI,IAAGrB,YAAAA,SAASG,IAAIiB,gBAAgB,eAA7BpB,uBAAAA,YAAkCY,OAAOT,IAAIiB,gBAAgB;IAClG,IAAIjB,IAAImB,OAAO,EAAEN,IAAIM,OAAO,GAAGV,OAAOT,IAAImB,OAAO;IAEjD,MAAMC,UAAUlB,WAAW;QAAEmB,SAASnB,SAASmB,OAAO,IAAIC;QAAWC,MAAMrB,SAASqB,IAAI,IAAID;IAAU,IAAIA;IAC1G,IAAIF,WAAYA,CAAAA,QAAQC,OAAO,IAAID,QAAQG,IAAI,AAAD,GAAIV,IAAIV,IAAI,GAAGiB;IAE7D,MAAMI,SAAS1B,6BAA4BE,oBAAAA,IAAIyB,YAAY,cAAhBzB,+BAAAA,oBAAoB,EAAE;IACjE,IAAI0B,MAAMC,OAAO,CAACH,WAAWA,OAAOI,MAAM,EAAEf,IAAIgB,EAAE,GAAGL;IAErD,MAAMM,SAAShC,6BAA4BE,oBAAAA,IAAI+B,YAAY,cAAhB/B,+BAAAA,oBAAoB,EAAE;IACjE,IAAI0B,MAAMC,OAAO,CAACG,WAAWA,OAAOF,MAAM,EAAEf,IAAImB,EAAE,GAAGF;IAErD,MAAMG,UAAUnC,6BAA4BE,qBAAAA,IAAIkC,aAAa,cAAjBlC,gCAAAA,qBAAqB,EAAE;IACnE,IAAI0B,MAAMC,OAAO,CAACM,YAAYA,QAAQL,MAAM,EAAEf,IAAIsB,GAAG,GAAGF;IAExD,IAAIjC,IAAIoC,WAAW,EAAEvB,IAAIwB,OAAO,GAAG5B,OAAOT,IAAIoC,WAAW;IACzD,IAAIV,MAAMC,OAAO,CAAC3B,IAAIsC,UAAU,KAAKtC,IAAIsC,UAAU,CAACV,MAAM,EAAEf,IAAI0B,MAAM,GAAGvC,IAAIsC,UAAU,CAACE,GAAG,CAAC/B;IAC5F,IAAIH,MAAMO,IAAIP,IAAI,GAAGA;IAErB,OAAOO;AACT"}
@@ -0,0 +1,20 @@
1
+ import type { ExecutionResult } from '@mcp-z/email';
2
+ import type { Client } from '@microsoft/microsoft-graph-client';
3
+ import type { OutlookQuery as QueryNode } from '../../schemas/outlook-query-schema.js';
4
+ import type { Logger } from '../../types.js';
5
+ export interface ExecuteQueryOptions {
6
+ readonly logger: Logger;
7
+ readonly limit?: number;
8
+ readonly includeBody?: boolean;
9
+ readonly maxPages?: number | null;
10
+ readonly pageSize?: number;
11
+ readonly pageToken?: string;
12
+ readonly timezone?: string;
13
+ readonly abortSignal?: AbortSignal;
14
+ }
15
+ /**
16
+ * Execute an Outlook query with direct, single-attempt execution.
17
+ * No planning, no fallbacks, no retries.
18
+ * Microsoft Graph errors are returned directly to the caller for actionable feedback.
19
+ */
20
+ export declare function executeQuery<T>(graph: Client, query: QueryNode | undefined, options: ExecuteQueryOptions, transform: (item: unknown) => T): Promise<ExecutionResult<T>>;
@@ -0,0 +1,48 @@
1
+ import { searchMessages } from './search-execution.js';
2
+ /**
3
+ * Execute an Outlook query with direct, single-attempt execution.
4
+ * No planning, no fallbacks, no retries.
5
+ * Microsoft Graph errors are returned directly to the caller for actionable feedback.
6
+ */ export async function executeQuery(graph, query, options, transform) {
7
+ const { logger, limit, includeBody, maxPages, pageSize, pageToken } = options;
8
+ // Single execution - direct query to Microsoft Graph API
9
+ logger.info('executeQuery: executing direct Outlook query');
10
+ try {
11
+ const result = await searchMessages(graph, {
12
+ ...query !== undefined && {
13
+ query
14
+ },
15
+ limit: limit !== null && limit !== void 0 ? limit : 50,
16
+ includeBody: includeBody !== null && includeBody !== void 0 ? includeBody : false,
17
+ maxPages: maxPages !== null && maxPages !== void 0 ? maxPages : null,
18
+ pageSize: pageSize !== null && pageSize !== void 0 ? pageSize : 50,
19
+ pageToken: pageToken !== null && pageToken !== void 0 ? pageToken : undefined,
20
+ logger
21
+ });
22
+ // Transform directly - if Microsoft Graph returns invalid data, fail loud
23
+ const transformedResults = result.messages.map((item, index)=>{
24
+ try {
25
+ return transform(item);
26
+ } catch (transformError) {
27
+ logger.error(`Transform function failed for item ${index}`, {
28
+ itemIndex: index,
29
+ error: transformError instanceof Error ? transformError.message : String(transformError)
30
+ });
31
+ throw new Error(`Transform failed at item ${index}: ${transformError}`);
32
+ }
33
+ });
34
+ logger.info(`executeQuery: succeeded with ${transformedResults.length} results`);
35
+ return {
36
+ success: true,
37
+ items: transformedResults,
38
+ metadata: {
39
+ nextPageToken: result.nextPageToken,
40
+ totalFetched: result.messages.length
41
+ }
42
+ };
43
+ } catch (error) {
44
+ // Re-throw errors directly - no fallback logic
45
+ logger.error('executeQuery: failed', error);
46
+ throw error;
47
+ }
48
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/kevin/Dev/Projects/ai/mcp-z/servers/mcp-outlook/src/email/querying/execute-query.ts"],"sourcesContent":["import type { ExecutionResult } from '@mcp-z/email';\nimport type { Client } from '@microsoft/microsoft-graph-client';\nimport type { OutlookQuery as QueryNode } from '../../schemas/outlook-query-schema.js';\nimport type { Logger } from '../../types.js';\nimport { searchMessages } from './search-execution.js';\n\nexport interface ExecuteQueryOptions {\n readonly logger: Logger;\n readonly limit?: number;\n readonly includeBody?: boolean;\n readonly maxPages?: number | null;\n readonly pageSize?: number;\n readonly pageToken?: string;\n readonly timezone?: string;\n readonly abortSignal?: AbortSignal;\n}\n\n/**\n * Execute an Outlook query with direct, single-attempt execution.\n * No planning, no fallbacks, no retries.\n * Microsoft Graph errors are returned directly to the caller for actionable feedback.\n */\nexport async function executeQuery<T>(graph: Client, query: QueryNode | undefined, options: ExecuteQueryOptions, transform: (item: unknown) => T): Promise<ExecutionResult<T>> {\n const { logger, limit, includeBody, maxPages, pageSize, pageToken } = options;\n\n // Single execution - direct query to Microsoft Graph API\n logger.info('executeQuery: executing direct Outlook query');\n\n try {\n const result = await searchMessages(graph, {\n ...(query !== undefined && { query }),\n limit: limit ?? 50,\n includeBody: includeBody ?? false,\n maxPages: maxPages ?? null,\n pageSize: pageSize ?? 50,\n pageToken: pageToken ?? undefined,\n logger,\n });\n\n // Transform directly - if Microsoft Graph returns invalid data, fail loud\n const transformedResults = result.messages.map((item, index) => {\n try {\n return transform(item);\n } catch (transformError) {\n logger.error(`Transform function failed for item ${index}`, {\n itemIndex: index,\n error: transformError instanceof Error ? transformError.message : String(transformError),\n });\n throw new Error(`Transform failed at item ${index}: ${transformError}`);\n }\n });\n\n logger.info(`executeQuery: succeeded with ${transformedResults.length} results`);\n\n return {\n success: true,\n items: transformedResults,\n metadata: {\n nextPageToken: result.nextPageToken,\n totalFetched: result.messages.length,\n },\n };\n } catch (error) {\n // Re-throw errors directly - no fallback logic\n logger.error('executeQuery: failed', error as Record<string, unknown>);\n throw error;\n }\n}\n"],"names":["searchMessages","executeQuery","graph","query","options","transform","logger","limit","includeBody","maxPages","pageSize","pageToken","info","result","undefined","transformedResults","messages","map","item","index","transformError","error","itemIndex","Error","message","String","length","success","items","metadata","nextPageToken","totalFetched"],"mappings":"AAIA,SAASA,cAAc,QAAQ,wBAAwB;AAavD;;;;CAIC,GACD,OAAO,eAAeC,aAAgBC,KAAa,EAAEC,KAA4B,EAAEC,OAA4B,EAAEC,SAA+B;IAC9I,MAAM,EAAEC,MAAM,EAAEC,KAAK,EAAEC,WAAW,EAAEC,QAAQ,EAAEC,QAAQ,EAAEC,SAAS,EAAE,GAAGP;IAEtE,yDAAyD;IACzDE,OAAOM,IAAI,CAAC;IAEZ,IAAI;QACF,MAAMC,SAAS,MAAMb,eAAeE,OAAO;YACzC,GAAIC,UAAUW,aAAa;gBAAEX;YAAM,CAAC;YACpCI,KAAK,EAAEA,kBAAAA,mBAAAA,QAAS;YAChBC,WAAW,EAAEA,wBAAAA,yBAAAA,cAAe;YAC5BC,QAAQ,EAAEA,qBAAAA,sBAAAA,WAAY;YACtBC,QAAQ,EAAEA,qBAAAA,sBAAAA,WAAY;YACtBC,SAAS,EAAEA,sBAAAA,uBAAAA,YAAaG;YACxBR;QACF;QAEA,0EAA0E;QAC1E,MAAMS,qBAAqBF,OAAOG,QAAQ,CAACC,GAAG,CAAC,CAACC,MAAMC;YACpD,IAAI;gBACF,OAAOd,UAAUa;YACnB,EAAE,OAAOE,gBAAgB;gBACvBd,OAAOe,KAAK,CAAC,CAAC,mCAAmC,EAAEF,OAAO,EAAE;oBAC1DG,WAAWH;oBACXE,OAAOD,0BAA0BG,QAAQH,eAAeI,OAAO,GAAGC,OAAOL;gBAC3E;gBACA,MAAM,IAAIG,MAAM,CAAC,yBAAyB,EAAEJ,MAAM,EAAE,EAAEC,gBAAgB;YACxE;QACF;QAEAd,OAAOM,IAAI,CAAC,CAAC,6BAA6B,EAAEG,mBAAmBW,MAAM,CAAC,QAAQ,CAAC;QAE/E,OAAO;YACLC,SAAS;YACTC,OAAOb;YACPc,UAAU;gBACRC,eAAejB,OAAOiB,aAAa;gBACnCC,cAAclB,OAAOG,QAAQ,CAACU,MAAM;YACtC;QACF;IACF,EAAE,OAAOL,OAAO;QACd,+CAA+C;QAC/Cf,OAAOe,KAAK,CAAC,wBAAwBA;QACrC,MAAMA;IACR;AACF"}
@@ -0,0 +1,32 @@
1
+ import type { OutlookQuery as QueryNode } from '../../schemas/outlook-query-schema.js';
2
+ export interface ODataFilterResult {
3
+ search: string | null;
4
+ filter: string | null;
5
+ requireBodyClientFilter: boolean;
6
+ }
7
+ export declare function toGraphFilter(query: QueryNode): ODataFilterResult;
8
+ export declare function toOutlookFilter(parsed: QueryNode, _options?: {
9
+ includeBodyContent?: boolean;
10
+ useCaseInsensitiveWrap?: boolean;
11
+ }): {
12
+ filter: string;
13
+ search: string;
14
+ requireBodyClientFilter: boolean;
15
+ filters: ExtractedFilters;
16
+ };
17
+ interface ExtractedFilters {
18
+ subjectIncludes: string[];
19
+ bodyIncludes: string[];
20
+ textIncludes: string[];
21
+ fromIncludes: string[];
22
+ toIncludes: string[];
23
+ ccIncludes: string[];
24
+ bccIncludes: string[];
25
+ categoriesIncludes: string[];
26
+ labelIncludes: string[];
27
+ hasAttachment?: boolean;
28
+ since?: string;
29
+ before?: string;
30
+ }
31
+ export declare function extractOutlookFilters(parsed: QueryNode): ExtractedFilters;
32
+ export {};
@@ -0,0 +1,424 @@
1
+ /**
2
+ * Outlook category mappings - case insensitive input to exact system categories
3
+ * Note: These are user-defined categories in Outlook, not system categories like Gmail
4
+ */ const OUTLOOK_CATEGORIES = {
5
+ personal: 'Personal',
6
+ work: 'Work',
7
+ family: 'Family',
8
+ travel: 'Travel',
9
+ important: 'Important',
10
+ urgent: 'Urgent'
11
+ };
12
+ /**
13
+ * Validate and map category name to Outlook system category
14
+ * Throws error for invalid categories (fail fast principle)
15
+ */ function mapOutlookCategory(category) {
16
+ // Input validation - fail fast on invalid input
17
+ if (!category || typeof category !== 'string') {
18
+ throw new Error(`Invalid category: expected non-empty string, got ${typeof category}`);
19
+ }
20
+ const trimmed = category.trim();
21
+ if (trimmed === '') {
22
+ throw new Error('Invalid category: empty string after trimming');
23
+ }
24
+ // Fail fast on unknown categories
25
+ const normalizedCategory = trimmed.toLowerCase();
26
+ const systemCategory = OUTLOOK_CATEGORIES[normalizedCategory];
27
+ if (!systemCategory) {
28
+ throw new Error(`Invalid Outlook category: "${category}". Valid categories: ${Object.keys(OUTLOOK_CATEGORIES).join(', ')}`);
29
+ }
30
+ return systemCategory;
31
+ }
32
+ export function toGraphFilter(query) {
33
+ let requireBodyClientFilter = false;
34
+ function L(s) {
35
+ // Microsoft Graph does NOT support toLower() function in OData filters
36
+ // Case-insensitive matching must be done client-side or via $search
37
+ return s;
38
+ }
39
+ function p(s) {
40
+ return `(${s})`;
41
+ }
42
+ function recip(coll, V) {
43
+ // Graph may reject functions on nested properties; use equality on nested address/name fields.
44
+ const left = `r/emailAddress/address eq ${V}`;
45
+ const right = `r/emailAddress/name eq ${V}`;
46
+ return `${coll}/any(r: ${left} or ${right})`;
47
+ }
48
+ function fv(field, raw) {
49
+ if (raw == null) return '';
50
+ const rawStr = String(raw);
51
+ // For text and body fields, skip OData filtering entirely (uses KQL search instead)
52
+ // Do this BEFORE validation so we don't throw on valid text/body queries
53
+ if (field === 'text' || field === 'body') {
54
+ if (rawStr.trim() === '') {
55
+ throw new Error(`Invalid ${field} value: empty string`);
56
+ }
57
+ requireBodyClientFilter = true;
58
+ return '';
59
+ }
60
+ // For all other fields, validate non-empty AFTER checking for null
61
+ if (rawStr.trim() === '') {
62
+ throw new Error(`Invalid ${field} value: empty string`);
63
+ }
64
+ const V = `'${rawStr.toLowerCase().replace(/'/g, "''")}'`;
65
+ switch(field){
66
+ case 'from':
67
+ {
68
+ // For email addresses emit equality checks on nested address/name;
69
+ // for name-only tokens, skip server-side filter (handled client-side or via $search).
70
+ if (rawStr.includes('@')) {
71
+ const addrEq = `${L('from/emailAddress/address')} eq ${V}`;
72
+ const nameEq = `${L('from/emailAddress/name')} eq ${V}`;
73
+ return p(`${addrEq} or ${nameEq}`);
74
+ }
75
+ // Don't emit a server-side filter for name-only 'from' tokens.
76
+ return '';
77
+ }
78
+ case 'to':
79
+ return recip('toRecipients', V);
80
+ case 'cc':
81
+ return recip('ccRecipients', V);
82
+ case 'bcc':
83
+ return recip('bccRecipients', V);
84
+ case 'subject':
85
+ // Microsoft Graph does NOT support contains() function in OData filters
86
+ // Use startswith as a partial alternative or rely on $search
87
+ if (rawStr.includes('-') || rawStr.length < 3) return '';
88
+ return `startswith(subject, ${V})`;
89
+ case 'categories':
90
+ {
91
+ // mapOutlookCategory will throw on invalid input (fail fast)
92
+ const systemCategory = mapOutlookCategory(rawStr);
93
+ // Use the categories OData property with exact case-sensitive match
94
+ return `categories/any(c: c eq '${systemCategory}')`;
95
+ }
96
+ case 'label':
97
+ {
98
+ // Direct passthrough to categories for Outlook (case-sensitive)
99
+ return `categories/any(c: c eq '${rawStr.replace(/'/g, "''")}')`;
100
+ }
101
+ default:
102
+ // Microsoft Graph does NOT support contains() function
103
+ // For unknown fields, skip server-side filtering
104
+ return '';
105
+ }
106
+ }
107
+ function chain(op, arr) {
108
+ if (!arr || arr.length === 0) {
109
+ throw new Error(`chain: empty array for ${op} operation`);
110
+ }
111
+ if (arr.length === 1) {
112
+ var _arr_;
113
+ const first = (_arr_ = arr[0]) !== null && _arr_ !== void 0 ? _arr_ : '';
114
+ return String(first);
115
+ }
116
+ const joined = arr.join(` ${op} `);
117
+ return p(joined);
118
+ }
119
+ function fieldExpr(field, op) {
120
+ if (typeof op === 'string') {
121
+ return fv(field, op);
122
+ }
123
+ if (Array.isArray(op.$any)) {
124
+ const results = op.$any.map((v)=>fv(field, String(v !== null && v !== void 0 ? v : '')));
125
+ // Filter out empty strings (from fields like text/body that don't generate OData filters)
126
+ const validResults = results.filter((s)=>s && s.trim());
127
+ if (validResults.length === 0) return '';
128
+ return chain('or', validResults);
129
+ }
130
+ if (Array.isArray(op.$all)) {
131
+ const results = op.$all.map((v)=>fv(field, String(v !== null && v !== void 0 ? v : '')));
132
+ // Filter out empty strings (from fields like text/body that don't generate OData filters)
133
+ const validResults = results.filter((s)=>s && s.trim());
134
+ if (validResults.length === 0) return '';
135
+ return chain('and', validResults);
136
+ }
137
+ if (Array.isArray(op.$none)) {
138
+ const results = op.$none.map((v)=>fv(field, String(v !== null && v !== void 0 ? v : '')));
139
+ // Filter out empty strings (from fields like text/body that don't generate OData filters)
140
+ const validResults = results.filter((s)=>s && s.trim());
141
+ if (validResults.length === 0) return '';
142
+ return `not ${p(chain('or', validResults))}`;
143
+ }
144
+ throw new Error(`Unknown field operator ${JSON.stringify(op)}`);
145
+ }
146
+ function dateExpr(d) {
147
+ var _parts_;
148
+ const parts = [];
149
+ if (d.$gte) parts.push(`receivedDateTime ge ${d.$gte}T00:00:00Z`);
150
+ if (d.$lt) parts.push(`receivedDateTime lt ${d.$lt}T00:00:00Z`);
151
+ return parts.length > 1 ? p(parts.join(' and ')) : (_parts_ = parts[0]) !== null && _parts_ !== void 0 ? _parts_ : '';
152
+ }
153
+ function emit(n) {
154
+ if (!n || typeof n !== 'object') return '';
155
+ if ('$and' in n && n.$and) {
156
+ const andParts = n.$and.map(emit).filter((part)=>Boolean(part));
157
+ if (andParts.length === 0) return '';
158
+ if (andParts.length === 1) {
159
+ const firstPart = andParts[0];
160
+ return firstPart !== null && firstPart !== void 0 ? firstPart : '';
161
+ }
162
+ return p(andParts.join(' and '));
163
+ }
164
+ if ('$or' in n && n.$or) {
165
+ const orParts = n.$or.map(emit).filter((part)=>Boolean(part));
166
+ if (orParts.length === 0) return '';
167
+ if (orParts.length === 1) {
168
+ const firstPart = orParts[0];
169
+ return firstPart !== null && firstPart !== void 0 ? firstPart : '';
170
+ }
171
+ return p(orParts.join(' or '));
172
+ }
173
+ if ('$not' in n && n.$not) {
174
+ const notExpr = emit(n.$not);
175
+ return notExpr ? `not (${notExpr})` : '';
176
+ }
177
+ if ('hasAttachment' in n && n.hasAttachment) return 'hasAttachments eq true';
178
+ if ('date' in n && n.date) return dateExpr(n.date);
179
+ const keys = Object.keys(n);
180
+ if (keys.length === 1) {
181
+ var _keys_;
182
+ const k0 = String((_keys_ = keys[0]) !== null && _keys_ !== void 0 ? _keys_ : '');
183
+ if (k0 && [
184
+ 'from',
185
+ 'to',
186
+ 'cc',
187
+ 'bcc',
188
+ 'subject',
189
+ 'text',
190
+ 'body',
191
+ 'categories',
192
+ 'label'
193
+ ].includes(k0)) {
194
+ const fieldValue = n[k0];
195
+ if (fieldValue) return fieldExpr(k0, fieldValue);
196
+ }
197
+ }
198
+ return '';
199
+ }
200
+ const filterStr = emit(query);
201
+ const terms = [];
202
+ function pushTerms(arr) {
203
+ if (Array.isArray(arr)) {
204
+ for (const t of arr)if ((t !== null && t !== void 0 ? t : '').toString().trim()) terms.push(String(t).trim());
205
+ }
206
+ }
207
+ function walk(node) {
208
+ if (!node || typeof node !== 'object') return;
209
+ if ('$and' in node && node.$and) {
210
+ node.$and.forEach(walk);
211
+ return;
212
+ }
213
+ if ('$or' in node && node.$or) {
214
+ node.$or.forEach(walk);
215
+ return;
216
+ }
217
+ if ('$not' in node && node.$not) {
218
+ walk(node.$not);
219
+ return;
220
+ }
221
+ if ('exactPhrase' in node && node.exactPhrase) {
222
+ // KQL uses double quotes for exact phrase matching
223
+ pushTerms([
224
+ `"${String(node.exactPhrase).replace(/"/g, '\\"')}"`
225
+ ]);
226
+ return;
227
+ }
228
+ if ('subject' in node && node.subject) {
229
+ if (typeof node.subject === 'string') {
230
+ pushTerms([
231
+ node.subject
232
+ ]);
233
+ } else {
234
+ pushTerms(node.subject.$any);
235
+ pushTerms(node.subject.$all);
236
+ pushTerms(node.subject.$none);
237
+ }
238
+ }
239
+ if ('body' in node && node.body) {
240
+ if (typeof node.body === 'string') {
241
+ pushTerms([
242
+ node.body
243
+ ]);
244
+ } else {
245
+ pushTerms(node.body.$any);
246
+ pushTerms(node.body.$all);
247
+ pushTerms(node.body.$none);
248
+ }
249
+ }
250
+ if ('text' in node && node.text) {
251
+ if (typeof node.text === 'string') {
252
+ pushTerms([
253
+ node.text
254
+ ]);
255
+ } else {
256
+ pushTerms(node.text.$any);
257
+ pushTerms(node.text.$all);
258
+ pushTerms(node.text.$none);
259
+ }
260
+ }
261
+ }
262
+ walk(query);
263
+ /**
264
+ * Escape KQL (Keyword Query Language) special characters in search terms.
265
+ * KQL special characters that need escaping: \ : ( ) { } [ ] " * ? < > - _
266
+ * According to Microsoft Graph KQL syntax, these must be escaped with backslash.
267
+ */ function escapeKQL(term) {
268
+ if (!term) return term;
269
+ // Escape backslash first, then other special characters
270
+ return term.replace(/\\/g, '\\\\').replace(/:/g, '\\:').replace(/\(/g, '\\(').replace(/\)/g, '\\)').replace(/\{/g, '\\{').replace(/\}/g, '\\}').replace(/\[/g, '\\[').replace(/\]/g, '\\]').replace(/"/g, '\\"').replace(/\*/g, '\\*').replace(/\?/g, '\\?').replace(/</g, '\\<').replace(/>/g, '\\>').replace(/-/g, '\\-').replace(/_/g, '\\_');
271
+ }
272
+ const mapped = terms.map((t)=>{
273
+ const escaped = escapeKQL(String(t));
274
+ return escaped;
275
+ });
276
+ const search = mapped.length ? mapped.join(' OR ') : null;
277
+ return {
278
+ search,
279
+ filter: filterStr && typeof filterStr === 'string' && filterStr.length ? filterStr : null,
280
+ requireBodyClientFilter
281
+ };
282
+ }
283
+ export function toOutlookFilter(parsed, _options) {
284
+ const graphResult = toGraphFilter(parsed);
285
+ const filters = extractOutlookFilters(parsed);
286
+ return {
287
+ filter: graphResult.filter,
288
+ search: graphResult.search,
289
+ requireBodyClientFilter: graphResult.requireBodyClientFilter,
290
+ filters
291
+ };
292
+ }
293
+ export function extractOutlookFilters(parsed) {
294
+ const filters = {
295
+ subjectIncludes: [],
296
+ bodyIncludes: [],
297
+ textIncludes: [],
298
+ fromIncludes: [],
299
+ toIncludes: [],
300
+ ccIncludes: [],
301
+ bccIncludes: [],
302
+ categoriesIncludes: [],
303
+ labelIncludes: []
304
+ };
305
+ function walk(node) {
306
+ if (!node || typeof node !== 'object') return;
307
+ if ('$and' in node && node.$and) {
308
+ node.$and.forEach(walk);
309
+ return;
310
+ }
311
+ if ('$or' in node && node.$or) {
312
+ node.$or.forEach(walk);
313
+ return;
314
+ }
315
+ if ('$not' in node && node.$not) {
316
+ walk(node.$not);
317
+ return;
318
+ }
319
+ if ('hasAttachment' in node && node.hasAttachment !== undefined) {
320
+ filters.hasAttachment = node.hasAttachment === true;
321
+ return;
322
+ }
323
+ if ('date' in node && node.date) {
324
+ if (node.date.$gte) filters.since = node.date.$gte;
325
+ if (node.date.$lt) filters.before = node.date.$lt;
326
+ return;
327
+ }
328
+ if ('subject' in node && node.subject) {
329
+ if (typeof node.subject === 'string') {
330
+ filters.subjectIncludes.push(node.subject);
331
+ } else {
332
+ if (node.subject.$any) filters.subjectIncludes.push(...node.subject.$any);
333
+ if (node.subject.$all) filters.subjectIncludes.push(...node.subject.$all);
334
+ }
335
+ }
336
+ if ('body' in node && node.body) {
337
+ if (typeof node.body === 'string') {
338
+ filters.bodyIncludes.push(node.body);
339
+ } else {
340
+ if (node.body.$any) filters.bodyIncludes.push(...node.body.$any);
341
+ if (node.body.$all) filters.bodyIncludes.push(...node.body.$all);
342
+ }
343
+ }
344
+ if ('text' in node && node.text) {
345
+ if (typeof node.text === 'string') {
346
+ filters.textIncludes.push(node.text);
347
+ filters.bodyIncludes.push(node.text);
348
+ } else {
349
+ if (node.text.$any) {
350
+ filters.textIncludes.push(...node.text.$any);
351
+ filters.bodyIncludes.push(...node.text.$any);
352
+ }
353
+ if (node.text.$all) {
354
+ filters.textIncludes.push(...node.text.$all);
355
+ filters.bodyIncludes.push(...node.text.$all);
356
+ }
357
+ }
358
+ }
359
+ if ('from' in node && node.from) {
360
+ if (typeof node.from === 'string') {
361
+ filters.fromIncludes.push(node.from);
362
+ } else {
363
+ if (node.from.$any) filters.fromIncludes.push(...node.from.$any);
364
+ if (node.from.$all) filters.fromIncludes.push(...node.from.$all);
365
+ }
366
+ }
367
+ if ('to' in node && node.to) {
368
+ if (typeof node.to === 'string') {
369
+ filters.toIncludes.push(node.to);
370
+ } else {
371
+ if (node.to.$any) filters.toIncludes.push(...node.to.$any);
372
+ if (node.to.$all) filters.toIncludes.push(...node.to.$all);
373
+ }
374
+ }
375
+ if ('cc' in node && node.cc) {
376
+ if (typeof node.cc === 'string') {
377
+ filters.ccIncludes.push(node.cc);
378
+ } else {
379
+ if (node.cc.$any) filters.ccIncludes.push(...node.cc.$any);
380
+ if (node.cc.$all) filters.ccIncludes.push(...node.cc.$all);
381
+ }
382
+ }
383
+ if ('bcc' in node && node.bcc) {
384
+ if (typeof node.bcc === 'string') {
385
+ filters.bccIncludes.push(node.bcc);
386
+ } else {
387
+ if (node.bcc.$any) filters.bccIncludes.push(...node.bcc.$any);
388
+ if (node.bcc.$all) filters.bccIncludes.push(...node.bcc.$all);
389
+ }
390
+ }
391
+ if ('categories' in node && node.categories) {
392
+ if (typeof node.categories === 'string') {
393
+ if (mapOutlookCategory(node.categories) !== null) {
394
+ filters.categoriesIncludes.push(node.categories);
395
+ }
396
+ } else {
397
+ // Filter out invalid categories to prevent memory leaks and maintain clean state
398
+ if (node.categories.$any) {
399
+ const validCategories = node.categories.$any.filter((cat)=>mapOutlookCategory(cat) !== null);
400
+ if (validCategories.length > 0) filters.categoriesIncludes.push(...validCategories);
401
+ }
402
+ if (node.categories.$all) {
403
+ const validCategories = node.categories.$all.filter((cat)=>mapOutlookCategory(cat) !== null);
404
+ if (validCategories.length > 0) filters.categoriesIncludes.push(...validCategories);
405
+ }
406
+ if (node.categories.$none) {
407
+ const validCategories = node.categories.$none.filter((cat)=>mapOutlookCategory(cat) !== null);
408
+ if (validCategories.length > 0) filters.categoriesIncludes.push(...validCategories);
409
+ }
410
+ }
411
+ }
412
+ if ('label' in node && node.label) {
413
+ if (typeof node.label === 'string') {
414
+ filters.labelIncludes.push(node.label);
415
+ } else {
416
+ if (node.label.$any) filters.labelIncludes.push(...node.label.$any);
417
+ if (node.label.$all) filters.labelIncludes.push(...node.label.$all);
418
+ if (node.label.$none) filters.labelIncludes.push(...node.label.$none);
419
+ }
420
+ }
421
+ }
422
+ walk(parsed);
423
+ return filters;
424
+ }