UNPKG

fexios

Version:

Fetch based HTTP client with similar API to axios for browser and Node.js

267 lines (262 loc) 12.4 kB
import { C as CallableInstance, i as isPlainObject } from './fexios.uBjPg0Vb.mjs'; /** * Fexios * @desc Fetch based HTTP client with similar API to axios for browser and Node.js */ declare class Fexios extends CallableInstance<[ string | URL | (Partial<FexiosRequestOptions> & { url: string | URL; }), Partial<FexiosRequestOptions>? ], Promise<FexiosFinalContext<any>>> { static readonly version: any; private static readonly FINAL_SYMBOL; baseConfigs: FexiosConfigs; get defaults(): FexiosConfigs; set defaults(configs: FexiosConfigs); static readonly DEFAULT_CONFIGS: FexiosConfigs; protected hooks: FexiosHookStore[]; static readonly ALL_METHODS: FexiosMethods[]; static readonly METHODS_WITHOUT_BODY: FexiosMethods[]; constructor(baseConfigs?: Partial<FexiosConfigs>); request<T = any>(url: string | URL, options?: Partial<FexiosRequestOptions>): Promise<FexiosFinalContext<T>>; request<T = any>(options: Partial<FexiosRequestOptions> & { url: string | URL; }): Promise<FexiosFinalContext<T>>; mergeQueries: <T = any>(...incomes: Array<Record<string, any> | URLSearchParams | FormData | Map<string, any> | ReadonlyMap<string, any> | string | null | undefined>) => T; mergeHeaders: (...incomes: Array<Record<string, unknown> | Headers | Map<string, unknown> | ReadonlyMap<string, unknown> | null | undefined>) => Headers; private applyDefaults; private restoreNulls; emit<E extends FexiosLifecycleEvents, C = FexiosLifecycleEventMap[E]>(event: E, ctx: C, opts?: { shouldHandleShortCircuitResponse?: boolean; }): Promise<C>; on<E extends FexiosLifecycleEvents, C = FexiosLifecycleEventMap[E]>(event: E, action: FexiosHook<C>, prepend?: boolean): this; off<E extends FexiosLifecycleEvents>(event: E, action: FexiosHook<FexiosLifecycleEventMap[E]>): this; off(event: '*' | null, action: FexiosHook<any>): this; private createInterceptor; readonly interceptors: FexiosInterceptors; private createMethodShortcut; extends(configs: Partial<FexiosConfigs>): Fexios; readonly create: typeof Fexios.create; static create(configs?: Partial<FexiosConfigs>): Fexios; private _plugins; plugin(plugin: FexiosPlugin): Promise<Fexios>; /** @deprecated Use `import { checkIsPlainObject } from 'fexios/utils'` instead */ readonly checkIsPlainObject: typeof isPlainObject; /** @deprecated Use `mergeQueries` instead */ readonly mergeQuery: <T = any>(...incomes: Array<Record<string, any> | URLSearchParams | FormData | Map<string, any> | ReadonlyMap<string, any> | string | null | undefined>) => T; } interface Fexios { <T = any>(url: string | URL, options?: Partial<FexiosRequestOptions>): Promise<FexiosFinalContext<T>>; <T = any>(options: Partial<FexiosRequestOptions> & { url: string | URL; }): Promise<FexiosFinalContext<T>>; } interface Fexios { get: FexiosRequestShortcut<'get'>; post: FexiosRequestShortcut<'post'>; put: FexiosRequestShortcut<'put'>; patch: FexiosRequestShortcut<'patch'>; delete: FexiosRequestShortcut<'delete'>; head: FexiosRequestShortcut<'head'>; options: FexiosRequestShortcut<'options'>; trace: FexiosRequestShortcut<'trace'>; } /** * Fexios response wrapper class * @param data Transformed response body * @param responseType Guessed response type */ declare class FexiosResponse<T = unknown> implements IFexiosResponse<T> { readonly rawResponse: IFexiosResponse['rawResponse']; readonly data: T; readonly responseType: IFexiosResponse['responseType']; constructor(rawResponse: IFexiosResponse['rawResponse'], data: T, responseType: IFexiosResponse['responseType']); readonly ok: boolean; readonly status: number; readonly statusText: string; readonly headers: Headers; readonly url: string; readonly redirected: boolean; } /** * Resolve response body based on content type and expected type * @param expectedType `undefined` means auto-detect based on content-type header. And also try JSON.stringify if it's a string. */ declare function createFexiosResponse<T = any>(rawResponse: Response, expectedType?: FexiosConfigs['responseType'], onProgress?: (progress: number, buffer?: Uint8Array) => void, shouldThrow?: (response: FexiosResponse<any>) => boolean | void, timeout?: number): Promise<FexiosResponse<T>>; declare function createFexiosWebSocketResponse(url: string | URL, response?: Response, timeout?: number): Promise<FexiosResponse<WebSocket>>; declare function createFexiosEventSourceResponse(url: string | URL, response?: Response, timeout?: number): Promise<FexiosResponse<EventSource>>; /** * Type definitions for Fexios */ type AwaitAble<T = unknown> = Promise<T> | T; type FetchLike = (input: Request | string | URL, init?: RequestInit) => Promise<Response>; interface FexiosConfigs { baseURL: string | URL; timeout: number; /** * Query parameters, its value can be: * - `null` - to remove the item * - `undefined` - to keep the item as is */ query: Record<string, any> | URLSearchParams; headers: Record<string, string | string[]> | Headers; credentials?: RequestInit['credentials']; cache?: RequestInit['cache']; mode?: RequestInit['mode']; /** * Whether to throw FexiosResponseError for non-OK response. * @default * ```ts * (response) => !response.ok * ``` */ shouldThrow?: (response: FexiosResponse<any>) => boolean | void; /** * Fexios will try its best to transform request body. * * * ### `"json"` * - If body is text-like, it will be parsed as JSON first. If parsing fails, it will be sent as is. * - If body is FormData or URLSearchParams, see `FexiosQueryBuilder.toQueryRecord` for conversion details. * * ### `"text"` * - Body always be sent as text. * - Even if body is not text-like, it will be converted to string using `String(body)`. * * ### `"form"` * - If body is FormData or URLSearchParams, it will be sent as is. * - Other transformations is NOT supported YET. * * ### `"blob"` * - If body is ArrayBuffer or TypedArray, it will be converted to Blob. * - If body is text-like, it will be converted to Blob using UTF-8 encoding. * * ### `"arrayBuffer"` * - If body is Blob or TypedArray, it will be converted to ArrayBuffer. * - If body is text-like, it will be converted to ArrayBuffer using UTF-8 encoding. * * ### `"ws"` * - If Response requires upgrading to WebSocket, it will be handled accordingly. * - Otherwise, an error will be thrown. * * ### `"stream"` * - If Response requires upgrading to ReadableStream, it will be handled accordingly. * - Otherwise, an error will be thrown. * * ### `undefined` * This means auto-detect based on content-type header. * - `application/json` -> JSON * - `text/plain` -> Try to parse as JSON, if fails, Text * - `text/*`, `application/text`, `application/xml`, `application/javascript` -> Text * - `multipart/form-data`, `application/x-www-form-urlencoded` -> Form * - `image/*`, `video/*`, `audio/*`, `application/pdf` -> Blob * - Others -> Try to detect if it's probably text data, if yes, Text, otherwise ArrayBuffer * - For unknown content-type, if content-length is 0, Text will be assumed. * - Upgrade to WebSocket / stream will be handled accordingly. * * If transformation fails, ArrayBuffer / stream / FormData will be sent as is. */ responseType?: 'json' | 'text' | 'form' | 'blob' | 'arrayBuffer' | 'ws' | 'stream'; fetch?: FetchLike; } interface FexiosRequestOptions extends Omit<FexiosConfigs, 'headers'> { url?: string | URL; method?: FexiosMethods; /** * Request headers, its value can be: * - `null` - to remove the header * - `undefined` - to keep the header as is */ headers: Record<string, string | string[] | null | undefined> | Headers; /** * Request body */ body?: Record<string, any> | string | FormData | URLSearchParams; abortController?: AbortController; onProgress?: (progress: number, buffer?: Uint8Array) => void; /** * Custom environment variables, can be any value. * Useful for passing data between hooks. */ customEnv?: any; } interface FexiosContext<T = any> extends FexiosRequestOptions { url: string; rawRequest?: Request; rawResponse?: Response; response?: FexiosResponse; /** Resolved response body */ data?: T; } type FexiosFinalContext<T = any> = Omit<Required<FexiosContext<T>>, 'onProgress' | 'abortController' | 'headers' | 'responseType' | 'url' | 'query' | 'data'> & { /** Response Headers */ readonly headers: Headers; /** * Resolved response body * @note * This is a read-only property, * if you want to completely replace the ctx.data, * you should return Response in `afterResponse` hook. * @example * ``` * // DO THIS √ * fx.on('afterResponse', (ctx) => { * return Response.json({ newData: 'new data' }, { status: 200 }) * }) * // DON'T DO THIS × * fx.on('afterResponse', (ctx) => { * ctx.data = { newData: 'new data' } // error! * return ctx * }) * ``` */ readonly data: T; /** * Response type of data * If not set in request options, it will be guessed based on content-type header. * May be different from required responseType in request options. */ readonly responseType: NonNullable<FexiosConfigs['responseType']>; /** Response URL */ readonly url: string; }; type FexiosHook<C = unknown> = (context: C) => AwaitAble<C | void | false | Response>; interface FexiosHookStore { event: FexiosLifecycleEvents; action: FexiosHook; } type FexiosLifecycleEvents = keyof FexiosLifecycleEventMap; interface FexiosLifecycleEventMap { beforeInit: Omit<FexiosContext, 'rawRequest' | 'rawResponse' | 'response' | 'data'>; beforeRequest: Required<Omit<FexiosContext, 'rawRequest' | 'rawResponse' | 'response' | 'data'>>; afterBodyTransformed: Required<Omit<FexiosContext, 'rawRequest' | 'rawResponse' | 'response' | 'data'>>; beforeActualFetch: Required<Omit<FexiosContext, 'rawResponse' | 'response' | 'data'>>; afterResponse: FexiosFinalContext; } interface FexiosInterceptor<E extends FexiosLifecycleEvents, C = FexiosLifecycleEventMap[E]> { handlers: () => FexiosHook[]; use: (hook: FexiosHook<C>, prepend?: boolean) => any; clear: () => void; } interface FexiosInterceptors { request: FexiosInterceptor<'beforeRequest'>; response: FexiosInterceptor<'afterResponse'>; } type LowerAndUppercase<T extends string> = Lowercase<T> | Uppercase<T>; type FexiosMethods = LowerAndUppercase<'get' | 'post' | 'put' | 'patch' | 'delete' | 'head' | 'options' | 'trace'>; type MethodsWithoutBody = LowerAndUppercase<'get' | 'head' | 'options' | 'trace'>; type FexiosRequestShortcut<M extends FexiosMethods> = M extends MethodsWithoutBody ? ShortcutWithoutBody : ShortcutWithBody; type ShortcutWithoutBody = <T = any>(url: string | URL, options?: Partial<FexiosRequestOptions>) => Promise<FexiosFinalContext<T>>; type ShortcutWithBody = <T = any>(url: string | URL, body?: Record<string, any> | string | URLSearchParams | FormData | null, options?: Partial<FexiosRequestOptions>) => Promise<FexiosFinalContext<T>>; interface IFexiosResponse<T = any> extends Pick<Response, 'ok' | 'status' | 'statusText' | 'headers' | 'url' | 'redirected'> { readonly rawResponse: Response; readonly data: T; readonly responseType: FexiosConfigs['responseType']; } type FexiosPlugin = { name: string; install: (app: Fexios) => Fexios | Promise<Fexios> | void; }; export { Fexios as F, FexiosResponse as o, createFexiosResponse as p, createFexiosWebSocketResponse as q, createFexiosEventSourceResponse as r }; export type { AwaitAble as A, IFexiosResponse as I, FetchLike as a, FexiosConfigs as b, FexiosRequestOptions as c, FexiosContext as d, FexiosFinalContext as e, FexiosHook as f, FexiosHookStore as g, FexiosLifecycleEvents as h, FexiosLifecycleEventMap as i, FexiosInterceptor as j, FexiosInterceptors as k, FexiosMethods as l, FexiosRequestShortcut as m, FexiosPlugin as n };