@jbctechsolutions/mcp-office365 3.0.0 → 4.0.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 (340) hide show
  1. package/README.md +42 -65
  2. package/dist/approval/hash.d.ts +8 -8
  3. package/dist/approval/token-manager.d.ts +12 -6
  4. package/dist/approval/token-manager.d.ts.map +1 -1
  5. package/dist/approval/token-manager.js +11 -3
  6. package/dist/approval/token-manager.js.map +1 -1
  7. package/dist/approval/types.d.ts +7 -3
  8. package/dist/approval/types.d.ts.map +1 -1
  9. package/dist/cli.d.ts +4 -0
  10. package/dist/cli.d.ts.map +1 -1
  11. package/dist/cli.js +18 -3
  12. package/dist/cli.js.map +1 -1
  13. package/dist/database/repository.d.ts +48 -48
  14. package/dist/database/repository.d.ts.map +1 -1
  15. package/dist/database/repository.js.map +1 -1
  16. package/dist/delta/mirror.d.ts +67 -0
  17. package/dist/delta/mirror.d.ts.map +1 -0
  18. package/dist/delta/mirror.js +183 -0
  19. package/dist/delta/mirror.js.map +1 -0
  20. package/dist/graph/auth/account-id.d.ts +19 -0
  21. package/dist/graph/auth/account-id.d.ts.map +1 -0
  22. package/dist/graph/auth/account-id.js +55 -0
  23. package/dist/graph/auth/account-id.js.map +1 -0
  24. package/dist/graph/auth/config.d.ts +1 -1
  25. package/dist/graph/auth/config.d.ts.map +1 -1
  26. package/dist/graph/auth/config.js +8 -0
  27. package/dist/graph/auth/config.js.map +1 -1
  28. package/dist/graph/auth/index.d.ts +1 -0
  29. package/dist/graph/auth/index.d.ts.map +1 -1
  30. package/dist/graph/auth/index.js +1 -0
  31. package/dist/graph/auth/index.js.map +1 -1
  32. package/dist/graph/client/graph-client.d.ts +105 -0
  33. package/dist/graph/client/graph-client.d.ts.map +1 -1
  34. package/dist/graph/client/graph-client.js +414 -18
  35. package/dist/graph/client/graph-client.js.map +1 -1
  36. package/dist/graph/client/immutable-id-middleware.d.ts +50 -0
  37. package/dist/graph/client/immutable-id-middleware.d.ts.map +1 -0
  38. package/dist/graph/client/immutable-id-middleware.js +137 -0
  39. package/dist/graph/client/immutable-id-middleware.js.map +1 -0
  40. package/dist/graph/content-readers.d.ts +0 -12
  41. package/dist/graph/content-readers.d.ts.map +1 -1
  42. package/dist/graph/content-readers.js +0 -21
  43. package/dist/graph/content-readers.js.map +1 -1
  44. package/dist/graph/index.d.ts +5 -6
  45. package/dist/graph/index.d.ts.map +1 -1
  46. package/dist/graph/index.js +5 -6
  47. package/dist/graph/index.js.map +1 -1
  48. package/dist/graph/mailbox-adapter.d.ts +15 -15
  49. package/dist/graph/mappers/contact-mapper.d.ts +4 -1
  50. package/dist/graph/mappers/contact-mapper.d.ts.map +1 -1
  51. package/dist/graph/mappers/contact-mapper.js +7 -3
  52. package/dist/graph/mappers/contact-mapper.js.map +1 -1
  53. package/dist/graph/mappers/email-mapper.d.ts.map +1 -1
  54. package/dist/graph/mappers/email-mapper.js +7 -4
  55. package/dist/graph/mappers/email-mapper.js.map +1 -1
  56. package/dist/graph/mappers/event-mapper.d.ts.map +1 -1
  57. package/dist/graph/mappers/event-mapper.js +6 -3
  58. package/dist/graph/mappers/event-mapper.js.map +1 -1
  59. package/dist/graph/mappers/folder-mapper.d.ts +0 -4
  60. package/dist/graph/mappers/folder-mapper.d.ts.map +1 -1
  61. package/dist/graph/mappers/folder-mapper.js +9 -19
  62. package/dist/graph/mappers/folder-mapper.js.map +1 -1
  63. package/dist/graph/mappers/index.d.ts +2 -2
  64. package/dist/graph/mappers/index.d.ts.map +1 -1
  65. package/dist/graph/mappers/index.js +2 -2
  66. package/dist/graph/mappers/index.js.map +1 -1
  67. package/dist/graph/mappers/task-mapper.d.ts +4 -2
  68. package/dist/graph/mappers/task-mapper.d.ts.map +1 -1
  69. package/dist/graph/mappers/task-mapper.js +7 -5
  70. package/dist/graph/mappers/task-mapper.js.map +1 -1
  71. package/dist/graph/mappers/utils.d.ts +0 -10
  72. package/dist/graph/mappers/utils.d.ts.map +1 -1
  73. package/dist/graph/mappers/utils.js +0 -19
  74. package/dist/graph/mappers/utils.js.map +1 -1
  75. package/dist/graph/repository.d.ts +400 -270
  76. package/dist/graph/repository.d.ts.map +1 -1
  77. package/dist/graph/repository.js +739 -1046
  78. package/dist/graph/repository.js.map +1 -1
  79. package/dist/ids/next-action.d.ts +29 -0
  80. package/dist/ids/next-action.d.ts.map +1 -0
  81. package/dist/ids/next-action.js +58 -0
  82. package/dist/ids/next-action.js.map +1 -0
  83. package/dist/ids/resolver.d.ts +2 -1
  84. package/dist/ids/resolver.d.ts.map +1 -1
  85. package/dist/ids/resolver.js +19 -4
  86. package/dist/ids/resolver.js.map +1 -1
  87. package/dist/ids/schema.d.ts +91 -0
  88. package/dist/ids/schema.d.ts.map +1 -0
  89. package/dist/ids/schema.js +131 -0
  90. package/dist/ids/schema.js.map +1 -0
  91. package/dist/ids/token.d.ts +7 -1
  92. package/dist/ids/token.d.ts.map +1 -1
  93. package/dist/ids/token.js +46 -7
  94. package/dist/ids/token.js.map +1 -1
  95. package/dist/index.d.ts +4 -6
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +63 -100
  98. package/dist/index.js.map +1 -1
  99. package/dist/parsers/index.d.ts +0 -1
  100. package/dist/parsers/index.d.ts.map +1 -1
  101. package/dist/parsers/index.js +0 -1
  102. package/dist/parsers/index.js.map +1 -1
  103. package/dist/registry/all-tools.d.ts.map +1 -1
  104. package/dist/registry/all-tools.js +8 -4
  105. package/dist/registry/all-tools.js.map +1 -1
  106. package/dist/registry/context.d.ts +1 -7
  107. package/dist/registry/context.d.ts.map +1 -1
  108. package/dist/registry/context.js +0 -11
  109. package/dist/registry/context.js.map +1 -1
  110. package/dist/registry/elicit-links.d.ts +35 -0
  111. package/dist/registry/elicit-links.d.ts.map +1 -0
  112. package/dist/registry/elicit-links.js +102 -0
  113. package/dist/registry/elicit-links.js.map +1 -0
  114. package/dist/registry/elicitor.d.ts +24 -0
  115. package/dist/registry/elicitor.d.ts.map +1 -0
  116. package/dist/registry/elicitor.js +51 -0
  117. package/dist/registry/elicitor.js.map +1 -0
  118. package/dist/registry/index.d.ts +2 -2
  119. package/dist/registry/index.d.ts.map +1 -1
  120. package/dist/registry/index.js +1 -1
  121. package/dist/registry/index.js.map +1 -1
  122. package/dist/registry/registry.d.ts +11 -0
  123. package/dist/registry/registry.d.ts.map +1 -1
  124. package/dist/registry/registry.js +87 -0
  125. package/dist/registry/registry.js.map +1 -1
  126. package/dist/registry/types.d.ts +61 -13
  127. package/dist/registry/types.d.ts.map +1 -1
  128. package/dist/state/delta-store.d.ts +85 -0
  129. package/dist/state/delta-store.d.ts.map +1 -0
  130. package/dist/state/delta-store.js +124 -0
  131. package/dist/state/delta-store.js.map +1 -0
  132. package/dist/state/schema.d.ts +2 -3
  133. package/dist/state/schema.d.ts.map +1 -1
  134. package/dist/state/schema.js +26 -3
  135. package/dist/state/schema.js.map +1 -1
  136. package/dist/state/store.d.ts +3 -0
  137. package/dist/state/store.d.ts.map +1 -1
  138. package/dist/state/store.js +4 -0
  139. package/dist/state/store.js.map +1 -1
  140. package/dist/tools/calendar-graph.d.ts.map +1 -1
  141. package/dist/tools/calendar-graph.js +10 -9
  142. package/dist/tools/calendar-graph.js.map +1 -1
  143. package/dist/tools/calendar-permissions.d.ts +7 -7
  144. package/dist/tools/calendar-permissions.d.ts.map +1 -1
  145. package/dist/tools/calendar-permissions.js +7 -4
  146. package/dist/tools/calendar-permissions.js.map +1 -1
  147. package/dist/tools/calendar.d.ts +14 -114
  148. package/dist/tools/calendar.d.ts.map +1 -1
  149. package/dist/tools/calendar.js +41 -202
  150. package/dist/tools/calendar.js.map +1 -1
  151. package/dist/tools/categories.d.ts +4 -4
  152. package/dist/tools/categories.d.ts.map +1 -1
  153. package/dist/tools/categories.js +5 -2
  154. package/dist/tools/categories.js.map +1 -1
  155. package/dist/tools/checklist-items.d.ts +9 -9
  156. package/dist/tools/checklist-items.d.ts.map +1 -1
  157. package/dist/tools/checklist-items.js +8 -5
  158. package/dist/tools/checklist-items.js.map +1 -1
  159. package/dist/tools/contact-folders.d.ts +2 -2
  160. package/dist/tools/contact-folders.d.ts.map +1 -1
  161. package/dist/tools/contact-folders.js +5 -2
  162. package/dist/tools/contact-folders.js.map +1 -1
  163. package/dist/tools/contacts-graph.d.ts +1 -1
  164. package/dist/tools/contacts-graph.d.ts.map +1 -1
  165. package/dist/tools/contacts-graph.js +8 -6
  166. package/dist/tools/contacts-graph.js.map +1 -1
  167. package/dist/tools/contacts.d.ts +9 -44
  168. package/dist/tools/contacts.d.ts.map +1 -1
  169. package/dist/tools/contacts.js +23 -131
  170. package/dist/tools/contacts.js.map +1 -1
  171. package/dist/tools/excel.d.ts +10 -10
  172. package/dist/tools/excel.d.ts.map +1 -1
  173. package/dist/tools/excel.js +9 -6
  174. package/dist/tools/excel.js.map +1 -1
  175. package/dist/tools/focused-overrides.d.ts +4 -4
  176. package/dist/tools/focused-overrides.d.ts.map +1 -1
  177. package/dist/tools/focused-overrides.js +5 -2
  178. package/dist/tools/focused-overrides.js.map +1 -1
  179. package/dist/tools/index.d.ts +4 -5
  180. package/dist/tools/index.d.ts.map +1 -1
  181. package/dist/tools/index.js +4 -6
  182. package/dist/tools/index.js.map +1 -1
  183. package/dist/tools/linked-resources.d.ts +7 -7
  184. package/dist/tools/linked-resources.d.ts.map +1 -1
  185. package/dist/tools/linked-resources.js +7 -4
  186. package/dist/tools/linked-resources.js.map +1 -1
  187. package/dist/tools/mail-graph.d.ts.map +1 -1
  188. package/dist/tools/mail-graph.js +21 -12
  189. package/dist/tools/mail-graph.js.map +1 -1
  190. package/dist/tools/mail-rules.d.ts +8 -8
  191. package/dist/tools/mail-rules.d.ts.map +1 -1
  192. package/dist/tools/mail-rules.js +7 -7
  193. package/dist/tools/mail-rules.js.map +1 -1
  194. package/dist/tools/mail-send.d.ts +27 -27
  195. package/dist/tools/mail-send.d.ts.map +1 -1
  196. package/dist/tools/mail-send.js +30 -19
  197. package/dist/tools/mail-send.js.map +1 -1
  198. package/dist/tools/mail.d.ts +22 -79
  199. package/dist/tools/mail.d.ts.map +1 -1
  200. package/dist/tools/mail.js +45 -293
  201. package/dist/tools/mail.js.map +1 -1
  202. package/dist/tools/mailbox-organization.d.ts +34 -37
  203. package/dist/tools/mailbox-organization.d.ts.map +1 -1
  204. package/dist/tools/mailbox-organization.js +72 -64
  205. package/dist/tools/mailbox-organization.js.map +1 -1
  206. package/dist/tools/meetings.d.ts +14 -14
  207. package/dist/tools/meetings.d.ts.map +1 -1
  208. package/dist/tools/meetings.js +8 -6
  209. package/dist/tools/meetings.js.map +1 -1
  210. package/dist/tools/onedrive.d.ts +16 -16
  211. package/dist/tools/onedrive.d.ts.map +1 -1
  212. package/dist/tools/onedrive.js +16 -11
  213. package/dist/tools/onedrive.js.map +1 -1
  214. package/dist/tools/onenote.d.ts +63 -0
  215. package/dist/tools/onenote.d.ts.map +1 -0
  216. package/dist/tools/onenote.js +221 -0
  217. package/dist/tools/onenote.js.map +1 -0
  218. package/dist/tools/planner-visualization.d.ts +5 -5
  219. package/dist/tools/planner-visualization.d.ts.map +1 -1
  220. package/dist/tools/planner-visualization.js +5 -4
  221. package/dist/tools/planner-visualization.js.map +1 -1
  222. package/dist/tools/planner.d.ts +59 -39
  223. package/dist/tools/planner.d.ts.map +1 -1
  224. package/dist/tools/planner.js +48 -23
  225. package/dist/tools/planner.js.map +1 -1
  226. package/dist/tools/shared-mailbox.d.ts +164 -0
  227. package/dist/tools/shared-mailbox.d.ts.map +1 -0
  228. package/dist/tools/shared-mailbox.js +318 -0
  229. package/dist/tools/shared-mailbox.js.map +1 -0
  230. package/dist/tools/sharepoint-lists.d.ts +131 -0
  231. package/dist/tools/sharepoint-lists.d.ts.map +1 -0
  232. package/dist/tools/sharepoint-lists.js +246 -0
  233. package/dist/tools/sharepoint-lists.js.map +1 -0
  234. package/dist/tools/sharepoint.d.ts +14 -14
  235. package/dist/tools/sharepoint.d.ts.map +1 -1
  236. package/dist/tools/sharepoint.js +11 -9
  237. package/dist/tools/sharepoint.js.map +1 -1
  238. package/dist/tools/task-attachments.d.ts +7 -7
  239. package/dist/tools/task-attachments.d.ts.map +1 -1
  240. package/dist/tools/task-attachments.js +7 -4
  241. package/dist/tools/task-attachments.js.map +1 -1
  242. package/dist/tools/task-lists.d.ts +3 -3
  243. package/dist/tools/task-lists.d.ts.map +1 -1
  244. package/dist/tools/task-lists.js +10 -6
  245. package/dist/tools/task-lists.js.map +1 -1
  246. package/dist/tools/tasks-graph.d.ts +2 -2
  247. package/dist/tools/tasks-graph.d.ts.map +1 -1
  248. package/dist/tools/tasks-graph.js +6 -4
  249. package/dist/tools/tasks-graph.js.map +1 -1
  250. package/dist/tools/tasks.d.ts +8 -43
  251. package/dist/tools/tasks.d.ts.map +1 -1
  252. package/dist/tools/tasks.js +19 -122
  253. package/dist/tools/tasks.js.map +1 -1
  254. package/dist/tools/teams.d.ts +46 -46
  255. package/dist/tools/teams.d.ts.map +1 -1
  256. package/dist/tools/teams.js +34 -26
  257. package/dist/tools/teams.js.map +1 -1
  258. package/dist/tools/what-changed.d.ts +48 -0
  259. package/dist/tools/what-changed.d.ts.map +1 -0
  260. package/dist/tools/what-changed.js +149 -0
  261. package/dist/tools/what-changed.js.map +1 -0
  262. package/dist/types/calendar.d.ts +1 -1
  263. package/dist/types/calendar.d.ts.map +1 -1
  264. package/dist/types/calendar.js.map +1 -1
  265. package/dist/types/contacts.d.ts +1 -1
  266. package/dist/types/contacts.d.ts.map +1 -1
  267. package/dist/types/contacts.js.map +1 -1
  268. package/dist/types/mail.d.ts +1 -1
  269. package/dist/types/mail.d.ts.map +1 -1
  270. package/dist/types/mail.js.map +1 -1
  271. package/dist/utils/errors.d.ts +15 -34
  272. package/dist/utils/errors.d.ts.map +1 -1
  273. package/dist/utils/errors.js +13 -49
  274. package/dist/utils/errors.js.map +1 -1
  275. package/dist/visualization/types.d.ts +4 -4
  276. package/package.json +3 -4
  277. package/dist/applescript/account-repository.d.ts +0 -30
  278. package/dist/applescript/account-repository.d.ts.map +0 -1
  279. package/dist/applescript/account-repository.js +0 -38
  280. package/dist/applescript/account-repository.js.map +0 -1
  281. package/dist/applescript/account-scripts.d.ts +0 -21
  282. package/dist/applescript/account-scripts.d.ts.map +0 -1
  283. package/dist/applescript/account-scripts.js +0 -180
  284. package/dist/applescript/account-scripts.js.map +0 -1
  285. package/dist/applescript/calendar-manager.d.ts +0 -44
  286. package/dist/applescript/calendar-manager.d.ts.map +0 -1
  287. package/dist/applescript/calendar-manager.js +0 -92
  288. package/dist/applescript/calendar-manager.js.map +0 -1
  289. package/dist/applescript/calendar-writer.d.ts +0 -36
  290. package/dist/applescript/calendar-writer.d.ts.map +0 -1
  291. package/dist/applescript/calendar-writer.js +0 -94
  292. package/dist/applescript/calendar-writer.js.map +0 -1
  293. package/dist/applescript/content-readers.d.ts +0 -114
  294. package/dist/applescript/content-readers.d.ts.map +0 -1
  295. package/dist/applescript/content-readers.js +0 -328
  296. package/dist/applescript/content-readers.js.map +0 -1
  297. package/dist/applescript/executor.d.ts +0 -60
  298. package/dist/applescript/executor.d.ts.map +0 -1
  299. package/dist/applescript/executor.js +0 -173
  300. package/dist/applescript/executor.js.map +0 -1
  301. package/dist/applescript/index.d.ts +0 -20
  302. package/dist/applescript/index.d.ts.map +0 -1
  303. package/dist/applescript/index.js +0 -29
  304. package/dist/applescript/index.js.map +0 -1
  305. package/dist/applescript/mail-sender.d.ts +0 -38
  306. package/dist/applescript/mail-sender.d.ts.map +0 -1
  307. package/dist/applescript/mail-sender.js +0 -67
  308. package/dist/applescript/mail-sender.js.map +0 -1
  309. package/dist/applescript/parser.d.ts +0 -235
  310. package/dist/applescript/parser.d.ts.map +0 -1
  311. package/dist/applescript/parser.js +0 -496
  312. package/dist/applescript/parser.js.map +0 -1
  313. package/dist/applescript/repository.d.ts +0 -64
  314. package/dist/applescript/repository.d.ts.map +0 -1
  315. package/dist/applescript/repository.js +0 -444
  316. package/dist/applescript/repository.js.map +0 -1
  317. package/dist/applescript/scripts.d.ts +0 -265
  318. package/dist/applescript/scripts.d.ts.map +0 -1
  319. package/dist/applescript/scripts.js +0 -1483
  320. package/dist/applescript/scripts.js.map +0 -1
  321. package/dist/parsers/olk15.d.ts +0 -87
  322. package/dist/parsers/olk15.d.ts.map +0 -1
  323. package/dist/parsers/olk15.js +0 -368
  324. package/dist/parsers/olk15.js.map +0 -1
  325. package/dist/tools/accounts.d.ts +0 -37
  326. package/dist/tools/accounts.d.ts.map +0 -1
  327. package/dist/tools/accounts.js +0 -68
  328. package/dist/tools/accounts.js.map +0 -1
  329. package/dist/tools/calendar-apple.d.ts +0 -39
  330. package/dist/tools/calendar-apple.d.ts.map +0 -1
  331. package/dist/tools/calendar-apple.js +0 -159
  332. package/dist/tools/calendar-apple.js.map +0 -1
  333. package/dist/tools/mail-apple.d.ts +0 -40
  334. package/dist/tools/mail-apple.d.ts.map +0 -1
  335. package/dist/tools/mail-apple.js +0 -146
  336. package/dist/tools/mail-apple.js.map +0 -1
  337. package/dist/tools/notes.d.ts +0 -86
  338. package/dist/tools/notes.d.ts.map +0 -1
  339. package/dist/tools/notes.js +0 -202
  340. package/dist/tools/notes.js.map +0 -1
