/** * Fetch with retry on HTTP 429 (rate limit). * * Sitecore's Orchestrate (campaign) and Brief APIs sit in front of Cosmos * DB, which returns **429 TooManyRequests** (`Sub Status 3200`) with an * `x-ms-retry-after-ms` hint when the per-second RU budget is exceeded — * common when a reconnect pushes a whole story's campaigns → deliverables * → tasks in a burst. * * We retry 429 ONLY for idempotent methods (GET/HEAD/PUT/DELETE/OPTIONS). * A naive "429 is rejected before processing, so retrying any write is safe" * is WRONG for the Orchestrate API: creating a campaign is a multi-step POST * (project → deliverables → tasks), and the API can apply part of a create * before Cosmos throttles a later step and returns 429 to us. Retrying that * POST then DUPLICATES the already-created entity (observed: duplicate * campaigns on regenerate). POST/PATCH are non-idempotent and carry no * idempotency key, so we surface their 429 to the caller instead of * retrying. Updates (PUT) and deletes — the bulk of a re-push / reconnect — * are idempotent and still retry, which is what the burst actually needs. * * The wait is the server's hint when present (`x-ms-retry-after-ms`, else a * standard `Retry-After` in seconds or as an HTTP-date), otherwise * exponential backoff + jitter capped at {@link MAX_BACKOFF_MS}. Network * errors and every non-429 response are returned/propagated unchanged for * the caller to map — this helper owns ONLY the rate-limit retry, nothing * else about the transport. * * Leaf module: imports no domain area (`src/shared/` constraint). */ export interface RateLimitRetryOptions { /** Per-attempt timeout (ms). 0 disables the per-attempt timeout. */ timeoutMs: number; /** Max 429 retries (default {@link DEFAULT_MAX_429_RETRIES} / env). */ maxRetries?: number; /** Backoff base in ms (default {@link DEFAULT_BASE_MS} / env). */ baseMs?: number; /** Caller's cancellation signal — chained into each attempt's timeout. */ signal?: AbortSignal; } /** * `fetch` with transparent retry on HTTP 429. The final response (a non-429 * outcome, or a 429 after the retry budget is spent) is returned for the * caller to handle exactly as before. */ export declare const fetchWithRateLimitRetry: (url: string, init: { method: string; headers: Record; body?: string; }, opts: RateLimitRetryOptions) => Promise;