UNPKG

ky

Version:

Tiny and elegant HTTP client based on the Fetch API

206 lines (185 loc) 7.56 kB
import { type KyOptionsRegistry } from '../types/options.js'; export declare const supportsRequestStreams: boolean; export declare const supportsAbortController: boolean; export declare const supportsAbortSignal: boolean; export declare const supportsResponseStreams: boolean; export declare const supportsFormData: boolean; export declare const requestMethods: readonly ["get", "post", "put", "patch", "head", "delete"]; export declare const responseTypes: { readonly json: "application/json"; readonly text: "text/*"; readonly formData: "multipart/form-data"; readonly arrayBuffer: "*/*"; readonly blob: "*/*"; readonly bytes: "*/*"; }; export declare const maxSafeTimeout = 2147483647; export declare const usualFormBoundarySize: number; export declare const stop: unique symbol; /** Options for forcing a retry via `ky.retry()`. */ export type ForceRetryOptions = { /** Custom delay in milliseconds before retrying. If not provided, uses the default retry delay calculation based on `retry.delay` configuration. **Note:** Custom delays bypass jitter and `backoffLimit`. This is intentional, as custom delays often come from server responses (e.g., `Retry-After` headers) and should be respected exactly as specified. */ delay?: number; /** Error code for the retry. This machine-readable identifier will be included in the error message passed to `beforeRetry` hooks, allowing you to distinguish between different types of forced retries. @example ``` return ky.retry({code: 'RATE_LIMIT'}); // Resulting error message: 'Forced retry: RATE_LIMIT' ``` */ code?: string; /** Original error that caused the retry. This allows you to preserve the error chain when forcing a retry based on caught exceptions. The error will be set as the `cause` of the `ForceRetryError`, enabling proper error chain traversal. @example ``` try { const data = await response.clone().json(); validateBusinessLogic(data); } catch (error) { return ky.retry({ code: 'VALIDATION_FAILED', cause: error // Preserves original error in chain }); } ``` */ cause?: Error; /** Custom request to use for the retry. This allows you to modify or completely replace the request during a forced retry. The custom request becomes the starting point for the retry - `beforeRetry` hooks can still further modify it if needed. **Note:** The custom request's `signal` will be replaced with Ky's managed signal to handle timeouts and user-provided abort signals correctly. If the original request body has been consumed, you must provide a new body or clone the request before consuming. @example ``` // Fallback to a different endpoint return ky.retry({ request: new Request('https://backup-api.com/endpoint', { method: request.method, headers: request.headers, }), code: 'BACKUP_ENDPOINT' }); // Retry with refreshed authentication token const data = await response.clone().json(); return ky.retry({ request: new Request(request, { headers: { ...Object.fromEntries(request.headers), 'Authorization': `Bearer ${data.newToken}` } }), code: 'TOKEN_REFRESHED' }); ``` */ request?: Request; }; /** Marker returned by ky.retry() to signal a forced retry from afterResponse hooks. */ export declare class RetryMarker { options?: ForceRetryOptions | undefined; constructor(options?: ForceRetryOptions | undefined); } /** Force a retry from an `afterResponse` hook. This allows you to retry a request based on the response content, even if the response has a successful status code. The retry will respect the `retry.limit` option and skip the `shouldRetry` check. The forced retry is observable in `beforeRetry` hooks, where the error will be a `ForceRetryError`. @param options - Optional configuration for the retry. @example ``` import ky, {isForceRetryError} from 'ky'; const api = ky.extend({ hooks: { afterResponse: [ async (request, options, response) => { // Retry based on response body content if (response.status === 200) { const data = await response.clone().json(); // Simple retry with default delay if (data.error?.code === 'TEMPORARY_ERROR') { return ky.retry(); } // Retry with custom delay from API response if (data.error?.code === 'RATE_LIMIT') { return ky.retry({ delay: data.error.retryAfter * 1000, code: 'RATE_LIMIT' }); } // Retry with a modified request (e.g., fallback endpoint) if (data.error?.code === 'FALLBACK_TO_BACKUP') { return ky.retry({ request: new Request('https://backup-api.com/endpoint', { method: request.method, headers: request.headers, }), code: 'BACKUP_ENDPOINT' }); } // Retry with refreshed authentication if (data.error?.code === 'TOKEN_REFRESH' && data.newToken) { return ky.retry({ request: new Request(request, { headers: { ...Object.fromEntries(request.headers), 'Authorization': `Bearer ${data.newToken}` } }), code: 'TOKEN_REFRESHED' }); } // Retry with cause to preserve error chain try { validateResponse(data); } catch (error) { return ky.retry({ code: 'VALIDATION_FAILED', cause: error }); } } } ], beforeRetry: [ ({error, retryCount}) => { // Observable in beforeRetry hooks if (isForceRetryError(error)) { console.log(`Forced retry #${retryCount}: ${error.message}`); // Example output: "Forced retry #1: Forced retry: RATE_LIMIT" } } ] } }); const response = await api.get('https://example.com/api'); ``` */ export declare const retry: (options?: ForceRetryOptions) => RetryMarker; export declare const kyOptionKeys: KyOptionsRegistry; export declare const vendorSpecificOptions: { readonly next: true; }; export declare const requestOptionsRegistry: { readonly method: true; readonly headers: true; readonly body: true; readonly mode: true; readonly credentials: true; readonly cache: true; readonly redirect: true; readonly referrer: true; readonly referrerPolicy: true; readonly integrity: true; readonly keepalive: true; readonly signal: true; readonly window: true; readonly duplex: true; };