alistair
Version:
81 lines (78 loc) • 4.13 kB
TypeScript
type Method = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options';
declare class HTTPClientError extends Error {
readonly count: number;
readonly request: Request;
readonly response: Response;
static readonly getErrorMessage: (count: number, response: Response) => string;
constructor(count: number, request: Request, response: Response);
}
/**
* Lifecycle describes a `.before()` and a `.failure()` function, which allow the developer
* to write advanced behaviours like backoff retries, automatic authorization header injection,
* easy rate limiting, etc
*/
interface Lifecycle {
/**
* Runs before every request, allows you to inject headers, modifiy the request, etc.
* It is safe to mutate the request that is passed in, or return a new instance of a Request.
*
* Note: If you implement retries with `.failure`, then `.before` will NOT be called on each
* retry. This is because it's possible to return the same request in the failure handler
* which would be a request that has *already had* the `.before()` transform applied (and so)
* `.before()` would be changing things that have already been changed.
*
* @param request The request that is about to be executed
* @returns A modified OR entirely new request instance
*/
before: (request: Request) => Promise<Request>;
/**
* Called when a request fails (dictated when response.ok = false)
*
* You can do one of three things inside of this function:
* - 1. Return the existing instance, or a new instance of a Request, which will queue up a
* retry with the (and if it fails AGAIN, the count will be incremented for
* the next failure call). You can use this behaviour to implement retries with
* backoff strategies.
*
* Be aware that returning a request here will NOT
* pass it through `.before()`, so make sure any transformations are applied beforehand.
*
* Also, it is totally okay to wait inside of .failure in the case of a rate limit for example
*
* - 2. Return undefined, which will throw the default HTTPClientError with the
* request and response that failed. This won't trigger any retries and will cause the original
* call to fail
*
* - 3. Throw an error, which won't trigger any retries and will also cause the original call to fail
*
* @param count - The number of times the request has failed
* @param request - The request that failed
* @param response - The response from the failed request
*/
failure: (count: number, request: Request, response: Response) => Promise<Request | void | undefined>;
}
type RequestTransformer<T> = (response: Response) => Promise<T>;
interface CompleteOptions<Transform> {
base: string;
transform: RequestTransformer<Transform>;
lifecycle: Lifecycle;
}
type RequestConfig = Omit<RequestInit, 'method' | 'body'> & {
body?: unknown;
};
type MethodHandler<Transform> = <T extends Transform = Transform>(path: string, config?: RequestConfig | undefined) => Promise<T>;
declare const defaultLifecycle: Lifecycle;
/**
* This type is just what createHTTPClient returns, you can use this if you want to type
* a class property or a variable or something, rather than doing `ReturnType<typeof createHTTPClient>`
*/
type HTTPClient<Transform> = Record<Method, MethodHandler<Transform>>;
declare function createHTTPClient<Transform = unknown>(rootOptions: {
base: string;
transform?: RequestTransformer<Transform>;
lifecycle?: Partial<Lifecycle>;
}): HTTPClient<Transform>;
declare function join<Base extends string, Path extends string>(base: Base, path: Path): string;
declare function isBodyInit(body: unknown): body is BodyInit;
declare function streamToBody<T>(stream: ReadableStream<T>): Promise<string>;
export { type CompleteOptions, type HTTPClient, HTTPClientError, type Lifecycle, type Method, type MethodHandler, type RequestConfig, type RequestTransformer, createHTTPClient, defaultLifecycle, isBodyInit, join, streamToBody };