@jbctechsolutions/mcp-office365 2.5.1

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 (339) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +667 -0
  3. package/dist/applescript/account-repository.d.ts +30 -0
  4. package/dist/applescript/account-repository.d.ts.map +1 -0
  5. package/dist/applescript/account-repository.js +38 -0
  6. package/dist/applescript/account-repository.js.map +1 -0
  7. package/dist/applescript/account-scripts.d.ts +21 -0
  8. package/dist/applescript/account-scripts.d.ts.map +1 -0
  9. package/dist/applescript/account-scripts.js +180 -0
  10. package/dist/applescript/account-scripts.js.map +1 -0
  11. package/dist/applescript/calendar-manager.d.ts +44 -0
  12. package/dist/applescript/calendar-manager.d.ts.map +1 -0
  13. package/dist/applescript/calendar-manager.js +92 -0
  14. package/dist/applescript/calendar-manager.js.map +1 -0
  15. package/dist/applescript/calendar-writer.d.ts +36 -0
  16. package/dist/applescript/calendar-writer.d.ts.map +1 -0
  17. package/dist/applescript/calendar-writer.js +94 -0
  18. package/dist/applescript/calendar-writer.js.map +1 -0
  19. package/dist/applescript/content-readers.d.ts +114 -0
  20. package/dist/applescript/content-readers.d.ts.map +1 -0
  21. package/dist/applescript/content-readers.js +328 -0
  22. package/dist/applescript/content-readers.js.map +1 -0
  23. package/dist/applescript/executor.d.ts +60 -0
  24. package/dist/applescript/executor.d.ts.map +1 -0
  25. package/dist/applescript/executor.js +173 -0
  26. package/dist/applescript/executor.js.map +1 -0
  27. package/dist/applescript/index.d.ts +20 -0
  28. package/dist/applescript/index.d.ts.map +1 -0
  29. package/dist/applescript/index.js +29 -0
  30. package/dist/applescript/index.js.map +1 -0
  31. package/dist/applescript/mail-sender.d.ts +38 -0
  32. package/dist/applescript/mail-sender.d.ts.map +1 -0
  33. package/dist/applescript/mail-sender.js +67 -0
  34. package/dist/applescript/mail-sender.js.map +1 -0
  35. package/dist/applescript/parser.d.ts +235 -0
  36. package/dist/applescript/parser.d.ts.map +1 -0
  37. package/dist/applescript/parser.js +496 -0
  38. package/dist/applescript/parser.js.map +1 -0
  39. package/dist/applescript/repository.d.ts +64 -0
  40. package/dist/applescript/repository.d.ts.map +1 -0
  41. package/dist/applescript/repository.js +444 -0
  42. package/dist/applescript/repository.js.map +1 -0
  43. package/dist/applescript/scripts.d.ts +265 -0
  44. package/dist/applescript/scripts.d.ts.map +1 -0
  45. package/dist/applescript/scripts.js +1483 -0
  46. package/dist/applescript/scripts.js.map +1 -0
  47. package/dist/approval/hash.d.ts +87 -0
  48. package/dist/approval/hash.d.ts.map +1 -0
  49. package/dist/approval/hash.js +102 -0
  50. package/dist/approval/hash.js.map +1 -0
  51. package/dist/approval/index.d.ts +13 -0
  52. package/dist/approval/index.d.ts.map +1 -0
  53. package/dist/approval/index.js +7 -0
  54. package/dist/approval/index.js.map +1 -0
  55. package/dist/approval/token-manager.d.ts +51 -0
  56. package/dist/approval/token-manager.d.ts.map +1 -0
  57. package/dist/approval/token-manager.js +111 -0
  58. package/dist/approval/token-manager.js.map +1 -0
  59. package/dist/approval/types.d.ts +44 -0
  60. package/dist/approval/types.d.ts.map +1 -0
  61. package/dist/approval/types.js +6 -0
  62. package/dist/approval/types.js.map +1 -0
  63. package/dist/cli.d.ts +30 -0
  64. package/dist/cli.d.ts.map +1 -0
  65. package/dist/cli.js +143 -0
  66. package/dist/cli.js.map +1 -0
  67. package/dist/config.d.ts +27 -0
  68. package/dist/config.d.ts.map +1 -0
  69. package/dist/config.js +42 -0
  70. package/dist/config.js.map +1 -0
  71. package/dist/database/connection.d.ts +77 -0
  72. package/dist/database/connection.d.ts.map +1 -0
  73. package/dist/database/connection.js +130 -0
  74. package/dist/database/connection.js.map +1 -0
  75. package/dist/database/index.d.ts +11 -0
  76. package/dist/database/index.d.ts.map +1 -0
  77. package/dist/database/index.js +11 -0
  78. package/dist/database/index.js.map +1 -0
  79. package/dist/database/queries.d.ts +93 -0
  80. package/dist/database/queries.d.ts.map +1 -0
  81. package/dist/database/queries.js +430 -0
  82. package/dist/database/queries.js.map +1 -0
  83. package/dist/database/repository.d.ts +198 -0
  84. package/dist/database/repository.d.ts.map +1 -0
  85. package/dist/database/repository.js +199 -0
  86. package/dist/database/repository.js.map +1 -0
  87. package/dist/graph/attachments.d.ts +72 -0
  88. package/dist/graph/attachments.d.ts.map +1 -0
  89. package/dist/graph/attachments.js +207 -0
  90. package/dist/graph/attachments.js.map +1 -0
  91. package/dist/graph/auth/config.d.ts +34 -0
  92. package/dist/graph/auth/config.d.ts.map +1 -0
  93. package/dist/graph/auth/config.js +78 -0
  94. package/dist/graph/auth/config.js.map +1 -0
  95. package/dist/graph/auth/device-code-flow.d.ts +55 -0
  96. package/dist/graph/auth/device-code-flow.d.ts.map +1 -0
  97. package/dist/graph/auth/device-code-flow.js +180 -0
  98. package/dist/graph/auth/device-code-flow.js.map +1 -0
  99. package/dist/graph/auth/index.d.ts +13 -0
  100. package/dist/graph/auth/index.d.ts.map +1 -0
  101. package/dist/graph/auth/index.js +13 -0
  102. package/dist/graph/auth/index.js.map +1 -0
  103. package/dist/graph/auth/token-cache.d.ts +41 -0
  104. package/dist/graph/auth/token-cache.d.ts.map +1 -0
  105. package/dist/graph/auth/token-cache.js +105 -0
  106. package/dist/graph/auth/token-cache.js.map +1 -0
  107. package/dist/graph/client/batch.d.ts +38 -0
  108. package/dist/graph/client/batch.d.ts.map +1 -0
  109. package/dist/graph/client/batch.js +33 -0
  110. package/dist/graph/client/batch.js.map +1 -0
  111. package/dist/graph/client/cache.d.ts +64 -0
  112. package/dist/graph/client/cache.d.ts.map +1 -0
  113. package/dist/graph/client/cache.js +108 -0
  114. package/dist/graph/client/cache.js.map +1 -0
  115. package/dist/graph/client/graph-client.d.ts +630 -0
  116. package/dist/graph/client/graph-client.d.ts.map +1 -0
  117. package/dist/graph/client/graph-client.js +1771 -0
  118. package/dist/graph/client/graph-client.js.map +1 -0
  119. package/dist/graph/client/index.d.ts +12 -0
  120. package/dist/graph/client/index.d.ts.map +1 -0
  121. package/dist/graph/client/index.js +12 -0
  122. package/dist/graph/client/index.js.map +1 -0
  123. package/dist/graph/content-readers.d.ts +106 -0
  124. package/dist/graph/content-readers.d.ts.map +1 -0
  125. package/dist/graph/content-readers.js +321 -0
  126. package/dist/graph/content-readers.js.map +1 -0
  127. package/dist/graph/index.d.ts +18 -0
  128. package/dist/graph/index.d.ts.map +1 -0
  129. package/dist/graph/index.js +23 -0
  130. package/dist/graph/index.js.map +1 -0
  131. package/dist/graph/mailbox-adapter.d.ts +30 -0
  132. package/dist/graph/mailbox-adapter.d.ts.map +1 -0
  133. package/dist/graph/mailbox-adapter.js +59 -0
  134. package/dist/graph/mailbox-adapter.js.map +1 -0
  135. package/dist/graph/mappers/contact-mapper.d.ts +14 -0
  136. package/dist/graph/mappers/contact-mapper.d.ts.map +1 -0
  137. package/dist/graph/mappers/contact-mapper.js +20 -0
  138. package/dist/graph/mappers/contact-mapper.js.map +1 -0
  139. package/dist/graph/mappers/email-mapper.d.ts +14 -0
  140. package/dist/graph/mappers/email-mapper.d.ts.map +1 -0
  141. package/dist/graph/mappers/email-mapper.js +44 -0
  142. package/dist/graph/mappers/email-mapper.js.map +1 -0
  143. package/dist/graph/mappers/event-mapper.d.ts +14 -0
  144. package/dist/graph/mappers/event-mapper.d.ts.map +1 -0
  145. package/dist/graph/mappers/event-mapper.js +31 -0
  146. package/dist/graph/mappers/event-mapper.js.map +1 -0
  147. package/dist/graph/mappers/folder-mapper.d.ts +22 -0
  148. package/dist/graph/mappers/folder-mapper.d.ts.map +1 -0
  149. package/dist/graph/mappers/folder-mapper.js +51 -0
  150. package/dist/graph/mappers/folder-mapper.js.map +1 -0
  151. package/dist/graph/mappers/index.d.ts +16 -0
  152. package/dist/graph/mappers/index.d.ts.map +1 -0
  153. package/dist/graph/mappers/index.js +16 -0
  154. package/dist/graph/mappers/index.js.map +1 -0
  155. package/dist/graph/mappers/task-mapper.d.ts +20 -0
  156. package/dist/graph/mappers/task-mapper.d.ts.map +1 -0
  157. package/dist/graph/mappers/task-mapper.js +27 -0
  158. package/dist/graph/mappers/task-mapper.js.map +1 -0
  159. package/dist/graph/mappers/utils.d.ts +97 -0
  160. package/dist/graph/mappers/utils.d.ts.map +1 -0
  161. package/dist/graph/mappers/utils.js +186 -0
  162. package/dist/graph/mappers/utils.js.map +1 -0
  163. package/dist/graph/repository.d.ts +1104 -0
  164. package/dist/graph/repository.d.ts.map +1 -0
  165. package/dist/graph/repository.js +2999 -0
  166. package/dist/graph/repository.js.map +1 -0
  167. package/dist/index.d.ts +21 -0
  168. package/dist/index.d.ts.map +1 -0
  169. package/dist/index.js +6052 -0
  170. package/dist/index.js.map +1 -0
  171. package/dist/parsers/html-stripper.d.ts +41 -0
  172. package/dist/parsers/html-stripper.d.ts.map +1 -0
  173. package/dist/parsers/html-stripper.js +179 -0
  174. package/dist/parsers/html-stripper.js.map +1 -0
  175. package/dist/parsers/index.d.ts +12 -0
  176. package/dist/parsers/index.d.ts.map +1 -0
  177. package/dist/parsers/index.js +12 -0
  178. package/dist/parsers/index.js.map +1 -0
  179. package/dist/parsers/olk15.d.ts +87 -0
  180. package/dist/parsers/olk15.d.ts.map +1 -0
  181. package/dist/parsers/olk15.js +368 -0
  182. package/dist/parsers/olk15.js.map +1 -0
  183. package/dist/signature.d.ts +22 -0
  184. package/dist/signature.d.ts.map +1 -0
  185. package/dist/signature.js +89 -0
  186. package/dist/signature.js.map +1 -0
  187. package/dist/tools/calendar-permissions.d.ts +79 -0
  188. package/dist/tools/calendar-permissions.d.ts.map +1 -0
  189. package/dist/tools/calendar-permissions.js +121 -0
  190. package/dist/tools/calendar-permissions.js.map +1 -0
  191. package/dist/tools/calendar.d.ts +208 -0
  192. package/dist/tools/calendar.d.ts.map +1 -0
  193. package/dist/tools/calendar.js +247 -0
  194. package/dist/tools/calendar.js.map +1 -0
  195. package/dist/tools/categories.d.ts +94 -0
  196. package/dist/tools/categories.d.ts.map +1 -0
  197. package/dist/tools/categories.js +117 -0
  198. package/dist/tools/categories.js.map +1 -0
  199. package/dist/tools/checklist-items.d.ts +89 -0
  200. package/dist/tools/checklist-items.d.ts.map +1 -0
  201. package/dist/tools/checklist-items.js +140 -0
  202. package/dist/tools/checklist-items.js.map +1 -0
  203. package/dist/tools/contacts.d.ts +94 -0
  204. package/dist/tools/contacts.d.ts.map +1 -0
  205. package/dist/tools/contacts.js +134 -0
  206. package/dist/tools/contacts.js.map +1 -0
  207. package/dist/tools/excel.d.ts +96 -0
  208. package/dist/tools/excel.d.ts.map +1 -0
  209. package/dist/tools/excel.js +165 -0
  210. package/dist/tools/excel.js.map +1 -0
  211. package/dist/tools/focused-overrides.d.ts +70 -0
  212. package/dist/tools/focused-overrides.d.ts.map +1 -0
  213. package/dist/tools/focused-overrides.js +117 -0
  214. package/dist/tools/focused-overrides.js.map +1 -0
  215. package/dist/tools/index.d.ts +22 -0
  216. package/dist/tools/index.d.ts.map +1 -0
  217. package/dist/tools/index.js +34 -0
  218. package/dist/tools/index.js.map +1 -0
  219. package/dist/tools/linked-resources.d.ts +74 -0
  220. package/dist/tools/linked-resources.d.ts.map +1 -0
  221. package/dist/tools/linked-resources.js +122 -0
  222. package/dist/tools/linked-resources.js.map +1 -0
  223. package/dist/tools/mail-rules.d.ts +98 -0
  224. package/dist/tools/mail-rules.d.ts.map +1 -0
  225. package/dist/tools/mail-rules.js +169 -0
  226. package/dist/tools/mail-rules.js.map +1 -0
  227. package/dist/tools/mail-send.d.ts +314 -0
  228. package/dist/tools/mail-send.d.ts.map +1 -0
  229. package/dist/tools/mail-send.js +555 -0
  230. package/dist/tools/mail-send.js.map +1 -0
  231. package/dist/tools/mail.d.ts +127 -0
  232. package/dist/tools/mail.d.ts.map +1 -0
  233. package/dist/tools/mail.js +311 -0
  234. package/dist/tools/mail.js.map +1 -0
  235. package/dist/tools/mailbox-organization.d.ts +301 -0
  236. package/dist/tools/mailbox-organization.d.ts.map +1 -0
  237. package/dist/tools/mailbox-organization.js +541 -0
  238. package/dist/tools/mailbox-organization.js.map +1 -0
  239. package/dist/tools/meetings.d.ts +114 -0
  240. package/dist/tools/meetings.d.ts.map +1 -0
  241. package/dist/tools/meetings.js +110 -0
  242. package/dist/tools/meetings.js.map +1 -0
  243. package/dist/tools/notes.d.ts +74 -0
  244. package/dist/tools/notes.d.ts.map +1 -0
  245. package/dist/tools/notes.js +136 -0
  246. package/dist/tools/notes.js.map +1 -0
  247. package/dist/tools/onedrive.d.ts +194 -0
  248. package/dist/tools/onedrive.d.ts.map +1 -0
  249. package/dist/tools/onedrive.js +257 -0
  250. package/dist/tools/onedrive.js.map +1 -0
  251. package/dist/tools/people.d.ts +129 -0
  252. package/dist/tools/people.d.ts.map +1 -0
  253. package/dist/tools/people.js +195 -0
  254. package/dist/tools/people.js.map +1 -0
  255. package/dist/tools/planner-visualization.d.ts +91 -0
  256. package/dist/tools/planner-visualization.d.ts.map +1 -0
  257. package/dist/tools/planner-visualization.js +192 -0
  258. package/dist/tools/planner-visualization.js.map +1 -0
  259. package/dist/tools/planner.d.ts +288 -0
  260. package/dist/tools/planner.d.ts.map +1 -0
  261. package/dist/tools/planner.js +368 -0
  262. package/dist/tools/planner.js.map +1 -0
  263. package/dist/tools/scheduling.d.ts +49 -0
  264. package/dist/tools/scheduling.d.ts.map +1 -0
  265. package/dist/tools/scheduling.js +115 -0
  266. package/dist/tools/scheduling.js.map +1 -0
  267. package/dist/tools/sharepoint.d.ts +115 -0
  268. package/dist/tools/sharepoint.d.ts.map +1 -0
  269. package/dist/tools/sharepoint.js +99 -0
  270. package/dist/tools/sharepoint.js.map +1 -0
  271. package/dist/tools/task-attachments.d.ts +74 -0
  272. package/dist/tools/task-attachments.d.ts.map +1 -0
  273. package/dist/tools/task-attachments.js +122 -0
  274. package/dist/tools/task-attachments.js.map +1 -0
  275. package/dist/tools/tasks.d.ts +74 -0
  276. package/dist/tools/tasks.d.ts.map +1 -0
  277. package/dist/tools/tasks.js +126 -0
  278. package/dist/tools/tasks.js.map +1 -0
  279. package/dist/tools/teams.d.ts +389 -0
  280. package/dist/tools/teams.d.ts.map +1 -0
  281. package/dist/tools/teams.js +546 -0
  282. package/dist/tools/teams.js.map +1 -0
  283. package/dist/types/calendar.d.ts +60 -0
  284. package/dist/types/calendar.d.ts.map +1 -0
  285. package/dist/types/calendar.js +15 -0
  286. package/dist/types/calendar.js.map +1 -0
  287. package/dist/types/contacts.d.ts +96 -0
  288. package/dist/types/contacts.d.ts.map +1 -0
  289. package/dist/types/contacts.js +41 -0
  290. package/dist/types/contacts.js.map +1 -0
  291. package/dist/types/index.d.ts +15 -0
  292. package/dist/types/index.d.ts.map +1 -0
  293. package/dist/types/index.js +16 -0
  294. package/dist/types/index.js.map +1 -0
  295. package/dist/types/mail.d.ts +108 -0
  296. package/dist/types/mail.d.ts.map +1 -0
  297. package/dist/types/mail.js +40 -0
  298. package/dist/types/mail.js.map +1 -0
  299. package/dist/types/notes.d.ts +26 -0
  300. package/dist/types/notes.d.ts.map +1 -0
  301. package/dist/types/notes.js +6 -0
  302. package/dist/types/notes.js.map +1 -0
  303. package/dist/types/tasks.d.ts +31 -0
  304. package/dist/types/tasks.d.ts.map +1 -0
  305. package/dist/types/tasks.js +6 -0
  306. package/dist/types/tasks.js.map +1 -0
  307. package/dist/utils/dates.d.ts +66 -0
  308. package/dist/utils/dates.d.ts.map +1 -0
  309. package/dist/utils/dates.js +94 -0
  310. package/dist/utils/dates.js.map +1 -0
  311. package/dist/utils/errors.d.ts +218 -0
  312. package/dist/utils/errors.d.ts.map +1 -0
  313. package/dist/utils/errors.js +306 -0
  314. package/dist/utils/errors.js.map +1 -0
  315. package/dist/utils/index.d.ts +10 -0
  316. package/dist/utils/index.d.ts.map +1 -0
  317. package/dist/utils/index.js +10 -0
  318. package/dist/utils/index.js.map +1 -0
  319. package/dist/visualization/html.d.ts +26 -0
  320. package/dist/visualization/html.d.ts.map +1 -0
  321. package/dist/visualization/html.js +306 -0
  322. package/dist/visualization/html.js.map +1 -0
  323. package/dist/visualization/markdown.d.ts +25 -0
  324. package/dist/visualization/markdown.d.ts.map +1 -0
  325. package/dist/visualization/markdown.js +186 -0
  326. package/dist/visualization/markdown.js.map +1 -0
  327. package/dist/visualization/mermaid.d.ts +25 -0
  328. package/dist/visualization/mermaid.d.ts.map +1 -0
  329. package/dist/visualization/mermaid.js +158 -0
  330. package/dist/visualization/mermaid.js.map +1 -0
  331. package/dist/visualization/svg.d.ts +25 -0
  332. package/dist/visualization/svg.d.ts.map +1 -0
  333. package/dist/visualization/svg.js +282 -0
  334. package/dist/visualization/svg.js.map +1 -0
  335. package/dist/visualization/types.d.ts +43 -0
  336. package/dist/visualization/types.d.ts.map +1 -0
  337. package/dist/visualization/types.js +34 -0
  338. package/dist/visualization/types.js.map +1 -0
  339. package/package.json +88 -0
