/** * Retry/backoff configuration for the Google API clients (GTM + GA4). * * googleapis is built on gaxios, which retries a request when the factory * options carry `retry: true` plus a `retryConfig`. This module centralizes * that config so every client (gtmClient, ga4Client) absorbs transient * 429/5xx/network failures with exponential backoff instead of surfacing them * to the caller on the first hit — the difference between "works under load" * and "falls over at the GTM API's per-minute quota". * * Safety: only idempotent READ methods (GET/HEAD/OPTIONS) are ever retried. * Mutations (POST/PUT/DELETE — i.e. anything behind the write/publish/delete * guardrails) are NEVER auto-retried, so an ambiguous failure can't be * double-applied. This is deliberately stricter than the gaxios default * (which also retries PUT/DELETE). * * Tuning (all optional): * GTM_MCP_RETRY_MAX attempts after the first failure (default 3; 0 disables) * GTM_MCP_RETRY_MAX_DELAY_MS cap on a single backoff sleep (default 30000) * GTM_MCP_RETRY_TOTAL_TIMEOUT_MS cap on first-request→last-retry wall time (default 60000) */ /** Structural subset of gaxios's RetryConfig (gaxios is a transitive dep). */ export interface RetryConfigShape { retry: number; noResponseRetries: number; httpMethodsToRetry: string[]; statusCodesToRetry: number[][]; retryDelayMultiplier: number; maxRetryDelay: number; totalTimeout: number; retryBackoff?: (err: unknown, defaultDelayMs: number) => Promise; onRetryAttempt?: (err: unknown) => void; } export interface RetryOptions { retry: boolean; retryConfig: RetryConfigShape; } /** Only ever retry read methods. Mutations must fail loudly, exactly once. */ export declare const SAFE_HTTP_METHODS_TO_RETRY: readonly ["GET", "HEAD", "OPTIONS"]; /** 408 (request timeout), 429 (quota), and all 5xx are transient. */ export declare const RETRYABLE_STATUS_RANGES: number[][]; /** * Apply full jitter to a backoff delay: uniform in [0.5x, 1.5x], clamped to * maxDelayMs. Pure — `rand` is injectable for tests (defaults to Math.random). */ export declare function jitteredDelay(baseMs: number, maxDelayMs: number, rand?: () => number): number; /** * The server's own instruction for how long to wait, in ms, or null when it gave none. * * On a 429 Google usually sends `Retry-After`, and retrying before it elapses is what turns one * throttle into a longer one. RFC 7231 allows two forms and both appear in practice: delta-seconds * ("120") and an HTTP-date ("Wed, 21 Oct 2026 07:28:00 GMT"), so both are read. * * `now` is injectable so the date branch is testable without freezing the clock. */ export declare function retryAfterMs(headers: unknown, now?: () => number): number | null; /** * How long to actually wait before the next attempt. * * Takes the LARGER of our computed backoff and the server's Retry-After, then clamps to maxDelayMs. * Larger, because either source may be the more conservative one and retrying sooner than EITHER * asks is the failure mode being fixed: our own backoff can be shorter than the server's * instruction on an early attempt, and the server's can be shorter than ours late in a sequence. * * The clamp is what keeps a single attempt bounded. A server asking for longer than the cap is not * disobeyed so much as deferred: the wait is capped, the retry fails again, and totalTimeout ends * the sequence with a real error rather than the tool hanging for minutes inside one call. */ export declare function effectiveRetryDelay(computedMs: number, serverMs: number | null, maxDelayMs: number): number; export interface BuildRetryOptionsOpts { /** * Additional HTTP methods to retry beyond the safe defaults. Only for * clients whose entire surface is read-only — e.g. the GA4 Data client, * where runReport/runRealtimeReport are pure reads carried over POST. * Never pass this for a client that can mutate (GTM). */ extraMethodsToRetry?: string[]; } /** * Build the gaxios retry options for a Google API client factory. The result * is spread into the factory call, e.g. `tagmanager({ version: 'v2', auth, * ...buildRetryOptions() })`, and applies to every request the client makes. */ export declare function buildRetryOptions(env?: NodeJS.ProcessEnv, opts?: BuildRetryOptionsOpts): RetryOptions; //# sourceMappingURL=apiRetry.d.ts.map