/** * HTTP Client * * Provides HTTP request utilities with progress tracking, * retries, and error handling using Bun's native fetch */ import { NetworkError } from '../core/errors/index.js'; /** * HTTP request options */ export interface HttpRequestOptions { timeout?: number; headers?: Record; retries?: number; retryDelay?: number; userAgent?: string; } /** * Download options with progress callback */ export interface DownloadOptions extends HttpRequestOptions { onProgress?: (percent: number, bytesDownloaded: number, totalBytes: number) => void; expectedSize?: number; } /** * HTTP response wrapper */ export interface HttpResponse { data: T; status: number; headers: Headers; url: string; } /** * HTTP error with additional context (status code, URL) * * Extends NetworkError with HTTP-specific fields. Auto-derives * the error code from the HTTP status (429 → RATE_LIMITED, 5xx → SERVER_ERROR). */ export declare class HttpError extends NetworkError { readonly status?: number | undefined; readonly url?: string | undefined; readonly name: string; constructor(message: string, status?: number | undefined, url?: string | undefined, retryable?: boolean); } /** * Thrown when a download response declares a non-binary content type * (e.g. `text/html` — a login wall, premium gate, error page, or an * externally-hosted resource landing page). Non-retryable: the server will * keep serving the same page. Overrides getUserMessage so the descriptive * reason survives NetworkError's canned CONNECTION_FAILED copy. */ export declare class BinaryContentTypeError extends HttpError { readonly contentType: string; readonly name: string; constructor(message: string, status: number | undefined, url: string, contentType: string); getUserMessage(): string; } /** * Circuit breaker options */ export interface CircuitBreakerOptions { /** Number of failures before opening circuit (default: 5) */ failureThreshold?: number; /** Time in ms before attempting to close circuit (default: 30000) */ resetTimeout?: number; /** Number of successful requests to fully close circuit (default: 2) */ successThreshold?: number; } /** * Circuit breaker pattern to prevent cascading failures * * States: * - closed: Normal operation, requests pass through * - open: Failures exceeded threshold, requests are blocked * - half-open: Testing if service has recovered * * @since v1.40.0 */ export declare class CircuitBreaker { private states; private readonly failureThreshold; private readonly resetTimeout; private readonly successThreshold; constructor(options?: CircuitBreakerOptions); /** * Extract hostname from URL */ private getHostname; /** * Check if a request can proceed for the given URL */ canRequest(url: string): boolean; /** * Get the current state for a URL */ getState(url: string): 'closed' | 'open' | 'half-open'; /** * Record a successful request */ recordSuccess(url: string): void; /** * Record a failed request */ recordFailure(url: string): void; /** * Reset the circuit breaker for a URL */ reset(url: string): void; /** * Reset all circuit breakers */ resetAll(): void; /** * Get statistics for all hosts */ getStats(): Map; } /** * Get the global circuit breaker instance */ export declare function getCircuitBreaker(): CircuitBreaker; /** * Perform a fetch that follows redirects manually, re-validating every 3xx * `Location` against {@link validateExternalUrl} before following it. * * SSRF hardening (redirect-based bypass): a plain `fetch(url, { redirect: * 'follow' })` validates only the INITIAL url — an attacker-controlled source * URL (user web manifest, per-plugin Jenkins composite) that returns a 30x to * an internal/metadata address (169.254.169.254, 127.0.0.1, ...) would be * followed unchecked. This helper validates each hop, so a redirect into a * blocked address throws a non-retryable {@link SecurityError} instead. * * Re-validate-and-follow (not hard-reject) because the source APIs legitimately * redirect (Modrinth/Hangar/GitHub 301->cdn, apex->www). This is the JSON-fetch * analogue of the download path's `validateRedirectUrl(url, response.url)`. * * @param url - Initial URL (caller must have already validated it) * @param options - RequestInit; `redirect` is forced to `'manual'` * @throws SecurityError if any redirect target fails validation (non-retryable) */ export declare function fetchSafeRedirect(url: string, options?: RequestInit): Promise; /** * Make an HTTP GET request and return JSON */ export declare function httpGet(url: string, options?: HttpRequestOptions): Promise>; /** * Make an HTTP POST request with retry logic */ export declare function httpPost(url: string, body: B, options?: HttpRequestOptions): Promise>; /** * Download result with metadata */ export interface DownloadResult { bytesDownloaded: number; url: string; suggestedFilename?: string; contentType?: string; } /** * Download a file to disk with progress tracking */ export declare function downloadFile(url: string, outputPath: string, options?: DownloadOptions): Promise; /** * Download a file to disk using streams (for large files) */ export declare function downloadFileStream(url: string, outputPath: string, options?: DownloadOptions): Promise; /** * Check if a URL is reachable */ export declare function isUrlReachable(url: string, timeoutMs?: number): Promise; /** * Get the final URL after following redirects */ export declare function getRedirectUrl(url: string): Promise; //# sourceMappingURL=http.d.ts.map