@@ -16,6 +16,7 @@ import { Client, ResponseType, AuthenticationHandler, RetryHandler, RetryHandler
16
16
  import { getAccessToken } from '../auth/index.js';
17
17
  import { buildBatchPayload, splitIntoBatches, parseBatchResponse } from './batch.js';
18
18
  import { ResponseCache, CacheTTL, createCacheKey } from './cache.js';
19
+ import { ImmutableIdMiddleware } from './immutable-id-middleware.js';
19
20
  // The SDK's RetryHandler only considers 429/503/504 retriable (its private
20
21
  // static RETRY_STATUS_CODES), gating `this.isRetry(response)` BEFORE our
21
22
  // shouldRetry callback runs — so a callback can only *narrow* that set, never
@@ -79,15 +80,19 @@ export class GraphClient {
79
80
  return shouldRetryGraphRequest(method, url, response?.status ?? 0);
80
81
  };
81
82
  // Chain mirrors the SDK default order (auth → retry → redirect → http),
82
- // minus the cosmetic TelemetryHandler. RedirectHandler matters: the
83
- // binary download endpoints (/content, /photo/$value, meeting recordings)
84
- // 302 to a pre-authenticated CDN URL, so the redirect must be followed
85
- // explicitly rather than relying on the underlying fetch default.
83
+ // minus the cosmetic TelemetryHandler, plus the immutable-ID preference
84
+ // (U5b-3) sitting right after auth so its Prefer header rides every retry
85
+ // attempt without being re-appended. RedirectHandler matters: the binary
86
+ // download endpoints (/content, /photo/$value, meeting recordings) 302 to
87
+ // a pre-authenticated CDN URL, so the redirect must be followed explicitly
88
+ // rather than relying on the underlying fetch default.
86
89
  const auth = new AuthenticationHandler(authProvider);
90
+ const immutableId = new ImmutableIdMiddleware();
87
91
  const retry = new RetryHandler(new RetryHandlerOptions(undefined, undefined, shouldRetry));
88
92
  const redirect = new RedirectHandler();
89
93
  const http = new HTTPMessageHandler();
90
- auth.setNext(retry);
94
+ auth.setNext(immutableId);
95
+ immutableId.setNext(retry);
91
96
  retry.setNext(redirect);
92
97
  redirect.setNext(http);
93
98
  this.client = Client.initWithMiddleware({ middleware: auth });
@@ -207,7 +212,9 @@ export class GraphClient {
207
212
  .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId,parentFolderId')
208
213
  .top(limit)
209
214
  .get();
210
- return response.value;
215
+ const messages = response.value;
216
+ await this.upgradeMessageIdsToImmutable(messages);
217
+ return messages;
211
218
  }
212
219
  /**
213
220
  * Searches messages in a specific folder.
@@ -220,7 +227,9 @@ export class GraphClient {
220
227
  .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId')
221
228
  .top(limit)
222
229
  .get();
223
- return response.value;
230
+ const messages = response.value;
231
+ await this.upgradeMessageIdsToImmutable(messages);
232
+ return messages;
224
233
  }
225
234
  /**
226
235
  * Property-only structured search (U7 / D9): `$filter` on messages. The filter
@@ -252,7 +261,9 @@ export class GraphClient {
252
261
  .select(MESSAGE_SEARCH_SELECT)
253
262
  .top(limit)
254
263
  .get();
255
- return response.value;
264
+ const messages = response.value;
265
+ await this.upgradeMessageIdsToImmutable(messages);
266
+ return messages;
256
267
  }
257
268
  /**
258
269
  * Mixed property + free-text structured search (U7 / D9): `POST /search/query`
@@ -281,7 +292,77 @@ export class GraphClient {
281
292
  const response = (await client.api('/search/query').post(body));
282
293
  const hits = response.value?.[0]?.hitsContainers?.[0]?.hits ?? [];
283
294
  // Guard against a hit without a resource so no undefined enters the mapper.
284
- return hits.map((h) => h.resource).filter((r) => r != null);
295
+ const messages = hits.map((h) => h.resource).filter((r) => r != null);
296
+ await this.upgradeMessageIdsToImmutable(messages);
297
+ return messages;
298
+ }
299
+ /**
300
+ * Translates Exchange item IDs between formats (U5b-3 / D2). Used to upgrade
301
+ * the mutable REST IDs that `$search` returns into immutable REST entry IDs, so
302
+ * search-minted self-encoding tokens (`em_`) survive a later move. Returns a map
303
+ * of source ID → immutable target ID; IDs that Graph could not translate are
304
+ * simply absent (partial success is normal and handled by the caller).
305
+ */
306
+ async translateExchangeIds(inputIds, sourceIdType = 'restId', targetIdType = 'restImmutableEntryId') {
307
+ const out = new Map();
308
+ if (inputIds.length === 0) {
309
+ return out;
310
+ }
311
+ const client = await this.getClient();
312
+ // Graph caps translateExchangeIds at 1000 input IDs per call; chunk to stay
313
+ // under it even though search result sets are far smaller.
314
+ for (let i = 0; i < inputIds.length; i += 1000) {
315
+ const chunk = inputIds.slice(i, i + 1000);
316
+ const response = (await client.api('/me/translateExchangeIds').post({
317
+ inputIds: chunk,
318
+ sourceIdType,
319
+ targetIdType,
320
+ }));
321
+ for (const pair of response.value ?? []) {
322
+ if (pair.sourceId != null && pair.sourceId.length > 0 && pair.targetId != null && pair.targetId.length > 0) {
323
+ out.set(pair.sourceId, pair.targetId);
324
+ }
325
+ }
326
+ }
327
+ return out;
328
+ }
329
+ /**
330
+ * Rewrites the mutable `$search`-minted IDs on a message list to their
331
+ * immutable equivalents in place (U5b-3 / D2), so the mapper mints durable
332
+ * `em_` tokens. Graceful degradation: if translation fails wholesale (throw) or
333
+ * for individual IDs (absent from the map), those messages keep their mutable
334
+ * ID — the `em_` token still resolves this session, it just isn't move-durable.
335
+ * Returns the number of IDs left un-upgraded (the caller's `degraded_ids` count).
336
+ */
337
+ async upgradeMessageIdsToImmutable(messages) {
338
+ const mutableIds = messages
339
+ .map((m) => m.id)
340
+ .filter((id) => typeof id === 'string' && id.length > 0);
341
+ if (mutableIds.length === 0) {
342
+ return 0;
343
+ }
344
+ let translated;
345
+ try {
346
+ translated = await this.translateExchangeIds(mutableIds);
347
+ }
348
+ catch {
349
+ // Whole-batch failure (throttled/unavailable): leave every ID mutable.
350
+ return mutableIds.length;
351
+ }
352
+ let degraded = 0;
353
+ for (const message of messages) {
354
+ if (typeof message.id !== 'string' || message.id.length === 0) {
355
+ continue;
356
+ }
357
+ const immutable = translated.get(message.id);
358
+ if (immutable != null) {
359
+ message.id = immutable;
360
+ }
361
+ else {
362
+ degraded += 1;
363
+ }
364
+ }
365
+ return degraded;
285
366
  }
286
367
  /**
287
368
  * Lists messages in a conversation by conversationId.
@@ -317,27 +398,62 @@ export class GraphClient {
317
398
  */
318
399
  async getMessagesDelta(folderId, deltaLink) {
319
400
  const client = await this.getClient();
320
- let response;
401
+ let page;
321
402
  if (deltaLink != null) {
322
- response = await client.api(deltaLink).get();
403
+ page = await client.api(deltaLink).get();
323
404
  }
324
405
  else {
325
- response = await client
406
+ page = await client
326
407
  .api(`/me/mailFolders/${folderId}/messages/delta`)
327
408
  .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,internetMessageId,parentFolderId')
328
409
  .top(50)
329
410
  .get();
330
411
  }
331
- const messages = [...(response.value ?? [])];
332
- let nextLink = response['@odata.nextLink'];
412
+ const messages = [...(page.value ?? [])];
413
+ // The deltaLink lands on the LAST page; paging through nextLinks and reading
414
+ // it from the first response would yield '' whenever the delta spans >1 page.
415
+ let nextLink = page['@odata.nextLink'];
333
416
  while (nextLink != null) {
334
- const nextPage = await client.api(nextLink).get();
335
- messages.push(...(nextPage.value ?? []));
336
- nextLink = nextPage['@odata.nextLink'];
417
+ page = await client.api(nextLink).get();
418
+ messages.push(...(page.value ?? []));
419
+ nextLink = page['@odata.nextLink'];
337
420
  }
338
- const newDeltaLink = response['@odata.deltaLink'] ?? '';
421
+ const newDeltaLink = page['@odata.deltaLink'] ?? '';
339
422
  return { messages, deltaLink: newDeltaLink };
340
423
  }
424
+ /**
425
+ * Gets calendar-view delta for incremental event sync (U12).
426
+ *
427
+ * The v1.0 event delta is served by `/me/calendarView/delta`, bounded by a
428
+ * start/end window that is baked into the returned deltaLink — subsequent
429
+ * rounds just follow that link. `$select` is unsupported here, so full event
430
+ * objects come back; deletes arrive as `@removed` entries. The deltaLink lands
431
+ * on the *last* page, so it is read after paging (not from the first response).
432
+ */
433
+ async getCalendarViewDelta(startDateTime, endDateTime, deltaLink) {
434
+ const client = await this.getClient();
435
+ let page;
436
+ if (deltaLink != null) {
437
+ page = await client.api(deltaLink).get();
438
+ }
439
+ else {
440
+ const start = encodeURIComponent(startDateTime);
441
+ const end = encodeURIComponent(endDateTime);
442
+ page = await client
443
+ .api(`/me/calendarView/delta?startDateTime=${start}&endDateTime=${end}`)
444
+ .header('Prefer', 'odata.maxpagesize=50')
445
+ .get();
446
+ }
447
+ const events = [...(page.value ?? [])];
448
+ let nextLink = page['@odata.nextLink'];
449
+ while (nextLink != null) {
450
+ page = await client.api(nextLink).get();
451
+ events.push(...(page.value ?? []));
452
+ nextLink = page['@odata.nextLink'];
453
+ }
454
+ const newDeltaLink = page['@odata.deltaLink'] ?? '';
455
+ return { events, deltaLink: newDeltaLink };
456
+ }
341
457
  // ===========================================================================
342
458
  // Mail Rules
343
459
  // ===========================================================================
@@ -1583,6 +1699,10 @@ export class GraphClient {
1583
1699
  const client = await this.getClient();
1584
1700
  return await client.api('/planner/buckets').post({ planId, name });
1585
1701
  }
1702
+ async getBucket(bucketId) {
1703
+ const client = await this.getClient();
1704
+ return await client.api(`/planner/buckets/${bucketId}`).get();
1705
+ }
1586
1706
  async updateBucket(bucketId, updates, etag) {
1587
1707
  const client = await this.getClient();
1588
1708
  return await client.api(`/planner/buckets/${bucketId}`).header('If-Match', etag).patch(updates);
@@ -1599,6 +1719,12 @@ export class GraphClient {
1599
1719
  const response = await client.api(`/planner/plans/${planId}/tasks`).get();
1600
1720
  return response.value;
1601
1721
  }
1722
+ /** All Planner tasks assigned to the signed-in user, across every plan. */
1723
+ async listMyPlannerTasks() {
1724
+ const client = await this.getClient();
1725
+ const response = await client.api('/me/planner/tasks').get();
1726
+ return response.value;
1727
+ }
1602
1728
  async getPlannerTask(taskId) {
1603
1729
  const client = await this.getClient();
1604
1730
  return await client.api(`/planner/tasks/${taskId}`).get();
@@ -1662,6 +1788,116 @@ export class GraphClient {
1662
1788
  const response = await client.api('/communications/getPresencesByUserId').post({ ids: userIds });
1663
1789
  return response.value;
1664
1790
  }
1791
+ // ===========================================================================
1792
+ // Shared Mailbox / Delegate Access (/users/{upn}/...) — read-only (#40)
1793
+ // ===========================================================================
1794
+ //
1795
+ // These mirror the `/me/...` read paths but target another user's mailbox,
1796
+ // calendar, or drive via delegate/shared access. Unlike the `/me` variants,
1797
+ // they deliberately DO NOT swallow errors: a 403 must surface (mapped to
1798
+ // GRAPH_PERMISSION_DENIED at the dispatch chokepoint) so the caller learns
1799
+ // they lack shared access rather than getting a silent empty/`null` result.
1800
+ // Results are returned with raw Graph ids (durable tokens are `/me`- and
1801
+ // account-scoped, so they cannot address another mailbox's items).
1802
+ async listSharedMailFolders(mailbox) {
1803
+ const client = await this.getClient();
1804
+ const response = await client
1805
+ .api(`/users/${encodeURIComponent(mailbox)}/mailFolders`)
1806
+ .select('id,displayName,parentFolderId,totalItemCount,unreadItemCount')
1807
+ .top(100)
1808
+ .get();
1809
+ return response.value;
1810
+ }
1811
+ async listSharedMessages(mailbox, folderId, limit = 25, unreadOnly = false) {
1812
+ const client = await this.getClient();
1813
+ const apiPath = folderId != null
1814
+ ? `/users/${encodeURIComponent(mailbox)}/mailFolders/${encodeURIComponent(folderId)}/messages`
1815
+ : `/users/${encodeURIComponent(mailbox)}/messages`;
1816
+ let request = client
1817
+ .api(apiPath)
1818
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId')
1819
+ .top(limit);
1820
+ if (unreadOnly) {
1821
+ // Graph rejects `$orderby` on a property not led by `$filter` (isRead),
1822
+ // so drop the sort when filtering unread and rely on the default order.
1823
+ request = request.filter('isRead eq false');
1824
+ }
1825
+ else {
1826
+ request = request.orderby('receivedDateTime desc');
1827
+ }
1828
+ const response = await request.get();
1829
+ return response.value;
1830
+ }
1831
+ async getSharedMessage(mailbox, messageId, includeBody = false) {
1832
+ const client = await this.getClient();
1833
+ const select = includeBody
1834
+ ? 'id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,body,bodyPreview,conversationId,parentFolderId'
1835
+ : 'id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId,parentFolderId';
1836
+ return await client
1837
+ .api(`/users/${encodeURIComponent(mailbox)}/messages/${encodeURIComponent(messageId)}`)
1838
+ .select(select)
1839
+ .get();
1840
+ }
1841
+ async searchSharedMessages(mailbox, query, limit = 25) {
1842
+ const client = await this.getClient();
1843
+ // Mail $search cannot be combined with $orderby, so ordering is omitted.
1844
+ // Strip embedded double quotes so a stray `"` can't break out of the
1845
+ // quoted KQL `$search="..."` term.
1846
+ const safeQuery = query.replace(/"/g, ' ');
1847
+ const response = await client
1848
+ .api(`/users/${encodeURIComponent(mailbox)}/messages`)
1849
+ .query({ $search: `"${safeQuery}"` })
1850
+ .select('id,subject,from,toRecipients,ccRecipients,receivedDateTime,sentDateTime,isRead,hasAttachments,importance,flag,bodyPreview,conversationId')
1851
+ .top(limit)
1852
+ .get();
1853
+ return response.value;
1854
+ }
1855
+ async listSharedEvents(mailbox, limit = 25, startDate, endDate) {
1856
+ const client = await this.getClient();
1857
+ if (startDate != null && endDate != null) {
1858
+ const response = await client
1859
+ .api(`/users/${encodeURIComponent(mailbox)}/calendarView`)
1860
+ .query({ startDateTime: startDate.toISOString(), endDateTime: endDate.toISOString() })
1861
+ .select('id,subject,start,end,location,isAllDay,organizer,attendees,bodyPreview')
1862
+ .orderby('start/dateTime')
1863
+ .top(limit)
1864
+ .get();
1865
+ return response.value;
1866
+ }
1867
+ const response = await client
1868
+ .api(`/users/${encodeURIComponent(mailbox)}/events`)
1869
+ .select('id,subject,start,end,location,isAllDay,organizer,attendees,bodyPreview')
1870
+ .orderby('start/dateTime')
1871
+ .top(limit)
1872
+ .get();
1873
+ return response.value;
1874
+ }
1875
+ async getSharedEvent(mailbox, eventId) {
1876
+ const client = await this.getClient();
1877
+ return await client
1878
+ .api(`/users/${encodeURIComponent(mailbox)}/events/${encodeURIComponent(eventId)}`)
1879
+ .select('id,subject,start,end,location,isAllDay,organizer,attendees,body,recurrence,bodyPreview')
1880
+ .get();
1881
+ }
1882
+ async listSharedDriveItems(mailbox, itemId) {
1883
+ const client = await this.getClient();
1884
+ const apiPath = itemId != null
1885
+ ? `/users/${encodeURIComponent(mailbox)}/drive/items/${encodeURIComponent(itemId)}/children`
1886
+ : `/users/${encodeURIComponent(mailbox)}/drive/root/children`;
1887
+ const response = await client.api(apiPath).get();
1888
+ return response.value;
1889
+ }
1890
+ async searchSharedDriveItems(mailbox, query, limit = 25) {
1891
+ const client = await this.getClient();
1892
+ // Escape for the OData string literal first (a lone `'` closes the literal;
1893
+ // OData escapes it by doubling), then URL-encode the whole term.
1894
+ const safeQuery = encodeURIComponent(query.replace(/'/g, "''"));
1895
+ const response = await client
1896
+ .api(`/users/${encodeURIComponent(mailbox)}/drive/root/search(q='${safeQuery}')`)
1897
+ .top(limit)
1898
+ .get();
1899
+ return response.value;
1900
+ }
1665
1901
  /**
1666
1902
  * Sends multiple requests in a single $batch call to the Graph API.
1667
1903
  * Automatically splits into multiple batches if there are more than 20 requests.
@@ -1853,6 +2089,166 @@ export class GraphClient {
1853
2089
  const client = await this.getClient();
1854
2090
  return await client.api(`/drives/${driveId}/items/${itemId}/content`).responseType(ResponseType.ARRAYBUFFER).get();
1855
2091
  }
2092
+ // ===========================================================================
2093
+ // SharePoint Lists
2094
+ // ===========================================================================
2095
+ /**
2096
+ * Lists the SharePoint lists in a site.
2097
+ */
2098
+ async listSharePointLists(siteId) {
2099
+ const client = await this.getClient();
2100
+ const response = await client
2101
+ .api(`/sites/${siteId}/lists`)
2102
+ .select('id,name,displayName,description,webUrl,createdDateTime,lastModifiedDateTime')
2103
+ .get();
2104
+ return response.value;
2105
+ }
2106
+ /**
2107
+ * Gets a specific SharePoint list.
2108
+ */
2109
+ async getSharePointList(siteId, listId) {
2110
+ const client = await this.getClient();
2111
+ return await client.api(`/sites/${siteId}/lists/${listId}`).get();
2112
+ }
2113
+ /**
2114
+ * Creates a SharePoint list in a site.
2115
+ */
2116
+ async createSharePointList(siteId, body) {
2117
+ const client = await this.getClient();
2118
+ return await client.api(`/sites/${siteId}/lists`).post(body);
2119
+ }
2120
+ /**
2121
+ * Lists the column definitions for a SharePoint list.
2122
+ */
2123
+ async listSharePointListColumns(siteId, listId) {
2124
+ const client = await this.getClient();
2125
+ const response = await client
2126
+ .api(`/sites/${siteId}/lists/${listId}/columns`)
2127
+ .get();
2128
+ return response.value;
2129
+ }
2130
+ /**
2131
+ * Lists the items in a SharePoint list, expanding their field values.
2132
+ */
2133
+ async listSharePointListItems(siteId, listId, limit = 50) {
2134
+ const client = await this.getClient();
2135
+ const response = await client
2136
+ .api(`/sites/${siteId}/lists/${listId}/items`)
2137
+ .expand('fields')
2138
+ .top(limit)
2139
+ .get();
2140
+ return response.value;
2141
+ }
2142
+ /**
2143
+ * Gets a specific SharePoint list item, expanding its field values.
2144
+ */
2145
+ async getSharePointListItem(siteId, listId, itemId) {
2146
+ const client = await this.getClient();
2147
+ return await client
2148
+ .api(`/sites/${siteId}/lists/${listId}/items/${itemId}`)
2149
+ .expand('fields')
2150
+ .get();
2151
+ }
2152
+ /**
2153
+ * Creates an item in a SharePoint list from a map of column → value.
2154
+ */
2155
+ async createSharePointListItem(siteId, listId, fields) {
2156
+ const client = await this.getClient();
2157
+ return await client.api(`/sites/${siteId}/lists/${listId}/items`).post({ fields });
2158
+ }
2159
+ /**
2160
+ * Updates the field values of a SharePoint list item.
2161
+ */
2162
+ async updateSharePointListItem(siteId, listId, itemId, fields) {
2163
+ const client = await this.getClient();
2164
+ return await client.api(`/sites/${siteId}/lists/${listId}/items/${itemId}/fields`).patch(fields);
2165
+ }
2166
+ /**
2167
+ * Deletes an item from a SharePoint list.
2168
+ */
2169
+ async deleteSharePointListItem(siteId, listId, itemId) {
2170
+ const client = await this.getClient();
2171
+ await client.api(`/sites/${siteId}/lists/${listId}/items/${itemId}`).delete();
2172
+ }
2173
+ // ===========================================================================
2174
+ // OneNote
2175
+ // ===========================================================================
2176
+ /**
2177
+ * Lists all OneNote notebooks for the current user.
2178
+ */
2179
+ async listNotebooks() {
2180
+ const client = await this.getClient();
2181
+ const response = await client.api('/me/onenote/notebooks').get();
2182
+ return response.value;
2183
+ }
2184
+ /**
2185
+ * Lists OneNote sections, optionally scoped to a notebook.
2186
+ */
2187
+ async listNoteSections(notebookGraphId) {
2188
+ const client = await this.getClient();
2189
+ const apiPath = notebookGraphId != null
2190
+ ? `/me/onenote/notebooks/${notebookGraphId}/sections`
2191
+ : '/me/onenote/sections';
2192
+ const response = await client.api(apiPath).get();
2193
+ return response.value;
2194
+ }
2195
+ /**
2196
+ * Lists OneNote pages, optionally scoped to a section.
2197
+ */
2198
+ async listNotePages(sectionGraphId) {
2199
+ const client = await this.getClient();
2200
+ if (sectionGraphId != null) {
2201
+ const response = await client.api(`/me/onenote/sections/${sectionGraphId}/pages`).get();
2202
+ return response.value;
2203
+ }
2204
+ const response = await client
2205
+ .api('/me/onenote/pages')
2206
+ .top(50)
2207
+ .orderby('lastModifiedDateTime desc')
2208
+ .get();
2209
+ return response.value;
2210
+ }
2211
+ /**
2212
+ * Gets a OneNote page's metadata.
2213
+ */
2214
+ async getNotePage(pageGraphId) {
2215
+ const client = await this.getClient();
2216
+ return await client.api(`/me/onenote/pages/${pageGraphId}`).get();
2217
+ }
2218
+ /**
2219
+ * Gets a OneNote page's HTML content.
2220
+ */
2221
+ async getNotePageContent(pageGraphId) {
2222
+ const client = await this.getClient();
2223
+ return await client
2224
+ .api(`/me/onenote/pages/${pageGraphId}/content`)
2225
+ .responseType(ResponseType.TEXT)
2226
+ .get();
2227
+ }
2228
+ /**
2229
+ * Searches OneNote pages by keyword.
2230
+ */
2231
+ async searchNotePages(query) {
2232
+ const client = await this.getClient();
2233
+ // Strip embedded double-quotes so they can't unbalance the quoted $search
2234
+ // expression (`$search="..."`) and 400 the request.
2235
+ const safeQuery = query.replace(/"/g, '');
2236
+ const response = await client
2237
+ .api('/me/onenote/pages')
2238
+ .search(`"${safeQuery}"`)
2239
+ .get();
2240
+ return response.value;
2241
+ }
2242
+ /**
2243
+ * Creates a new OneNote page in a section from raw HTML.
2244
+ */
2245
+ async createNotePage(sectionGraphId, html) {
2246
+ const client = await this.getClient();
2247
+ return await client
2248
+ .api(`/me/onenote/sections/${sectionGraphId}/pages`)
2249
+ .header('Content-Type', 'text/html')
2250
+ .post(html);
2251
+ }
1856
2252
  }
1857
2253
  /**
1858
2254
  * Creates a new Graph client instance.