@@ -0,0 +1,1771 @@
1
+ /**
2
+ * Copyright (c) 2026 JBC Tech Solutions, LLC
3
+ * Licensed under the MIT License. See LICENSE file in the project root.
4
+ */
5
+ /**
6
+ * Microsoft Graph API client wrapper.
7
+ *
8
+ * Provides a typed interface to the Graph API with:
9
+ * - Automatic token management
10
+ * - Response caching
11
+ * - Pagination support
12
+ * - Error handling
13
+ */
14
+ import 'isomorphic-fetch';
15
+ import { Client } from '@microsoft/microsoft-graph-client';
16
+ import { getAccessToken } from '../auth/index.js';
17
+ import { buildBatchPayload, splitIntoBatches, parseBatchResponse } from './batch.js';
18
+ import { ResponseCache, CacheTTL, createCacheKey } from './cache.js';
19
+ /**
20
+ * Graph client wrapper with caching and token management.
21
+ */
22
+ export class GraphClient {
23
+ client = null;
24
+ cache = new ResponseCache();
25
+ deviceCodeCallback;
26
+ constructor(deviceCodeCallback) {
27
+ this.deviceCodeCallback = deviceCodeCallback;
28
+ }
29
+ /**
30
+ * Gets or creates the Graph client instance.
31
+ */
32
+ // eslint-disable-next-line @typescript-eslint/require-await
33
+ async getClient() {
34
+ if (this.client == null) {
35
+ this.client = Client.init({
36
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
37
+ authProvider: async (done) => {
38
+ try {
39
+ const token = await getAccessToken(this.deviceCodeCallback);
40
+ done(null, token);
41
+ }
42
+ catch (error) {
43
+ done(error, null);
44
+ }
45
+ },
46
+ });
47
+ }
48
+ return this.client;
49
+ }
50
+ /**
51
+ * Clears the response cache.
52
+ */
53
+ clearCache() {
54
+ this.cache.clear();
55
+ }
56
+ // ===========================================================================
57
+ // Mail Folders
58
+ // ===========================================================================
59
+ /**
60
+ * Lists all mail folders.
61
+ */
62
+ async listMailFolders() {
63
+ const cacheKey = createCacheKey('listMailFolders');
64
+ const cached = this.cache.get(cacheKey);
65
+ if (cached != null) {
66
+ return cached;
67
+ }
68
+ const client = await this.getClient();
69
+ const result = [];
70
+ // Get top-level folders with pagination
71
+ let response = await client
72
+ .api('/me/mailFolders')
73
+ .select('id,displayName,parentFolderId,totalItemCount,unreadItemCount')
74
+ .top(100)
75
+ .get();
76
+ result.push(...response.value);
77
+ // Handle pagination
78
+ while (response['@odata.nextLink'] != null) {
79
+ response = await client.api(response['@odata.nextLink']).get();
80
+ result.push(...response.value);
81
+ }
82
+ // Also get child folders (one level deep)
83
+ for (const folder of [...result]) {
84
+ try {
85
+ const children = await client
86
+ .api(`/me/mailFolders/${folder.id}/childFolders`)
87
+ .select('id,displayName,parentFolderId,totalItemCount,unreadItemCount')
88
+ .get();
89
+ result.push(...children.value);
90
+ }
91
+ catch {
92
+ // Some folders may not have children or may not be accessible
93
+ }
94
+ }
95
+ this.cache.set(cacheKey, result, CacheTTL.FOLDERS);
96
+ return result;
97
+ }
98
+ /**
99
+ * Gets a specific mail folder by ID.
100
+ */
101
+ async getMailFolder(folderId) {
102
+ const client = await this.getClient();
103
+ try {
104
+ return await client
105
+ .api(`/me/mailFolders/${folderId}`)
106
+ .select('id,displayName,parentFolderId,totalItemCount,unreadItemCount')
107
+ .get();
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ // ===========================================================================
114
+ // Messages (Emails)
115
+ // ===========================================================================
116
+ /**
117
+ * Lists messages in a folder with pagination.
118
+ */
119
+ async listMessages(folderId, limit = 50, skip = 0) {
120
+ const cacheKey = createCacheKey('listMessages', folderId, limit, skip);
121
+ const cached = this.cache.get(cacheKey);
122
+ if (cached != null) {
123
+ return cached;
124
+ }
125
+ const client = await this.getClient();
126
+ const response = await client
127
+ .api(`/me/mailFolders/${folderId}/messages`)
128
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId')
129
+ .orderby('receivedDateTime desc')
130
+ .top(limit)
131
+ .skip(skip)
132
+ .get();
133
+ const result = response.value;
134
+ this.cache.set(cacheKey, result, CacheTTL.EMAILS);
135
+ return result;
136
+ }
137
+ /**
138
+ * Lists unread messages in a folder.
139
+ */
140
+ async listUnreadMessages(folderId, limit = 50, skip = 0) {
141
+ const client = await this.getClient();
142
+ const response = await client
143
+ .api(`/me/mailFolders/${folderId}/messages`)
144
+ .filter('isRead eq false')
145
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId')
146
+ .orderby('receivedDateTime desc')
147
+ .top(limit)
148
+ .skip(skip)
149
+ .get();
150
+ return response.value;
151
+ }
152
+ /**
153
+ * Searches messages across all folders.
154
+ */
155
+ async searchMessages(query, limit = 50) {
156
+ const client = await this.getClient();
157
+ const response = await client
158
+ .api('/me/messages')
159
+ .search(`"${query}"`)
160
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId,parentFolderId')
161
+ .top(limit)
162
+ .get();
163
+ return response.value;
164
+ }
165
+ /**
166
+ * Searches messages in a specific folder.
167
+ */
168
+ async searchMessagesInFolder(folderId, query, limit = 50) {
169
+ const client = await this.getClient();
170
+ const response = await client
171
+ .api(`/me/mailFolders/${folderId}/messages`)
172
+ .search(`"${query}"`)
173
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId')
174
+ .top(limit)
175
+ .get();
176
+ return response.value;
177
+ }
178
+ /**
179
+ * Searches messages using raw KQL (Keyword Query Language).
180
+ * Unlike searchMessages, the query is passed directly without quote-wrapping,
181
+ * enabling KQL operators like from:, subject:, hasAttachments:, received>=, AND, OR.
182
+ */
183
+ async searchMessagesKql(query, limit = 50) {
184
+ const client = await this.getClient();
185
+ const response = await client
186
+ .api('/me/messages')
187
+ .search(query)
188
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId,parentFolderId')
189
+ .top(limit)
190
+ .get();
191
+ return response.value;
192
+ }
193
+ /**
194
+ * Searches messages in a specific folder using raw KQL.
195
+ */
196
+ async searchMessagesKqlInFolder(folderId, query, limit = 50) {
197
+ const client = await this.getClient();
198
+ const response = await client
199
+ .api(`/me/mailFolders/${folderId}/messages`)
200
+ .search(query)
201
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId,parentFolderId')
202
+ .top(limit)
203
+ .get();
204
+ return response.value;
205
+ }
206
+ /**
207
+ * Lists messages in a conversation by conversationId.
208
+ */
209
+ async listConversationMessages(conversationId, limit = 50) {
210
+ const client = await this.getClient();
211
+ const response = await client
212
+ .api('/me/messages')
213
+ .filter(`conversationId eq '${conversationId}'`)
214
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId,parentFolderId')
215
+ .orderby('receivedDateTime asc')
216
+ .top(limit)
217
+ .get();
218
+ return response.value;
219
+ }
220
+ /**
221
+ * Gets a specific message with full body.
222
+ */
223
+ async getMessage(messageId) {
224
+ const client = await this.getClient();
225
+ try {
226
+ return await client
227
+ .api(`/me/messages/${messageId}`)
228
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,body,bodyPreview,conversationId,internetMessageId,parentFolderId')
229
+ .get();
230
+ }
231
+ catch {
232
+ return null;
233
+ }
234
+ }
235
+ /**
236
+ * Gets message delta for incremental sync.
237
+ */
238
+ async getMessagesDelta(folderId, deltaLink) {
239
+ const client = await this.getClient();
240
+ let response;
241
+ if (deltaLink != null) {
242
+ response = await client.api(deltaLink).get();
243
+ }
244
+ else {
245
+ response = await client
246
+ .api(`/me/mailFolders/${folderId}/messages/delta`)
247
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId,parentFolderId')
248
+ .top(50)
249
+ .get();
250
+ }
251
+ const messages = [...(response.value ?? [])];
252
+ let nextLink = response['@odata.nextLink'];
253
+ while (nextLink != null) {
254
+ const nextPage = await client.api(nextLink).get();
255
+ messages.push(...(nextPage.value ?? []));
256
+ nextLink = nextPage['@odata.nextLink'];
257
+ }
258
+ const newDeltaLink = response['@odata.deltaLink'] ?? '';
259
+ return { messages, deltaLink: newDeltaLink };
260
+ }
261
+ // ===========================================================================
262
+ // Mail Rules
263
+ // ===========================================================================
264
+ /**
265
+ * Lists all inbox mail rules.
266
+ */
267
+ async listMailRules() {
268
+ const client = await this.getClient();
269
+ const response = await client
270
+ .api('/me/mailFolders/inbox/messageRules')
271
+ .get();
272
+ return response.value;
273
+ }
274
+ /**
275
+ * Creates a new inbox mail rule.
276
+ */
277
+ async createMailRule(rule) {
278
+ const client = await this.getClient();
279
+ const result = await client
280
+ .api('/me/mailFolders/inbox/messageRules')
281
+ .post(rule);
282
+ this.cache.clear();
283
+ return result;
284
+ }
285
+ /**
286
+ * Deletes an inbox mail rule.
287
+ */
288
+ async deleteMailRule(ruleId) {
289
+ const client = await this.getClient();
290
+ await client
291
+ .api(`/me/mailFolders/inbox/messageRules/${ruleId}`)
292
+ .delete();
293
+ this.cache.clear();
294
+ }
295
+ // ===========================================================================
296
+ // Automatic Replies (Out of Office)
297
+ // ===========================================================================
298
+ /**
299
+ * Gets the automatic replies (OOF) settings.
300
+ */
301
+ async getAutomaticReplies() {
302
+ const client = await this.getClient();
303
+ return await client.api('/me/mailboxSettings/automaticRepliesSetting').get();
304
+ }
305
+ /**
306
+ * Sets the automatic replies (OOF) settings.
307
+ */
308
+ async setAutomaticReplies(settings) {
309
+ const client = await this.getClient();
310
+ await client.api('/me/mailboxSettings').patch({ automaticRepliesSetting: settings });
311
+ }
312
+ // ===========================================================================
313
+ // Mailbox Settings
314
+ // ===========================================================================
315
+ /**
316
+ * Gets the full mailbox settings for the current user.
317
+ */
318
+ async getMailboxSettings() {
319
+ const client = await this.getClient();
320
+ return await client.api('/me/mailboxSettings').get();
321
+ }
322
+ /**
323
+ * Updates mailbox settings for the current user.
324
+ */
325
+ async updateMailboxSettings(settings) {
326
+ const client = await this.getClient();
327
+ await client.api('/me/mailboxSettings').patch(settings);
328
+ }
329
+ // ===========================================================================
330
+ // Calendars
331
+ // ===========================================================================
332
+ /**
333
+ * Lists all calendars.
334
+ */
335
+ async listCalendars() {
336
+ const cacheKey = createCacheKey('listCalendars');
337
+ const cached = this.cache.get(cacheKey);
338
+ if (cached != null) {
339
+ return cached;
340
+ }
341
+ const client = await this.getClient();
342
+ const response = await client
343
+ .api('/me/calendars')
344
+ .select('id,name,color,isDefaultCalendar,canEdit')
345
+ .get();
346
+ const result = response.value;
347
+ this.cache.set(cacheKey, result, CacheTTL.FOLDERS);
348
+ return result;
349
+ }
350
+ // ===========================================================================
351
+ // Events
352
+ // ===========================================================================
353
+ /**
354
+ * Lists events with optional date range.
355
+ */
356
+ async listEvents(limit = 50, calendarId, startDate, endDate) {
357
+ const client = await this.getClient();
358
+ // If date range provided, use calendarView
359
+ if (startDate != null && endDate != null) {
360
+ const baseUrl = calendarId != null
361
+ ? `/me/calendars/${calendarId}/calendarView`
362
+ : '/me/calendarView';
363
+ const response = await client
364
+ .api(baseUrl)
365
+ .query({
366
+ startDateTime: startDate.toISOString(),
367
+ endDateTime: endDate.toISOString(),
368
+ })
369
+ .select('id,subject,start,end,location,isAllDay,organizer,attendees,body,recurrence,iCalUId')
370
+ .orderby('start/dateTime')
371
+ .top(limit)
372
+ .get();
373
+ return response.value;
374
+ }
375
+ // Otherwise, get upcoming events
376
+ const baseUrl = calendarId != null
377
+ ? `/me/calendars/${calendarId}/events`
378
+ : '/me/events';
379
+ const response = await client
380
+ .api(baseUrl)
381
+ .select('id,subject,start,end,location,isAllDay,organizer,attendees,body,recurrence,iCalUId')
382
+ .orderby('start/dateTime')
383
+ .top(limit)
384
+ .get();
385
+ return response.value;
386
+ }
387
+ /**
388
+ * Gets a specific event.
389
+ */
390
+ async getEvent(eventId) {
391
+ const client = await this.getClient();
392
+ try {
393
+ return await client
394
+ .api(`/me/events/${eventId}`)
395
+ .select('id,subject,start,end,location,isAllDay,organizer,attendees,body,recurrence,iCalUId')
396
+ .get();
397
+ }
398
+ catch {
399
+ return null;
400
+ }
401
+ }
402
+ /**
403
+ * Lists instances of a recurring event within a date range.
404
+ */
405
+ async listEventInstances(eventId, startDateTime, endDateTime) {
406
+ const client = await this.getClient();
407
+ const response = await client
408
+ .api(`/me/events/${eventId}/instances`)
409
+ .query({ startDateTime, endDateTime })
410
+ .select('id,subject,start,end,location,isAllDay,isCancelled,organizer,recurrence,bodyPreview')
411
+ .get();
412
+ return response.value;
413
+ }
414
+ // ===========================================================================
415
+ // Calendar Write Operations
416
+ // ===========================================================================
417
+ /**
418
+ * Creates a new calendar event.
419
+ */
420
+ async createEvent(event, calendarId) {
421
+ const client = await this.getClient();
422
+ const url = calendarId != null
423
+ ? `/me/calendars/${calendarId}/events`
424
+ : '/me/events';
425
+ const result = await client
426
+ .api(url)
427
+ .post(event);
428
+ this.cache.clear();
429
+ return result;
430
+ }
431
+ /**
432
+ * Updates an existing calendar event.
433
+ */
434
+ async updateEvent(eventId, updates) {
435
+ const client = await this.getClient();
436
+ await client
437
+ .api(`/me/events/${eventId}`)
438
+ .patch(updates);
439
+ this.cache.clear();
440
+ }
441
+ /**
442
+ * Deletes a calendar event.
443
+ */
444
+ async deleteEvent(eventId) {
445
+ const client = await this.getClient();
446
+ await client
447
+ .api(`/me/events/${eventId}`)
448
+ .delete();
449
+ this.cache.clear();
450
+ }
451
+ /**
452
+ * Responds to a calendar event invitation.
453
+ */
454
+ async respondToEvent(eventId, response, sendResponse, comment) {
455
+ const client = await this.getClient();
456
+ const actionMap = {
457
+ accept: 'accept',
458
+ decline: 'decline',
459
+ tentative: 'tentativelyAccept',
460
+ };
461
+ const action = actionMap[response];
462
+ await client
463
+ .api(`/me/events/${eventId}/${action}`)
464
+ .post({ sendResponse, comment: comment ?? '' });
465
+ this.cache.clear();
466
+ }
467
+ // ===========================================================================
468
+ // Contacts
469
+ // ===========================================================================
470
+ /**
471
+ * Lists contacts with pagination.
472
+ */
473
+ async listContacts(limit = 50, skip = 0) {
474
+ const cacheKey = createCacheKey('listContacts', limit, skip);
475
+ const cached = this.cache.get(cacheKey);
476
+ if (cached != null) {
477
+ return cached;
478
+ }
479
+ const client = await this.getClient();
480
+ const response = await client
481
+ .api('/me/contacts')
482
+ .select('id,displayName,givenName,surname,middleName,nickName,companyName,jobTitle,department,emailAddresses,homePhones,businessPhones,mobilePhone,homeAddress,businessAddress,personalNotes')
483
+ .orderby('displayName')
484
+ .top(limit)
485
+ .skip(skip)
486
+ .get();
487
+ const result = response.value;
488
+ this.cache.set(cacheKey, result, CacheTTL.CONTACTS);
489
+ return result;
490
+ }
491
+ /**
492
+ * Searches contacts by display name.
493
+ */
494
+ async searchContacts(query, limit = 50) {
495
+ const client = await this.getClient();
496
+ const response = await client
497
+ .api('/me/contacts')
498
+ .filter(`contains(displayName,'${query}')`)
499
+ .select('id,displayName,givenName,surname,middleName,nickName,companyName,jobTitle,department,emailAddresses,homePhones,businessPhones,mobilePhone,homeAddress,businessAddress,personalNotes')
500
+ .top(limit)
501
+ .get();
502
+ return response.value;
503
+ }
504
+ /**
505
+ * Gets a specific contact.
506
+ */
507
+ async getContact(contactId) {
508
+ const client = await this.getClient();
509
+ try {
510
+ return await client
511
+ .api(`/me/contacts/${contactId}`)
512
+ .select('id,displayName,givenName,surname,middleName,nickName,companyName,jobTitle,department,emailAddresses,homePhones,businessPhones,mobilePhone,homeAddress,businessAddress,personalNotes')
513
+ .get();
514
+ }
515
+ catch {
516
+ return null;
517
+ }
518
+ }
519
+ // ===========================================================================
520
+ // Contact Write Operations
521
+ // ===========================================================================
522
+ /**
523
+ * Creates a new contact.
524
+ */
525
+ async createContact(contact) {
526
+ const client = await this.getClient();
527
+ const result = await client
528
+ .api('/me/contacts')
529
+ .post(contact);
530
+ this.cache.clear();
531
+ return result;
532
+ }
533
+ /**
534
+ * Updates an existing contact.
535
+ */
536
+ async updateContact(contactId, updates) {
537
+ const client = await this.getClient();
538
+ await client
539
+ .api(`/me/contacts/${contactId}`)
540
+ .patch(updates);
541
+ this.cache.clear();
542
+ }
543
+ /**
544
+ * Deletes a contact.
545
+ */
546
+ async deleteContact(contactId) {
547
+ const client = await this.getClient();
548
+ await client
549
+ .api(`/me/contacts/${contactId}`)
550
+ .delete();
551
+ this.cache.clear();
552
+ }
553
+ // ===========================================================================
554
+ // Contact Photos
555
+ // ===========================================================================
556
+ /**
557
+ * Gets the photo for a contact as raw binary data.
558
+ */
559
+ async getContactPhoto(contactId) {
560
+ const client = await this.getClient();
561
+ return await client
562
+ .api(`/me/contacts/${contactId}/photo/$value`)
563
+ .get();
564
+ }
565
+ /**
566
+ * Sets or updates the photo for a contact.
567
+ */
568
+ async setContactPhoto(contactId, photoData, contentType) {
569
+ const client = await this.getClient();
570
+ await client
571
+ .api(`/me/contacts/${contactId}/photo/$value`)
572
+ .header('Content-Type', contentType)
573
+ .put(photoData);
574
+ this.cache.clear();
575
+ }
576
+ // ===========================================================================
577
+ // Contact Folders
578
+ // ===========================================================================
579
+ /**
580
+ * Lists all contact folders.
581
+ */
582
+ async listContactFolders() {
583
+ const client = await this.getClient();
584
+ const response = await client.api('/me/contactFolders').get();
585
+ return response.value;
586
+ }
587
+ /**
588
+ * Creates a new contact folder.
589
+ */
590
+ async createContactFolder(displayName) {
591
+ const client = await this.getClient();
592
+ const result = await client.api('/me/contactFolders').post({ displayName });
593
+ this.cache.clear();
594
+ return result;
595
+ }
596
+ /**
597
+ * Deletes a contact folder.
598
+ */
599
+ async deleteContactFolder(folderId) {
600
+ const client = await this.getClient();
601
+ await client.api(`/me/contactFolders/${folderId}`).delete();
602
+ this.cache.clear();
603
+ }
604
+ /**
605
+ * Lists contacts in a specific contact folder.
606
+ */
607
+ async listContactsInFolder(folderId, limit = 100) {
608
+ const client = await this.getClient();
609
+ const response = await client
610
+ .api(`/me/contactFolders/${folderId}/contacts`)
611
+ .select('id,displayName,givenName,surname,emailAddresses,businessPhones,mobilePhone,jobTitle,companyName')
612
+ .top(limit)
613
+ .get();
614
+ return response.value;
615
+ }
616
+ // ===========================================================================
617
+ // Tasks (Microsoft To Do)
618
+ // ===========================================================================
619
+ /**
620
+ * Lists task lists.
621
+ */
622
+ async listTaskLists() {
623
+ const cacheKey = createCacheKey('listTaskLists');
624
+ const cached = this.cache.get(cacheKey);
625
+ if (cached != null) {
626
+ return cached;
627
+ }
628
+ const client = await this.getClient();
629
+ const response = await client
630
+ .api('/me/todo/lists')
631
+ .select('id,displayName,isOwner,isShared,wellknownListName')
632
+ .get();
633
+ const result = response.value;
634
+ this.cache.set(cacheKey, result, CacheTTL.FOLDERS);
635
+ return result;
636
+ }
637
+ /**
638
+ * Lists tasks in a task list.
639
+ */
640
+ async listTasks(taskListId, limit = 50, skip = 0, includeCompleted = true) {
641
+ const client = await this.getClient();
642
+ let api = client
643
+ .api(`/me/todo/lists/${taskListId}/tasks`)
644
+ .select('id,title,status,importance,dueDateTime,completedDateTime,body,createdDateTime,lastModifiedDateTime,isReminderOn,reminderDateTime')
645
+ .top(limit)
646
+ .skip(skip);
647
+ if (!includeCompleted) {
648
+ api = api.filter("status ne 'completed'");
649
+ }
650
+ const response = await api.get();
651
+ return response.value;
652
+ }
653
+ /**
654
+ * Lists all tasks across all task lists.
655
+ */
656
+ async listAllTasks(limit = 50, skip = 0, includeCompleted = true) {
657
+ const taskLists = await this.listTaskLists();
658
+ const allTasks = [];
659
+ for (const list of taskLists) {
660
+ if (list.id == null)
661
+ continue;
662
+ const tasks = await this.listTasks(list.id, 100, 0, includeCompleted);
663
+ for (const task of tasks) {
664
+ allTasks.push({ ...task, taskListId: list.id });
665
+ }
666
+ }
667
+ // Sort by due date, then slice for pagination
668
+ allTasks.sort((a, b) => {
669
+ if (a.dueDateTime == null && b.dueDateTime == null)
670
+ return 0;
671
+ if (a.dueDateTime == null)
672
+ return 1;
673
+ if (b.dueDateTime == null)
674
+ return -1;
675
+ return new Date(a.dueDateTime.dateTime ?? '').getTime() - new Date(b.dueDateTime.dateTime ?? '').getTime();
676
+ });
677
+ return allTasks.slice(skip, skip + limit);
678
+ }
679
+ /**
680
+ * Gets a specific task.
681
+ */
682
+ async getTask(taskListId, taskId) {
683
+ const client = await this.getClient();
684
+ try {
685
+ return await client
686
+ .api(`/me/todo/lists/${taskListId}/tasks/${taskId}`)
687
+ .select('id,title,status,importance,dueDateTime,completedDateTime,body,createdDateTime,lastModifiedDateTime,isReminderOn,reminderDateTime')
688
+ .get();
689
+ }
690
+ catch {
691
+ return null;
692
+ }
693
+ }
694
+ // ===========================================================================
695
+ // Write Operations
696
+ // ===========================================================================
697
+ /**
698
+ * Moves a message to a different folder.
699
+ */
700
+ async moveMessage(messageId, destinationFolderId) {
701
+ const client = await this.getClient();
702
+ await client
703
+ .api(`/me/messages/${messageId}/move`)
704
+ .post({ destinationId: destinationFolderId });
705
+ this.cache.clear(); // Invalidate cache after mutation
706
+ }
707
+ /**
708
+ * Deletes a message (moves to Deleted Items).
709
+ */
710
+ async deleteMessage(messageId) {
711
+ const client = await this.getClient();
712
+ // Move to deletedItems well-known folder
713
+ await client
714
+ .api(`/me/messages/${messageId}/move`)
715
+ .post({ destinationId: 'deleteditems' });
716
+ this.cache.clear();
717
+ }
718
+ /**
719
+ * Archives a message (moves to Archive folder).
720
+ */
721
+ async archiveMessage(messageId) {
722
+ const client = await this.getClient();
723
+ await client
724
+ .api(`/me/messages/${messageId}/move`)
725
+ .post({ destinationId: 'archive' });
726
+ this.cache.clear();
727
+ }
728
+ /**
729
+ * Moves a message to the Junk folder.
730
+ */
731
+ async junkMessage(messageId) {
732
+ const client = await this.getClient();
733
+ await client
734
+ .api(`/me/messages/${messageId}/move`)
735
+ .post({ destinationId: 'junkemail' });
736
+ this.cache.clear();
737
+ }
738
+ /**
739
+ * Updates message properties (read status, flag, categories).
740
+ */
741
+ async updateMessage(messageId, updates) {
742
+ const client = await this.getClient();
743
+ await client
744
+ .api(`/me/messages/${messageId}`)
745
+ .patch(updates);
746
+ this.cache.clear();
747
+ }
748
+ /**
749
+ * Creates a new mail folder.
750
+ */
751
+ async createMailFolder(displayName, parentFolderId) {
752
+ const client = await this.getClient();
753
+ const url = parentFolderId != null
754
+ ? `/me/mailFolders/${parentFolderId}/childFolders`
755
+ : '/me/mailFolders';
756
+ const result = await client
757
+ .api(url)
758
+ .post({ displayName });
759
+ this.cache.clear();
760
+ return result;
761
+ }
762
+ /**
763
+ * Deletes a mail folder.
764
+ */
765
+ async deleteMailFolder(folderId) {
766
+ const client = await this.getClient();
767
+ await client
768
+ .api(`/me/mailFolders/${folderId}`)
769
+ .delete();
770
+ this.cache.clear();
771
+ }
772
+ /**
773
+ * Renames a mail folder.
774
+ */
775
+ async renameMailFolder(folderId, newName) {
776
+ const client = await this.getClient();
777
+ await client
778
+ .api(`/me/mailFolders/${folderId}`)
779
+ .patch({ displayName: newName });
780
+ this.cache.clear();
781
+ }
782
+ /**
783
+ * Moves a mail folder to a new parent.
784
+ */
785
+ async moveMailFolder(folderId, destinationParentId) {
786
+ const client = await this.getClient();
787
+ await client
788
+ .api(`/me/mailFolders/${folderId}/move`)
789
+ .post({ destinationId: destinationParentId });
790
+ this.cache.clear();
791
+ }
792
+ /**
793
+ * Deletes all messages in a folder.
794
+ */
795
+ async emptyMailFolder(folderId) {
796
+ const client = await this.getClient();
797
+ // Get all messages in the folder
798
+ let response = await client
799
+ .api(`/me/mailFolders/${folderId}/messages`)
800
+ .select('id')
801
+ .top(100)
802
+ .get();
803
+ // Delete each message
804
+ for (const message of response.value) {
805
+ if (message.id != null) {
806
+ await client
807
+ .api(`/me/messages/${message.id}/move`)
808
+ .post({ destinationId: 'deleteditems' });
809
+ }
810
+ }
811
+ // Handle pagination
812
+ while (response['@odata.nextLink'] != null) {
813
+ response = await client.api(response['@odata.nextLink']).get();
814
+ for (const message of response.value) {
815
+ if (message.id != null) {
816
+ await client
817
+ .api(`/me/messages/${message.id}/move`)
818
+ .post({ destinationId: 'deleteditems' });
819
+ }
820
+ }
821
+ }
822
+ this.cache.clear();
823
+ }
824
+ // ===========================================================================
825
+ // Draft & Send Operations
826
+ // ===========================================================================
827
+ /**
828
+ * Creates a new draft message.
829
+ */
830
+ async createDraft(message) {
831
+ const client = await this.getClient();
832
+ const result = await client
833
+ .api('/me/messages')
834
+ .post(message);
835
+ this.cache.clear();
836
+ return result;
837
+ }
838
+ /**
839
+ * Updates an existing draft message.
840
+ */
841
+ async updateDraft(messageId, updates) {
842
+ const client = await this.getClient();
843
+ const result = await client
844
+ .api(`/me/messages/${messageId}`)
845
+ .patch(updates);
846
+ this.cache.clear();
847
+ return result;
848
+ }
849
+ /**
850
+ * Sends an existing draft message.
851
+ */
852
+ async sendDraft(messageId) {
853
+ const client = await this.getClient();
854
+ await client
855
+ .api(`/me/messages/${messageId}/send`)
856
+ .post(null);
857
+ this.cache.clear();
858
+ }
859
+ /**
860
+ * Sends a new email directly without creating a draft.
861
+ */
862
+ async sendMail(message) {
863
+ const client = await this.getClient();
864
+ await client
865
+ .api('/me/sendMail')
866
+ .post({ message });
867
+ this.cache.clear();
868
+ }
869
+ /**
870
+ * Replies to a message, or replies to all recipients.
871
+ */
872
+ async replyMessage(messageId, comment, replyAll) {
873
+ const client = await this.getClient();
874
+ const action = replyAll ? 'replyAll' : 'reply';
875
+ await client
876
+ .api(`/me/messages/${messageId}/${action}`)
877
+ .post({ comment });
878
+ this.cache.clear();
879
+ }
880
+ /**
881
+ * Forwards a message to specified recipients.
882
+ */
883
+ async forwardMessage(messageId, toRecipients, comment) {
884
+ const client = await this.getClient();
885
+ const body = { toRecipients };
886
+ if (comment != null) {
887
+ body.comment = comment;
888
+ }
889
+ await client
890
+ .api(`/me/messages/${messageId}/forward`)
891
+ .post(body);
892
+ this.cache.clear();
893
+ }
894
+ /**
895
+ * Creates a reply draft for a message.
896
+ */
897
+ async createReplyDraft(messageId) {
898
+ const client = await this.getClient();
899
+ const result = await client
900
+ .api(`/me/messages/${messageId}/createReply`)
901
+ .post(null);
902
+ this.cache.clear();
903
+ return result;
904
+ }
905
+ /**
906
+ * Creates a reply-all draft for a message.
907
+ */
908
+ async createReplyAllDraft(messageId) {
909
+ const client = await this.getClient();
910
+ const result = await client
911
+ .api(`/me/messages/${messageId}/createReplyAll`)
912
+ .post(null);
913
+ this.cache.clear();
914
+ return result;
915
+ }
916
+ /**
917
+ * Creates a forward draft for a message.
918
+ */
919
+ async createForwardDraft(messageId) {
920
+ const client = await this.getClient();
921
+ const result = await client
922
+ .api(`/me/messages/${messageId}/createForward`)
923
+ .post(null);
924
+ this.cache.clear();
925
+ return result;
926
+ }
927
+ // ---------------------------------------------------------------------------
928
+ // Calendar Scheduling
929
+ // ---------------------------------------------------------------------------
930
+ /**
931
+ * Gets the free/busy schedule for one or more people.
932
+ * POST /me/calendar/getSchedule
933
+ */
934
+ async getSchedule(params) {
935
+ const client = await this.getClient();
936
+ const response = await client.api('/me/calendar/getSchedule').post(params);
937
+ return response.value;
938
+ }
939
+ /**
940
+ * Suggests meeting times for a set of attendees.
941
+ * POST /me/findMeetingTimes
942
+ */
943
+ async findMeetingTimes(params) {
944
+ const client = await this.getClient();
945
+ return (await client.api('/me/findMeetingTimes').post(params));
946
+ }
947
+ // ===========================================================================
948
+ // Attachment Operations
949
+ // ===========================================================================
950
+ /**
951
+ * Lists attachments on a message.
952
+ */
953
+ async listAttachments(messageId) {
954
+ const client = await this.getClient();
955
+ const response = await client
956
+ .api(`/me/messages/${messageId}/attachments`)
957
+ .select('id,name,size,contentType,isInline')
958
+ .get();
959
+ return response.value;
960
+ }
961
+ /**
962
+ * Gets a specific attachment with full content (including contentBytes).
963
+ */
964
+ async getAttachment(messageId, attachmentId) {
965
+ const client = await this.getClient();
966
+ return await client
967
+ .api(`/me/messages/${messageId}/attachments/${attachmentId}`)
968
+ .get();
969
+ }
970
+ /**
971
+ * Adds an inline base64 attachment to a message (<= 3MB).
972
+ */
973
+ async addAttachment(messageId, attachment) {
974
+ const client = await this.getClient();
975
+ const result = await client
976
+ .api(`/me/messages/${messageId}/attachments`)
977
+ .post(attachment);
978
+ this.cache.clear();
979
+ return result;
980
+ }
981
+ /**
982
+ * Creates an upload session for large file attachments (> 3MB).
983
+ */
984
+ async createUploadSession(messageId, body) {
985
+ const client = await this.getClient();
986
+ return await client
987
+ .api(`/me/messages/${messageId}/attachments/createUploadSession`)
988
+ .post(body);
989
+ }
990
+ // ===========================================================================
991
+ // Tasks (Microsoft To Do) - continued
992
+ // ===========================================================================
993
+ /**
994
+ * Searches tasks by title.
995
+ */
996
+ async searchTasks(query, limit = 50) {
997
+ const allTasks = await this.listAllTasks(1000, 0, true);
998
+ const queryLower = query.toLowerCase();
999
+ const matched = allTasks.filter((task) => task.title?.toLowerCase().includes(queryLower) ?? false);
1000
+ return matched.slice(0, limit);
1001
+ }
1002
+ // ===========================================================================
1003
+ // Task Write Operations
1004
+ // ===========================================================================
1005
+ /**
1006
+ * Creates a new task in a task list.
1007
+ */
1008
+ async createTask(taskListId, task) {
1009
+ const client = await this.getClient();
1010
+ const result = await client
1011
+ .api(`/me/todo/lists/${taskListId}/tasks`)
1012
+ .post(task);
1013
+ this.cache.clear();
1014
+ return result;
1015
+ }
1016
+ /**
1017
+ * Updates an existing task.
1018
+ */
1019
+ async updateTask(taskListId, taskId, updates) {
1020
+ const client = await this.getClient();
1021
+ const result = await client
1022
+ .api(`/me/todo/lists/${taskListId}/tasks/${taskId}`)
1023
+ .patch(updates);
1024
+ this.cache.clear();
1025
+ return result;
1026
+ }
1027
+ /**
1028
+ * Deletes a task.
1029
+ */
1030
+ async deleteTask(taskListId, taskId) {
1031
+ const client = await this.getClient();
1032
+ await client
1033
+ .api(`/me/todo/lists/${taskListId}/tasks/${taskId}`)
1034
+ .delete();
1035
+ this.cache.clear();
1036
+ }
1037
+ /**
1038
+ * Creates a new task list.
1039
+ */
1040
+ async createTaskList(displayName) {
1041
+ const client = await this.getClient();
1042
+ const result = await client
1043
+ .api('/me/todo/lists')
1044
+ .post({ displayName });
1045
+ this.cache.clear();
1046
+ return result;
1047
+ }
1048
+ /**
1049
+ * Updates a task list (e.g. rename).
1050
+ */
1051
+ async updateTaskList(listId, updates) {
1052
+ const client = await this.getClient();
1053
+ await client.api(`/me/todo/lists/${listId}`).patch(updates);
1054
+ this.cache.clear();
1055
+ }
1056
+ /**
1057
+ * Deletes a task list.
1058
+ */
1059
+ async deleteTaskList(listId) {
1060
+ const client = await this.getClient();
1061
+ await client.api(`/me/todo/lists/${listId}`).delete();
1062
+ this.cache.clear();
1063
+ }
1064
+ // ===========================================================================
1065
+ // Master Categories
1066
+ // ===========================================================================
1067
+ /**
1068
+ * Lists all master categories.
1069
+ */
1070
+ async listMasterCategories() {
1071
+ const client = await this.getClient();
1072
+ const response = await client.api('/me/outlook/masterCategories').get();
1073
+ return response.value;
1074
+ }
1075
+ /**
1076
+ * Creates a new master category.
1077
+ */
1078
+ async createMasterCategory(displayName, color) {
1079
+ const client = await this.getClient();
1080
+ const result = await client.api('/me/outlook/masterCategories').post({ displayName, color });
1081
+ this.cache.clear();
1082
+ return result;
1083
+ }
1084
+ /**
1085
+ * Deletes a master category.
1086
+ */
1087
+ async deleteMasterCategory(categoryId) {
1088
+ const client = await this.getClient();
1089
+ await client.api(`/me/outlook/masterCategories/${categoryId}`).delete();
1090
+ this.cache.clear();
1091
+ }
1092
+ // ===========================================================================
1093
+ // Focused Inbox Overrides
1094
+ // ===========================================================================
1095
+ /**
1096
+ * Lists all focused inbox overrides.
1097
+ */
1098
+ async listFocusedOverrides() {
1099
+ const client = await this.getClient();
1100
+ const response = await client.api('/me/inferenceClassification/overrides').get();
1101
+ return response.value;
1102
+ }
1103
+ /**
1104
+ * Creates a focused inbox override.
1105
+ */
1106
+ async createFocusedOverride(senderAddress, classifyAs) {
1107
+ const client = await this.getClient();
1108
+ const result = await client.api('/me/inferenceClassification/overrides').post({
1109
+ classifyAs,
1110
+ senderEmailAddress: { address: senderAddress },
1111
+ });
1112
+ this.cache.clear();
1113
+ return result;
1114
+ }
1115
+ /**
1116
+ * Deletes a focused inbox override.
1117
+ */
1118
+ async deleteFocusedOverride(overrideId) {
1119
+ const client = await this.getClient();
1120
+ await client.api(`/me/inferenceClassification/overrides/${overrideId}`).delete();
1121
+ this.cache.clear();
1122
+ }
1123
+ // ===========================================================================
1124
+ // Message Headers & MIME
1125
+ // ===========================================================================
1126
+ /**
1127
+ * Gets internet message headers for a message.
1128
+ */
1129
+ async getMessageHeaders(messageId) {
1130
+ const client = await this.getClient();
1131
+ const message = await client
1132
+ .api(`/me/messages/${messageId}`)
1133
+ .select('internetMessageHeaders')
1134
+ .get();
1135
+ return (message.internetMessageHeaders ?? []);
1136
+ }
1137
+ /**
1138
+ * Gets the MIME content of a message.
1139
+ */
1140
+ async getMessageMime(messageId) {
1141
+ const client = await this.getClient();
1142
+ return await client.api(`/me/messages/${messageId}/$value`).get();
1143
+ }
1144
+ // ===========================================================================
1145
+ // Calendar Groups
1146
+ // ===========================================================================
1147
+ /**
1148
+ * Lists all calendar groups.
1149
+ */
1150
+ async listCalendarGroups() {
1151
+ const client = await this.getClient();
1152
+ const response = await client.api('/me/calendarGroups').get();
1153
+ return response.value;
1154
+ }
1155
+ /**
1156
+ * Creates a new calendar group.
1157
+ */
1158
+ async createCalendarGroup(name) {
1159
+ const client = await this.getClient();
1160
+ const result = await client.api('/me/calendarGroups').post({ name });
1161
+ this.cache.clear();
1162
+ return result;
1163
+ }
1164
+ // ===========================================================================
1165
+ // Calendar Permissions
1166
+ // ===========================================================================
1167
+ /**
1168
+ * Lists all permissions for a calendar.
1169
+ */
1170
+ async listCalendarPermissions(calendarId) {
1171
+ const client = await this.getClient();
1172
+ const response = await client.api(`/me/calendars/${calendarId}/calendarPermissions`).get();
1173
+ return response.value;
1174
+ }
1175
+ /**
1176
+ * Creates a calendar permission (shares a calendar).
1177
+ */
1178
+ async createCalendarPermission(calendarId, permission) {
1179
+ const client = await this.getClient();
1180
+ const result = await client.api(`/me/calendars/${calendarId}/calendarPermissions`).post(permission);
1181
+ this.cache.clear();
1182
+ return result;
1183
+ }
1184
+ /**
1185
+ * Deletes a calendar permission.
1186
+ */
1187
+ async deleteCalendarPermission(calendarId, permissionId) {
1188
+ const client = await this.getClient();
1189
+ await client.api(`/me/calendars/${calendarId}/calendarPermissions/${permissionId}`).delete();
1190
+ this.cache.clear();
1191
+ }
1192
+ // ===========================================================================
1193
+ // Room Lists & Rooms
1194
+ // ===========================================================================
1195
+ /**
1196
+ * GET /me/findRoomLists
1197
+ */
1198
+ async listRoomLists() {
1199
+ const client = await this.getClient();
1200
+ const response = await client.api('/me/findRoomLists').get();
1201
+ return response.value;
1202
+ }
1203
+ /**
1204
+ * GET /me/findRooms or /me/findRooms(RoomList='...')
1205
+ */
1206
+ async listRooms(roomListEmail) {
1207
+ const client = await this.getClient();
1208
+ const endpoint = roomListEmail != null
1209
+ ? `/me/findRooms(RoomList='${roomListEmail}')`
1210
+ : '/me/findRooms';
1211
+ const response = await client.api(endpoint).get();
1212
+ return response.value;
1213
+ }
1214
+ // ===========================================================================
1215
+ // Mail Tips
1216
+ // ===========================================================================
1217
+ /**
1218
+ * Gets mail tips for the specified email addresses.
1219
+ */
1220
+ async getMailTips(emailAddresses) {
1221
+ const client = await this.getClient();
1222
+ const response = await client.api('/me/getMailTips').post({
1223
+ emailAddresses,
1224
+ mailTipsOptions: 'automaticReplies,mailboxFullStatus,maxMessageSize,deliveryRestriction,externalMemberCount',
1225
+ });
1226
+ return response.value;
1227
+ }
1228
+ // ===========================================================================
1229
+ // Teams
1230
+ // ===========================================================================
1231
+ /**
1232
+ * Lists all teams the current user has joined.
1233
+ */
1234
+ async listJoinedTeams() {
1235
+ const client = await this.getClient();
1236
+ const response = await client.api('/me/joinedTeams').get();
1237
+ return response.value;
1238
+ }
1239
+ /**
1240
+ * Lists all channels in a team.
1241
+ */
1242
+ async listChannels(teamId) {
1243
+ const client = await this.getClient();
1244
+ const response = await client.api(`/teams/${teamId}/channels`).get();
1245
+ return response.value;
1246
+ }
1247
+ /**
1248
+ * Gets a specific channel.
1249
+ */
1250
+ async getChannel(teamId, channelId) {
1251
+ const client = await this.getClient();
1252
+ return await client.api(`/teams/${teamId}/channels/${channelId}`).get();
1253
+ }
1254
+ /**
1255
+ * Creates a new channel in a team.
1256
+ */
1257
+ async createChannel(teamId, displayName, description) {
1258
+ const client = await this.getClient();
1259
+ const body = { displayName };
1260
+ if (description != null)
1261
+ body['description'] = description;
1262
+ return await client.api(`/teams/${teamId}/channels`).post(body);
1263
+ }
1264
+ /**
1265
+ * Updates a channel's properties.
1266
+ */
1267
+ async updateChannel(teamId, channelId, updates) {
1268
+ const client = await this.getClient();
1269
+ await client.api(`/teams/${teamId}/channels/${channelId}`).patch(updates);
1270
+ }
1271
+ /**
1272
+ * Deletes a channel.
1273
+ */
1274
+ async deleteChannel(teamId, channelId) {
1275
+ const client = await this.getClient();
1276
+ await client.api(`/teams/${teamId}/channels/${channelId}`).delete();
1277
+ }
1278
+ /**
1279
+ * Lists members of a team.
1280
+ */
1281
+ async listTeamMembers(teamId) {
1282
+ const client = await this.getClient();
1283
+ const response = await client.api(`/teams/${teamId}/members`).get();
1284
+ return response.value;
1285
+ }
1286
+ // ===========================================================================
1287
+ // Channel Messages
1288
+ // ===========================================================================
1289
+ /**
1290
+ * Lists recent messages in a channel.
1291
+ */
1292
+ async listChannelMessages(teamId, channelId, top = 25) {
1293
+ const client = await this.getClient();
1294
+ const response = await client.api(`/teams/${teamId}/channels/${channelId}/messages`).top(top).get();
1295
+ return response.value;
1296
+ }
1297
+ /**
1298
+ * Gets a specific channel message.
1299
+ */
1300
+ async getChannelMessage(teamId, channelId, messageId) {
1301
+ const client = await this.getClient();
1302
+ return await client.api(`/teams/${teamId}/channels/${channelId}/messages/${messageId}`).get();
1303
+ }
1304
+ /**
1305
+ * Lists replies to a channel message.
1306
+ */
1307
+ async listChannelMessageReplies(teamId, channelId, messageId) {
1308
+ const client = await this.getClient();
1309
+ const response = await client.api(`/teams/${teamId}/channels/${channelId}/messages/${messageId}/replies`).get();
1310
+ return response.value;
1311
+ }
1312
+ /**
1313
+ * Sends a new message to a channel.
1314
+ */
1315
+ async sendChannelMessage(teamId, channelId, body, contentType = 'html') {
1316
+ const client = await this.getClient();
1317
+ return await client.api(`/teams/${teamId}/channels/${channelId}/messages`).post({
1318
+ body: { contentType, content: body },
1319
+ });
1320
+ }
1321
+ /**
1322
+ * Replies to a channel message.
1323
+ */
1324
+ async replyToChannelMessage(teamId, channelId, messageId, body, contentType = 'html') {
1325
+ const client = await this.getClient();
1326
+ return await client.api(`/teams/${teamId}/channels/${channelId}/messages/${messageId}/replies`).post({
1327
+ body: { contentType, content: body },
1328
+ });
1329
+ }
1330
+ // ===========================================================================
1331
+ // Chats
1332
+ // ===========================================================================
1333
+ async listChats(top = 25) {
1334
+ const client = await this.getClient();
1335
+ const response = await client.api('/me/chats')
1336
+ .top(top)
1337
+ .orderby('lastMessagePreview/createdDateTime desc')
1338
+ .expand('lastMessagePreview')
1339
+ .get();
1340
+ return response.value;
1341
+ }
1342
+ async getChat(chatId) {
1343
+ const client = await this.getClient();
1344
+ return await client.api(`/me/chats/${chatId}`).get();
1345
+ }
1346
+ async listChatMessages(chatId, top = 25) {
1347
+ const client = await this.getClient();
1348
+ const response = await client.api(`/me/chats/${chatId}/messages`).top(top).get();
1349
+ return response.value;
1350
+ }
1351
+ async sendChatMessage(chatId, body, contentType = 'html') {
1352
+ const client = await this.getClient();
1353
+ return await client.api(`/me/chats/${chatId}/messages`).post({
1354
+ body: { contentType, content: body },
1355
+ });
1356
+ }
1357
+ async getChatMessage(chatId, messageId) {
1358
+ const client = await this.getClient();
1359
+ return await client.api(`/me/chats/${chatId}/messages/${messageId}`).get();
1360
+ }
1361
+ // Channel message reactions
1362
+ async setChannelMessageReaction(teamId, channelId, messageId, reactionType) {
1363
+ const client = await this.getClient();
1364
+ await client.api(`/teams/${teamId}/channels/${channelId}/messages/${messageId}/setReaction`)
1365
+ .post({ reactionType });
1366
+ }
1367
+ async unsetChannelMessageReaction(teamId, channelId, messageId, reactionType) {
1368
+ const client = await this.getClient();
1369
+ await client.api(`/teams/${teamId}/channels/${channelId}/messages/${messageId}/unsetReaction`)
1370
+ .post({ reactionType });
1371
+ }
1372
+ // Chat message reactions
1373
+ async setChatMessageReaction(chatId, messageId, reactionType) {
1374
+ const client = await this.getClient();
1375
+ await client.api(`/chats/${chatId}/messages/${messageId}/setReaction`)
1376
+ .post({ reactionType });
1377
+ }
1378
+ async unsetChatMessageReaction(chatId, messageId, reactionType) {
1379
+ const client = await this.getClient();
1380
+ await client.api(`/chats/${chatId}/messages/${messageId}/unsetReaction`)
1381
+ .post({ reactionType });
1382
+ }
1383
+ async listChatMembers(chatId) {
1384
+ const client = await this.getClient();
1385
+ const response = await client.api(`/me/chats/${chatId}/members`).get();
1386
+ return response.value;
1387
+ }
1388
+ // ===========================================================================
1389
+ // Checklist Items
1390
+ // ===========================================================================
1391
+ /**
1392
+ * Lists checklist items on a task.
1393
+ */
1394
+ async listChecklistItems(taskListId, taskId) {
1395
+ const client = await this.getClient();
1396
+ const response = await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/checklistItems`).get();
1397
+ return response.value;
1398
+ }
1399
+ /**
1400
+ * Creates a checklist item on a task.
1401
+ */
1402
+ async createChecklistItem(taskListId, taskId, displayName, isChecked = false) {
1403
+ const client = await this.getClient();
1404
+ return await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/checklistItems`).post({
1405
+ displayName,
1406
+ isChecked,
1407
+ });
1408
+ }
1409
+ /**
1410
+ * Updates a checklist item.
1411
+ */
1412
+ async updateChecklistItem(taskListId, taskId, checklistItemId, updates) {
1413
+ const client = await this.getClient();
1414
+ await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/checklistItems/${checklistItemId}`).patch(updates);
1415
+ }
1416
+ /**
1417
+ * Deletes a checklist item.
1418
+ */
1419
+ async deleteChecklistItem(taskListId, taskId, checklistItemId) {
1420
+ const client = await this.getClient();
1421
+ await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/checklistItems/${checklistItemId}`).delete();
1422
+ }
1423
+ // ===========================================================================
1424
+ // Linked Resources
1425
+ // ===========================================================================
1426
+ async listLinkedResources(taskListId, taskId) {
1427
+ const client = await this.getClient();
1428
+ const response = await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/linkedResources`).get();
1429
+ return response.value;
1430
+ }
1431
+ async createLinkedResource(taskListId, taskId, webUrl, applicationName, displayName) {
1432
+ const client = await this.getClient();
1433
+ const body = { webUrl, applicationName };
1434
+ if (displayName != null)
1435
+ body['displayName'] = displayName;
1436
+ return await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/linkedResources`).post(body);
1437
+ }
1438
+ async deleteLinkedResource(taskListId, taskId, linkedResourceId) {
1439
+ const client = await this.getClient();
1440
+ await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/linkedResources/${linkedResourceId}`).delete();
1441
+ }
1442
+ // ===========================================================================
1443
+ // Task Attachments
1444
+ // ===========================================================================
1445
+ async listTaskAttachments(taskListId, taskId) {
1446
+ const client = await this.getClient();
1447
+ const response = await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/attachments`).get();
1448
+ return response.value;
1449
+ }
1450
+ async createTaskAttachment(taskListId, taskId, name, contentBytes, contentType = 'application/octet-stream') {
1451
+ const client = await this.getClient();
1452
+ return await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/attachments`).post({
1453
+ '@odata.type': '#microsoft.graph.taskFileAttachment',
1454
+ name,
1455
+ contentBytes,
1456
+ contentType,
1457
+ });
1458
+ }
1459
+ async deleteTaskAttachment(taskListId, taskId, attachmentId) {
1460
+ const client = await this.getClient();
1461
+ await client.api(`/me/todo/lists/${taskListId}/tasks/${taskId}/attachments/${attachmentId}`).delete();
1462
+ }
1463
+ // ===========================================================================
1464
+ // Planner
1465
+ // ===========================================================================
1466
+ async listPlans() {
1467
+ const client = await this.getClient();
1468
+ const response = await client.api('/me/planner/plans').get();
1469
+ return response.value;
1470
+ }
1471
+ async getPlan(planId) {
1472
+ const client = await this.getClient();
1473
+ return await client.api(`/planner/plans/${planId}`).get();
1474
+ }
1475
+ async createPlan(title, groupId) {
1476
+ const client = await this.getClient();
1477
+ return await client.api('/planner/plans').post({
1478
+ title,
1479
+ owner: groupId,
1480
+ container: { url: `https://graph.microsoft.com/v1.0/groups/${groupId}`, type: 'group' },
1481
+ });
1482
+ }
1483
+ async updatePlan(planId, updates, etag) {
1484
+ const client = await this.getClient();
1485
+ return await client.api(`/planner/plans/${planId}`).header('If-Match', etag).patch(updates);
1486
+ }
1487
+ async listBuckets(planId) {
1488
+ const client = await this.getClient();
1489
+ const response = await client.api(`/planner/plans/${planId}/buckets`).get();
1490
+ return response.value;
1491
+ }
1492
+ async createBucket(planId, name) {
1493
+ const client = await this.getClient();
1494
+ return await client.api('/planner/buckets').post({ planId, name });
1495
+ }
1496
+ async updateBucket(bucketId, updates, etag) {
1497
+ const client = await this.getClient();
1498
+ return await client.api(`/planner/buckets/${bucketId}`).header('If-Match', etag).patch(updates);
1499
+ }
1500
+ async deleteBucket(bucketId, etag) {
1501
+ const client = await this.getClient();
1502
+ await client.api(`/planner/buckets/${bucketId}`).header('If-Match', etag).delete();
1503
+ }
1504
+ // ===========================================================================
1505
+ // Planner Tasks
1506
+ // ===========================================================================
1507
+ async listPlannerTasks(planId) {
1508
+ const client = await this.getClient();
1509
+ const response = await client.api(`/planner/plans/${planId}/tasks`).get();
1510
+ return response.value;
1511
+ }
1512
+ async getPlannerTask(taskId) {
1513
+ const client = await this.getClient();
1514
+ return await client.api(`/planner/tasks/${taskId}`).get();
1515
+ }
1516
+ async createPlannerTask(task) {
1517
+ const client = await this.getClient();
1518
+ return await client.api('/planner/tasks').post(task);
1519
+ }
1520
+ async updatePlannerTask(taskId, updates, etag) {
1521
+ const client = await this.getClient();
1522
+ return await client.api(`/planner/tasks/${taskId}`).header('If-Match', etag).patch(updates);
1523
+ }
1524
+ async deletePlannerTask(taskId, etag) {
1525
+ const client = await this.getClient();
1526
+ await client.api(`/planner/tasks/${taskId}`).header('If-Match', etag).delete();
1527
+ }
1528
+ async getPlannerTaskDetails(taskId) {
1529
+ const client = await this.getClient();
1530
+ return await client.api(`/planner/tasks/${taskId}/details`).get();
1531
+ }
1532
+ async updatePlannerTaskDetails(taskId, updates, etag) {
1533
+ const client = await this.getClient();
1534
+ return await client.api(`/planner/tasks/${taskId}/details`).header('If-Match', etag).patch(updates);
1535
+ }
1536
+ // ===========================================================================
1537
+ // People & Presence
1538
+ // ===========================================================================
1539
+ async listRelevantPeople(top = 25) {
1540
+ const client = await this.getClient();
1541
+ const response = await client.api('/me/people').top(top).get();
1542
+ return response.value;
1543
+ }
1544
+ async searchPeople(query, top = 25) {
1545
+ const client = await this.getClient();
1546
+ const response = await client.api('/me/people').search('"' + query + '"').top(top).get();
1547
+ return response.value;
1548
+ }
1549
+ async getManager() {
1550
+ const client = await this.getClient();
1551
+ return await client.api('/me/manager').get();
1552
+ }
1553
+ async getDirectReports() {
1554
+ const client = await this.getClient();
1555
+ const response = await client.api('/me/directReports').get();
1556
+ return response.value;
1557
+ }
1558
+ async getUserProfile(identifier) {
1559
+ const client = await this.getClient();
1560
+ return await client.api(`/users/${identifier}`).get();
1561
+ }
1562
+ async getUserPhoto(identifier) {
1563
+ const client = await this.getClient();
1564
+ return await client.api(`/users/${identifier}/photo/$value`).get();
1565
+ }
1566
+ async getUserPresence(identifier) {
1567
+ const client = await this.getClient();
1568
+ return await client.api(`/users/${identifier}/presence`).get();
1569
+ }
1570
+ async getUsersPresence(userIds) {
1571
+ const client = await this.getClient();
1572
+ const response = await client.api('/communications/getPresencesByUserId').post({ ids: userIds });
1573
+ return response.value;
1574
+ }
1575
+ /**
1576
+ * Sends multiple requests in a single $batch call to the Graph API.
1577
+ * Automatically splits into multiple batches if there are more than 20 requests.
1578
+ */
1579
+ async batchRequests(requests) {
1580
+ const client = await this.getClient();
1581
+ const batches = splitIntoBatches(requests);
1582
+ const allResults = new Map();
1583
+ for (const batch of batches) {
1584
+ const payload = buildBatchPayload(batch);
1585
+ const response = await client.api('/$batch').post(payload);
1586
+ const results = parseBatchResponse(response);
1587
+ for (const [id, result] of results) {
1588
+ allResults.set(id, result);
1589
+ }
1590
+ }
1591
+ return allResults;
1592
+ }
1593
+ // ===========================================================================
1594
+ // Online Meetings
1595
+ // ===========================================================================
1596
+ async listOnlineMeetings(limit = 20) {
1597
+ const client = await this.getClient();
1598
+ const response = await client.api('/me/onlineMeetings')
1599
+ .top(limit)
1600
+ .orderby('startDateTime desc')
1601
+ .get();
1602
+ return response.value;
1603
+ }
1604
+ async getOnlineMeeting(meetingId) {
1605
+ const client = await this.getClient();
1606
+ return await client.api(`/me/onlineMeetings/${meetingId}`).get();
1607
+ }
1608
+ async listMeetingRecordings(meetingId) {
1609
+ const client = await this.getClient();
1610
+ const response = await client.api(`/me/onlineMeetings/${meetingId}/recordings`).get();
1611
+ return response.value;
1612
+ }
1613
+ async getMeetingRecordingContent(meetingId, recordingId) {
1614
+ const client = await this.getClient();
1615
+ return await client.api(`/me/onlineMeetings/${meetingId}/recordings/${recordingId}/content`).get();
1616
+ }
1617
+ async listMeetingTranscripts(meetingId) {
1618
+ const client = await this.getClient();
1619
+ const response = await client.api(`/me/onlineMeetings/${meetingId}/transcripts`).get();
1620
+ return response.value;
1621
+ }
1622
+ async getMeetingTranscriptContent(meetingId, transcriptId, format = 'text/vtt') {
1623
+ const client = await this.getClient();
1624
+ return await client.api(`/me/onlineMeetings/${meetingId}/transcripts/${transcriptId}/content`)
1625
+ .header('Accept', format)
1626
+ .get();
1627
+ }
1628
+ // ===========================================================================
1629
+ // Excel Online (Workbook)
1630
+ // ===========================================================================
1631
+ /**
1632
+ * Lists worksheets in an Excel workbook.
1633
+ */
1634
+ async listWorksheets(driveItemId) {
1635
+ const client = await this.getClient();
1636
+ const response = await client.api(`/me/drive/items/${driveItemId}/workbook/worksheets`).get();
1637
+ return response.value;
1638
+ }
1639
+ /**
1640
+ * Gets cell values for a specific range in a worksheet.
1641
+ */
1642
+ async getWorksheetRange(driveItemId, worksheetName, range) {
1643
+ const client = await this.getClient();
1644
+ return await client.api(`/me/drive/items/${driveItemId}/workbook/worksheets/${encodeURIComponent(worksheetName)}/range(address='${encodeURIComponent(range)}')`).get();
1645
+ }
1646
+ /**
1647
+ * Gets the used range (all data) for a worksheet.
1648
+ */
1649
+ async getUsedRange(driveItemId, worksheetName) {
1650
+ const client = await this.getClient();
1651
+ return await client.api(`/me/drive/items/${driveItemId}/workbook/worksheets/${encodeURIComponent(worksheetName)}/usedRange`).get();
1652
+ }
1653
+ /**
1654
+ * Updates cell values for a specific range in a worksheet.
1655
+ */
1656
+ async updateWorksheetRange(driveItemId, worksheetName, range, values) {
1657
+ const client = await this.getClient();
1658
+ return await client.api(`/me/drive/items/${driveItemId}/workbook/worksheets/${encodeURIComponent(worksheetName)}/range(address='${encodeURIComponent(range)}')`).patch({ values });
1659
+ }
1660
+ /**
1661
+ * Gets rows from a named table in an Excel workbook.
1662
+ */
1663
+ async getTableData(driveItemId, tableName) {
1664
+ const client = await this.getClient();
1665
+ const response = await client.api(`/me/drive/items/${driveItemId}/workbook/tables/${encodeURIComponent(tableName)}/rows`).get();
1666
+ return response.value;
1667
+ }
1668
+ // ===========================================================================
1669
+ // OneDrive
1670
+ // ===========================================================================
1671
+ async listDriveItems(itemId) {
1672
+ const client = await this.getClient();
1673
+ const apiPath = itemId != null ? `/me/drive/items/${itemId}/children` : '/me/drive/root/children';
1674
+ const response = await client.api(apiPath).get();
1675
+ return response.value;
1676
+ }
1677
+ async searchDriveItems(query, limit = 25) {
1678
+ const client = await this.getClient();
1679
+ const response = await client.api(`/me/drive/root/search(q='${encodeURIComponent(query)}')`).top(limit).get();
1680
+ return response.value;
1681
+ }
1682
+ async getDriveItem(itemId) {
1683
+ const client = await this.getClient();
1684
+ return await client.api(`/me/drive/items/${itemId}`).get();
1685
+ }
1686
+ async downloadDriveItem(itemId) {
1687
+ const client = await this.getClient();
1688
+ return await client.api(`/me/drive/items/${itemId}/content`).get();
1689
+ }
1690
+ async uploadDriveItem(parentPath, fileName, content) {
1691
+ const client = await this.getClient();
1692
+ return await client.api(`/me/drive/root:/${parentPath}/${fileName}:/content`)
1693
+ .header('Content-Type', 'application/octet-stream')
1694
+ .put(content);
1695
+ }
1696
+ async listRecentDriveItems() {
1697
+ const client = await this.getClient();
1698
+ const response = await client.api('/me/drive/recent').get();
1699
+ return response.value;
1700
+ }
1701
+ async listSharedWithMe() {
1702
+ const client = await this.getClient();
1703
+ const response = await client.api('/me/drive/sharedWithMe').get();
1704
+ return response.value;
1705
+ }
1706
+ async createSharingLink(itemId, type, scope) {
1707
+ const client = await this.getClient();
1708
+ return await client.api(`/me/drive/items/${itemId}/createLink`).post({ type, scope });
1709
+ }
1710
+ async deleteDriveItem(itemId) {
1711
+ const client = await this.getClient();
1712
+ await client.api(`/me/drive/items/${itemId}`).delete();
1713
+ }
1714
+ // ===========================================================================
1715
+ // SharePoint Sites & Document Libraries
1716
+ // ===========================================================================
1717
+ /**
1718
+ * Lists sites the current user follows.
1719
+ */
1720
+ async listFollowedSites() {
1721
+ const client = await this.getClient();
1722
+ const response = await client.api('/me/followedSites').get();
1723
+ return response.value;
1724
+ }
1725
+ /**
1726
+ * Searches for SharePoint sites by keyword.
1727
+ */
1728
+ async searchSites(query) {
1729
+ const client = await this.getClient();
1730
+ const response = await client.api(`/sites?search=${encodeURIComponent(query)}`).get();
1731
+ return response.value;
1732
+ }
1733
+ /**
1734
+ * Gets a specific SharePoint site by ID.
1735
+ */
1736
+ async getSite(siteId) {
1737
+ const client = await this.getClient();
1738
+ return await client.api(`/sites/${siteId}`).get();
1739
+ }
1740
+ /**
1741
+ * Lists document libraries (drives) for a SharePoint site.
1742
+ */
1743
+ async listDocumentLibraries(siteId) {
1744
+ const client = await this.getClient();
1745
+ const response = await client.api(`/sites/${siteId}/drives`).get();
1746
+ return response.value;
1747
+ }
1748
+ /**
1749
+ * Lists items in a document library or folder.
1750
+ */
1751
+ async listLibraryItems(driveId, itemId) {
1752
+ const client = await this.getClient();
1753
+ const apiPath = itemId != null ? `/drives/${driveId}/items/${itemId}/children` : `/drives/${driveId}/root/children`;
1754
+ const response = await client.api(apiPath).get();
1755
+ return response.value;
1756
+ }
1757
+ /**
1758
+ * Downloads a file from a document library.
1759
+ */
1760
+ async downloadLibraryFile(driveId, itemId) {
1761
+ const client = await this.getClient();
1762
+ return await client.api(`/drives/${driveId}/items/${itemId}/content`).get();
1763
+ }
1764
+ }
1765
+ /**
1766
+ * Creates a new Graph client instance.
1767
+ */
1768
+ export function createGraphClient(deviceCodeCallback) {
1769
+ return new GraphClient(deviceCodeCallback);
1770
+ }
1771
+ //# sourceMappingURL=graph-client.js.map