The Graph client previously failed the call on the first 429/503. The
request loop now retries these transient statuses before giving up.
Behavior:
- 429 and 503 are retried up to OUTLOOK_MAX_RETRIES times.
- Retry-After header is honored when Graph sends it, clamped to
MAX_RETRY_DELAY_MS.
- Otherwise exponential backoff with full jitter, same clamp.
- 401 still throws UNAUTHORIZED immediately (no retry, no point).
- Other 4xx (400/403/404, etc.) are NOT retried -- these are caller
errors, retrying just burns the rate-limit budget.
New config knobs, all env-overridable:
- OUTLOOK_MAX_RETRIES (default 3)
- OUTLOOK_BASE_RETRY_DELAY_MS (default 1000)
- OUTLOOK_MAX_RETRY_DELAY_MS (default 30000)
Implementation:
- Refactored the request into makeSingleRequest + optionsForRequest
helpers so the retry loop sits above them without duplicating the
response parsing.
- Empty-body success (202/204, e.g. sendMail, DELETE) is preserved.
- sleep and getRetryDelay are exported for the test.
Tests:
- tests/backoff.test.js: spins up a local HTTPS server, asserts
getRetryDelay honors Retry-After and clamps to MAX_RETRY_DELAY_MS,
and that callGraphAPI retries on 429 and fails after maxAttempts.
- Handle empty 2xx Graph API responses without JSON parse errors
- Fix list-rules handler import (handleListRules named export)
- Add timezone-aware display formatting using MS_TIMEZONE / DEFAULT_TIMEZONE
- Return created event ID in create-event success message
- Change default timezone from Windows name to IANA (America/New_York)
Bug fixes (non-breaking):
- Register accept-event tool in calendar module (was dead code)
- Add missing callGraphAPI + ensureAuthenticated imports to rules/index.js
(edit-rule-sequence would throw ReferenceError at runtime)
- Make calendar event timezone configurable via MS_TIMEZONE env var
(was hardcoded to UTC; default is now Eastern Standard Time)
Version bump: 1.0.0 → 1.0.1
README updated: 21 tools, MS_TIMEZONE in config table, known issues pruned