@hyper-fetch/core
Version:
Cache, Queue and Persist your requests no matter if you are online or offline!
223 lines • 17.1 kB
TypeScript
import { RequestSendType, PayloadType, RequestJSON, RequestOptionsType, RequestConfigurationType, PayloadMapperType, RequestInstance, RequestMapper, ResponseMapper, ExtractUrlParams, RetryOnErrorCallbackType, OptimisticCallback } from './request.types';
import { RequestHooks } from './request.hooks';
import { ClientInstance } from '../client';
import { ResponseErrorType, ResponseSuccessType, ResponseType } from '../adapter';
import { ExtractClientAdapterType, ExtractClientGlobalError, ExtractParamsType, EmptyTypes, ExtractAdapterMethodType, ExtractAdapterOptionsType, HydrateDataType, SyncOrAsync } from '../types';
import { MockerConfigType, MockResponseType } from '../mocker';
type ClientAdapterOptions<C extends ClientInstance> = ExtractAdapterOptionsType<ExtractClientAdapterType<C>>;
type ClientAdapterMethod<C extends ClientInstance> = ExtractAdapterMethodType<ExtractClientAdapterType<C>>;
type ClientRequestOptions<E, C extends ClientInstance> = RequestOptionsType<E, ClientAdapterOptions<C>, ClientAdapterMethod<C>>;
/**
* Request is a class that represents a request sent to the server. It contains all the necessary information to make a request, like endpoint, method, headers, data, and much more.
* It is executed at any time via methods like `send` or `exec`.
*
* We can set it up with options like endpoint, method, headers and more.
* We can choose some of advanced settings like cache, invalidation patterns, concurrency, retries and much, much more.
*
* @info We should not use this class directly in the standard development flow.
* We can initialize it using the `createRequest` method on the **Client** class.
*
* @attention The most important thing about the request is that it keeps data in the format that can be dumped.
* This is necessary for the persistence and different dispatcher storage types.
* This class doesn't have any callback methods by design and communicate with dispatcher and cache by events.
*
* It should be serializable to JSON and deserializable back to the class.
* Serialization should not affect the result of the request, so it's methods and functional part should be only syntax sugar for given runtime.
*/
export declare class Request<Response, Payload, QueryParams, LocalError, Endpoint extends string, Client extends ClientInstance, HasPayload extends true | false = false, HasParams extends true | false = false, HasQuery extends true | false = false, MutationContext = undefined> {
readonly client: Client;
readonly requestOptions: ClientRequestOptions<Endpoint, Client>;
readonly initialRequestConfiguration?: RequestConfigurationType<Payload, Endpoint extends string ? ExtractUrlParams<Endpoint> : never, QueryParams, Endpoint, ClientAdapterOptions<Client>, ClientAdapterMethod<Client>> | undefined;
endpoint: Endpoint;
headers?: HeadersInit;
auth: boolean;
method: ClientAdapterMethod<Client>;
params: ExtractUrlParams<Endpoint> | EmptyTypes;
payload: PayloadType<Payload>;
queryParams: QueryParams | EmptyTypes;
options?: ClientAdapterOptions<Client> | undefined;
cancelable: boolean;
retry: number;
retryTime: number;
cacheTime: number;
cache: boolean;
staleTime: number;
queued: boolean;
offline: boolean;
abortKey: string;
cacheKey: string;
queryKey: string;
used: boolean;
deduplicate: boolean;
deduplicateTime: number | null;
scope: string | null;
/**
* Instance-level lifecycle hooks. These callbacks fire for every `send()` / `exec()` call
* made on this request instance (and its clones), without needing to pass them to `send()` each time.
* Useful for cross-cutting concerns like logging, analytics, or toast notifications.
*
* Each method registers a callback and returns an unsubscribe function.
* Multiple listeners per hook are supported.
*/
$hooks: RequestHooks<RequestInstance>;
isMockerEnabled: boolean;
unstable_mock?: {
fn: (options: {
request: RequestInstance;
requestId: string;
}) => MockResponseType<Response, LocalError | ExtractClientGlobalError<Client>, ExtractClientAdapterType<Client>>;
config: MockerConfigType;
};
/** @internal */
unstable_payloadMapper?: PayloadMapperType<Payload>;
/** @internal */
unstable_requestMapper?: RequestMapper<any, any>;
/** @internal */
unstable_responseMapper?: ResponseMapper<this, ResponseSuccessType<any, any> | ResponseErrorType<any, any>>;
/** @internal */
retryOnError?: RetryOnErrorCallbackType<RequestInstance>;
/** @internal */
optimistic?: OptimisticCallback<RequestInstance, any>;
unstable_hasParams: HasParams;
unstable_hasPayload: HasPayload;
unstable_hasQuery: HasQuery;
unstable_hasMutationContext: MutationContext;
private updatedAbortKey;
private updatedCacheKey;
private updatedQueryKey;
constructor(client: Client, requestOptions: ClientRequestOptions<Endpoint, Client>, initialRequestConfiguration?: RequestConfigurationType<Payload, Endpoint extends string ? ExtractUrlParams<Endpoint> : never, QueryParams, Endpoint, ClientAdapterOptions<Client>, ClientAdapterMethod<Client>> | undefined);
/** Set the request headers. Returns a cloned request with the new headers applied. */
setHeaders: (headers: HeadersInit) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set whether authentication interceptors should run for this request. */
setAuth: (auth: boolean) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set the URL path parameters (e.g., `:userId`). */
setParams: <P extends ExtractParamsType<this>>(params: P) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, P extends null ? false : true, HasQuery, MutationContext>;
/** Set the request body payload. */
setPayload: <P extends Payload>(payload: P) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, P extends null ? false : true, HasParams, HasQuery, MutationContext>;
/** Set the query parameters appended to the URL. */
setQueryParams: (queryParams: QueryParams) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, true, MutationContext>;
/** Set adapter-specific options (e.g., axios config, fetch init). */
setOptions: (options: ClientAdapterOptions<Client>) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, true, MutationContext>;
/**
* Set a scope identifier for this request.
* All keys (cache, queue, abort) are prefixed with this scope, isolating
* the request from other scopes. In "server" client mode, setting a scope
* also enables caching (which is otherwise disabled to prevent cross-request leaks).
*/
setScope: (scopeId: string) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set whether in-flight requests with the same abort key are cancelled when a new one is dispatched. */
setCancelable: (cancelable: boolean) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set the number of retry attempts on failure. */
setRetry: (retry: ClientRequestOptions<Endpoint, Client>["retry"]) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set the delay in milliseconds between retry attempts. */
setRetryTime: (retryTime: ClientRequestOptions<Endpoint, Client>["retryTime"]) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/**
* Set a callback that controls whether a failed request should be retried.
* Called on each failed attempt before scheduling the next retry.
* Return `true` to allow the retry, `false` to stop retrying immediately.
*/
setRetryOnError: (callback: RetryOnErrorCallbackType<Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery>>) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/**
* Configure optimistic update behavior for this request.
* The callback runs before the request is sent (in React's `useSubmit`) and receives
* the request, client, and payload. Return `context` (available in submit callbacks),
* `rollback` (called automatically on failure/abort), and `invalidate` (cache keys
* invalidated on success).
*/
setOptimistic: <Ctx>(callback: OptimisticCallback<this, Ctx>) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, Ctx>;
/** Set how long (in ms) the response remains in cache before being garbage collected. */
setCacheTime: (cacheTime: ClientRequestOptions<Endpoint, Client>["cacheTime"]) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set whether this request should use the cache. */
setCache: (cache: ClientRequestOptions<Endpoint, Client>["cache"]) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set how long (in ms) cached data is considered fresh before triggering a revalidation. */
setStaleTime: (staleTime: ClientRequestOptions<Endpoint, Client>["staleTime"]) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set whether the request should be queued and executed sequentially rather than immediately. */
setQueued: (queued: boolean) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Override the abort key used to cancel this request. */
setAbortKey: (abortKey: string) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Override the cache key used to store/retrieve the response. */
setCacheKey: (cacheKey: string) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Override the query key that identifies this request in the dispatcher queue. */
setQueryKey: (queryKey: string) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Enable or disable request deduplication. When enabled, concurrent identical requests share a single response. */
setDeduplicate: (deduplicate: boolean) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set the time window (in ms) during which identical requests are deduplicated. */
setDeduplicateTime: (deduplicateTime: number) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Mark the request as used (prevents automatic refetching in hooks). */
setUsed: (used: boolean) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Set whether the request should be stored in the offline queue when there is no network connection. */
setOffline: (offline: boolean) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Attach a mock handler to this request. When mocking is enabled, the handler is called instead of the real adapter. */
setMock: (fn: (options: {
request: Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery>;
requestId: string;
}) => SyncOrAsync<MockResponseType<Response, LocalError | ExtractClientGlobalError<Client>, ExtractClientAdapterType<Client>>>, config?: MockerConfigType) => this;
/** Remove any attached mock handler and disable mocking for this request. */
clearMock: () => this;
/** Enable or disable the mocker for this request without removing the mock handler. */
setMockingEnabled: (isMockerEnabled: boolean) => this;
/**
* Map data before it gets send to the server
* @param payloadMapper
* @returns
*/
setPayloadMapper: <MappedPayload extends any | Promise<any>>(payloadMapper: (data: Payload) => MappedPayload) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/**
* Map request before it gets send to the server
* @param requestMapper mapper of the request
* @returns new request
*/
setRequestMapper: <NewRequest extends RequestInstance>(requestMapper: RequestMapper<this, NewRequest>) => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/**
* Map the response to the new interface
* @param responseMapper our mapping callback
* @returns new response
*/
setResponseMapper: <MappedResponse extends ResponseSuccessType<any, any> | ResponseErrorType<any, any>>(responseMapper?: ResponseMapper<this, MappedResponse>) => Request<MappedResponse extends ResponseType<infer R, any, any> ? R : Response, Payload, QueryParams, MappedResponse extends ResponseType<any, infer E, any> ? E : LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
private paramsMapper;
/** Serialize the request configuration into a plain JSON object for persistence or transfer. */
toJSON(): RequestJSON<this>;
/** Create a new request instance with optional configuration overrides. Used internally by all setter methods. */
clone<NewData extends true | false = HasPayload, NewParams extends true | false = HasParams, NewQueryParams extends true | false = HasQuery>(configuration?: RequestConfigurationType<Payload, (typeof this)["params"], QueryParams, Endpoint, ClientAdapterOptions<Client>, ClientAdapterMethod<Client>>): Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, NewData, NewParams, NewQueryParams, MutationContext>;
/** Abort all in-flight requests sharing this request's abort key. */
abort: () => Request<Response, Payload, QueryParams, LocalError, Endpoint, Client, HasPayload, HasParams, HasQuery, MutationContext>;
/** Extract the current cache data for this request into a portable hydration payload (useful for SSR). */
dehydrate: (config?: {
/** in case of using adapter without cache we can provide response to dehydrate */
response?: ResponseType<Response, LocalError | ExtractClientGlobalError<Client>, ExtractClientAdapterType<Client>>;
/** override cache data */
override?: boolean;
}) => HydrateDataType<Response, LocalError | ExtractClientGlobalError<Client>, ExtractClientAdapterType<Client>> | undefined;
/**
* Read the response from cache data
*
* If it returns error and data at the same time, it means that latest request was failed
* and we show previous data from cache together with error received from actual request
*/
read(): ResponseType<Response, LocalError | ExtractClientGlobalError<Client>, ExtractClientAdapterType<Client>> | undefined;
/**
* Method to use the request WITHOUT adding it to cache and queues. This mean it will make simple request without queue side effects.
* @param options
* @disableReturns
* @returns
* ```tsx
* Promise<[Data | null, Error | null, HttpStatus]>
* ```
*/
exec: RequestSendType<this>;
/**
* Method used to perform requests with usage of cache and queues
* @param options
* @param requestCallback
* @disableReturns
* @returns
* ```tsx
* Promise<{ data: Data | null, error: Error | null, status: HttpStatus, ... }>
* ```
*/
send: RequestSendType<this>;
/** Reconstruct a Request instance from a previously serialized JSON representation. */
static fromJSON: <NewResponse, NewPayload, NewQueryParams, NewLocalError, NewEndpoint extends string, NewClient extends ClientInstance, NewHasPayload extends true | false = false, NewHasParams extends true | false = false, NewHasQuery extends true | false = false>(client: NewClient, json: RequestJSON<Request<NewResponse, NewPayload, NewQueryParams, NewLocalError, NewEndpoint, NewClient, NewHasPayload, NewHasParams, NewHasQuery>>) => Request<NewResponse, NewPayload, NewQueryParams, NewLocalError, NewEndpoint, NewClient, NewHasPayload, NewHasParams, NewHasQuery, undefined>;
}
export {};
//# sourceMappingURL=request.d.ts.map