fetchff
Version:
<div align="center"> <img src="./docs/logo.png" alt="logo" width="380"/>
964 lines (950 loc) • 50.6 kB
TypeScript
type RequestInterceptor<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> = (config: RequestConfig<ResponseData, RequestBody, QueryParams, PathParams>) => RequestConfig<ResponseData, RequestBody, QueryParams, PathParams> | void | Promise<RequestConfig<ResponseData, RequestBody, QueryParams, PathParams>> | Promise<void>;
type ResponseInterceptor<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> = (response: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>) => FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | Promise<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>> | void | Promise<void>;
type ErrorInterceptor<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> = (error: ResponseError<ResponseData, RequestBody, QueryParams, PathParams>) => void | Promise<void>;
type RetryInterceptor<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> = (response: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>, retryAttempt: number) => void | Promise<void>;
type Method = 'get' | 'GET' | 'delete' | 'DELETE' | 'head' | 'HEAD' | 'options' | 'OPTIONS' | 'post' | 'POST' | 'put' | 'PUT' | 'patch' | 'PATCH' | 'purge' | 'PURGE' | 'link' | 'LINK' | 'unlink' | 'UNLINK';
type DefaultResponse = any;
type NativeFetch = typeof fetch;
/**
* A short-hand type to create a generic request structure with customizable types for response data, request body, query parameters, and URL path parameters.
*
* @template ResponseData - The type of the response data. Defaults to `DefaultResponse`.
* @template RequestBody - The type of the request body. Defaults to `DefaultPayload`.
* @template QueryParams - The type of the query parameters. Defaults to `DefaultParams`.
* @template UrlPathParams - The type of the URL path parameters. Defaults to `DefaultUrlParams`.
*
* @property response - The response data of type `ResponseData`.
* @property body - The request body of type `RequestBody`.
* @property params - The query parameters of type `QueryParams`.
* @property urlPathParams - The URL path parameters of type `UrlPathParams`.
*/
type Req<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, UrlPathParams = DefaultUrlParams> = {
response: ResponseData;
params: QueryParams;
urlPathParams: UrlPathParams;
body: RequestBody;
};
type DefaultRequestType = {
response?: DefaultResponse;
body?: DefaultPayload;
params?: QueryParams;
urlPathParams?: UrlPathParams;
};
type CustomFetcher = <ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams>(url: string, config?: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody> | null) => PromiseLike<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>> | FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | Response | PromiseLike<Response> | PromiseLike<unknown>;
type ErrorHandlingStrategy = 'reject' | 'silent' | 'defaultResponse' | 'softFail';
interface HeadersObject {
[key: string]: string;
}
interface ExtendedResponse<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> extends Omit<Response, 'headers'> {
/**
* Return response data as parsed JSON (default) or the raw response body.
*/
data: ResponseData extends [unknown] ? any : ResponseData;
/**
* Error object if the request failed.
* This will be `null` if the request was successful.
*/
error: ResponseError<ResponseData, RequestBody, QueryParams, PathParams> | null;
/**
* Plain headers object containing the response headers.
*/
headers: HeadersObject & HeadersInit;
/**
* Request configuration used to make the request.
*/
config: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>;
/**
* Function to mutate the cached data.
* It updates the cache with new data and optionally triggers revalidation.
*
* @param {ResponseData} data - The new data to set in the cache.
* @param {MutationSettings} [mutationSettings] - Optional settings for the mutation.
* - `revalidate`: If true, it will trigger a revalidation after mutating the cache.
* @returns {Promise<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null>} The updated response or null if no cache key is set.
*/
mutate: (data: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>['data'], mutationSettings?: MutationSettings) => Promise<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null>;
/**
* Indicates if the request is currently fetching data.
* This is true during any request in progress excluding background revalidations.
*/
isFetching: boolean;
/**
* Indicates if the request was successful (2xx status codes).
* This is true if the response is OK (2xx) and no error was thrown.
*/
isSuccess: boolean;
/**
* Indicates if the request resulted in an error.
* True in cases of: non-2xx status code, network error, request failed, or response parsing error.
*/
isError: boolean;
}
/**
* Represents the response from a `fetchf()` request.
*
* @template ResponseData - The type of the data returned in the response.
* @template RequestBody - The type of the request body sent in the request.
* @template QueryParams - The type of the query parameters used in the request.
* @template PathParams - The type of the path parameters used in the request.
*/
type FetchResponse<ResponseData = any, RequestBody = any, QueryParams = any, PathParams = any> = ExtendedResponse<ResponseData, RequestBody, QueryParams, PathParams>;
interface ResponseError<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> extends Error {
status: number;
statusText: string;
isCancelled: boolean;
request: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>;
config: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>;
response: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null;
}
type RetryFunction<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> = (response: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>, attempt: number) => Promise<boolean | null> | boolean | null;
type PollingFunction<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> = (response: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>, attempts: number) => boolean;
type CacheKeyFunction<_ResponseData = DefaultResponse, _RequestBody = DefaultPayload, _QueryParams = DefaultParams, _PathParams = DefaultUrlParams> = <ResponseData = _ResponseData, RequestBody = _RequestBody, QueryParams = _QueryParams, PathParams = _PathParams>(config: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>) => string;
type CacheBusterFunction<_ResponseData = DefaultResponse, _RequestBody = DefaultPayload, _QueryParams = DefaultParams, _PathParams = DefaultUrlParams> = <ResponseData = _ResponseData, RequestBody = _RequestBody, QueryParams = _QueryParams, PathParams = _PathParams>(config: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>) => boolean;
type CacheSkipFunction<_ResponseData = DefaultResponse, _RequestBody = DefaultPayload, _QueryParams = DefaultParams, _PathParams = DefaultUrlParams> = <ResponseData = _ResponseData, RequestBody = _RequestBody, QueryParams = _QueryParams, PathParams = _PathParams>(response: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>, config: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>) => boolean;
interface MutationSettings {
refetch?: boolean;
}
/**
* Configuration object for retry related options
*/
interface RetryConfig<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> {
/**
* Maximum number of retry attempts.
* @default 0
*/
retries?: number;
/**
* Delay between retries in milliseconds.
* @default 1000
*/
delay?: number;
/**
* Exponential backoff.
* @default 1.5
*/
backoff?: number;
/**
* Maximum delay between retries in milliseconds.
* @default 30000
*/
maxDelay?: number;
/**
* Reset timeout when retrying requests
* @default true
*/
resetTimeout?: boolean;
/**
* Retry only on specific status codes.
* @url https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
* @default [
* 408, // Request Timeout
* 409, // Conflict
* 425, // Too Early
* 429, // Too Many Requests
* 500, // Internal Server Error
* 502, // Bad Gateway
* 503, // Service Unavailable
* 504, // Gateway Timeout
* ]
*/
retryOn?: number[];
/**
* A function that determines whether a failed or successful request should be retried, based on the response and the current attempt number.
* Return `true` to retry, or `false` to stop retrying.
* @param response - The response object from the failed request.
* @param attempt - The current retry attempt number (starting from 1).
* @returns `true` to retry, `false` to stop retrying, `null` to use default retry logic (retryOn headers check).
*/
shouldRetry?: RetryFunction<ResponseData, RequestBody, QueryParams, PathParams>;
}
/**
* Configuration object for cache related options
*/
interface CacheOptions<ResponseData = DefaultResponse, QueryParams = DefaultParams, PathParams = DefaultUrlParams, RequestBody = DefaultPayload> {
/**
* Time in seconds after which the cache entry is removed.
* This is the time to live (TTL) for the cache entry.
* - Set to `-1` to remove cache as soon as consumer is not using the data (e.g., a component unmounts), it is deleted from cache.
* - Set to `0` to immediately discard of cache. The cache is immediately discarded, forces fetch every time.
* - Set to `undefined` to disable cache (no cache).
*
* @default undefined (no cache)
*/
cacheTime?: number;
/**
* Time in seconds for which the cache entry is considered valid (fresh).
* After this time, the entry may be considered stale (expired) and background revalidation is triggered.
* This is implementing the SWR (stale-while-revalidate) pattern.
* - Set to a number greater than `0` to specify number of seconds during which cached data is considered "fresh".
* - Set to `0` to set data as stale immediately (always eligible to refetch).
* - Set to `undefined` to disable SWR pattern (data is never considered stale).
*
* @default undefined (disable SWR pattern) or 300 (5 minutes) in libraries like React.
*/
staleTime?: number;
/**
* Cache key generator function or string.
* Lets you customize how cache entries are identified for requests.
* - You can provide a function that returns a cache key string based on the request config.
* - You can provide a fixed string to use as the cache key.
* - Set to null to use the default cache key generator.
*
* @param config - The request configuration.
* @default null (uses the default cache key generator, which considers: method, URL, query params, path params, mode, credentials, cache, redirect, referrer, integrity, headers, and body)
*/
cacheKey?: CacheKeyFunction<ResponseData, RequestBody, QueryParams, PathParams> | string | null;
/**
* Cache Buster Function
* It is called when a cache entry exists and you want to invalidate or refresh the cache under certain conditions
* @param config - Request configuration.
* @default (config)=>false Busting cache is disabled by default. Return true to change that
*/
cacheBuster?: CacheBusterFunction<ResponseData, RequestBody, QueryParams, PathParams>;
/**
* Skip Cache Function
* Determines whether to set or skip setting caching for a request based on the response.
* @param response - Parsed Response.
* @param config - Request configuration.
* @default (response,config)=>false Bypassing cache is disabled by default. Return true to skip cache
*/
skipCache?: CacheSkipFunction<ResponseData, RequestBody, QueryParams, PathParams>;
/**
* If true, error responses (non-2xx) will also be cached.
* @default false
*/
cacheErrors?: boolean;
/**
* INTERNAL, DO NOT USE.
* This is used internally to mark requests that have cache keys generated automatically.
*/
_isAutoKey?: boolean;
/**
* INTERNAL, DO NOT USE.
* This is used internally to store the previous cache key.
*/
_prevKey?: string | null;
}
/**
* ExtendedRequestConfig<ResponseData, RequestBody, QueryParams, PathParams>
*
* This interface extends the standard `RequestInit` from the Fetch API, providing additional options
* for handling requests, including custom error handling strategies, request interception, and more.
*/
interface ExtendedRequestConfig<ResponseData = any, RequestBody = any, QueryParams_ = any, PathParams = any> extends Omit<RequestInit, 'body'>, CacheOptions {
/**
* Custom error handling strategy for the request.
* - `'reject'`: Rejects the promise with an error (default).
* - `'silent'`: Silently handles errors without rejecting.
* - `'defaultResponse'`: Returns a default response in case of an error.
* - `'softFail'`: Returns full response object even in case of error (no try/catch necessary).
*/
strategy?: ErrorHandlingStrategy;
/**
* A default response to return if the request fails
* @default undefined
*/
defaultResponse?: any;
/**
* If `true`, flattens the response object, extracting the data directly instead of keeping it nested.
*/
flattenResponse?: boolean;
/**
* Function to transform or select a subset of the response data before it is returned.
* This is called with the raw response data and should return the transformed data.
* @param data - The raw response data.
* @returns The transformed or selected data.
*/
select?: <T = ResponseData, R = any>(data: T) => R;
/**
* If true, the ongoing previous requests will be automatically cancelled.
* @default false
*/
cancellable?: boolean;
/**
* If `true`, rejects the request promise when the request is cancelled.
* @default false
*/
rejectCancelled?: boolean;
/**
* If true, automatically revalidates the request when the window regains focus.
* @default false
*/
refetchOnFocus?: boolean;
/**
* If true, automatically revalidates the request when the browser regains network connectivity.
* @default false
*/
refetchOnReconnect?: boolean;
/**
* Whether to automatically run the request as soon as the handler is created.
* - If `true`, the request is sent immediately (useful for React/Vue hooks).
* - If `false`, you must call a function to trigger the request manually.
* Primarily used in UI frameworks (e.g., React/Vue hooks); has no effect for direct fetchf() usage.
* @default true
*/
immediate?: boolean;
/**
* If true, keeps the previous data while fetching new data.
* Useful for UI frameworks to avoid showing empty/loading states between requests.
* Primarily used in UI frameworks (e.g., React/Vue hooks); has no effect for direct fetchf() usage.
* @default false
*/
keepPreviousData?: boolean;
/**
* An object representing dynamic URL path parameters.
* For example, `{ userId: 1 }` would replace `:userId` in the URL with `1`.
*/
urlPathParams?: UrlPathParams<PathParams>;
/**
* Configuration options for retrying failed requests.
*/
retry?: RetryConfig<ResponseData, RequestBody, QueryParams_, PathParams>;
/**
* The URL of the request. This can be a full URL or a relative path combined with `baseURL`.
*/
url?: string;
/**
* The HTTP method to use for the request (e.g., 'GET', 'POST', etc.).
* @default GET
*/
method?: Method | string;
/**
* The base URL to prepend to the `url` when making the request.
*/
baseURL?: string;
/**
* Alias for base URL.
*/
apiUrl?: string;
/**
* An object representing the headers to include with the request.
*/
headers?: HeadersInit;
/**
* Query parameters to include in the request URL.
*/
params?: QueryParams<QueryParams_>;
/**
* Indicates whether credentials (such as cookies) should be included with the request.
*/
withCredentials?: boolean;
/**
* An `AbortSignal` object that can be used to cancel the request.
*/
signal?: AbortSignal;
/**
* Data to be sent as the request body, extending the native Fetch API's `body` option.
* Supports `BodyInit`, objects, arrays, and strings, with automatic serialization.
*/
body?: BodyPayload<RequestBody>;
/**
* Alias for "body"
*/
data?: BodyPayload<RequestBody>;
/**
* A function or array of functions to intercept the request before it is sent.
*/
onRequest?: RequestInterceptor<ResponseData, RequestBody, QueryParams_, PathParams> | RequestInterceptor<ResponseData, RequestBody, QueryParams_, PathParams>[];
/**
* A function or array of functions to intercept the response before it is resolved.
*/
onResponse?: ResponseInterceptor<ResponseData, RequestBody, QueryParams_, PathParams> | ResponseInterceptor<ResponseData, RequestBody, QueryParams_, PathParams>[];
/**
* A function to handle errors that occur during the request or response processing.
*/
onError?: ErrorInterceptor<ResponseData, RequestBody, QueryParams_, PathParams> | ErrorInterceptor<ResponseData, RequestBody, QueryParams_, PathParams>[];
/**
* A function that is called after each failed request attempt, before the retry delay.
* Can be used for logging, side effects, or modifying the response/config before retrying.
* @param response - The response object from the failed request.
* @param attempt - The current retry attempt number (starting from 0).
*/
onRetry?: RetryInterceptor<ResponseData, RequestBody, QueryParams_, PathParams> | RetryInterceptor<ResponseData, RequestBody, QueryParams_, PathParams>[];
/**
* The maximum time (in milliseconds) the request can take before automatically being aborted. 0 seconds disables the timeout.
* @default 30000 (30 seconds)
*/
timeout?: number;
/**
* Time window, in miliseconds, during which identical requests are deduplicated (treated as single request).
* @default 0 (0 milliseconds means no deduplication)
*/
dedupeTime?: number;
/**
* The time (in milliseconds) between the end of one polling attempt and the start of the next.
* Set 0 to disable polling.
* @default 0 (polling disabled)
*/
pollingInterval?: number;
/**
* The time (in milliseconds) to wait before each polling attempt begins. Adds a delay before each poll is started (including the first one).
* @default 0 (no delay)
*/
pollingDelay?: number;
/**
* Maximum number of polling attempts before stopping.
* Set to < 1 for unlimited attempts.
* @default 0 (unlimited)
*/
maxPollingAttempts?: number;
/**
* Function to determine if polling should stop based on the response.
* @param response - The response data.
* @returns `true` to stop polling, `false` to continue.
*/
shouldStopPolling?: PollingFunction<ResponseData, RequestBody, QueryParams_, PathParams>;
/**
* A custom fetcher instance to handle requests instead of the default implementation.
* When `null`, the default fetch behavior is used.
*
* @example:
* const customFetcher: CustomFetcher = (url, config) => fetch(url, config);
* const data = await fetchf('/endpoint', { fetcher: customFetcher });
*
* @default null
*/
fetcher?: CustomFetcher | null;
/**
* A custom logger instance to handle warnings and errors.
* When `null`, logging is disabled.
*
* @example:
* const customLogger: Logger = { warn: console.warn, error: console.error };
* fetchf('/endpoint', { logger: customLogger });
*
* @default null (Logging is disabled)
*/
logger?: FetcherLogger | null;
/**
* @deprecated Use the "immediate" property instead for controlling request execution.
* This property is provided for compatibility with React Query.
*/
enabled?: boolean;
/**
* @deprecated Use the "refetchOnFocus" property instead for controlling refetch on window focus.
* This property is provided for compatibility with React Query.
*/
refetchOnWindowFocus?: boolean;
/**
* @deprecated Use "onResponse" instead for transforming response data.
* This property is provided for compatibility with React Query.
*/
onSuccess?: any;
/**
* @deprecated Use "onResponse" or "onError" instead for handling settled requests.
* This property is provided for compatibility with React Query.
*/
onSettled?: any;
/**
* @deprecated Use the "strategy: 'reject'" property instead for enabling Suspense mode.
* If true, enables Suspense mode for UI frameworks like React.
* Suspense mode will throw a promise while loading, allowing components to suspend rendering.
* This property is provided for compatibility with React Query.
* @default false
*/
suspense?: boolean;
/**
* @deprecated Use "immediate" instead for controlling request execution on component mount.
* If true, automatically retries the request when the handler/component mounts.
* This property is provided for compatibility with React Query.
* @default false
*/
retryOnMount?: boolean;
/**
* @deprecated Use the "pollingInterval" property instead for controlling periodic refetching.
* This property is provided for compatibility with React Query.
*/
refetchInterval?: number;
/**
* @deprecated Use "defaultResponse" instead.
* If set, provides fallback data to use when the request fails or is loading.
* This property is provided for compatibility with React Query.
*/
fallbackData?: any;
/**
* @deprecated Use "dedupeTime" instead for controlling request deduplication.
* If set, requests made within this interval (in milliseconds) will be deduplicated.
* This property is provided for compatibility with SWR.
*/
dedupingInterval?: number;
/**
* @deprecated Use "pollingInterval" instead for periodic refresh of the request.
* If set, enables periodic refresh of the request at the specified interval (in milliseconds).
* Useful for polling or auto-refresh scenarios.
* This property is provided for compatibility with SWR.
*/
refreshInterval?: number;
/**
* @deprecated Use "pollingInterval" instead for enabling periodic refresh.
* If true, enables periodic refresh of the request.
* This property is provided for compatibility with SWR.
*/
refreshIntervalEnabled?: boolean;
/**
* @deprecated Use the "refetchOnReconnect" property instead for controlling refetch on reconnect.
* This property is provided for compatibility with SWR.
*/
revalidateOnReconnect?: boolean;
/**
* @deprecated Use the "refetchOnFocus" property instead for controlling refetch on window focus.
* This property is provided for compatibility with with SWR.
*/
revalidateOnFocus?: boolean;
/**
* @deprecated Use the "fetcher" property instead for providing a custom fetch function.
* This property is provided for compatibility with React Query.
*/
queryFn?: CustomFetcher | null;
/**
* @deprecated Use the "cacheKey" property instead for customizing cache identification.
* This property is provided for compatibility with React Query and SWR.
*/
queryKey?: string | null;
}
interface FetcherLogger extends Partial<Console> {
warn(message?: any, ...optionalParams: any[]): void;
error?(message?: any, ...optionalParams: any[]): void;
}
type RequestConfig<ResponseData = any, QueryParams = any, PathParams = any, RequestBody = any> = ExtendedRequestConfig<ResponseData, RequestBody, QueryParams, PathParams>;
type FetcherConfig<ResponseData = any, RequestBody = any, QueryParams = any, PathParams = any> = Omit<ExtendedRequestConfig<ResponseData, RequestBody, QueryParams, PathParams>, 'url'> & {
url: string;
cacheKey?: string | null;
};
interface NameValuePair {
name: string;
value: string;
}
declare const emptyObjectSymbol: unique symbol;
type EmptyObject = {
[emptyObjectSymbol]?: never;
};
type DefaultParams = Record<string, any> | URLSearchParams | NameValuePair[] | EmptyObject | null;
type DefaultUrlParams = Record<string, any>;
type DefaultPayload = Record<string, any>;
declare type QueryParams<ParamsType = DefaultParams> = (ParamsType & EmptyObject) | URLSearchParams | NameValuePair[] | EmptyObject | null;
declare type UrlPathParams<UrlParamsType = DefaultUrlParams> = ([UrlParamsType] extends [DefaultUrlParams] ? UrlParamsType & EmptyObject : UrlParamsType) | EmptyObject | null;
declare type BodyPayload<PayloadType = DefaultPayload> = BodyInit | (PayloadType & EmptyObject) | PayloadType[] | null;
type EndpointDefaults = Endpoint<DefaultRequestType>;
/**
* Represents an API endpoint definition with optional type parameters for various request and response components.
*
* @template T - An object that can specify the following optional properties:
* @property response - The expected response type returned by the endpoint (default: `DefaultResponse`).
* @property body - The type of the request body accepted by the endpoint (default: `BodyPayload`).
* @property params - The type of the query parameters accepted by the endpoint (default: `QueryParams`).
* @property urlPathParams - The type of the path parameters accepted by the endpoint (default: `UrlPathParams`).
*
* @example
* interface EndpointTypes {
* getUser: Endpoint<{ response: UserResponse }>;
* getPosts: Endpoint<{
* response: PostsResponse;
* params: PostsQueryParams;
* urlPathParams: PostsUrlPathParams;
* body: PostsRequestBody;
* }>;
* }
*/
type Endpoint<T extends DefaultRequestType = DefaultRequestType> = EndpointFunction<T>;
type EndpointReq<ResponseData extends DefaultResponse | undefined = DefaultResponse, RequestBody extends DefaultPayload | undefined = DefaultPayload, QueryParams extends DefaultParams | undefined = DefaultParams, UrlPathParams extends DefaultUrlParams | undefined = DefaultUrlParams> = Endpoint<Req<ResponseData, RequestBody, QueryParams, UrlPathParams>>;
type MergeEndpointShape<O extends Partial<DefaultRequestType>, T extends DefaultRequestType> = {
response: O extends {
response: infer R;
} ? R : T extends {
response: infer R;
} ? R : DefaultResponse;
body: O extends {
body: infer B;
} ? B : T extends {
body: infer B;
} ? B : BodyPayload;
params: O extends {
params: infer P;
} ? P : T extends {
params: infer P;
} ? P : QueryParams;
urlPathParams: O extends {
urlPathParams: infer U;
} ? U : T extends {
urlPathParams: infer U;
} ? U : UrlPathParams;
};
interface EndpointFunction<T extends Partial<DefaultRequestType> = DefaultRequestType> {
<O extends Partial<DefaultRequestType> = {}>(requestConfig?: RequestConfig<MergeEndpointShape<O, T>['response'], MergeEndpointShape<O, T>['params'], MergeEndpointShape<O, T>['urlPathParams'], MergeEndpointShape<O, T>['body']>): Promise<FetchResponse<MergeEndpointShape<O, T>['response'], MergeEndpointShape<O, T>['body'], MergeEndpointShape<O, T>['params'], MergeEndpointShape<O, T>['urlPathParams']>>;
}
interface RequestEndpointFunction<EndpointTypes> {
<O extends Partial<DefaultRequestType> = {}>(endpointNameOrUrl: keyof EndpointTypes | string, requestConfig?: RequestConfig<MergeEndpointShape<O, DefaultRequestType>['response'], MergeEndpointShape<O, DefaultRequestType>['params'], MergeEndpointShape<O, DefaultRequestType>['urlPathParams'], MergeEndpointShape<O, DefaultRequestType>['body']>): Promise<FetchResponse<MergeEndpointShape<O, DefaultRequestType>['response'], MergeEndpointShape<O, DefaultRequestType>['body'], MergeEndpointShape<O, DefaultRequestType>['params'], MergeEndpointShape<O, DefaultRequestType>['urlPathParams']>>;
}
type MergeWithEndpointDef<EndpointTypes, K extends keyof EndpointTypes, O extends Partial<DefaultRequestType>> = MergeEndpointShape<O, EndpointTypes[K] extends Endpoint<infer S> ? S : DefaultRequestType>;
type EndpointMethod<EndpointTypes, K extends keyof EndpointTypes> = <O extends Partial<DefaultRequestType> = {}>(requestConfig?: RequestConfig<MergeWithEndpointDef<EndpointTypes, K, O>['response'], MergeWithEndpointDef<EndpointTypes, K, O>['params'], MergeWithEndpointDef<EndpointTypes, K, O>['urlPathParams'], MergeWithEndpointDef<EndpointTypes, K, O>['body']>) => Promise<FetchResponse<MergeWithEndpointDef<EndpointTypes, K, O>['response'], MergeWithEndpointDef<EndpointTypes, K, O>['body'], MergeWithEndpointDef<EndpointTypes, K, O>['params'], MergeWithEndpointDef<EndpointTypes, K, O>['urlPathParams']>>;
/**
* Maps the method names from `EndpointTypes` to their corresponding `Endpoint` type definitions.
*
* @template EndpointTypes - The object containing endpoint method definitions.
*/
type EndpointsRecord<EndpointTypes> = {
[K in keyof EndpointTypes]: EndpointMethod<EndpointTypes, K>;
};
/**
* Defines default endpoints based on the provided `EndpointsSettings`.
*
* This type provides default implementations for endpoints in `EndpointsSettings`, using `EndpointDefaults`.
*
* @template EndpointsSettings - The configuration object for endpoints.
*/
type DefaultEndpoints<EndpointsSettings> = {
[K in keyof EndpointsSettings]: EndpointDefaults;
};
type RequestConfigUrlRequired = Omit<RequestConfig, 'url'> & {
url: string;
};
/**
* Configuration for API endpoints, where each key is an endpoint name or string, and the value is the request configuration.
*
* @template EndpointTypes - The object containing endpoint method definitions.
*/
type EndpointsConfig<EndpointTypes> = Record<keyof EndpointTypes | string, RequestConfigUrlRequired>;
/**
* Part of the endpoints configuration, derived from `EndpointsSettings` based on the `EndpointTypes`.
*
* This type handles defaulting to endpoints configuration when particular Endpoints Methods are not provided.
*
* @template EndpointsSettings - The configuration object for endpoints.
* @template EndpointTypes - The object containing endpoint method definitions.
*/
type EndpointsConfigPart<EndpointsSettings, EndpointTypes extends object> = [
EndpointsSettings
] extends [never] ? unknown : DefaultEndpoints<Omit<EndpointsSettings, keyof EndpointTypes>>;
/**
* Provides the methods available from the API handler, combining endpoint record types, endpoints configuration,
* and default methods.
*
* @template EndpointTypes - The object containing endpoint method definitions.
* @template EndpointsSettings - The configuration object for endpoints.
*/
type ApiHandlerMethods<EndpointTypes extends object, EndpointsSettings> = EndpointsRecord<EndpointTypes> & // Provided interface
EndpointsConfigPart<EndpointsSettings, EndpointTypes> & // Derived defaults from 'endpoints'
ApiHandlerDefaultMethods<EndpointTypes>;
/**
* Defines the default methods available within the API handler.
*
* This includes configuration, endpoint settings, request handler, instance retrieval, and a generic request method.
*
* @template EndpointTypes - The object containing endpoint method definitions.
*/
type ApiHandlerDefaultMethods<EndpointTypes> = {
config: ApiHandlerConfig<EndpointTypes>;
endpoints: EndpointsConfig<EndpointTypes>;
request: RequestEndpointFunction<EndpointTypes>;
};
type RequireApiUrlOrBaseURL = {
apiUrl: string;
baseURL?: never;
} | {
apiUrl?: never;
baseURL: string;
};
/**
* Configuration for the API handler, including API URL and endpoints.
*
* @template EndpointTypes - The object containing endpoint method definitions.
*/
type ApiHandlerConfig<EndpointTypes> = RequestConfig & RequireApiUrlOrBaseURL & {
endpoints: EndpointsConfig<EndpointTypes>;
};
type RefetchFunction<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> = (forceRefresh?: boolean | any, requestConfig?: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>) => Promise<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null>;
interface UseFetcherResult<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams> {
/**
* The fetched data, or null if not yet available.
* This will be null if the request is in progress or if no data has been fetched yet.
*/
data: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>['data'] | null;
/**
* The error encountered during the fetch operation, if any.
* If the request was successful, this will be null.
*/
error: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>['error'] | null;
/**
* Indicates if this is the first fetching attempt for the request since the hook was mounted.
* Useful for showing loading indicators before any data is fetched.
* @returns true when there is no data nor error yet and during any request in progress or is about to start.
*/
isFirstFetch: boolean;
/**
* This is an alias for `isLoading`.
* Indicates if the request is currently loading data.
* @returns true during any request in progress excluding background revalidations.
* @see isLoading
*/
isFetching: boolean;
/**
* Indicates if the request is currently loading data.
* @returns true during any request in progress excluding background revalidations.
*/
isLoading: boolean;
/**
* Indicates if the request was successful (2xx status codes).
* @returns true if the response is OK (2xx) and no error was thrown.
*/
isSuccess: boolean;
/**
* Indicates if the request resulted in an error.
* @returns true in cases of: non-2xx status code, network error, request failed, or response parsing error.
*/
isError: boolean;
/**
* Indicates if the request is currently refetching data.
* This is true when a fetch is in progress and there is already data displayed (i.e., not the initial load).
* Useful for showing a subtle loading indicator when updating existing data.
* @returns true when the request is refetching data.
*/
isRefetching: boolean;
/**
* Function to mutate the cached data.
* It updates the cache with new data and optionally triggers revalidation.
*
* @param {ResponseData} data - The new data to set in the cache.
* @param {MutationSettings} [mutationSettings] - Optional settings for the mutation.
* - `revalidate`: If true, it will trigger a revalidation after mutating the cache.
* @returns {Promise<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null>} The updated response or null if no cache key is set.
*/
mutate: (data: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>['data'], mutationSettings?: MutationSettings) => Promise<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null>;
/**
* Function to refetch the data from the server.
* This will trigger a new fetch operation and update the cache with the latest data.
*
* @returns {Promise<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null>} The new fetch response or null if no URL is set.
*/
refetch: RefetchFunction<ResponseData, RequestBody, QueryParams, PathParams>;
/**
* The configuration object used for this fetcher instance.
* This contains the settings and options passed to the hook.
*/
config: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>['config'] | undefined;
/**
* The HTTP headers returned with the response, or undefined if not available.
*/
headers: FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>['headers'] | undefined;
}
/**
* Sends an HTTP request to the specified URL using the provided configuration and returns a typed response.
*
* @typeParam ResponseData - The expected shape of the response data. Defaults to `DefaultResponse`.
* @typeParam RequestBody - The type of the request payload/body. Defaults to `DefaultPayload`.
* @typeParam QueryParams - The type of the query parameters. Defaults to `DefaultParams`.
* @typeParam PathParams - The type of the path parameters. Defaults to `DefaultUrlParams`.
*
* @param url - The endpoint URL to which the request will be sent.
* @param config - Optional configuration object for the request, including headers, method, body, query, and path parameters.
*
* @returns A promise that resolves to a `FetchResponse` containing the typed response data and request metadata.
*
* @example
* ```typescript
* const { data } = await fetchf<UserData>('/api/user', { method: 'GET' });
* console.log(data);
* ```
*/
declare function fetchf<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams>(url: string, reqConfig?: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody> | null): Promise<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>>;
/**
* Creates an instance of API Handler.
* It creates an API fetcher function using native fetch() or a custom fetcher if passed as "fetcher".
* @see https://github.com/MattCCC/fetchff#configuration
*
* @param {Object} config - Configuration object for the API fetcher (see link above for full options).
* @param {Object} config.endpoints - An object containing endpoint definitions.
* @param {string} [config.baseURL] - The base URL for the API.
* @param {Object} [config.headers] - Optional default headers to include in every request.
* @param {Function} [config.onError] - Optional callback function for handling errors.
* @returns API handler functions and endpoints to call
*
* @example
* // Define endpoint paths
* const endpoints = {
* getUser: '/user',
* createPost: '/post',
* };
*
* // Create the API fetcher with configuration
* const api = createApiFetcher({
* endpoints,
* apiUrl: 'https://example.com/api',
* onError(error) {
* console.log('Request failed', error);
* },
* headers: {
* 'my-auth-key': 'example-auth-key-32rjjfa',
* },
* });
*
* // Fetch user data
* const response = await api.getUser({ userId: 1, ratings: [1, 2] })
*/
declare function createApiFetcher<EndpointTypes extends object, EndpointsSettings = never>(config: ApiHandlerConfig<EndpointTypes>): ApiHandlerMethods<EndpointTypes, EndpointsSettings>;
/**
* Overwrites the default configuration with the provided custom configuration.
*
* @param {Partial<RequestConfig>} customConfig - The custom configuration to merge into the default config.
* @returns {Partial<RequestConfig>} - The updated default configuration object.
*/
declare function setDefaultConfig(customConfig: Partial<RequestConfig>): Partial<RequestConfig>;
/**
* Returns a shallow copy of the current default configuration.
*
* @returns {RequestConfig} - The current default configuration.
*/
declare function getDefaultConfig(): RequestConfig;
/**
* Build request configuration from defaults and overrides.
* This function merges the default configuration with the provided request configuration,
* @param {string} url - Request url
* @param {RequestConfig<ResponseData, QueryParams, PathParams, RequestBody> | null | undefined} reqConfig - Request configuration
* @return {RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>} - Merged request configuration
*/
declare function buildConfig<ResponseData, RequestBody, QueryParams, PathParams>(url: string, reqConfig?: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody> | null): RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>;
interface CacheEntry<T> {
data: T;
time: number;
stale?: number;
expiry?: number;
}
/**
* Generates a unique cache key for a given URL and fetch options, ensuring that key factors
* like method, headers, body, and other options are included in the cache key.
* Headers and other objects are sorted by key to ensure consistent cache keys.
*
* @param {RequestConfig} config - The fetch options that may affect the request. The most important are:
* @property {string} [method="GET"] - The HTTP method (GET, POST, etc.).
* @property {HeadersInit} [headers={}] - The request headers.
* @property {BodyInit | null} [body=""] - The body of the request (only for methods like POST, PUT).
* @property {RequestCredentials} [credentials="same-origin"] - Whether to include credentials (include, same-origin, omit).
* @property {RequestCache} [cache="default"] - The cache mode (e.g., default, no-store, reload).
* @returns {string} - A unique cache key string based on the provided options.
*
* @example
* const cacheKey = generateCacheKey({
* url: 'https://api.example.com/data',
* method: 'POST',
* headers: { 'Content-Type': 'application/json' },
* body: JSON.stringify({ name: 'Alice' }),
* mode: 'cors',
* credentials: 'include',
* });
* console.log(cacheKey);
*/
declare function generateCacheKey(config: RequestConfig, cacheKeyCheck?: boolean): string;
/**
* Retrieves a cache entry if it exists and is not expired.
*
* @param {string} key Cache key to utilize
* @returns {CacheEntry<T> | null} - The cache entry if it exists and is not expired, null otherwise.
*/
declare function getCache<ResponseData, RequestBody, QueryParams, PathParams>(key: string | null): CacheEntry<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams>> | null | undefined;
/**
* Sets a new cache entry or updates an existing one, with optional TTL (time-to-live).
*
* @param {string} key Cache key to utilize
* @param {T} data - The data to be cached.
* @param {number} [ttl] - Optional TTL in seconds. If not provided, the cache entry will not expire.
* @param {number} [staleTime] - Optional stale time in seconds. If provided, the cache entry will be considered stale after this time.
*/
declare function setCache<T = unknown>(key: string, data: T, ttl?: number, staleTime?: number): void;
/**
* Invalidates (deletes) a cache entry.
*
* @param {string} key Cache key to utilize
* @param {boolean} [removeExpired=false] - If true, only deletes the cache entry if it is expired or stale.
*/
declare function deleteCache(key: string, removeExpired?: boolean): void;
/**
* Mutates a cache entry with new data and optionally revalidates it.
*
* @param {string | null} key Cache key to utilize. If null, no mutation occurs.
* @param {ResponseData} newData - The new data to be cached.
* @param {MutationSettings|undefined} settings - Mutation settings.
*/
declare function mutate<ResponseData = DefaultResponse, RequestBody = DefaultPayload, QueryParams = DefaultParams, PathParams = DefaultUrlParams>(key: string | null, newData: ResponseData, settings?: MutationSettings): Promise<FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null>;
/**
* Retrieves a cached response if available and valid, otherwise returns null.
*
* @template ResponseData - The type of the response data.
* @template RequestBody - The type of the request body.
* @template QueryParams - The type of the query parameters.
* @template PathParams - The type of the path parameters.
* @param {string | null} cacheKey - The cache key to look up.
* @param {number | undefined} cacheTime - The maximum time to cache entry.
* @param {RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>} requestConfig - The fetcher configuration.
* @returns {FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null} - The cached response or null.
*/
declare function getCachedResponse<ResponseData, RequestBody, QueryParams, PathParams>(cacheKey: string | null, cacheTime: number | undefined, requestConfig: RequestConfig<ResponseData, QueryParams, PathParams, RequestBody>): FetchResponse<ResponseData, RequestBody, QueryParams, PathParams> | null;
type EventType = 'focus' | 'online';
/**
* Triggers revalidation for all registered entries based on the given event type.
* For example, if it's a 'focus' event, it will revalidate entries that have the `refetchOnFocus` flag set.
* Updates the timestamp and invokes the revalidator function for each applicable entry.
*
* @param type - The type of event that caused the revalidation (e.g., 'focus' or 'online').
* @param isStaleRevalidation - If `true`, uses background revalidator and doesn't mark as in-flight.
*/
declare function revalidateAll(type: EventType, isStaleRevalidation?: boolean): void;
/**
* Revalidates an entry by executing the registered revalidation function.
*
* @param key The unique identifier for the cache entry to revalidate. If `null`, no revalidation occurs.
* @param isStaleRevalidation - If `true`, it does not mark revalidated requests as in-flight.
* @returns A promise that resolves to the result of the revalidator function, or
* `null` if no key or revalidator is found, or a `FetchResponse` if applicable.
*/
declare function revalidate<T = unknown>(key: string | null, isStaleRevalidation?: boolean): Promise<T | null | FetchResponse>;
/**
* Removes all revalidators associated with the specified event type.
*
* @param type - The event type whose revalidators should be removed.
*/
declare function removeRevalidators(type: EventType): void;
declare function subscribe<T>(key: string | null, fn: (response: T) => void): () => void;
/**
* Removes a request from the queue and clears its timeout.
*
* @param key - Unique key for the request.
* @param {boolean} error - Optional error to abort the request with. If null, the request is simply removed but no abort sent.
* @returns {Promise<void>} - A promise that resolves when the request is aborted and removed.
*/
declare function abortRequest(key: string | null, error?: DOMException | null | string): Promise<void>;
/**
* Retrieves the in-flight promise for a request key if it exists and is within the dedupeTime interval.
*
* @param key - Unique key for the request.
* @param dedupeTime - Deduplication time in milliseconds.
* @returns {Promise<T> | null} - The in-flight promise or null.
*/
declare function getInFlightPromise<T = unknown>(key: string | null, dedupeTime: number): Promise<T> | null;
/**
* Detects if the user is on a slow network connection
* @returns {boolean} True if connection is slow, false otherwise or if detection unavailable
*/
declare const isSlowConnection: () => boolean;
/**
* @module timeout-wheel
* @description
* Ultra-minimal timing wheel implementation optimized for max performance & many requests.
* For most of the cases it's 4-100x faster than setTimeout and setInterval alone.
* Provides efficient scheduling and cancellation of timeouts using a circular array.
*
* Position 0 → 1 → 2 → ... → 599 → 0 → 1 → 2 ...
* Time: 0s 1s 2s 599s 600s 601s 602s
*
* The timing wheel consists of 600 slots (one per second for 10 min).
* Each slot contains a list of timeout items, each associated with a unique key and callback.
* Timeouts are scheduled by placing them in the appropriate slot based on the delay in seconds.
* The wheel advances every second, executing and removing callbacks as their timeouts expire.
* Defaults to setTimeout if the delay exceeds 10 minutes or is not divisible by 1000.
*
* @remarks
* - Designed for minimal footprint and simplicity.
* - Only supports second-level granularity (minimum timeout: 1 second).
* - Automatically stops the internal timer when no timeouts remain.
*/
type TimeoutCallback = () => unknown | Promise<unknown>;
declare const addTimeout: (key: string, cb: TimeoutCallback, ms: number) => void;
export { type ApiHandlerConfig, type ApiHandlerDefaultMethods, type ApiHandlerMethods, type BodyPayload, type CacheBusterFunction, type CacheKeyFunction, type CacheOptions, type CacheSkipFunction, type CustomFetcher, type DefaultParams, type DefaultPayload, type DefaultRequestType, type DefaultResponse, type DefaultUrlParams, type EmptyObject, type Endpoint, type EndpointReq, type EndpointsConfig, type ErrorHandlingStrategy, type ExtendedRequestConfig, type ExtendedResponse, type FetchResponse, type FetcherConfig, type FetcherLogger, type HeadersObject, type Method, type MutationSettings, type Nat