fexios
Version:
Fetch based HTTP client with similar API to axios for browser and Node.js
1 lines • 48.5 kB
Source Map (JSON)
{"version":3,"file":"index.cjs","sources":["../src/errors.ts","../src/utils.ts","../src/response.ts","../src/query-builder.ts","../node_modules/.pnpm/callable-instance@2.0.0/node_modules/callable-instance/index.js","../src/fexios.ts","../src/index.ts"],"sourcesContent":["import type { FexiosContext, IFexiosResponse } from './types'\n\n/**\n * Error codes for Fexios\n */\nexport enum FexiosErrorCodes {\n BODY_USED = 'BODY_USED',\n NO_BODY_READER = 'NO_BODY_READER',\n TIMEOUT = 'TIMEOUT',\n NETWORK_ERROR = 'NETWORK_ERROR',\n BODY_NOT_ALLOWED = 'BODY_NOT_ALLOWED',\n HOOK_CONTEXT_CHANGED = 'HOOK_CONTEXT_CHANGED',\n ABORTED_BY_HOOK = 'ABORTED_BY_HOOK',\n INVALID_HOOK_CALLBACK = 'INVALID_HOOK_CALLBACK',\n UNEXPECTED_HOOK_RETURN = 'UNEXPECTED_HOOK_RETURN',\n}\n\n/**\n * Base Fexios error class\n */\nexport class FexiosError extends Error {\n name = 'FexiosError'\n constructor(\n readonly code: FexiosErrorCodes | string,\n message?: string,\n readonly context?: FexiosContext,\n options?: ErrorOptions\n ) {\n super(message, options)\n }\n}\n\n/**\n * Fexios response error class for HTTP errors\n */\nexport class FexiosResponseError<T> extends FexiosError {\n name = 'FexiosResponseError'\n constructor(\n message: string,\n readonly response: IFexiosResponse<T>,\n options?: ErrorOptions\n ) {\n super(response.statusText, message, undefined, options)\n }\n}\n\n/**\n * Check if the error is a FexiosError that not caused by Response error\n */\nexport const isFexiosError = (e: any): boolean => {\n return !(e instanceof FexiosResponseError) && e instanceof FexiosError\n}\n","/**\n * Utility functions for Fexios\n */\n\n/**\n * Check if the data is likely text content\n */\nexport function checkIfTextData(\n uint8Array: Uint8Array,\n maxBytesToCheck = 2048\n): boolean {\n if (!(uint8Array instanceof Uint8Array)) {\n throw new TypeError('Input must be a Uint8Array')\n }\n\n if (uint8Array.length === 0) {\n return true\n }\n\n // Check at least 256 bytes, up to maxBytesToCheck\n const bytesToCheck = Math.min(\n Math.max(uint8Array.length, 256),\n maxBytesToCheck\n )\n const dataToCheck = uint8Array.slice(0, bytesToCheck)\n\n // 1. Check for BOM and common binary file headers\n if (hasBinaryHeader(dataToCheck)) {\n return false\n }\n\n // 2. Analyze byte distribution characteristics\n const stats = analyzeByteDistribution(dataToCheck)\n\n // Too many null bytes likely indicate binary data\n if (stats.nullByteRatio > 0.05) {\n return false\n }\n\n // Too many high bytes might indicate binary data\n if (stats.highByteRatio > 0.95) {\n return false\n }\n\n // 3. Try multiple encodings for decoding\n const encodings = ['utf-8', 'utf-16le', 'utf-16be', 'iso-8859-1']\n let bestScore = -1\n let isValidText = false\n\n for (const encoding of encodings) {\n try {\n const decoder = new TextDecoder(encoding, { fatal: true })\n const decodedString = decoder.decode(dataToCheck)\n const score = calculateTextScore(decodedString)\n\n if (score > bestScore) {\n bestScore = score\n isValidText = score > 0.7 // Text confidence threshold\n }\n } catch (error) {\n // Decoding failed, try next encoding\n continue\n }\n }\n\n return isValidText\n}\n\n/**\n * Check for common binary file headers\n */\nfunction hasBinaryHeader(data: Uint8Array): boolean {\n if (data.length < 4) return false\n\n // Common binary file header signatures\n const binaryHeaders = [\n [0x89, 0x50, 0x4e, 0x47], // PNG\n [0xff, 0xd8, 0xff], // JPEG\n [0x47, 0x49, 0x46], // GIF\n [0x25, 0x50, 0x44, 0x46], // PDF\n [0x50, 0x4b, 0x03, 0x04], // ZIP/Office documents\n [0x50, 0x4b, 0x05, 0x06], // ZIP empty archive\n [0x50, 0x4b, 0x07, 0x08], // ZIP spanned archive\n [0x7f, 0x45, 0x4c, 0x46], // ELF executable\n [0x4d, 0x5a], // Windows executable\n [0xca, 0xfe, 0xba, 0xbe], // Java class file\n [0x00, 0x00, 0x01, 0x00], // ICO\n [0x52, 0x49, 0x46, 0x46], // RIFF (AVI, WAV, etc.)\n ]\n\n for (const header of binaryHeaders) {\n if (data.length >= header.length) {\n let matches = true\n for (let i = 0; i < header.length; i++) {\n if (data[i] !== header[i]) {\n matches = false\n break\n }\n }\n if (matches) return true\n }\n }\n\n return false\n}\n\n/**\n * Analyze byte distribution characteristics\n */\nfunction analyzeByteDistribution(data: Uint8Array): {\n nullByteRatio: number\n highByteRatio: number\n controlCharRatio: number\n} {\n let nullBytes = 0\n let highBytes = 0\n let controlChars = 0\n\n for (const byte of data) {\n if (byte === 0) {\n nullBytes++\n }\n if (byte > 127) {\n highBytes++\n }\n // Control characters (excluding common ones like newline, tab, etc.)\n if (\n (byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) ||\n byte === 127\n ) {\n controlChars++\n }\n }\n\n return {\n nullByteRatio: nullBytes / data.length,\n highByteRatio: highBytes / data.length,\n controlCharRatio: controlChars / data.length,\n }\n}\n\n/**\n * Calculate text content confidence score\n */\nfunction calculateTextScore(text: string): number {\n if (text.length === 0) return 1\n\n let score = 1.0\n let printableChars = 0\n let textLikeChars = 0\n\n for (let i = 0; i < text.length; i++) {\n const char = text[i]\n const code = char.charCodeAt(0)\n\n // Printable ASCII characters\n if (code >= 32 && code <= 126) {\n printableChars++\n textLikeChars++\n }\n // Common whitespace characters\n else if (code === 9 || code === 10 || code === 13 || code === 32) {\n textLikeChars++\n }\n // Unicode characters (possibly text in other languages)\n else if (code > 127 && code < 0xfffe) {\n // Check if it's a valid Unicode character\n if (!isControlCharacter(code) && !isPrivateUse(code)) {\n textLikeChars++\n }\n }\n // Control characters or special characters lower the score\n else {\n score -= 0.1\n }\n }\n\n // Adjust score based on printable character ratio\n const textRatio = textLikeChars / text.length\n score *= textRatio\n\n // Boost score if common text patterns are found\n if (hasTextPatterns(text)) {\n score *= 1.1\n }\n\n return Math.max(0, Math.min(1, score))\n}\n\n/**\n * Check if the character code is a control character\n */\nfunction isControlCharacter(code: number): boolean {\n return (code >= 0 && code <= 31) || (code >= 127 && code <= 159)\n}\n\n/**\n * Check if the character code is in private use area\n */\nfunction isPrivateUse(code: number): boolean {\n return (\n (code >= 0xe000 && code <= 0xf8ff) ||\n (code >= 0xf0000 && code <= 0xffffd) ||\n (code >= 0x100000 && code <= 0x10fffd)\n )\n}\n\n/**\n * Check for common text patterns\n */\nfunction hasTextPatterns(text: string): boolean {\n // Check for words, sentences and other text features\n const patterns = [\n /\\b\\w+\\b/, // Words\n /[.!?]+\\s/, // Sentence endings\n /\\s+/, // Whitespace\n /[a-zA-Z]{3,}/, // English words\n /[\\u4e00-\\u9fa5]+/, // Chinese characters\n /\\d+/, // Numbers\n ]\n\n return patterns.some((pattern) => pattern.test(text))\n}\n\n/**\n * Check if given payload is a plain object\n * \"plain object\", means it is not an instance of any class or built-in type,\n * or just like Record<string, any> in TypeScript.\n */\nexport function checkIsPlainObject(\n payload: any\n): payload is Record<string, any> {\n // exclude non-object and null values\n if (typeof payload !== 'object' || payload === null) {\n return false\n }\n\n // exclude built-in types like Date, RegExp, etc.\n if (Object.prototype.toString.call(payload) !== '[object Object]') {\n return false\n }\n\n // finally check the prototype chain\n // if the prototype is Object.prototype or null, it's 99% a plain object\n // Note: why proto === null is ok? // Object.create(null)\n const proto = Object.getPrototypeOf(payload)\n return proto === Object.prototype || proto === null\n}\n\n/**\n * Remove all undefined and null properties from an object\n * Also handles empty strings based on options\n */\nexport function dropUndefinedAndNull<T extends Record<string, any>>(\n obj: T,\n options: { dropEmptyString?: boolean } = {}\n): Partial<T> {\n const newObj: Record<string, any> = {}\n Object.entries(obj).forEach(([key, value]) => {\n // Always drop undefined and null\n if (value === undefined || value === null) {\n return\n }\n // Optionally drop empty strings\n if (options.dropEmptyString && value === '') {\n return\n }\n newObj[key] = value\n })\n return newObj as Partial<T>\n}\n","import type { FexiosConfigs, IFexiosResponse as IFexiosResponse } from './types'\nimport { FexiosError, FexiosErrorCodes, FexiosResponseError } from './errors'\nimport { checkIfTextData } from './utils'\n\n/**\n * Fexios response wrapper class\n */\nexport class FexiosResponse<T = any> implements IFexiosResponse<T> {\n public ok: boolean\n public status: number\n public statusText: string\n public headers: Headers\n\n constructor(\n public rawResponse: Response,\n public data: T,\n overrides?: Partial<Omit<FexiosResponse<T>, 'rawResponse' | 'data'>>\n ) {\n this.ok = rawResponse.ok\n this.status = rawResponse.status\n this.statusText = rawResponse.statusText\n this.headers = rawResponse.headers\n Object.entries(overrides || {}).forEach(([key, value]) => {\n ;(this as any)[key] = value\n })\n }\n}\n\n/**\n * Resolve response body based on content type and expected type\n */\nexport async function resolveResponseBody<T = any>(\n rawResponse: Response,\n expectType?: FexiosConfigs['responseType'],\n onProgress?: (progress: number, buffer?: Uint8Array) => void\n): Promise<FexiosResponse<T>> {\n if (rawResponse.bodyUsed) {\n throw new FexiosError(\n FexiosErrorCodes.BODY_USED,\n 'Response body has already been used or locked'\n )\n }\n\n const contentType = rawResponse.headers.get('content-type') || ''\n const contentLength = Number(rawResponse.headers.get('content-length')) || 0\n\n // Helper methods for content type checking\n const isJsonContent = (contentType: string, expectType?: string) =>\n expectType === 'json' || contentType.startsWith('application/json')\n\n const isBinaryContent = (\n contentType: string,\n buffer: Uint8Array,\n expectType?: string\n ) =>\n expectType === 'blob' ||\n (contentType.startsWith('image/') &&\n !contentType.startsWith('image/svg')) ||\n contentType.startsWith('video/') ||\n contentType.startsWith('audio/') ||\n !checkIfTextData(buffer)\n\n // Check if the response is a WebSocket\n if (\n (rawResponse.status === 101 ||\n rawResponse.status === 426 ||\n rawResponse.headers.get('upgrade')) &&\n typeof globalThis.WebSocket !== 'undefined'\n ) {\n const ws = new WebSocket(rawResponse.url)\n await new Promise<any>((resolve, reject) => {\n ws.onopen = resolve\n ws.onerror = reject\n })\n return new FexiosResponse(rawResponse, ws as T, {\n ok: true,\n status: 101,\n statusText: 'Switching Protocols',\n })\n }\n // Check if the response is a EventSource\n // But only if the content-type is not 'text' or 'json'\n else if (\n contentType.startsWith('text/event-stream') &&\n !['text', 'json'].includes(expectType || '') &&\n typeof globalThis.EventSource !== 'undefined'\n ) {\n const es = new EventSource(rawResponse.url)\n await new Promise<any>((resolve, reject) => {\n es.onopen = resolve\n es.onerror = reject\n })\n return new FexiosResponse(rawResponse, es as T)\n }\n // Check if expectType is 'stream'\n else if (expectType === 'stream') {\n return new FexiosResponse(\n rawResponse,\n rawResponse.body as ReadableStream as T\n )\n }\n // Check if the response is a ReadableStream\n else {\n const responseCopy = rawResponse.clone()\n const reader = responseCopy.body?.getReader()\n if (!reader) {\n throw new FexiosError(\n FexiosErrorCodes.NO_BODY_READER,\n 'Failed to get ReadableStream from response body'\n )\n }\n let buffer = new Uint8Array()\n while (true) {\n const { done, value } = await reader.read()\n if (done) break\n\n if (value) {\n buffer = new Uint8Array([...buffer, ...value])\n if (onProgress && contentLength > 0) {\n const progress = Math.min(buffer.length / contentLength, 1)\n onProgress(progress, buffer)\n }\n }\n }\n\n const res = new FexiosResponse(rawResponse, undefined as any)\n\n if (expectType === 'arrayBuffer') {\n res.data = buffer.buffer as T\n return res\n }\n\n // If request expects JSON, try to parse it\n if (isJsonContent(contentType, expectType)) {\n try {\n const jsonString = new TextDecoder().decode(buffer)\n res.data = JSON.parse(jsonString) as T\n } catch (e) {\n console.warn('Failed to parse response data as JSON:', e)\n }\n }\n\n // Guess the response type, maybe a Blob?\n if (\n typeof res.data !== 'string' &&\n isBinaryContent(contentType, buffer, expectType)\n ) {\n res.data = new Blob([buffer], {\n type: rawResponse.headers.get('content-type') || undefined,\n }) as Blob as T\n } else {\n // Otherwise, try to decode the buffer as text\n res.data = new TextDecoder().decode(buffer) as T\n }\n\n if (typeof res.data === 'string' && expectType !== 'text') {\n const trimmedData = (res.data as string).trim()\n const firstChar = trimmedData[0]\n const lastChar = trimmedData[trimmedData.length - 1]\n if (\n (firstChar === '{' && lastChar === '}') ||\n (firstChar === '[' && lastChar === ']')\n ) {\n try {\n res.data = JSON.parse(res.data as string) as T\n } catch (_) {\n // NOOP\n }\n }\n }\n\n // Fall back to the buffer if the data is still not resolved\n if (typeof res.data === 'undefined') {\n res.data = buffer.length > 0 ? (buffer as any) : undefined\n }\n\n if (!res.ok) {\n throw new FexiosResponseError(\n `Request failed with status code ${rawResponse.status}`,\n res as any\n )\n } else {\n return res\n }\n }\n}\n","/**\n * Static utility class for building URL search parameters\n *\n * @example\n * { foo: 'bar', baz: ['qux', 'quux'] } // ?foo=bar&baz=qux&baz=quux\n * @example\n * { 'foo[]': 'bar', 'baz[]': ['qux', 'quux'] } // ?foo[]=bar&baz[]=qux&baz[]=quux\n */\nexport class FexiosQueryBuilder {\n /**\n * Build URLSearchParams from a record object with proper array handling\n * @param query - The query object containing key-value pairs\n * @returns URLSearchParams instance\n */\n static makeSearchParams(query: Record<string, any>): URLSearchParams {\n const searchParams = new URLSearchParams()\n\n Object.entries(query).forEach(([key, value]) => {\n if (Array.isArray(value)) {\n // For array values, add multiple entries with the same key\n // This works for both regular keys and keys ending with '[]'\n value.forEach((v) => searchParams.append(key, String(v)))\n } else {\n searchParams.set(key, String(value))\n }\n })\n\n return searchParams\n }\n\n /**\n * Build query string from a record object with proper array handling\n * @param query - The query object containing key-value pairs\n * @returns URL-encoded query string\n */\n static makeQueryString(query: Record<string, any>): string {\n return this.makeSearchParams(query).toString()\n }\n}\n","function CallableInstance(property) {\n var func = this.constructor.prototype[property];\n var apply = function() { return func.apply(apply, arguments); }\n Object.setPrototypeOf(apply, this.constructor.prototype);\n Object.getOwnPropertyNames(func).forEach(function (p) {\n Object.defineProperty(apply, p, Object.getOwnPropertyDescriptor(func, p));\n });\n return apply;\n}\nCallableInstance.prototype = Object.create(Function.prototype);\n\nmodule.exports = CallableInstance;\n","import CallableInstance from 'callable-instance'\nimport type {\n FexiosConfigs,\n FexiosContext,\n FexiosRequestOptions,\n FexiosFinalContext,\n FexiosMethods,\n FexiosHookStore,\n FexiosLifecycleEvents,\n FexiosHook,\n FexiosInterceptor,\n FexiosInterceptors,\n FexiosRequestShortcut,\n} from './types'\nimport { FexiosError, FexiosErrorCodes } from './errors'\nimport { FexiosResponse, resolveResponseBody } from './response'\nimport { FexiosQueryBuilder } from './query-builder'\nimport { checkIsPlainObject, dropUndefinedAndNull } from './utils'\n\n/**\n * Fexios\n * @desc Fetch based HTTP client with similar API to axios for browser and Node.js\n */\nexport class Fexios extends CallableInstance<\n [\n string | URL | Partial<FexiosRequestOptions>,\n Partial<FexiosRequestOptions>?\n ],\n Promise<FexiosFinalContext<any>>\n> {\n protected hooks: FexiosHookStore[] = []\n readonly DEFAULT_CONFIGS: FexiosConfigs = {\n baseURL: '',\n timeout: 60 * 1000,\n credentials: 'same-origin',\n headers: {},\n query: {},\n responseType: undefined,\n }\n private readonly ALL_METHODS: FexiosMethods[] = [\n 'get',\n 'post',\n 'put',\n 'patch',\n 'delete',\n 'head',\n 'options',\n 'trace',\n ]\n private readonly METHODS_WITHOUT_BODY: FexiosMethods[] = [\n 'get',\n 'head',\n 'options',\n 'trace',\n ]\n\n constructor(public baseConfigs: Partial<FexiosConfigs> = {}) {\n super('request')\n this.ALL_METHODS.forEach(this.createMethodShortcut.bind(this))\n }\n\n async request<T = any>(\n url: string | URL,\n options?: Partial<FexiosRequestOptions>\n ): Promise<FexiosFinalContext<T>>\n async request<T = any>(\n options: Partial<FexiosRequestOptions> & { url: string | URL }\n ): Promise<FexiosFinalContext<T>>\n async request<T = any>(\n urlOrOptions:\n | string\n | URL\n | (Partial<FexiosRequestOptions> & { url: string | URL }),\n options?: Partial<FexiosRequestOptions>\n ): Promise<FexiosFinalContext<T>> {\n let ctx: FexiosContext = (options = options || {}) as any\n if (typeof urlOrOptions === 'string' || urlOrOptions instanceof URL) {\n ctx.url = urlOrOptions.toString()\n } else if (typeof urlOrOptions === 'object') {\n ctx = { ...urlOrOptions, ...ctx }\n }\n ctx = await this.emit('beforeInit', ctx)\n\n const baseUrlString =\n options.baseURL || this.baseConfigs.baseURL || globalThis.location?.href\n const baseURL = baseUrlString\n ? new URL(baseUrlString, globalThis.location?.href)\n : undefined\n const reqURL = new URL(ctx.url.toString(), baseURL)\n ctx.url = reqURL.href\n ctx.baseURL = baseURL ? baseURL.href : reqURL.origin\n\n ctx.headers = this.mergeHeaders(\n this.baseConfigs.headers,\n options.headers\n ) as any\n\n // Extract query parameters from different sources\n // Priority: requestOptions > requestURL > defaultOptions > baseURL\n const baseUrlQuery = baseURL?.searchParams\n // Create a copy of requestUrlQuery before clearing the URL search params\n const requestUrlQuery = new URLSearchParams(reqURL.searchParams)\n\n // Clear the URL search params temporarily\n reqURL.search = ''\n ctx.url = reqURL.href\n\n // prettier-ignore\n ctx.query = this.mergeQuery(\n baseUrlQuery, // baseURL query (lowest priority)\n this.baseConfigs.query, // defaultOptions (baseOptions)\n requestUrlQuery, // requestURL query (urlParams)\n options.query // requestOptions (highest priority)\n )\n\n // Build search params with proper array handling\n reqURL.search = FexiosQueryBuilder.makeQueryString(ctx.query)\n ctx.url = reqURL.toString()\n\n if (\n this.METHODS_WITHOUT_BODY.includes(\n ctx.method?.toLocaleLowerCase() as FexiosMethods\n ) &&\n ctx.body\n ) {\n throw new FexiosError(\n FexiosErrorCodes.BODY_NOT_ALLOWED,\n `Request method \"${ctx.method}\" does not allow body`\n )\n }\n\n ctx = await this.emit('beforeRequest', ctx)\n\n let body: string | FormData | URLSearchParams | Blob | undefined\n if (typeof ctx.body !== 'undefined' && ctx.body !== null) {\n // Automatically transform JSON object to JSON string\n if (\n ctx.body instanceof Blob ||\n ctx.body instanceof FormData ||\n ctx.body instanceof URLSearchParams\n ) {\n body = ctx.body\n } else if (typeof ctx.body === 'object' && ctx.body !== null) {\n body = JSON.stringify(ctx.body)\n ;(ctx.headers as any)['content-type'] = 'application/json'\n } else {\n body = ctx.body\n }\n }\n\n // Adjust content-type header\n if (!(options.headers as any)?.['content-type'] && body) {\n if (body instanceof FormData || body instanceof URLSearchParams) {\n // Let the browser automatically set content-type for FormData/URLSearchParams\n delete (ctx.headers as any)['content-type']\n } else if (typeof body === 'string' && typeof ctx.body === 'object') {\n ;(ctx.headers as any)['content-type'] = 'application/json'\n } else if (body instanceof Blob) {\n ;(ctx.headers as any)['content-type'] = body.type\n }\n }\n\n ctx.body = body\n ctx = await this.emit('afterBodyTransformed', ctx)\n\n const abortController =\n ctx.abortController || globalThis.AbortController\n ? new AbortController()\n : undefined\n const rawRequest = new Request(ctx.url, {\n method: ctx.method || 'GET',\n credentials: ctx.credentials,\n cache: ctx.cache,\n mode: ctx.mode,\n headers: ctx.headers,\n body: ctx.body as any,\n signal: abortController?.signal,\n })\n ctx.rawRequest = rawRequest\n\n ctx = await this.emit('beforeActualFetch', ctx)\n\n const timeout = ctx.timeout || this.baseConfigs.timeout || 60 * 1000\n\n if (ctx.url.startsWith('ws')) {\n console.info('WebSocket:', ctx.url)\n try {\n const ws = new WebSocket(ctx.url)\n\n // Wait for connection to establish or fail\n await new Promise<void>((resolve, reject) => {\n const connectionTimeout = setTimeout(() => {\n reject(\n new FexiosError(\n FexiosErrorCodes.TIMEOUT,\n `WebSocket connection timed out after ${timeout}ms`,\n ctx\n )\n )\n }, timeout)\n\n ws.onopen = () => {\n clearTimeout(connectionTimeout)\n resolve()\n }\n ws.onerror = (event) => {\n clearTimeout(connectionTimeout)\n reject(\n new FexiosError(\n FexiosErrorCodes.NETWORK_ERROR,\n `WebSocket connection failed`,\n ctx\n )\n )\n }\n ws.onclose = (event) => {\n // Only reject if the closure wasn't normal and we haven't resolved yet\n if (event.code !== 1000) {\n clearTimeout(connectionTimeout)\n reject(\n new FexiosError(\n FexiosErrorCodes.NETWORK_ERROR,\n `WebSocket closed with code ${event.code}`,\n ctx\n )\n )\n }\n }\n })\n\n ctx.rawResponse = new Response()\n ctx.response = new FexiosResponse(ctx.rawResponse, ws as any, {\n ok: true,\n status: 101,\n statusText: 'Switching Protocols',\n })\n ctx.data = ws\n ctx.headers = new Headers()\n return this.emit('afterResponse', ctx) as any\n } catch (error) {\n if (error instanceof FexiosError) {\n throw error\n }\n throw new FexiosError(\n FexiosErrorCodes.NETWORK_ERROR,\n `WebSocket creation failed: ${error}`,\n ctx\n )\n }\n }\n\n let timer: NodeJS.Timeout | undefined\n\n try {\n if (abortController) {\n timer = setTimeout(() => {\n abortController.abort()\n }, timeout)\n }\n\n const rawResponse = await fetch(ctx.rawRequest!).catch((err) => {\n if (timer) clearTimeout(timer)\n if (abortController?.signal.aborted) {\n throw new FexiosError(\n FexiosErrorCodes.TIMEOUT,\n `Request timed out after ${timeout}ms`,\n ctx\n )\n }\n throw new FexiosError(FexiosErrorCodes.NETWORK_ERROR, err.message, ctx)\n })\n\n if (timer) clearTimeout(timer)\n\n ctx.rawResponse = rawResponse\n ctx.response = await resolveResponseBody(\n rawResponse,\n ctx.responseType,\n (progress, buffer) => {\n console.info('Download progress:', progress)\n options?.onProgress?.(progress, buffer)\n }\n )\n ctx.data = ctx.response.data\n ctx.headers = ctx.response.headers\n\n return this.emit('afterResponse', ctx) as any\n } catch (error) {\n if (timer) clearTimeout(timer)\n throw error\n }\n }\n\n mergeQuery(\n base: Record<string, any> | string | URLSearchParams | undefined,\n ...income: (Record<string, any> | string | URLSearchParams | undefined)[]\n ): Record<string, any> {\n const result: Record<string, any> = {}\n\n const processQuerySource = (source: typeof base) => {\n if (!source) return\n\n if (checkIsPlainObject(source)) {\n Object.entries(source).forEach(([key, value]) => {\n if (value === undefined || value === null) {\n delete result[key]\n } else if (Array.isArray(value)) {\n // Handle array values\n if (key.endsWith('[]')) {\n // For keys ending with '[]', keep multiple entries with the same key\n // Store as array to be processed later when building URLSearchParams\n result[key] = value.map(String)\n } else {\n // For regular keys, create multiple query parameters with the same name\n result[key] = value.map(String)\n }\n } else {\n result[key] = String(value)\n }\n })\n } else {\n const query = new URLSearchParams(source)\n query.forEach((value, key) => {\n result[key] = value\n })\n }\n }\n\n processQuerySource(base)\n income.forEach(processQuerySource)\n\n return result\n }\n\n mergeHeaders(\n base: Record<string, any> | Headers | undefined,\n ...income: (Record<string, any> | Headers | undefined)[]\n ): Record<string, string> {\n const obj: Record<string, string> = {}\n const baseHeaders = new Headers(base)\n for (const item of income) {\n if (item === undefined || item === null) continue\n\n const isPlainInput = checkIsPlainObject(item)\n if (isPlainInput) {\n const processedItem = dropUndefinedAndNull(item)\n // Skip if after processing, the object is empty\n if (Object.keys(processedItem).length === 0) continue\n\n const header = new Headers(processedItem as Record<string, string>)\n header.forEach((value, key) => {\n baseHeaders.set(key, value)\n })\n } else {\n const header = new Headers(item)\n header.forEach((value, key) => {\n baseHeaders.set(key, value)\n })\n }\n }\n baseHeaders.forEach((value, key) => {\n obj[key] = value\n })\n return obj\n }\n\n async emit<C = FexiosContext>(event: FexiosLifecycleEvents, ctx: C) {\n const hooks = this.hooks.filter((hook) => hook.event === event)\n try {\n let index = 0\n for (const hook of hooks) {\n const hookName = `${event}#${hook.action.name || `anonymous#${index}`}`\n\n // Set a symbol to check if the hook overrides the original context\n const symbol = Symbol('FexiosHookContext')\n ;(ctx as any)[symbol] = symbol\n\n const newCtx = (await hook.action.call(this, ctx)) as Awaited<C | false>\n\n // Excepted abort signal\n if (newCtx === false) {\n throw new FexiosError(\n FexiosErrorCodes.ABORTED_BY_HOOK,\n `Request aborted by hook \"${hookName}\"`,\n ctx as FexiosContext\n )\n }\n // Good\n else if (\n typeof newCtx === 'object' &&\n (newCtx as any)[symbol] === symbol\n ) {\n ctx = newCtx as C\n }\n // Unexpected return value\n else {\n // @ts-ignore prevent esbuild optimize\n const console = globalThis[''.concat('console')]\n try {\n throw new FexiosError(\n FexiosErrorCodes.HOOK_CONTEXT_CHANGED,\n `Hook \"${hookName}\" should return the original FexiosContext or return false to abort the request, but got \"${newCtx}\".`\n )\n } catch (e: any) {\n console.warn(e.stack || e)\n }\n }\n\n // Clean up\n delete (ctx as any)[symbol]\n\n index++\n }\n } catch (e) {\n return Promise.reject(e)\n }\n return ctx\n }\n\n on<C = FexiosContext>(\n event: FexiosLifecycleEvents,\n action: FexiosHook<C>,\n prepend = false\n ) {\n if (typeof action !== 'function') {\n throw new FexiosError(\n FexiosErrorCodes.INVALID_HOOK_CALLBACK,\n `Hook should be a function, but got \"${typeof action}\"`\n )\n }\n this.hooks[prepend ? 'unshift' : 'push']({\n event,\n action: action as FexiosHook,\n })\n return this\n }\n\n off(event: FexiosLifecycleEvents | '*' | null, action: FexiosHook<any>) {\n if (event === '*' || !event) {\n this.hooks = this.hooks.filter((hook) => hook.action !== action)\n } else {\n this.hooks = this.hooks.filter(\n (hook) => hook.event !== event || hook.action !== action\n )\n }\n return this\n }\n\n private createInterceptor<T extends FexiosLifecycleEvents>(\n event: T\n ): FexiosInterceptor {\n return {\n handlers: () =>\n this.hooks\n .filter((hook) => hook.event === event)\n .map((hook) => hook.action),\n use: <C = FexiosContext>(hook: FexiosHook<C>, prepend = false) => {\n return this.on(event, hook, prepend)\n },\n clear: () => {\n this.hooks = this.hooks.filter((hook) => hook.event !== event)\n },\n }\n }\n\n readonly interceptors: FexiosInterceptors = {\n request: this.createInterceptor('beforeRequest'),\n response: this.createInterceptor('afterResponse'),\n }\n\n private createMethodShortcut(method: FexiosMethods) {\n Object.defineProperty(this, method, {\n value: (\n url: string | URL,\n bodyOrQuery?: Record<string, any> | string | URLSearchParams,\n options?: Partial<FexiosRequestOptions>\n ) => {\n if (\n this.METHODS_WITHOUT_BODY.includes(\n method.toLocaleLowerCase() as FexiosMethods\n )\n ) {\n options = bodyOrQuery as any\n } else {\n options = options || {}\n options.body = bodyOrQuery\n }\n return this.request(url, {\n ...options,\n method: method as FexiosMethods,\n })\n },\n })\n return this\n }\n\n extends(configs: Partial<FexiosConfigs>) {\n const fexios = new Fexios({ ...this.baseConfigs, ...configs })\n fexios.hooks = [...this.hooks]\n return fexios\n }\n\n readonly create = Fexios.create\n static create(configs?: Partial<FexiosConfigs>) {\n return new Fexios(configs)\n }\n\n /**\n * Remove all undefined and null properties from an object\n * Also handles empty strings based on options\n * @deprecated Use dropUndefinedAndNull from utils instead\n */\n readonly dropUndefinedAndNull = dropUndefinedAndNull\n\n /**\n * Check if given payload is a plain object\n * @deprecated Use checkIsPlainObject from utils instead\n */\n readonly checkIsPlainObject = checkIsPlainObject\n}\n\n// declare method shortcuts\nexport interface Fexios {\n get: FexiosRequestShortcut<'get'>\n post: FexiosRequestShortcut<'post'>\n put: FexiosRequestShortcut<'put'>\n patch: FexiosRequestShortcut<'patch'>\n delete: FexiosRequestShortcut<'delete'>\n head: FexiosRequestShortcut<'head'>\n options: FexiosRequestShortcut<'options'>\n trace: FexiosRequestShortcut<'trace'>\n}\n","/**\n * Fexios\n * @desc Fetch based HTTP client with similar API to axios for browser and Node.js\n *\n * @license MIT\n * @author dragon-fish <dragon-fish@qq.com>\n */\n\n// Export all types\nexport * from './types'\n\n// Export errors\nexport * from './errors'\n\n// Export response utilities\nexport * from './response'\n\n// Export query builder\nexport * from './query-builder'\n\n// Export utilities\nexport * from './utils'\n\n// Export main Fexios class\nexport * from './fexios'\n\n// Support for direct import\nimport { Fexios } from './fexios'\nexport const createFexios = Fexios.create\nexport const fexios = createFexios()\nexport default fexios\n\n// Set global fexios instance for browser\ndeclare global {\n interface Window {\n fexios: Fexios\n }\n}\nif (typeof globalThis !== 'undefined') {\n ;(globalThis as any).fexios = fexios\n} else if (typeof window !== 'undefined') {\n window.fexios = fexios\n}\n"],"names":["FexiosErrorCodes","FexiosError","code","message","context","options","FexiosResponseError","response","isFexiosError","e","checkIfTextData","uint8Array","maxBytesToCheck","bytesToCheck","dataToCheck","hasBinaryHeader","stats","analyzeByteDistribution","encodings","bestScore","isValidText","encoding","decodedString","score","calculateTextScore","data","binaryHeaders","header","matches","i","nullBytes","highBytes","controlChars","byte","text","textLikeChars","isControlCharacter","isPrivateUse","textRatio","hasTextPatterns","pattern","checkIsPlainObject","payload","proto","dropUndefinedAndNull","obj","newObj","key","value","FexiosResponse","rawResponse","overrides","resolveResponseBody","expectType","onProgress","contentType","contentLength","isJsonContent","isBinaryContent","buffer","ws","resolve","reject","es","reader","_a","done","progress","res","jsonString","trimmedData","firstChar","lastChar","FexiosQueryBuilder","query","searchParams","v","CallableInstance","property","func","apply","p","callableInstance","Fexios","baseConfigs","urlOrOptions","ctx","baseUrlString","baseURL","_b","reqURL","baseUrlQuery","requestUrlQuery","_c","body","_d","abortController","rawRequest","timeout","connectionTimeout","event","error","timer","err","base","income","result","processQuerySource","source","baseHeaders","item","processedItem","hooks","hook","index","hookName","symbol","newCtx","console","action","prepend","method","url","bodyOrQuery","configs","fexios","createFexios"],"mappings":"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","x_google_ignoreList":[4]}