(options = {})
| 269 | } |
| 270 | |
| 271 | async function fetchMicrosoftMailboxMessages(options = {}) { |
| 272 | const { |
| 273 | clientId, |
| 274 | refreshToken, |
| 275 | mailbox = 'INBOX', |
| 276 | top = 5, |
| 277 | fetchImpl, |
| 278 | signal, |
| 279 | log = null, |
| 280 | } = options; |
| 281 | |
| 282 | if (!refreshToken) { |
| 283 | throw new Error('Microsoft refresh token is empty.'); |
| 284 | } |
| 285 | if (!clientId) { |
| 286 | throw new Error('Microsoft client_id is empty.'); |
| 287 | } |
| 288 | |
| 289 | const errors = []; |
| 290 | for (const plan of TRANSPORT_PLANS) { |
| 291 | for (const strategyName of plan.strategyNames) { |
| 292 | try { |
| 293 | const tokenData = await exchangeRefreshToken(clientId, refreshToken, { |
| 294 | fetchImpl, |
| 295 | signal, |
| 296 | strategyName, |
| 297 | }); |
| 298 | const rawMessages = plan.transport === 'graph' |
| 299 | ? await fetchGraphMessages(tokenData.access_token, { mailbox, top, fetchImpl, signal }) |
| 300 | : await fetchOutlookMessages(tokenData.access_token, { mailbox, top, fetchImpl, signal }); |
| 301 | |
| 302 | return { |
| 303 | tokenData, |
| 304 | nextRefreshToken: String(tokenData?.refresh_token || '').trim(), |
| 305 | tokenStrategy: strategyName, |
| 306 | transport: plan.transport, |
| 307 | mailbox: normalizeMailboxLabel(mailbox), |
| 308 | messages: rawMessages.map((message) => normalizeMessage(message, mailbox)), |
| 309 | }; |
| 310 | } catch (error) { |
| 311 | const message = error?.message || String(error); |
| 312 | errors.push(`${plan.transport}/${strategyName}: ${message}`); |
| 313 | if (typeof log === 'function') { |
| 314 | log(`mailbox=${normalizeMailboxLabel(mailbox)} ${plan.transport}/${strategyName} failed: ${message}`); |
| 315 | } |
| 316 | } |
| 317 | } |
| 318 | } |
| 319 | |
| 320 | throw new Error(`Microsoft mailbox request failed: ${errors.join(' | ')}`); |
| 321 | } |
| 322 | |
| 323 | function delay(timeoutMs, signal) { |
| 324 | if (timeoutMs <= 0) { |
no test coverage detected