@zayne-labs/callapi 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- "use strict";var e,r=Object.defineProperty,t=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,n={};((e,t)=>{for(var o in t)r(e,o,{get:t[o],enumerable:!0})})(n,{HTTPError:()=>E,callApi:()=>T,createFetchClient:()=>g,isHTTPError:()=>h,isHTTPErrorInstance:()=>w,toQueryString:()=>l}),module.exports=(e=n,((e,n,a,i)=>{if(n&&"object"==typeof n||"function"==typeof n)for(let l of o(n))s.call(e,l)||l===a||r(e,l,{get:()=>n[l],enumerable:!(i=t(n,l))||i.enumerable});return e})(r({},"__esModule",{value:!0}),e));var a=e=>!("object"!=typeof e||null===e||e instanceof FormData||Array.isArray(e)),i=e=>"string"==typeof e,l=e=>e?new URLSearchParams(e).toString():(console.error("toQueryString:","No query params provided!"),null),c=e=>{return!e||a(e)?e:Object.fromEntries((r=e,Array.isArray(r)?e:e.entries()));var r},u=Object.keys({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"}).map(Number),p=["GET"],d=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],y=(e,r)=>{const t=Object.entries(e).filter((([e])=>!r.includes(e)));return Object.fromEntries(t)},f=(e,r)=>{const t=new Set(r),o=Object.entries(e).filter((([e])=>t.has(e)));return Object.fromEntries(o)},m=e=>[f(e,d),y(e,d)],b=(e,r,t)=>{const o=((e,r)=>({json:async()=>r?r(await e.text()):e.json(),arrayBuffer:()=>e.arrayBuffer(),blob:()=>e.blob(),formData:()=>e.formData(),text:()=>e.text()}))(e,t);if(!Object.hasOwn(o,r))throw new Error(`Invalid response type: ${r}`);return o[r]()},h=e=>a(e)&&"HTTPError"===e.name,E=class extends Error{response;errorData;name="HTTPError";isHTTPError=!0;constructor(e,r){const{defaultErrorMessage:t,response:o,errorData:s}=e;super(s.message??t,r),this.errorData=s,this.response=o}},w=e=>e instanceof E||a(e)&&"HTTPError"===e.name&&!0===e.isHTTPError,g=e=>{const r=new Map,[t,o]=m(e??{}),{headers:s,body:n,signal:d,...y}=t,f=async(e,t)=>{const[h,g]=m(t??{}),{signal:T=d,body:D=n,headers:O,...R}=h,P={bodySerializer:JSON.stringify,responseType:"json",baseURL:"",retries:0,retryDelay:0,retryCodes:u,retryMethods:p,defaultErrorMessage:"Failed to fetch data from server!",cancelRedundantRequests:!0,...o,...g},j=r.get(e);if(j&&P.cancelRedundantRequests){const r=new DOMException(`Automatic cancelation of the previous unfinished request to this same url: ${e}`,"AbortError");j.abort(r)}const v=new AbortController;r.set(e,v);const q=P.timeout?AbortSignal.timeout(P.timeout):null,$=AbortSignal.any([v.signal,...q?[q]:[],...T?[T]:[]]),M={signal:$,method:"GET",body:a(D)?P.bodySerializer(D):D,headers:s||O||P.auth||a(D)?{...a(D)&&{"Content-Type":"application/json",Accept:"application/json"},...(S=D,"string"==typeof S&&S.includes("=")&&{"Content-Type":"application/x-www-form-urlencoded"}),...i(P.auth)&&{Authorization:`Bearer ${P.auth}`},...a(P.auth)&&{Authorization:"bearer"in P.auth?`Bearer ${P.auth.bearer}`:`Token ${P.auth.token}`},...c(s),...c(O)}:void 0,...y,...R};var S;try{await(P.onRequest?.({request:M,options:P}));const r=await fetch(`${P.baseURL}${((e,r)=>{if(!r)return e;const t=l(r);return e.endsWith("?")?`${e}${t}`:e.includes("?")?`${e}&${t}`:`${e}?${t}`})(e,P.query)}`,M);if(!r.ok&&!$.aborted&&P.retries>0&&P.retryCodes.includes(r.status)&&P.retryMethods.includes(M.method))return await(e=>{if(0===e)return;const{promise:r,resolve:t}=Promise.withResolvers();return setTimeout(t,e),r})(P.retryDelay),await f(e,{...t,retries:P.retries-1});if(!r.ok){const e=await b(P.cloneResponse?r.clone():r,P.responseType,P.responseParser);throw new E({errorData:e,response:r,defaultErrorMessage:P.defaultErrorMessage})}const o=await b(P.cloneResponse?r.clone():r,P.responseType,P.responseParser),s=P.responseValidator?P.responseValidator(o):o;return await(P.onResponse?.({data:s,response:P.cloneResponse?r.clone():r,request:M,options:P})),(e=>{const{options:r,response:t,successData:o}=e,s={data:o,error:null,response:t};return void 0===r.resultMode||"all"===r.resultMode?s:{onlySuccess:s.data,onlyError:s.error,onlyResponse:s.response}[r.resultMode]})({successData:s,response:r,options:P})}catch(e){const r=(e=>{const{error:r,options:t}=e;return(e={})=>{const{errorData:o,message:s,response:n}=e;if("function"==typeof t.throwOnError?t.throwOnError(r):t.throwOnError)throw r;return{data:null,error:{name:r?.name??"UnknownError",errorData:o??r,message:s??r?.message??t.defaultErrorMessage},response:n??null}}})({error:e,options:P});if(e instanceof DOMException&&"TimeoutError"===e.name){const t=`Request timed out after ${P.timeout}ms`;return console.error(`${e.name}:`,t),r({message:t})}if(e instanceof DOMException&&"AbortError"===e.name){const t=`Request aborted due to ${e.message}`;return console.error(`${e.name}:`,t),r({message:t})}if(w(e)){const{errorData:t,response:o}=e;return await Promise.allSettled([P.onResponseError?.({errorData:t,response:P.cloneResponse?o.clone():o,request:M,options:P}),P.onError?.({errorData:t,response:o,error:null,options:P,request:M})]),r({errorData:t,message:t?.message,response:o})}return await Promise.allSettled([P.onRequestError?.({request:M,error:e,options:P}),P.onError?.({request:M,error:e,options:P,errorData:null,response:null})]),r()}finally{r.delete(e)}};return f.create=g,f.cancel=(e,t)=>{t?r.get(e)?.abort(t):r.get(e)?.abort()},f},T=g();//# sourceMappingURL=index.cjs.map
1
+ "use strict";var e,r=Object.defineProperty,t=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,n={};((e,t)=>{for(var o in t)r(e,o,{get:t[o],enumerable:!0})})(n,{callApi:()=>E,createFetchClient:()=>w}),module.exports=(e=n,((e,n,a,i)=>{if(n&&"object"==typeof n||"function"==typeof n)for(let l of o(n))s.call(e,l)||l===a||r(e,l,{get:()=>n[l],enumerable:!(i=t(n,l))||i.enumerable});return e})(r({},"__esModule",{value:!0}),e));var a=e=>!("object"!=typeof e||null===e||e instanceof FormData||Array.isArray(e)),i=e=>"string"==typeof e,l=(e,r)=>{if(!r)return e;const t=(e=>e?new URLSearchParams(e).toString():(console.error("toQueryString:","No query params provided!"),null))(r);return e.endsWith("?")?`${e}${t}`:e.includes("?")?`${e}&${t}`:`${e}?${t}`},u=e=>{return!e||a(e)?e:Object.fromEntries((r=e,Array.isArray(r)?e:e.entries()));var r},c=Object.keys({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"}).map(Number),p=["GET"],d=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],y=(e,r)=>{const t=Object.entries(e).filter((([e])=>!r.includes(e)));return Object.fromEntries(t)},f=(e,r)=>{const t=new Set(r),o=Object.entries(e).filter((([e])=>t.has(e)));return Object.fromEntries(o)},m=e=>[f(e,d),y(e,d)],h=(e,r,t)=>{const o=((e,r)=>({arrayBuffer:()=>e.arrayBuffer(),blob:()=>e.blob(),formData:()=>e.formData(),json:async()=>r?r(await e.text()):e.json(),text:()=>e.text()}))(e,t);if(!Object.hasOwn(o,r))throw new Error(`Invalid response type: ${r}`);return o[r]()},b=class extends Error{errorData;isHTTPError=!0;name="HTTPError";response;constructor(e,r){const{defaultErrorMessage:t,errorData:o,response:s}=e;super(o.message??t,r),this.errorData=o,this.response=s}},w=e=>{const r=new Map,[t,o]=m(e??{}),{body:s,headers:n,signal:d,...f}=t,E=async(e,t)=>{const[w,g]=m(t??{}),{body:R=s,headers:O,signal:D=d,...T}=w,q={baseURL:"",bodySerializer:JSON.stringify,cancelRedundantRequests:!0,defaultErrorMessage:"Failed to fetch data from server!",responseType:"json",retries:0,retryCodes:c,retryDelay:0,retryMethods:p,...o,...g},$={body:a(R)?q.bodySerializer(R):R,headers:n||O||q.auth||a(R)?{...a(R)&&{Accept:"application/json","Content-Type":"application/json"},...(j=R,"string"==typeof j&&j.includes("=")&&{"Content-Type":"application/x-www-form-urlencoded"}),...i(q.auth)&&{Authorization:`Bearer ${q.auth}`},...a(q.auth)&&{Authorization:"bearer"in q.auth?`Bearer ${q.auth.bearer}`:`Token ${q.auth.token}`},...u(n),...u(O)}:void 0,method:"GET",...f,...T};var j;const v=((e,r)=>`${e} | ${JSON.stringify(r??{})}`)(e,y({...$,...q},["onRequest","onResponse","onResponseError","onError","onRequestError"])),M=r.get(v);if(M&&q.cancelRedundantRequests){const r=new DOMException(`Automatic cancelation of the previous unfinished request to the same url, with the same fetch options: ${e}`,"AbortError");M.abort(r)}const P=new AbortController;r.set(v,P);const S=q.timeout?AbortSignal.timeout(q.timeout):null,A=AbortSignal.any([P.signal,...S?[S]:[],...D?[D]:[]]),x={signal:A,...$};try{await(q.onRequest?.({options:q,request:x}));const r=await fetch(`${q.baseURL}${l(e,q.query)}`,x);if(!r.ok&&!A.aborted&&q.retries>0&&q.retryCodes.includes(r.status)&&q.retryMethods.includes(x.method))return await(e=>{if(0===e)return;const{promise:r,resolve:t}=Promise.withResolvers();return setTimeout(t,e),r})(q.retryDelay),await E(e,{...t,retries:q.retries-1});if(!r.ok){const e=await h(q.cloneResponse?r.clone():r,q.responseType,q.responseParser);throw new b({defaultErrorMessage:q.defaultErrorMessage,errorData:e,response:r})}const o=await h(q.cloneResponse?r.clone():r,q.responseType,q.responseParser),s=q.responseValidator?q.responseValidator(o):o;return await(q.onResponse?.({data:s,options:q,request:x,response:q.cloneResponse?r.clone():r})),(e=>{const{options:r,response:t,successData:o}=e,s={data:o,error:null,response:t};return r.resultMode&&"all"!==r.resultMode?{onlyError:s.error,onlyResponse:s.response,onlySuccess:s.data}[r.resultMode]:s})({options:q,response:r,successData:s})}catch(e){const r=(e=>{const{error:r,options:t}=e;return(e={})=>{const{errorData:o,message:s,response:n}=e;if("function"==typeof t.throwOnError?t.throwOnError(r):t.throwOnError)throw r;return{data:null,error:{errorData:o??r,message:s??r?.message??t.defaultErrorMessage,name:r?.name??"UnknownError"},response:n??null}}})({error:e,options:q});if(e instanceof DOMException&&"TimeoutError"===e.name){const t=`Request timed out after ${q.timeout}ms`;return console.error(`${e.name}:`,t),r({message:t})}if(e instanceof DOMException&&"AbortError"===e.name){const t=`Request aborted due to ${e.message}`;return console.error(`${e.name}:`,t),r({message:t})}if((e=>e instanceof b||a(e)&&"HTTPError"===e.name&&!0===e.isHTTPError)(e)){const{errorData:t,response:o}=e;return await Promise.allSettled([q.onResponseError?.({errorData:t,options:q,request:x,response:q.cloneResponse?o.clone():o}),q.onError?.({error:null,errorData:t,options:q,request:x,response:o})]),r({errorData:t,message:t?.message,response:o})}return await Promise.allSettled([q.onRequestError?.({error:e,options:q,request:x}),q.onError?.({error:e,errorData:null,options:q,request:x,response:null})]),r()}finally{r.delete(v)}};return E.create=w,E},E=w();//# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts","../../src/typeof.ts","../../src/utils.ts","../../src/createFetchClient.ts"],"sourcesContent":["export { callApi, createFetchClient } from \"./createFetchClient\";\n\nexport type {\n\t$RequestOptions,\n\tExtraOptions,\n\tFetchConfig,\n\tResponseContext,\n\tResponseErrorContext,\n\tErrorContext,\n} from \"./types\";\n\nexport { HTTPError, isHTTPError, isHTTPErrorInstance, toQueryString } from \"./utils\";\n","import type { AnyFunction } from \"./type-helpers\";\n\nexport const isArray = <TArray>(value: unknown): value is TArray[] => Array.isArray(value);\n\nexport const isObject = <TObject extends Record<string, unknown>>(value: unknown): value is TObject => {\n\treturn (\n\t\ttypeof value === \"object\" && value !== null && !(value instanceof FormData) && !Array.isArray(value)\n\t);\n};\n\nexport const isFunction = <TFunction extends AnyFunction>(value: unknown): value is TFunction =>\n\ttypeof value === \"function\";\n\nexport const isString = (value: unknown) => typeof value === \"string\";\n\nexport const isQueryString = (value: unknown): value is string =>\n\ttypeof value === \"string\" && value.includes(\"=\");\n","import { isArray, isFunction, isObject } from \"./typeof\";\nimport type {\n\t$BaseRequestOptions,\n\t$RequestOptions,\n\tApiErrorVariant,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tPossibleErrorObject,\n} from \"./types\";\n\ntype ToQueryStringFn = {\n\t(params: ExtraOptions[\"query\"]): string | null;\n\t(params: Required<ExtraOptions>[\"query\"]): string;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"toQueryString:\", \"No query params provided!\");\n\n\t\treturn null as never;\n\t}\n\n\treturn new URLSearchParams(params as Record<string, string>).toString();\n};\n\nexport const mergeUrlWithParams = (url: string, params: ExtraOptions[\"query\"]): string => {\n\tif (!params) {\n\t\treturn url;\n\t}\n\n\tconst paramsString = toQueryString(params);\n\n\tif (url.endsWith(\"?\")) {\n\t\treturn `${url}${paramsString}`;\n\t}\n\n\tif (url.includes(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\treturn `${url}?${paramsString}`;\n};\n\nexport const objectifyHeaders = (headers: RequestInit[\"headers\"]): Record<string, string> | undefined => {\n\tif (!headers || isObject(headers)) {\n\t\treturn headers;\n\t}\n\n\treturn Object.fromEntries(isArray(headers) ? headers : headers.entries());\n};\n\nconst retryCodesLookup = {\n\t408: \"Request Timeout\",\n\t409: \"Conflict\",\n\t425: \"Too Early\",\n\t429: \"Too Many Requests\",\n\t500: \"Internal Server Error\",\n\t502: \"Bad Gateway\",\n\t503: \"Service Unavailable\",\n\t504: \"Gateway Timeout\",\n};\n\nexport const defaultRetryCodes: Required<BaseConfig>[\"retryCodes\"] =\n\tObject.keys(retryCodesLookup).map(Number);\n\nexport const defaultRetryMethods: Required<BaseConfig>[\"retryMethods\"] = [\"GET\"];\n\nexport const fetchSpecificKeys = [\n\t\"body\",\n\t\"integrity\",\n\t\"method\",\n\t\"headers\",\n\t\"signal\",\n\t\"cache\",\n\t\"redirect\",\n\t\"window\",\n\t\"credentials\",\n\t\"keepalive\",\n\t\"referrer\",\n\t\"priority\",\n\t\"mode\",\n\t\"referrerPolicy\",\n] satisfies Array<keyof FetchConfig>;\n\nconst omitKeys = <TObject extends Record<string, unknown>, const TOmitArray extends Array<keyof TObject>>(\n\tinitialObject: TObject,\n\tkeysToOmit: TOmitArray\n) => {\n\tconst arrayFromFilteredObject = Object.entries(initialObject).filter(\n\t\t([key]) => !keysToOmit.includes(key)\n\t);\n\n\tconst updatedObject = Object.fromEntries(arrayFromFilteredObject);\n\n\treturn updatedObject as Omit<TObject, keyof TOmitArray>;\n};\n\nconst pickKeys = <TObject extends Record<string, unknown>, const TPickArray extends Array<keyof TObject>>(\n\tinitialObject: TObject,\n\tkeysToPick: TPickArray\n) => {\n\tconst keysToPickSet = new Set(keysToPick);\n\n\tconst arrayFromInitObject = Object.entries(initialObject);\n\n\tconst filteredArray = arrayFromInitObject.filter(([objectKey]) => keysToPickSet.has(objectKey));\n\n\tconst updatedObject = Object.fromEntries(filteredArray);\n\n\treturn updatedObject as Pick<TObject, TPickArray[number]>;\n};\n\nexport const splitConfig = <TObject extends object>(\n\tconfig: TObject\n): [\"body\" extends keyof TObject ? $RequestOptions : $BaseRequestOptions, ExtraOptions] => [\n\tpickKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n\tomitKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n];\n\nexport const handleResponseType = <TResponse>(\n\tresponse: Response,\n\tparser?: Required<ExtraOptions>[\"responseParser\"]\n) => ({\n\tjson: async () => {\n\t\tif (parser) {\n\t\t\treturn parser(await response.text());\n\t\t}\n\n\t\treturn response.json() as Promise<TResponse>;\n\t},\n\tarrayBuffer: () => response.arrayBuffer() as Promise<TResponse>,\n\tblob: () => response.blob() as Promise<TResponse>,\n\tformData: () => response.formData() as Promise<TResponse>,\n\ttext: () => response.text() as Promise<TResponse>,\n});\n\nexport const getResponseData = <TResponse>(\n\tresponse: Response,\n\tresponseType: keyof ReturnType<typeof handleResponseType>,\n\tparser: ExtraOptions[\"responseParser\"]\n) => {\n\tconst RESPONSE_TYPE_LOOKUP = handleResponseType<TResponse>(response, parser);\n\n\tif (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, responseType)) {\n\t\tthrow new Error(`Invalid response type: ${responseType}`);\n\t}\n\n\treturn RESPONSE_TYPE_LOOKUP[responseType]();\n};\n\ntype data = {\n\tsuccessData: unknown;\n\toptions: ExtraOptions;\n\tresponse: Response;\n};\n\n// == The CallApiResult type is used to cast all return statements due to a design limitation in ts.\n// LINK - See https://www.zhenghao.io/posts/type-functions for more info\nexport const resolveSuccessResult = <CallApiResult>(info: data): CallApiResult => {\n\tconst { options, response, successData } = info;\n\n\tconst apiDetails = {\n\t\tdata: successData,\n\t\terror: null,\n\t\tresponse,\n\t};\n\n\tif (options.resultMode === undefined || options.resultMode === \"all\") {\n\t\treturn apiDetails as CallApiResult;\n\t}\n\n\treturn {\n\t\tonlySuccess: apiDetails.data,\n\t\tonlyError: apiDetails.error,\n\t\tonlyResponse: apiDetails.response,\n\t}[options.resultMode] as CallApiResult;\n};\n\n// == Using curring here so error and options are not required to be passed every time, instead to be captured once by way of closure\nexport const getResolveErrorResultFn = <CallApiResult>($info: {\n\terror?: unknown;\n\toptions: ExtraOptions;\n}) => {\n\tconst { error, options } = $info;\n\n\ttype ErrorInfo = {\n\t\tresponse?: Response;\n\t\terrorData?: unknown;\n\t\tmessage?: string;\n\t};\n\n\tconst resolveErrorResult = (info: ErrorInfo = {}): CallApiResult => {\n\t\tconst { errorData, message, response } = info;\n\n\t\tconst shouldThrowOnError = isFunction(options.throwOnError)\n\t\t\t? options.throwOnError(error as Error)\n\t\t\t: options.throwOnError;\n\n\t\tif (shouldThrowOnError) {\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn {\n\t\t\tdata: null,\n\t\t\terror: {\n\t\t\t\tname: (error as PossibleErrorObject)?.name ?? \"UnknownError\",\n\t\t\t\terrorData: errorData ?? error,\n\t\t\t\tmessage: message ?? (error as PossibleErrorObject)?.message ?? options.defaultErrorMessage,\n\t\t\t},\n\t\t\tresponse: response ?? null,\n\t\t} as CallApiResult;\n\t};\n\n\treturn resolveErrorResult;\n};\n\nexport const isHTTPError = <TErrorData>(error: ApiErrorVariant<TErrorData>[\"error\"] | null) => {\n\treturn isObject(error) && error.name === \"HTTPError\";\n};\n\ntype ErrorDetails<TErrorResponse> = {\n\terrorData: TErrorResponse;\n\tresponse: Response;\n\tdefaultErrorMessage: string;\n};\n\ntype ErrorOptions = {\n\tcause?: unknown;\n};\n\nexport class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {\n\tresponse: ErrorDetails<TErrorResponse>[\"response\"];\n\terrorData: ErrorDetails<TErrorResponse>[\"errorData\"];\n\n\toverride name = \"HTTPError\" as const;\n\n\tisHTTPError = true;\n\n\tconstructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions) {\n\t\tconst { defaultErrorMessage, response, errorData } = errorDetails;\n\n\t\tsuper((errorData as { message?: string }).message ?? defaultErrorMessage, errorOptions);\n\n\t\tthis.errorData = errorData;\n\t\tthis.response = response;\n\t}\n}\n\n// prettier-ignore\nexport const isHTTPErrorInstance = <TErrorResponse>(\n\terror: unknown\n): error is HTTPError<TErrorResponse> => {\n\treturn (\n\t\terror instanceof HTTPError || (isObject(error) && error.name === \"HTTPError\" && error.isHTTPError === true)\n\t);\n};\n\nexport const waitUntil = (delay: number) => {\n\tif (delay === 0) return;\n\n\tconst { promise, resolve } = Promise.withResolvers();\n\n\tsetTimeout(resolve, delay);\n\n\treturn promise;\n};\n","import { isObject, isQueryString, isString } from \"./typeof\";\nimport type {\n\t$RequestOptions,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tGetCallApiResult,\n\tPossibleErrorObject,\n\tResultModeUnion,\n} from \"./types\";\nimport {\n\tHTTPError,\n\tdefaultRetryCodes,\n\tdefaultRetryMethods,\n\tgetResolveErrorResultFn,\n\tgetResponseData,\n\tisHTTPErrorInstance,\n\tmergeUrlWithParams,\n\tobjectifyHeaders,\n\tresolveSuccessResult,\n\tsplitConfig,\n\twaitUntil,\n} from \"./utils\";\n\nexport const createFetchClient = <\n\tTBaseData,\n\tTBaseErrorData = unknown,\n\tTBaseResultMode extends ResultModeUnion = \"all\",\n>(\n\tbaseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>\n) => {\n\tconst abortControllerStore = new Map<string, AbortController>();\n\n\tconst [baseFetchConfig, baseExtraOptions] = splitConfig(baseConfig ?? {});\n\n\tconst {\n\t\theaders: baseHeaders,\n\t\tbody: baseBody,\n\t\tsignal: baseSignal,\n\t\t...restOfBaseFetchConfig\n\t} = baseFetchConfig;\n\n\t/* eslint-disable complexity */\n\tconst callApi = async <\n\t\tTData = TBaseData,\n\t\tTErrorData = TBaseErrorData,\n\t\tTResultMode extends ResultModeUnion = TBaseResultMode,\n\t>(\n\t\turl: string,\n\t\tconfig?: FetchConfig<TData, TErrorData, TResultMode>\n\t): Promise<GetCallApiResult<TData, TErrorData, TResultMode>> => {\n\t\ttype CallApiResult = GetCallApiResult<TData, TErrorData, TResultMode>;\n\n\t\tconst [fetchConfig, extraOptions] = splitConfig(config ?? {});\n\n\t\tconst { signal = baseSignal, body = baseBody, headers, ...restOfFetchConfig } = fetchConfig;\n\n\t\t// == Default Options\n\t\tconst options = {\n\t\t\tbodySerializer: JSON.stringify,\n\t\t\tresponseType: \"json\",\n\t\t\tbaseURL: \"\",\n\t\t\tretries: 0,\n\t\t\tretryDelay: 0,\n\t\t\tretryCodes: defaultRetryCodes,\n\t\t\tretryMethods: defaultRetryMethods,\n\t\t\tdefaultErrorMessage: \"Failed to fetch data from server!\",\n\t\t\tcancelRedundantRequests: true,\n\t\t\t...baseExtraOptions,\n\t\t\t...extraOptions,\n\t\t} satisfies ExtraOptions;\n\n\t\tconst prevFetchController = abortControllerStore.get(url);\n\n\t\tif (prevFetchController && options.cancelRedundantRequests) {\n\t\t\tconst reason = new DOMException(\n\t\t\t\t`Automatic cancelation of the previous unfinished request to this same url: ${url}`,\n\t\t\t\t\"AbortError\"\n\t\t\t);\n\t\t\tprevFetchController.abort(reason);\n\t\t}\n\n\t\tconst newFetchController = new AbortController();\n\n\t\tabortControllerStore.set(url, newFetchController);\n\n\t\tconst timeoutSignal = options.timeout ? AbortSignal.timeout(options.timeout) : null;\n\n\t\tconst combinedSignal = AbortSignal.any([\n\t\t\tnewFetchController.signal,\n\t\t\t...(timeoutSignal ? [timeoutSignal] : []),\n\t\t\t...(signal ? [signal] : []),\n\t\t]);\n\n\t\tconst requestInit = {\n\t\t\tsignal: combinedSignal,\n\n\t\t\tmethod: \"GET\",\n\n\t\t\tbody: isObject(body) ? options.bodySerializer(body) : body,\n\n\t\t\t// == Return undefined if the following conditions are not met (so that native fetch would auto set the correct headers):\n\t\t\t// - headers are provided\n\t\t\t// - The body is an object\n\t\t\t// - The auth option is provided\n\t\t\theaders:\n\t\t\t\tbaseHeaders || headers || options.auth || isObject(body)\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...(isObject(body) && {\n\t\t\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isQueryString(body) && {\n\t\t\t\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isString(options.auth) && {\n\t\t\t\t\t\t\t\tAuthorization: `Bearer ${options.auth}`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isObject(options.auth) && {\n\t\t\t\t\t\t\t\tAuthorization:\n\t\t\t\t\t\t\t\t\t\"bearer\" in options.auth\n\t\t\t\t\t\t\t\t\t\t? `Bearer ${options.auth.bearer}`\n\t\t\t\t\t\t\t\t\t\t: `Token ${options.auth.token}`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...objectifyHeaders(baseHeaders),\n\t\t\t\t\t\t\t...objectifyHeaders(headers),\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\n\t\t\t...restOfBaseFetchConfig,\n\t\t\t...restOfFetchConfig,\n\t\t} satisfies $RequestOptions;\n\n\t\ttry {\n\t\t\tawait options.onRequest?.({ request: requestInit, options });\n\n\t\t\tconst response = await fetch(\n\t\t\t\t`${options.baseURL}${mergeUrlWithParams(url, options.query)}`,\n\t\t\t\trequestInit\n\t\t\t);\n\n\t\t\tconst shouldRetry =\n\t\t\t\t!response.ok &&\n\t\t\t\t!combinedSignal.aborted &&\n\t\t\t\toptions.retries > 0 &&\n\t\t\t\toptions.retryCodes.includes(response.status) &&\n\t\t\t\toptions.retryMethods.includes(requestInit.method);\n\n\t\t\tif (shouldRetry) {\n\t\t\t\tawait waitUntil(options.retryDelay);\n\n\t\t\t\treturn await callApi(url, { ...config, retries: options.retries - 1 });\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorData = await getResponseData<TErrorData>(\n\t\t\t\t\toptions.cloneResponse ? response.clone() : response,\n\t\t\t\t\toptions.responseType,\n\t\t\t\t\toptions.responseParser\n\t\t\t\t);\n\n\t\t\t\t// == Pushing all error handling responsibilities to the catch block\n\t\t\t\tthrow new HTTPError({\n\t\t\t\t\terrorData,\n\t\t\t\t\tresponse,\n\t\t\t\t\tdefaultErrorMessage: options.defaultErrorMessage,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst successData = await getResponseData<TData>(\n\t\t\t\toptions.cloneResponse ? response.clone() : response,\n\t\t\t\toptions.responseType,\n\t\t\t\toptions.responseParser\n\t\t\t);\n\n\t\t\tconst validSuccessData = options.responseValidator\n\t\t\t\t? options.responseValidator(successData)\n\t\t\t\t: successData;\n\n\t\t\tawait options.onResponse?.({\n\t\t\t\tdata: validSuccessData,\n\t\t\t\tresponse: options.cloneResponse ? response.clone() : response,\n\t\t\t\trequest: requestInit,\n\t\t\t\toptions,\n\t\t\t});\n\n\t\t\treturn resolveSuccessResult<CallApiResult>({ successData: validSuccessData, response, options });\n\n\t\t\t// == Exhaustive Error handling\n\t\t} catch (error) {\n\t\t\tconst resolveErrorResult = getResolveErrorResultFn<CallApiResult>({ error, options });\n\n\t\t\tif (error instanceof DOMException && error.name === \"TimeoutError\") {\n\t\t\t\tconst message = `Request timed out after ${options.timeout}ms`;\n\n\t\t\t\tconsole.error(`${error.name}:`, message);\n\n\t\t\t\treturn resolveErrorResult({ message });\n\t\t\t}\n\n\t\t\tif (error instanceof DOMException && error.name === \"AbortError\") {\n\t\t\t\tconst message = `Request aborted due to ${error.message}`;\n\n\t\t\t\tconsole.error(`${error.name}:`, message);\n\n\t\t\t\treturn resolveErrorResult({ message });\n\t\t\t}\n\n\t\t\tif (isHTTPErrorInstance<TErrorData>(error)) {\n\t\t\t\tconst { errorData, response } = error;\n\n\t\t\t\tvoid (await Promise.allSettled([\n\t\t\t\t\toptions.onResponseError?.({\n\t\t\t\t\t\terrorData,\n\t\t\t\t\t\tresponse: options.cloneResponse ? response.clone() : response,\n\t\t\t\t\t\trequest: requestInit,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t}),\n\n\t\t\t\t\t// == Also call the onError interceptor\n\t\t\t\t\toptions.onError?.({\n\t\t\t\t\t\terrorData,\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\terror: null,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\trequest: requestInit,\n\t\t\t\t\t}),\n\t\t\t\t]));\n\n\t\t\t\treturn resolveErrorResult({\n\t\t\t\t\terrorData,\n\t\t\t\t\tmessage: (errorData as PossibleErrorObject)?.message,\n\t\t\t\t\tresponse,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvoid (await Promise.allSettled([\n\t\t\t\t// == At this point only the request errors exist, so the request error interceptor is called\n\t\t\t\toptions.onRequestError?.({ request: requestInit, error: error as Error, options }),\n\n\t\t\t\t// == Also call the onError interceptor\n\t\t\t\toptions.onError?.({\n\t\t\t\t\trequest: requestInit,\n\t\t\t\t\terror: error as Error,\n\t\t\t\t\toptions,\n\t\t\t\t\terrorData: null,\n\t\t\t\t\tresponse: null,\n\t\t\t\t}),\n\t\t\t]));\n\n\t\t\treturn resolveErrorResult();\n\n\t\t\t// == Removing the now unneeded AbortController from store\n\t\t} finally {\n\t\t\tabortControllerStore.delete(url);\n\t\t}\n\t};\n\n\tcallApi.create = createFetchClient;\n\n\tcallApi.cancel = (url: string, reason?: unknown) => {\n\t\treason ? abortControllerStore.get(url)?.abort(reason) : abortControllerStore.get(url)?.abort();\n\t};\n\n\treturn callApi;\n};\n\nexport const callApi = createFetchClient();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,UAAU,CAAS,UAAsC,MAAM,QAAQ,KAAK;AAElF,IAAM,WAAW,CAA0C,UAAqC;AACtG,SACC,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,iBAAiB,aAAa,CAAC,MAAM,QAAQ,KAAK;AAErG;AAEO,IAAM,aAAa,CAAgC,UACzD,OAAO,UAAU;AAEX,IAAM,WAAW,CAAC,UAAmB,OAAO,UAAU;AAEtD,IAAM,gBAAgB,CAAC,UAC7B,OAAO,UAAU,YAAY,MAAM,SAAS,GAAG;;;ACAzC,IAAM,gBAAiC,CAAC,WAAW;AACzD,MAAI,CAAC,QAAQ;AACZ,YAAQ,MAAM,kBAAkB,2BAA2B;AAE3D,WAAO;AAAA,EACR;AAEA,SAAO,IAAI,gBAAgB,MAAgC,EAAE,SAAS;AACvE;AAEO,IAAM,qBAAqB,CAAC,KAAa,WAA0C;AACzF,MAAI,CAAC,QAAQ;AACZ,WAAO;AAAA,EACR;AAEA,QAAM,eAAe,cAAc,MAAM;AAEzC,MAAI,IAAI,SAAS,GAAG,GAAG;AACtB,WAAO,GAAG,GAAG,GAAG,YAAY;AAAA,EAC7B;AAEA,MAAI,IAAI,SAAS,GAAG,GAAG;AACtB,WAAO,GAAG,GAAG,IAAI,YAAY;AAAA,EAC9B;AAEA,SAAO,GAAG,GAAG,IAAI,YAAY;AAC9B;AAEO,IAAM,mBAAmB,CAAC,YAAwE;AACxG,MAAI,CAAC,WAAW,SAAS,OAAO,GAAG;AAClC,WAAO;AAAA,EACR;AAEA,SAAO,OAAO,YAAY,QAAQ,OAAO,IAAI,UAAU,QAAQ,QAAQ,CAAC;AACzE;AAEA,IAAM,mBAAmB;AAAA,EACxB,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACN;AAEO,IAAM,oBACZ,OAAO,KAAK,gBAAgB,EAAE,IAAI,MAAM;AAElC,IAAM,sBAA4D,CAAC,KAAK;AAExE,IAAM,oBAAoB;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAEA,IAAM,WAAW,CAChB,eACA,eACI;AACJ,QAAM,0BAA0B,OAAO,QAAQ,aAAa,EAAE;AAAA,IAC7D,CAAC,CAAC,GAAG,MAAM,CAAC,WAAW,SAAS,GAAG;AAAA,EACpC;AAEA,QAAM,gBAAgB,OAAO,YAAY,uBAAuB;AAEhE,SAAO;AACR;AAEA,IAAM,WAAW,CAChB,eACA,eACI;AACJ,QAAM,gBAAgB,IAAI,IAAI,UAAU;AAExC,QAAM,sBAAsB,OAAO,QAAQ,aAAa;AAExD,QAAM,gBAAgB,oBAAoB,OAAO,CAAC,CAAC,SAAS,MAAM,cAAc,IAAI,SAAS,CAAC;AAE9F,QAAM,gBAAgB,OAAO,YAAY,aAAa;AAEtD,SAAO;AACR;AAEO,IAAM,cAAc,CAC1B,WAC0F;AAAA,EAC1F,SAAS,QAAmC,iBAAiB;AAAA,EAC7D,SAAS,QAAmC,iBAAiB;AAC9D;AAEO,IAAM,qBAAqB,CACjC,UACA,YACK;AAAA,EACL,MAAM,YAAY;AACjB,QAAI,QAAQ;AACX,aAAO,OAAO,MAAM,SAAS,KAAK,CAAC;AAAA,IACpC;AAEA,WAAO,SAAS,KAAK;AAAA,EACtB;AAAA,EACA,aAAa,MAAM,SAAS,YAAY;AAAA,EACxC,MAAM,MAAM,SAAS,KAAK;AAAA,EAC1B,UAAU,MAAM,SAAS,SAAS;AAAA,EAClC,MAAM,MAAM,SAAS,KAAK;AAC3B;AAEO,IAAM,kBAAkB,CAC9B,UACA,cACA,WACI;AACJ,QAAM,uBAAuB,mBAA8B,UAAU,MAAM;AAE3E,MAAI,CAAC,OAAO,OAAO,sBAAsB,YAAY,GAAG;AACvD,UAAM,IAAI,MAAM,0BAA0B,YAAY,EAAE;AAAA,EACzD;AAEA,SAAO,qBAAqB,YAAY,EAAE;AAC3C;AAUO,IAAM,uBAAuB,CAAgB,SAA8B;AACjF,QAAM,EAAE,SAAS,UAAU,YAAY,IAAI;AAE3C,QAAM,aAAa;AAAA,IAClB,MAAM;AAAA,IACN,OAAO;AAAA,IACP;AAAA,EACD;AAEA,MAAI,QAAQ,eAAe,UAAa,QAAQ,eAAe,OAAO;AACrE,WAAO;AAAA,EACR;AAEA,SAAO;AAAA,IACN,aAAa,WAAW;AAAA,IACxB,WAAW,WAAW;AAAA,IACtB,cAAc,WAAW;AAAA,EAC1B,EAAE,QAAQ,UAAU;AACrB;AAGO,IAAM,0BAA0B,CAAgB,UAGjD;AACL,QAAM,EAAE,OAAO,QAAQ,IAAI;AAQ3B,QAAM,qBAAqB,CAAC,OAAkB,CAAC,MAAqB;AACnE,UAAM,EAAE,WAAW,SAAS,SAAS,IAAI;AAEzC,UAAM,qBAAqB,WAAW,QAAQ,YAAY,IACvD,QAAQ,aAAa,KAAc,IACnC,QAAQ;AAEX,QAAI,oBAAoB;AACvB,YAAM;AAAA,IACP;AAEA,WAAO;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,QACN,MAAO,OAA+B,QAAQ;AAAA,QAC9C,WAAW,aAAa;AAAA,QACxB,SAAS,WAAY,OAA+B,WAAW,QAAQ;AAAA,MACxE;AAAA,MACA,UAAU,YAAY;AAAA,IACvB;AAAA,EACD;AAEA,SAAO;AACR;AAEO,IAAM,cAAc,CAAa,UAAuD;AAC9F,SAAO,SAAS,KAAK,KAAK,MAAM,SAAS;AAC1C;AAYO,IAAM,YAAN,cAAkE,MAAM;AAAA,EAC9E;AAAA,EACA;AAAA,EAES,OAAO;AAAA,EAEhB,cAAc;AAAA,EAEd,YAAY,cAA4C,cAA6B;AACpF,UAAM,EAAE,qBAAqB,UAAU,UAAU,IAAI;AAErD,UAAO,UAAmC,WAAW,qBAAqB,YAAY;AAEtF,SAAK,YAAY;AACjB,SAAK,WAAW;AAAA,EACjB;AACD;AAGO,IAAM,sBAAsB,CAClC,UACwC;AACxC,SACC,iBAAiB,aAAc,SAAS,KAAK,KAAK,MAAM,SAAS,eAAe,MAAM,gBAAgB;AAExG;AAEO,IAAM,YAAY,CAAC,UAAkB;AAC3C,MAAI,UAAU,EAAG;AAEjB,QAAM,EAAE,SAAS,QAAQ,IAAI,QAAQ,cAAc;AAEnD,aAAW,SAAS,KAAK;AAEzB,SAAO;AACR;;;AClPO,IAAM,oBAAoB,CAKhC,eACI;AACJ,QAAM,uBAAuB,oBAAI,IAA6B;AAE9D,QAAM,CAAC,iBAAiB,gBAAgB,IAAI,YAAY,cAAc,CAAC,CAAC;AAExE,QAAM;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,GAAG;AAAA,EACJ,IAAI;AAGJ,QAAMA,WAAU,OAKf,KACA,WAC+D;AAG/D,UAAM,CAAC,aAAa,YAAY,IAAI,YAAY,UAAU,CAAC,CAAC;AAE5D,UAAM,EAAE,SAAS,YAAY,OAAO,UAAU,SAAS,GAAG,kBAAkB,IAAI;AAGhF,UAAM,UAAU;AAAA,MACf,gBAAgB,KAAK;AAAA,MACrB,cAAc;AAAA,MACd,SAAS;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,qBAAqB;AAAA,MACrB,yBAAyB;AAAA,MACzB,GAAG;AAAA,MACH,GAAG;AAAA,IACJ;AAEA,UAAM,sBAAsB,qBAAqB,IAAI,GAAG;AAExD,QAAI,uBAAuB,QAAQ,yBAAyB;AAC3D,YAAM,SAAS,IAAI;AAAA,QAClB,8EAA8E,GAAG;AAAA,QACjF;AAAA,MACD;AACA,0BAAoB,MAAM,MAAM;AAAA,IACjC;AAEA,UAAM,qBAAqB,IAAI,gBAAgB;AAE/C,yBAAqB,IAAI,KAAK,kBAAkB;AAEhD,UAAM,gBAAgB,QAAQ,UAAU,YAAY,QAAQ,QAAQ,OAAO,IAAI;AAE/E,UAAM,iBAAiB,YAAY,IAAI;AAAA,MACtC,mBAAmB;AAAA,MACnB,GAAI,gBAAgB,CAAC,aAAa,IAAI,CAAC;AAAA,MACvC,GAAI,SAAS,CAAC,MAAM,IAAI,CAAC;AAAA,IAC1B,CAAC;AAED,UAAM,cAAc;AAAA,MACnB,QAAQ;AAAA,MAER,QAAQ;AAAA,MAER,MAAM,SAAS,IAAI,IAAI,QAAQ,eAAe,IAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,MAMtD,SACC,eAAe,WAAW,QAAQ,QAAQ,SAAS,IAAI,IACpD;AAAA,QACA,GAAI,SAAS,IAAI,KAAK;AAAA,UACrB,gBAAgB;AAAA,UAChB,QAAQ;AAAA,QACT;AAAA,QACA,GAAI,cAAc,IAAI,KAAK;AAAA,UAC1B,gBAAgB;AAAA,QACjB;AAAA,QACA,GAAI,SAAS,QAAQ,IAAI,KAAK;AAAA,UAC7B,eAAe,UAAU,QAAQ,IAAI;AAAA,QACtC;AAAA,QACA,GAAI,SAAS,QAAQ,IAAI,KAAK;AAAA,UAC7B,eACC,YAAY,QAAQ,OACjB,UAAU,QAAQ,KAAK,MAAM,KAC7B,SAAS,QAAQ,KAAK,KAAK;AAAA,QAChC;AAAA,QACA,GAAG,iBAAiB,WAAW;AAAA,QAC/B,GAAG,iBAAiB,OAAO;AAAA,MAC5B,IACC;AAAA,MAEJ,GAAG;AAAA,MACH,GAAG;AAAA,IACJ;AAEA,QAAI;AACH,YAAM,QAAQ,YAAY,EAAE,SAAS,aAAa,QAAQ,CAAC;AAE3D,YAAM,WAAW,MAAM;AAAA,QACtB,GAAG,QAAQ,OAAO,GAAG,mBAAmB,KAAK,QAAQ,KAAK,CAAC;AAAA,QAC3D;AAAA,MACD;AAEA,YAAM,cACL,CAAC,SAAS,MACV,CAAC,eAAe,WAChB,QAAQ,UAAU,KAClB,QAAQ,WAAW,SAAS,SAAS,MAAM,KAC3C,QAAQ,aAAa,SAAS,YAAY,MAAM;AAEjD,UAAI,aAAa;AAChB,cAAM,UAAU,QAAQ,UAAU;AAElC,eAAO,MAAMA,SAAQ,KAAK,EAAE,GAAG,QAAQ,SAAS,QAAQ,UAAU,EAAE,CAAC;AAAA,MACtE;AAEA,UAAI,CAAC,SAAS,IAAI;AACjB,cAAM,YAAY,MAAM;AAAA,UACvB,QAAQ,gBAAgB,SAAS,MAAM,IAAI;AAAA,UAC3C,QAAQ;AAAA,UACR,QAAQ;AAAA,QACT;AAGA,cAAM,IAAI,UAAU;AAAA,UACnB;AAAA,UACA;AAAA,UACA,qBAAqB,QAAQ;AAAA,QAC9B,CAAC;AAAA,MACF;AAEA,YAAM,cAAc,MAAM;AAAA,QACzB,QAAQ,gBAAgB,SAAS,MAAM,IAAI;AAAA,QAC3C,QAAQ;AAAA,QACR,QAAQ;AAAA,MACT;AAEA,YAAM,mBAAmB,QAAQ,oBAC9B,QAAQ,kBAAkB,WAAW,IACrC;AAEH,YAAM,QAAQ,aAAa;AAAA,QAC1B,MAAM;AAAA,QACN,UAAU,QAAQ,gBAAgB,SAAS,MAAM,IAAI;AAAA,QACrD,SAAS;AAAA,QACT;AAAA,MACD,CAAC;AAED,aAAO,qBAAoC,EAAE,aAAa,kBAAkB,UAAU,QAAQ,CAAC;AAAA,IAGhG,SAAS,OAAO;AACf,YAAM,qBAAqB,wBAAuC,EAAE,OAAO,QAAQ,CAAC;AAEpF,UAAI,iBAAiB,gBAAgB,MAAM,SAAS,gBAAgB;AACnE,cAAM,UAAU,2BAA2B,QAAQ,OAAO;AAE1D,gBAAQ,MAAM,GAAG,MAAM,IAAI,KAAK,OAAO;AAEvC,eAAO,mBAAmB,EAAE,QAAQ,CAAC;AAAA,MACtC;AAEA,UAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AACjE,cAAM,UAAU,0BAA0B,MAAM,OAAO;AAEvD,gBAAQ,MAAM,GAAG,MAAM,IAAI,KAAK,OAAO;AAEvC,eAAO,mBAAmB,EAAE,QAAQ,CAAC;AAAA,MACtC;AAEA,UAAI,oBAAgC,KAAK,GAAG;AAC3C,cAAM,EAAE,WAAW,SAAS,IAAI;AAEhC,aAAM,MAAM,QAAQ,WAAW;AAAA,UAC9B,QAAQ,kBAAkB;AAAA,YACzB;AAAA,YACA,UAAU,QAAQ,gBAAgB,SAAS,MAAM,IAAI;AAAA,YACrD,SAAS;AAAA,YACT;AAAA,UACD,CAAC;AAAA;AAAA,UAGD,QAAQ,UAAU;AAAA,YACjB;AAAA,YACA;AAAA,YACA,OAAO;AAAA,YACP;AAAA,YACA,SAAS;AAAA,UACV,CAAC;AAAA,QACF,CAAC;AAED,eAAO,mBAAmB;AAAA,UACzB;AAAA,UACA,SAAU,WAAmC;AAAA,UAC7C;AAAA,QACD,CAAC;AAAA,MACF;AAEA,WAAM,MAAM,QAAQ,WAAW;AAAA;AAAA,QAE9B,QAAQ,iBAAiB,EAAE,SAAS,aAAa,OAAuB,QAAQ,CAAC;AAAA;AAAA,QAGjF,QAAQ,UAAU;AAAA,UACjB,SAAS;AAAA,UACT;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,UAAU;AAAA,QACX,CAAC;AAAA,MACF,CAAC;AAED,aAAO,mBAAmB;AAAA,IAG3B,UAAE;AACD,2BAAqB,OAAO,GAAG;AAAA,IAChC;AAAA,EACD;AAEA,EAAAA,SAAQ,SAAS;AAEjB,EAAAA,SAAQ,SAAS,CAAC,KAAa,WAAqB;AACnD,aAAS,qBAAqB,IAAI,GAAG,GAAG,MAAM,MAAM,IAAI,qBAAqB,IAAI,GAAG,GAAG,MAAM;AAAA,EAC9F;AAEA,SAAOA;AACR;AAEO,IAAM,UAAU,kBAAkB;","names":["callApi"]}
1
+ {"version":3,"sources":["../../src/index.ts","../../src/typeof.ts","../../src/utils.ts","../../src/createFetchClient.ts"],"sourcesContent":["export { callApi, createFetchClient } from \"./createFetchClient\";\n\nexport type {\n\t$RequestOptions,\n\tExtraOptions,\n\tFetchConfig,\n\tResponseContext,\n\tResponseErrorContext,\n\tErrorContext,\n} from \"./types\";\n","import type { AnyFunction } from \"./type-helpers\";\n\nexport const isArray = <TArray>(value: unknown): value is TArray[] => Array.isArray(value);\n\nexport const isObject = <TObject extends Record<string, unknown>>(value: unknown): value is TObject => {\n\treturn (\n\t\ttypeof value === \"object\" && value !== null && !(value instanceof FormData) && !Array.isArray(value)\n\t);\n};\n\nexport const isFunction = <TFunction extends AnyFunction>(value: unknown): value is TFunction =>\n\ttypeof value === \"function\";\n\nexport const isString = (value: unknown) => typeof value === \"string\";\n\nexport const isQueryString = (value: unknown): value is string =>\n\ttypeof value === \"string\" && value.includes(\"=\");\n","import { isArray, isFunction, isObject } from \"./typeof\";\nimport type {\n\t$BaseRequestOptions,\n\t$RequestOptions,\n\tApiErrorVariant,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tPossibleErrorObject,\n} from \"./types\";\n\n// prettier-ignore\nexport const getRequestKey = <TConfig extends Record<string, unknown>>(url: string, config?: TConfig) => `${url} | ${JSON.stringify(config ?? {})}`;\n\ntype ToQueryStringFn = {\n\t(params: ExtraOptions[\"query\"]): null | string;\n\t(params: Required<ExtraOptions>[\"query\"]): string;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"toQueryString:\", \"No query params provided!\");\n\n\t\treturn null as never;\n\t}\n\n\treturn new URLSearchParams(params as Record<string, string>).toString();\n};\n\nexport const mergeUrlWithParams = (url: string, params: ExtraOptions[\"query\"]): string => {\n\tif (!params) {\n\t\treturn url;\n\t}\n\n\tconst paramsString = toQueryString(params);\n\n\tif (url.endsWith(\"?\")) {\n\t\treturn `${url}${paramsString}`;\n\t}\n\n\tif (url.includes(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\treturn `${url}?${paramsString}`;\n};\n\nexport const objectifyHeaders = (headers: RequestInit[\"headers\"]): Record<string, string> | undefined => {\n\tif (!headers || isObject(headers)) {\n\t\treturn headers;\n\t}\n\n\treturn Object.fromEntries(isArray(headers) ? headers : headers.entries());\n};\n\nconst retryCodesLookup = {\n\t408: \"Request Timeout\",\n\t409: \"Conflict\",\n\t425: \"Too Early\",\n\t429: \"Too Many Requests\",\n\t500: \"Internal Server Error\",\n\t502: \"Bad Gateway\",\n\t503: \"Service Unavailable\",\n\t504: \"Gateway Timeout\",\n};\n\nexport const defaultRetryCodes: Required<BaseConfig>[\"retryCodes\"] =\n\tObject.keys(retryCodesLookup).map(Number);\n\nexport const defaultRetryMethods: Required<BaseConfig>[\"retryMethods\"] = [\"GET\"];\n\nexport const fetchSpecificKeys = [\n\t\"body\",\n\t\"integrity\",\n\t\"method\",\n\t\"headers\",\n\t\"signal\",\n\t\"cache\",\n\t\"redirect\",\n\t\"window\",\n\t\"credentials\",\n\t\"keepalive\",\n\t\"referrer\",\n\t\"priority\",\n\t\"mode\",\n\t\"referrerPolicy\",\n] satisfies Array<keyof FetchConfig>;\n\nexport const omitKeys = <\n\tTObject extends Record<string, unknown>,\n\tconst TOmitArray extends Array<keyof TObject>,\n>(\n\tinitialObject: TObject,\n\tkeysToOmit: TOmitArray\n) => {\n\tconst arrayFromFilteredObject = Object.entries(initialObject).filter(\n\t\t([key]) => !keysToOmit.includes(key)\n\t);\n\n\tconst updatedObject = Object.fromEntries(arrayFromFilteredObject);\n\n\treturn updatedObject as Omit<TObject, keyof TOmitArray>;\n};\n\nconst pickKeys = <TObject extends Record<string, unknown>, const TPickArray extends Array<keyof TObject>>(\n\tinitialObject: TObject,\n\tkeysToPick: TPickArray\n) => {\n\tconst keysToPickSet = new Set(keysToPick);\n\n\tconst arrayFromInitObject = Object.entries(initialObject);\n\n\tconst filteredArray = arrayFromInitObject.filter(([objectKey]) => keysToPickSet.has(objectKey));\n\n\tconst updatedObject = Object.fromEntries(filteredArray);\n\n\treturn updatedObject as Pick<TObject, TPickArray[number]>;\n};\n\nexport const splitConfig = <TObject extends object>(\n\tconfig: TObject\n): [\"body\" extends keyof TObject ? $RequestOptions : $BaseRequestOptions, ExtraOptions] => [\n\tpickKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n\tomitKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n];\n\nexport const handleResponseType = <TResponse>(\n\tresponse: Response,\n\tparser?: Required<ExtraOptions>[\"responseParser\"]\n) => ({\n\tarrayBuffer: () => response.arrayBuffer() as Promise<TResponse>,\n\tblob: () => response.blob() as Promise<TResponse>,\n\tformData: () => response.formData() as Promise<TResponse>,\n\tjson: async () => {\n\t\tif (parser) {\n\t\t\treturn parser(await response.text());\n\t\t}\n\n\t\treturn response.json() as Promise<TResponse>;\n\t},\n\ttext: () => response.text() as Promise<TResponse>,\n});\n\nexport const getResponseData = <TResponse>(\n\tresponse: Response,\n\tresponseType: keyof ReturnType<typeof handleResponseType>,\n\tparser: ExtraOptions[\"responseParser\"]\n) => {\n\tconst RESPONSE_TYPE_LOOKUP = handleResponseType<TResponse>(response, parser);\n\n\tif (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, responseType)) {\n\t\tthrow new Error(`Invalid response type: ${responseType}`);\n\t}\n\n\treturn RESPONSE_TYPE_LOOKUP[responseType]();\n};\n\ntype data = {\n\toptions: ExtraOptions;\n\tresponse: Response;\n\tsuccessData: unknown;\n};\n\n// == The CallApiResult type is used to cast all return statements due to a design limitation in ts.\n// LINK - See https://www.zhenghao.io/posts/type-functions for more info\nexport const resolveSuccessResult = <CallApiResult>(info: data): CallApiResult => {\n\tconst { options, response, successData } = info;\n\n\tconst apiDetails = {\n\t\tdata: successData,\n\t\terror: null,\n\t\tresponse,\n\t};\n\n\tif (!options.resultMode || options.resultMode === \"all\") {\n\t\treturn apiDetails as CallApiResult;\n\t}\n\n\treturn {\n\t\tonlyError: apiDetails.error,\n\t\tonlyResponse: apiDetails.response,\n\t\tonlySuccess: apiDetails.data,\n\t}[options.resultMode] as CallApiResult;\n};\n\n// == Using curring here so error and options are not required to be passed every time, instead to be captured once by way of closure\nexport const getResolveErrorResultFn = <CallApiResult>($info: {\n\terror?: unknown;\n\toptions: ExtraOptions;\n}) => {\n\tconst { error, options } = $info;\n\n\ttype ErrorInfo = {\n\t\terrorData?: unknown;\n\t\tmessage?: string;\n\t\tresponse?: Response;\n\t};\n\n\tconst resolveErrorResult = (info: ErrorInfo = {}): CallApiResult => {\n\t\tconst { errorData, message, response } = info;\n\n\t\tconst shouldThrowOnError = isFunction(options.throwOnError)\n\t\t\t? options.throwOnError(error as Error)\n\t\t\t: options.throwOnError;\n\n\t\tif (shouldThrowOnError) {\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn {\n\t\t\tdata: null,\n\t\t\terror: {\n\t\t\t\terrorData: errorData ?? error,\n\t\t\t\tmessage: message ?? (error as PossibleErrorObject)?.message ?? options.defaultErrorMessage,\n\t\t\t\tname: (error as PossibleErrorObject)?.name ?? \"UnknownError\",\n\t\t\t},\n\t\t\tresponse: response ?? null,\n\t\t} as CallApiResult;\n\t};\n\n\treturn resolveErrorResult;\n};\n\nexport const isHTTPError = <TErrorData>(error: ApiErrorVariant<TErrorData>[\"error\"] | null) => {\n\treturn isObject(error) && error.name === \"HTTPError\";\n};\n\ntype ErrorDetails<TErrorResponse> = {\n\tdefaultErrorMessage: string;\n\terrorData: TErrorResponse;\n\tresponse: Response;\n};\n\ntype ErrorOptions = {\n\tcause?: unknown;\n};\n\nexport class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {\n\terrorData: ErrorDetails<TErrorResponse>[\"errorData\"];\n\tisHTTPError = true;\n\n\toverride name = \"HTTPError\" as const;\n\n\tresponse: ErrorDetails<TErrorResponse>[\"response\"];\n\n\tconstructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions) {\n\t\tconst { defaultErrorMessage, errorData, response } = errorDetails;\n\n\t\tsuper((errorData as { message?: string }).message ?? defaultErrorMessage, errorOptions);\n\n\t\tthis.errorData = errorData;\n\t\tthis.response = response;\n\t}\n}\n\n// prettier-ignore\nexport const isHTTPErrorInstance = <TErrorResponse>(\n\terror: unknown\n): error is HTTPError<TErrorResponse> => {\n\treturn (\n\t\terror instanceof HTTPError || (isObject(error) && error.name === \"HTTPError\" && error.isHTTPError === true)\n\t);\n};\n\nexport const waitUntil = (delay: number) => {\n\tif (delay === 0) return;\n\n\tconst { promise, resolve } = Promise.withResolvers();\n\n\tsetTimeout(resolve, delay);\n\n\treturn promise;\n};\n","import { isObject, isQueryString, isString } from \"./typeof\";\nimport type {\n\t$RequestOptions,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tGetCallApiResult,\n\tPossibleErrorObject,\n\tResultModeUnion,\n} from \"./types\";\nimport {\n\tHTTPError,\n\tdefaultRetryCodes,\n\tdefaultRetryMethods,\n\tgetRequestKey,\n\tgetResolveErrorResultFn,\n\tgetResponseData,\n\tisHTTPErrorInstance,\n\tmergeUrlWithParams,\n\tobjectifyHeaders,\n\tomitKeys,\n\tresolveSuccessResult,\n\tsplitConfig,\n\twaitUntil,\n} from \"./utils\";\n\nexport const createFetchClient = <\n\tTBaseData,\n\tTBaseErrorData = unknown,\n\tTBaseResultMode extends ResultModeUnion = undefined,\n>(\n\tbaseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>\n) => {\n\tconst abortControllerStore = new Map<string, AbortController>();\n\n\tconst [baseFetchConfig, baseExtraOptions] = splitConfig(baseConfig ?? {});\n\n\tconst {\n\t\tbody: baseBody,\n\t\theaders: baseHeaders,\n\t\tsignal: baseSignal,\n\t\t...restOfBaseFetchConfig\n\t} = baseFetchConfig;\n\n\t/* eslint-disable complexity */\n\tconst callApi = async <\n\t\tTData = TBaseData,\n\t\tTErrorData = TBaseErrorData,\n\t\tTResultMode extends ResultModeUnion = TBaseResultMode,\n\t>(\n\t\turl: string,\n\t\tconfig?: FetchConfig<TData, TErrorData, TResultMode>\n\t): Promise<GetCallApiResult<TData, TErrorData, TResultMode>> => {\n\t\ttype CallApiResult = GetCallApiResult<TData, TErrorData, TResultMode>;\n\n\t\tconst [fetchConfig, extraOptions] = splitConfig(config ?? {});\n\n\t\tconst { body = baseBody, headers, signal = baseSignal, ...restOfFetchConfig } = fetchConfig;\n\n\t\t// == Default Extra Options\n\t\tconst options = {\n\t\t\tbaseURL: \"\",\n\t\t\tbodySerializer: JSON.stringify,\n\t\t\tcancelRedundantRequests: true,\n\t\t\tdefaultErrorMessage: \"Failed to fetch data from server!\",\n\t\t\tresponseType: \"json\",\n\t\t\tretries: 0,\n\t\t\tretryCodes: defaultRetryCodes,\n\t\t\tretryDelay: 0,\n\t\t\tretryMethods: defaultRetryMethods,\n\t\t\t...baseExtraOptions,\n\t\t\t...extraOptions,\n\t\t} satisfies ExtraOptions;\n\n\t\t// == Default Fetch Config\n\t\tconst defaultFetchOptions = {\n\t\t\tbody: isObject(body) ? options.bodySerializer(body) : body,\n\n\t\t\t// - The auth option is provided\n\t\t\theaders:\n\t\t\t\tbaseHeaders || headers || options.auth || isObject(body)\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...(isObject(body) && {\n\t\t\t\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isQueryString(body) && {\n\t\t\t\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isString(options.auth) && {\n\t\t\t\t\t\t\t\tAuthorization: `Bearer ${options.auth}`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isObject(options.auth) && {\n\t\t\t\t\t\t\t\tAuthorization:\n\t\t\t\t\t\t\t\t\t\"bearer\" in options.auth\n\t\t\t\t\t\t\t\t\t\t? `Bearer ${options.auth.bearer}`\n\t\t\t\t\t\t\t\t\t\t: `Token ${options.auth.token}`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...objectifyHeaders(baseHeaders),\n\t\t\t\t\t\t\t...objectifyHeaders(headers),\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\n\t\t\t// == Return undefined if the following conditions are not met (so that native fetch would auto set the correct headers):\n\t\t\t// - headers are provided\n\t\t\t// - The body is an object\n\t\t\tmethod: \"GET\",\n\n\t\t\t...restOfBaseFetchConfig,\n\t\t\t...restOfFetchConfig,\n\t\t} satisfies $RequestOptions;\n\n\t\tconst requestKey = getRequestKey(\n\t\t\turl,\n\t\t\tomitKeys({ ...defaultFetchOptions, ...options }, [\n\t\t\t\t\"onRequest\",\n\t\t\t\t\"onResponse\",\n\t\t\t\t\"onResponseError\",\n\t\t\t\t\"onError\",\n\t\t\t\t\"onRequestError\",\n\t\t\t])\n\t\t);\n\n\t\tconst prevFetchController = abortControllerStore.get(requestKey);\n\n\t\tif (prevFetchController && options.cancelRedundantRequests) {\n\t\t\tconst reason = new DOMException(\n\t\t\t\t`Automatic cancelation of the previous unfinished request to the same url, with the same fetch options: ${url}`,\n\t\t\t\t\"AbortError\"\n\t\t\t);\n\n\t\t\tprevFetchController.abort(reason);\n\t\t}\n\n\t\tconst newFetchController = new AbortController();\n\n\t\tabortControllerStore.set(requestKey, newFetchController);\n\n\t\tconst timeoutSignal = options.timeout ? AbortSignal.timeout(options.timeout) : null;\n\n\t\tconst combinedSignal = AbortSignal.any([\n\t\t\tnewFetchController.signal,\n\t\t\t...(timeoutSignal ? [timeoutSignal] : []),\n\t\t\t...(signal ? [signal] : []),\n\t\t]);\n\n\t\tconst requestInit = {\n\t\t\tsignal: combinedSignal,\n\t\t\t...defaultFetchOptions,\n\t\t} satisfies $RequestOptions;\n\n\t\ttry {\n\t\t\tawait options.onRequest?.({ options, request: requestInit });\n\n\t\t\tconst response = await fetch(\n\t\t\t\t`${options.baseURL}${mergeUrlWithParams(url, options.query)}`,\n\t\t\t\trequestInit\n\t\t\t);\n\n\t\t\tconst shouldRetry =\n\t\t\t\t!response.ok &&\n\t\t\t\t!combinedSignal.aborted &&\n\t\t\t\toptions.retries > 0 &&\n\t\t\t\toptions.retryCodes.includes(response.status) &&\n\t\t\t\toptions.retryMethods.includes(requestInit.method);\n\n\t\t\tif (shouldRetry) {\n\t\t\t\tawait waitUntil(options.retryDelay);\n\n\t\t\t\treturn await callApi(url, { ...config, retries: options.retries - 1 });\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorData = await getResponseData<TErrorData>(\n\t\t\t\t\toptions.cloneResponse ? response.clone() : response,\n\t\t\t\t\toptions.responseType,\n\t\t\t\t\toptions.responseParser\n\t\t\t\t);\n\n\t\t\t\t// == Pushing all error handling responsibilities to the catch block\n\t\t\t\tthrow new HTTPError({\n\t\t\t\t\tdefaultErrorMessage: options.defaultErrorMessage,\n\t\t\t\t\terrorData,\n\t\t\t\t\tresponse,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst successData = await getResponseData<TData>(\n\t\t\t\toptions.cloneResponse ? response.clone() : response,\n\t\t\t\toptions.responseType,\n\t\t\t\toptions.responseParser\n\t\t\t);\n\n\t\t\tconst validSuccessData = options.responseValidator\n\t\t\t\t? options.responseValidator(successData)\n\t\t\t\t: successData;\n\n\t\t\tawait options.onResponse?.({\n\t\t\t\tdata: validSuccessData,\n\t\t\t\toptions,\n\t\t\t\trequest: requestInit,\n\t\t\t\tresponse: options.cloneResponse ? response.clone() : response,\n\t\t\t});\n\n\t\t\treturn resolveSuccessResult<CallApiResult>({ options, response, successData: validSuccessData });\n\n\t\t\t// == Exhaustive Error handling\n\t\t} catch (error) {\n\t\t\tconst resolveErrorResult = getResolveErrorResultFn<CallApiResult>({ error, options });\n\n\t\t\tif (error instanceof DOMException && error.name === \"TimeoutError\") {\n\t\t\t\tconst message = `Request timed out after ${options.timeout}ms`;\n\n\t\t\t\tconsole.error(`${error.name}:`, message);\n\n\t\t\t\treturn resolveErrorResult({ message });\n\t\t\t}\n\n\t\t\tif (error instanceof DOMException && error.name === \"AbortError\") {\n\t\t\t\tconst message = `Request aborted due to ${error.message}`;\n\n\t\t\t\tconsole.error(`${error.name}:`, message);\n\n\t\t\t\treturn resolveErrorResult({ message });\n\t\t\t}\n\n\t\t\tif (isHTTPErrorInstance<TErrorData>(error)) {\n\t\t\t\tconst { errorData, response } = error;\n\n\t\t\t\tvoid (await Promise.allSettled([\n\t\t\t\t\toptions.onResponseError?.({\n\t\t\t\t\t\terrorData,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\trequest: requestInit,\n\t\t\t\t\t\tresponse: options.cloneResponse ? response.clone() : response,\n\t\t\t\t\t}),\n\n\t\t\t\t\t// == Also call the onError interceptor\n\t\t\t\t\toptions.onError?.({\n\t\t\t\t\t\terror: null,\n\t\t\t\t\t\terrorData,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\trequest: requestInit,\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t}),\n\t\t\t\t]));\n\n\t\t\t\treturn resolveErrorResult({\n\t\t\t\t\terrorData,\n\t\t\t\t\tmessage: (errorData as PossibleErrorObject)?.message,\n\t\t\t\t\tresponse,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvoid (await Promise.allSettled([\n\t\t\t\t// == At this point only the request errors exist, so the request error interceptor is called\n\t\t\t\toptions.onRequestError?.({ error: error as Error, options, request: requestInit }),\n\n\t\t\t\t// == Also call the onError interceptor\n\t\t\t\toptions.onError?.({\n\t\t\t\t\terror: error as Error,\n\t\t\t\t\terrorData: null,\n\t\t\t\t\toptions,\n\t\t\t\t\trequest: requestInit,\n\t\t\t\t\tresponse: null,\n\t\t\t\t}),\n\t\t\t]));\n\n\t\t\treturn resolveErrorResult();\n\n\t\t\t// == Removing the now unneeded AbortController from store\n\t\t} finally {\n\t\t\tabortControllerStore.delete(requestKey);\n\t\t}\n\t};\n\n\tcallApi.create = createFetchClient;\n\n\treturn callApi;\n};\n\nexport const callApi = createFetchClient();\n"],"mappings":"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","names":["callApi"]}
@@ -8,137 +8,68 @@ type Prettify<TObject> = {
8
8
  [Key in keyof TObject]: TObject[Key];
9
9
  } & NonNullable<unknown>;
10
10
 
11
- type ToQueryStringFn = {
12
- (params: ExtraOptions["query"]): string | null;
13
- (params: Required<ExtraOptions>["query"]): string;
14
- };
15
- declare const toQueryString: ToQueryStringFn;
16
11
  declare const fetchSpecificKeys: ("body" | "method" | "headers" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "priority" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window")[];
17
12
  declare const handleResponseType: <TResponse>(response: Response, parser?: Required<ExtraOptions>["responseParser"]) => {
18
- json: () => Promise<Record<string, unknown> | TResponse>;
19
13
  arrayBuffer: () => Promise<TResponse>;
20
14
  blob: () => Promise<TResponse>;
21
15
  formData: () => Promise<TResponse>;
16
+ json: () => Promise<Record<string, unknown> | TResponse>;
22
17
  text: () => Promise<TResponse>;
23
18
  };
24
- declare const isHTTPError: <TErrorData>(error: ApiErrorVariant<TErrorData>["error"] | null) => error is {
25
- name: "HTTPError";
26
- errorData: TErrorData;
27
- message: string;
28
- };
29
19
  type ErrorDetails<TErrorResponse> = {
20
+ defaultErrorMessage: string;
30
21
  errorData: TErrorResponse;
31
22
  response: Response;
32
- defaultErrorMessage: string;
33
23
  };
34
24
  type ErrorOptions = {
35
25
  cause?: unknown;
36
26
  };
37
27
  declare class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {
38
- response: ErrorDetails<TErrorResponse>["response"];
39
28
  errorData: ErrorDetails<TErrorResponse>["errorData"];
40
- name: "HTTPError";
41
29
  isHTTPError: boolean;
30
+ name: "HTTPError";
31
+ response: ErrorDetails<TErrorResponse>["response"];
42
32
  constructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions);
43
33
  }
44
- declare const isHTTPErrorInstance: <TErrorResponse>(error: unknown) => error is HTTPError<TErrorResponse>;
45
34
 
46
35
  interface $RequestOptions extends Pick<FetchConfig, (typeof fetchSpecificKeys)[number]> {
47
36
  }
48
37
  interface ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = ResultModeUnion> {
49
- /** Optional body of the request, can be a object or any other supported body type. */
50
- body?: Record<string, unknown> | RequestInit["body"];
51
- /**
52
- * @description HTTP method for the request.
53
- * @default "GET"
54
- */
55
- method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE" | AnyString;
56
- /**
57
- * @description Query parameters to append to the URL.
58
- */
59
- query?: Record<string, string | number | boolean>;
60
38
  /**
61
39
  * @description Authorization header value.
62
40
  */
63
- auth?: string | {
41
+ auth?: {
64
42
  bearer: string;
65
43
  token?: never;
66
44
  } | {
67
- token: string;
68
45
  bearer?: never;
69
- };
46
+ token: string;
47
+ } | string;
70
48
  /**
71
- * @description Custom function to validate the response data.
49
+ * @description Base URL to be prepended to all request URLs
72
50
  */
73
- responseValidator?: (data: unknown) => TData;
51
+ baseURL?: string;
52
+ /** Optional body of the request, can be a object or any other supported body type. */
53
+ body?: Record<string, unknown> | RequestInit["body"];
74
54
  /**
75
55
  * @description Custom function to serialize the body object into a string.
76
56
  */
77
57
  bodySerializer?: (bodyData: Record<string, unknown>) => string;
78
- /**
79
- * @description Custom function to parse the response string into a object.
80
- */
81
- responseParser?: (responseString: string) => Record<string, unknown>;
82
- /**
83
- * @description Mode of the result, can influence how results are handled or returned.
84
- * Can be set to "all" | "onlySuccess" | "onlyError" | "onlyResponse".
85
- * @default "all"
86
- */
87
- resultMode?: TResultMode;
88
58
  /**
89
59
  * @description If true, cancels previous unfinished requests to the same URL.
90
60
  * @default true
91
61
  */
92
62
  cancelRedundantRequests?: boolean;
93
- /**
94
- * @description Base URL to be prepended to all request URLs
95
- */
96
- baseURL?: string;
97
- /**
98
- * @description Request timeout in milliseconds
99
- */
100
- timeout?: number;
101
- /**
102
- * @description Default error message to use if none is provided from a response.
103
- * @default "Failed to fetch data from server!"
104
- */
105
- defaultErrorMessage?: string;
106
63
  /**
107
64
  * @description Whether to clone the response, so response.json and the like can used in the interceptors.
108
65
  * @default false
109
66
  */
110
67
  cloneResponse?: boolean;
111
68
  /**
112
- * If true or the function returns true, throws errors instead of returning them
113
- * The function is passed the error object and can be used to conditionally throw the error
114
- * @default false
115
- */
116
- throwOnError?: boolean | ((error?: Error | HTTPError<TErrorData>) => boolean);
117
- /**
118
- * @description Expected response type, affects how response is parsed
119
- * @default "json"
120
- */
121
- responseType?: keyof ReturnType<typeof handleResponseType>;
122
- /**
123
- * @description Number of retry attempts for failed requests
124
- * @default 0
125
- */
126
- retries?: number;
127
- /**
128
- * @description Delay between retries in milliseconds
129
- * @default 500
130
- */
131
- retryDelay?: number;
132
- /**
133
- * @description HTTP status codes that trigger a retry
134
- * @default [409, 425, 429, 500, 502, 503, 504]
135
- */
136
- retryCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>;
137
- /**
138
- * HTTP methods that are allowed to retry
139
- * @default ["GET", "POST"]
69
+ * @description Default error message to use if none is provided from a response.
70
+ * @default "Failed to fetch data from server!"
140
71
  */
141
- retryMethods?: Array<"GET" | "POST" | AnyString>;
72
+ defaultErrorMessage?: string;
142
73
  /**
143
74
  * @description an optional field you can fill with additional information,
144
75
  * to associate with the request, typically used for logging or tracing.
@@ -162,53 +93,111 @@ interface ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extend
162
93
  * ```
163
94
  */
164
95
  meta?: Record<string, unknown>;
96
+ /**
97
+ * @description HTTP method for the request.
98
+ * @default "GET"
99
+ */
100
+ method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT" | AnyString;
101
+ /**
102
+ * @description Interceptor to be called when an error occurs during the fetch request OR when an error response is received from the api
103
+ * It is basically a combination of `onRequestError` and `onResponseError` interceptors
104
+ */
105
+ onError?: (anyErrorContext: ErrorContext<TErrorData>) => Promise<void> | void;
165
106
  /** @description Interceptor to be called just before the request is made, allowing for modifications or additional operations. */
166
107
  onRequest?: (requestContext: {
167
- request: $RequestOptions;
168
108
  options: ExtraOptions;
169
- }) => void | Promise<void>;
109
+ request: $RequestOptions;
110
+ }) => Promise<void> | void;
170
111
  /** @description Interceptor to be called when an error occurs during the fetch request. */
171
112
  onRequestError?: (requestErrorContext: {
172
113
  error: Error;
173
- request: $RequestOptions;
174
114
  options: ExtraOptions;
175
- }) => void | Promise<void>;
115
+ request: $RequestOptions;
116
+ }) => Promise<void> | void;
176
117
  /** @description Interceptor to be called when a successful response is received from the api. */
177
- onResponse?: (responseContext: ResponseContext<TData>) => void | Promise<void>;
118
+ onResponse?: (responseContext: ResponseContext<TData>) => Promise<void> | void;
178
119
  /** @description Interceptor to be called when an error response is received from the api. */
179
- onResponseError?: (responseErrorContext: ResponseErrorContext<TErrorData>) => void | Promise<void>;
120
+ onResponseError?: (responseErrorContext: ResponseErrorContext<TErrorData>) => Promise<void> | void;
180
121
  /**
181
- * @description Interceptor to be called when an error occurs during the fetch request OR when an error response is received from the api
182
- * It is basically a combination of `onRequestError` and `onResponseError` interceptors
122
+ * @description Query parameters to append to the URL.
123
+ */
124
+ query?: Record<string, boolean | number | string>;
125
+ /**
126
+ * @description Custom function to parse the response string into a object.
127
+ */
128
+ responseParser?: (responseString: string) => Record<string, unknown>;
129
+ /**
130
+ * @description Expected response type, affects how response is parsed
131
+ * @default "json"
132
+ */
133
+ responseType?: keyof ReturnType<typeof handleResponseType>;
134
+ /**
135
+ * @description Custom function to validate the response data.
136
+ */
137
+ responseValidator?: (data: unknown) => TData;
138
+ /**
139
+ * @description Mode of the result, can influence how results are handled or returned.
140
+ * Can be set to "all" | "onlySuccess" | "onlyError" | "onlyResponse".
141
+ * @default "all"
142
+ */
143
+ resultMode?: TResultMode;
144
+ /**
145
+ * @description Number of retry attempts for failed requests
146
+ * @default 0
147
+ */
148
+ retries?: number;
149
+ /**
150
+ * @description HTTP status codes that trigger a retry
151
+ * @default [409, 425, 429, 500, 502, 503, 504]
183
152
  */
184
- onError?: (anyErrorContext: ErrorContext<TErrorData>) => void | Promise<void>;
153
+ retryCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>;
154
+ /**
155
+ * @description Delay between retries in milliseconds
156
+ * @default 500
157
+ */
158
+ retryDelay?: number;
159
+ /**
160
+ * HTTP methods that are allowed to retry
161
+ * @default ["GET", "POST"]
162
+ */
163
+ retryMethods?: Array<"GET" | "POST" | AnyString>;
164
+ /**
165
+ * If true or the function returns true, throws errors instead of returning them
166
+ * The function is passed the error object and can be used to conditionally throw the error
167
+ * @default false
168
+ */
169
+ throwOnError?: ((error?: Error | HTTPError<TErrorData>) => boolean) | boolean;
170
+ /**
171
+ * @description Request timeout in milliseconds
172
+ */
173
+ timeout?: number;
185
174
  }
186
175
  type ResponseContext<TData> = Prettify<{
187
176
  data: TData;
188
- response: Response;
189
- request: $RequestOptions;
190
177
  options: ExtraOptions;
178
+ request: $RequestOptions;
179
+ response: Response;
191
180
  }>;
192
181
  type ResponseErrorContext<TErrorData> = Prettify<{
193
182
  errorData: TErrorData;
194
- response: Response;
195
- request: $RequestOptions;
196
183
  options: ExtraOptions;
184
+ request: $RequestOptions;
185
+ response: Response;
197
186
  }>;
198
187
  type ErrorContext<TErrorData> = Prettify<{
199
- errorData?: TErrorData;
200
- error: null;
201
- response: Response;
202
- request: $RequestOptions;
203
- options: ExtraOptions;
204
- } | {
205
188
  error: Error;
206
189
  errorData?: null;
207
- response: null;
190
+ options: ExtraOptions;
208
191
  request: $RequestOptions;
192
+ response: null;
193
+ } | {
194
+ error: null;
195
+ errorData?: TErrorData;
209
196
  options: ExtraOptions;
197
+ request: $RequestOptions;
198
+ response: Response;
210
199
  }>;
211
- interface FetchConfig<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = "all"> extends Omit<RequestInit, "method" | "body">, ExtraOptions<TData, TErrorData, TResultMode> {
200
+ interface FetchConfig<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = "all"> extends Omit<RequestInit, "body" | "method">, ExtraOptions<TData, TErrorData, TResultMode> {
212
201
  }
213
202
  type BaseConfig<TBaseData = unknown, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all"> = FetchConfig<TBaseData, TBaseErrorData, TBaseResultMode>;
214
203
  type ApiSuccessVariant<TData> = {
@@ -217,51 +206,48 @@ type ApiSuccessVariant<TData> = {
217
206
  response: Response;
218
207
  };
219
208
  type PossibleErrorNames = {
220
- _: "AbortError" | "TimeoutError" | "SyntaxError" | "TypeError" | "Error" | "UnknownError";
209
+ _: "AbortError" | "Error" | "SyntaxError" | "TimeoutError" | "TypeError" | "UnknownError";
221
210
  }["_"];
222
211
  type ApiErrorVariant<TErrorData> = {
223
212
  data: null;
224
213
  error: {
225
- name: "HTTPError";
226
- errorData: TErrorData;
214
+ errorData: Error;
227
215
  message: string;
216
+ name: PossibleErrorNames;
228
217
  };
229
- response: Response;
218
+ response: null;
230
219
  } | {
231
220
  data: null;
232
221
  error: {
233
- name: PossibleErrorNames;
234
- errorData: Error;
222
+ errorData: TErrorData;
235
223
  message: string;
224
+ name: "HTTPError";
236
225
  };
237
- response: null;
226
+ response: Response;
238
227
  };
239
228
  type ResultModeMap<TData = unknown, TErrorData = unknown> = {
240
- all: ApiSuccessVariant<TData> | ApiErrorVariant<TErrorData>;
241
- onlySuccess: ApiSuccessVariant<TData>["data"];
229
+ all: ApiErrorVariant<TErrorData> | ApiSuccessVariant<TData>;
242
230
  onlyError: ApiErrorVariant<TErrorData>["error"];
243
231
  onlyResponse: Response;
232
+ onlySuccess: ApiSuccessVariant<TData>["data"];
244
233
  };
245
234
  type ResultModeUnion = {
246
235
  _: {
247
236
  [Key in keyof ResultModeMap]: Key;
248
- }[keyof ResultModeMap];
237
+ }[keyof ResultModeMap] | undefined;
249
238
  }["_"];
250
- type GetCallApiResult<TData, TErrorData, TResultMode extends ResultModeUnion> = ResultModeMap<TData, TErrorData>[TResultMode];
239
+ type GetCallApiResult<TData, TErrorData, TResultMode> = TResultMode extends NonNullable<ResultModeUnion> ? ResultModeMap<TData, TErrorData>[TResultMode] : ResultModeMap<TData, TErrorData>["all"];
251
240
 
252
- declare const createFetchClient: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all">(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
241
+ declare const createFetchClient: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = undefined>(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
253
242
  <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeUnion = TBaseResultMode>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode>): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
254
243
  create: any;
255
- cancel(url: string, reason?: unknown): void;
256
244
  };
257
245
  declare const callApi: {
258
- <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = "all">(url: string, config?: FetchConfig<TData, TErrorData, TResultMode> | undefined): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
259
- create: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all">(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
246
+ <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = undefined>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode> | undefined): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
247
+ create: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = undefined>(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
260
248
  <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeUnion = TBaseResultMode>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode>): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
261
249
  create: any;
262
- cancel(url: string, reason?: unknown): void;
263
250
  };
264
- cancel(url: string, reason?: unknown): void;
265
251
  };
266
252
 
267
- export { type $RequestOptions, type ErrorContext, type ExtraOptions, type FetchConfig, HTTPError, type ResponseContext, type ResponseErrorContext, callApi, createFetchClient, isHTTPError, isHTTPErrorInstance, toQueryString };
253
+ export { type $RequestOptions, type ErrorContext, type ExtraOptions, type FetchConfig, type ResponseContext, type ResponseErrorContext, callApi, createFetchClient };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/typeof.ts"],"names":[],"mappings":";AAEO,IAAM,UAAU,CAAS,UAAsC,MAAM,QAAQ,KAAK;AAElF,IAAM,WAAW,CAA0C,UAAqC;AACtG,SACC,OAAO,UAAU,YAAY,UAAU,QAAQ,EAAE,iBAAiB,aAAa,CAAC,MAAM,QAAQ,KAAK;AAErG;AAEO,IAAM,aAAa,CAAgC,UACzD,OAAO,UAAU;AAEX,IAAM,WAAW,CAAC,UAAmB,OAAO,UAAU;AAEtD,IAAM,gBAAgB,CAAC,UAC7B,OAAO,UAAU,YAAY,MAAM,SAAS,GAAG","sourcesContent":["import type { AnyFunction } from \"./type-helpers\";\n\nexport const isArray = <TArray>(value: unknown): value is TArray[] => Array.isArray(value);\n\nexport const isObject = <TObject extends Record<string, unknown>>(value: unknown): value is TObject => {\n\treturn (\n\t\ttypeof value === \"object\" && value !== null && !(value instanceof FormData) && !Array.isArray(value)\n\t);\n};\n\nexport const isFunction = <TFunction extends AnyFunction>(value: unknown): value is TFunction =>\n\ttypeof value === \"function\";\n\nexport const isString = (value: unknown) => typeof value === \"string\";\n\nexport const isQueryString = (value: unknown): value is string =>\n\ttypeof value === \"string\" && value.includes(\"=\");\n"]}
1
+ {"version":3,"sources":["../../src/typeof.ts"],"names":[],"mappings":";AAEO,IAAM,OAAU,GAAA,CAAS,KAAsC,KAAA,KAAA,CAAM,QAAQ,KAAK,EAAA;AAE5E,IAAA,QAAA,GAAW,CAA0C,KAAqC,KAAA;AACtG,EACC,OAAA,OAAO,KAAU,KAAA,QAAA,IAAY,KAAU,KAAA,IAAA,IAAQ,EAAE,KAAA,YAAiB,QAAa,CAAA,IAAA,CAAC,KAAM,CAAA,OAAA,CAAQ,KAAK,CAAA,CAAA;AAErG,EAAA;AAEO,IAAM,UAAa,GAAA,CAAgC,KACzD,KAAA,OAAO,KAAU,KAAA,WAAA;AAEX,IAAM,QAAW,GAAA,CAAC,KAAmB,KAAA,OAAO,KAAU,KAAA,SAAA;AAEhD,IAAA,aAAA,GAAgB,CAAC,KAC7B,KAAA,OAAO,UAAU,QAAY,IAAA,KAAA,CAAM,SAAS,GAAG","file":"chunk-AKFUJ4JG.js","sourcesContent":["import type { AnyFunction } from \"./type-helpers\";\n\nexport const isArray = <TArray>(value: unknown): value is TArray[] => Array.isArray(value);\n\nexport const isObject = <TObject extends Record<string, unknown>>(value: unknown): value is TObject => {\n\treturn (\n\t\ttypeof value === \"object\" && value !== null && !(value instanceof FormData) && !Array.isArray(value)\n\t);\n};\n\nexport const isFunction = <TFunction extends AnyFunction>(value: unknown): value is TFunction =>\n\ttypeof value === \"function\";\n\nexport const isString = (value: unknown) => typeof value === \"string\";\n\nexport const isQueryString = (value: unknown): value is string =>\n\ttypeof value === \"string\" && value.includes(\"=\");\n"]}
@@ -0,0 +1 @@
1
+ import{isObject as r,isArray as e,isFunction as o}from"./chunk-AKFUJ4JG.js";var t=(r,e)=>`${r} | ${JSON.stringify(e??{})}`,s=r=>r?new URLSearchParams(r).toString():(console.error("toQueryString:","No query params provided!"),null),n=(r,e)=>{if(!e)return r;const o=s(e);return r.endsWith("?")?`${r}${o}`:r.includes("?")?`${r}&${o}`:`${r}?${o}`},a=o=>!o||r(o)?o:Object.fromEntries(e(o)?o:o.entries()),i=Object.keys({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"}).map(Number),l=["GET"],c=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],u=(r,e)=>{const o=Object.entries(r).filter((([r])=>!e.includes(r)));return Object.fromEntries(o)},m=(r,e)=>{const o=new Set(e),t=Object.entries(r).filter((([r])=>o.has(r)));return Object.fromEntries(t)},d=r=>[m(r,c),u(r,c)],f=(r,e)=>({arrayBuffer:()=>r.arrayBuffer(),blob:()=>r.blob(),formData:()=>r.formData(),json:async()=>e?e(await r.text()):r.json(),text:()=>r.text()}),p=(r,e,o)=>{const t=f(r,o);if(!Object.hasOwn(t,e))throw new Error(`Invalid response type: ${e}`);return t[e]()},E=r=>{const{options:e,response:o,successData:t}=r,s={data:t,error:null,response:o};return e.resultMode&&"all"!==e.resultMode?{onlyError:s.error,onlyResponse:s.response,onlySuccess:s.data}[e.resultMode]:s},y=r=>{const{error:e,options:t}=r;return(r={})=>{const{errorData:s,message:n,response:a}=r;if(o(t.throwOnError)?t.throwOnError(e):t.throwOnError)throw e;return{data:null,error:{errorData:s??e,message:n??e?.message??t.defaultErrorMessage,name:e?.name??"UnknownError"},response:a??null}}},h=e=>r(e)&&"HTTPError"===e.name,w=class extends Error{errorData;isHTTPError=!0;name="HTTPError";response;constructor(r,e){const{defaultErrorMessage:o,errorData:t,response:s}=r;super(t.message??o,e),this.errorData=t,this.response=s}},T=e=>e instanceof w||r(e)&&"HTTPError"===e.name&&!0===e.isHTTPError,b=r=>{if(0===r)return;const{promise:e,resolve:o}=Promise.withResolvers();return setTimeout(o,r),e};export{w as HTTPError,i as defaultRetryCodes,l as defaultRetryMethods,c as fetchSpecificKeys,t as getRequestKey,y as getResolveErrorResultFn,p as getResponseData,f as handleResponseType,h as isHTTPError,T as isHTTPErrorInstance,n as mergeUrlWithParams,a as objectifyHeaders,u as omitKeys,E as resolveSuccessResult,d as splitConfig,s as toQueryString,b as waitUntil};//# sourceMappingURL=chunk-F6RUPSGH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils.ts"],"names":[],"mappings":"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","file":"chunk-F6RUPSGH.js","sourcesContent":["import { isArray, isFunction, isObject } from \"./typeof\";\nimport type {\n\t$BaseRequestOptions,\n\t$RequestOptions,\n\tApiErrorVariant,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tPossibleErrorObject,\n} from \"./types\";\n\n// prettier-ignore\nexport const getRequestKey = <TConfig extends Record<string, unknown>>(url: string, config?: TConfig) => `${url} | ${JSON.stringify(config ?? {})}`;\n\ntype ToQueryStringFn = {\n\t(params: ExtraOptions[\"query\"]): null | string;\n\t(params: Required<ExtraOptions>[\"query\"]): string;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"toQueryString:\", \"No query params provided!\");\n\n\t\treturn null as never;\n\t}\n\n\treturn new URLSearchParams(params as Record<string, string>).toString();\n};\n\nexport const mergeUrlWithParams = (url: string, params: ExtraOptions[\"query\"]): string => {\n\tif (!params) {\n\t\treturn url;\n\t}\n\n\tconst paramsString = toQueryString(params);\n\n\tif (url.endsWith(\"?\")) {\n\t\treturn `${url}${paramsString}`;\n\t}\n\n\tif (url.includes(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\treturn `${url}?${paramsString}`;\n};\n\nexport const objectifyHeaders = (headers: RequestInit[\"headers\"]): Record<string, string> | undefined => {\n\tif (!headers || isObject(headers)) {\n\t\treturn headers;\n\t}\n\n\treturn Object.fromEntries(isArray(headers) ? headers : headers.entries());\n};\n\nconst retryCodesLookup = {\n\t408: \"Request Timeout\",\n\t409: \"Conflict\",\n\t425: \"Too Early\",\n\t429: \"Too Many Requests\",\n\t500: \"Internal Server Error\",\n\t502: \"Bad Gateway\",\n\t503: \"Service Unavailable\",\n\t504: \"Gateway Timeout\",\n};\n\nexport const defaultRetryCodes: Required<BaseConfig>[\"retryCodes\"] =\n\tObject.keys(retryCodesLookup).map(Number);\n\nexport const defaultRetryMethods: Required<BaseConfig>[\"retryMethods\"] = [\"GET\"];\n\nexport const fetchSpecificKeys = [\n\t\"body\",\n\t\"integrity\",\n\t\"method\",\n\t\"headers\",\n\t\"signal\",\n\t\"cache\",\n\t\"redirect\",\n\t\"window\",\n\t\"credentials\",\n\t\"keepalive\",\n\t\"referrer\",\n\t\"priority\",\n\t\"mode\",\n\t\"referrerPolicy\",\n] satisfies Array<keyof FetchConfig>;\n\nexport const omitKeys = <\n\tTObject extends Record<string, unknown>,\n\tconst TOmitArray extends Array<keyof TObject>,\n>(\n\tinitialObject: TObject,\n\tkeysToOmit: TOmitArray\n) => {\n\tconst arrayFromFilteredObject = Object.entries(initialObject).filter(\n\t\t([key]) => !keysToOmit.includes(key)\n\t);\n\n\tconst updatedObject = Object.fromEntries(arrayFromFilteredObject);\n\n\treturn updatedObject as Omit<TObject, keyof TOmitArray>;\n};\n\nconst pickKeys = <TObject extends Record<string, unknown>, const TPickArray extends Array<keyof TObject>>(\n\tinitialObject: TObject,\n\tkeysToPick: TPickArray\n) => {\n\tconst keysToPickSet = new Set(keysToPick);\n\n\tconst arrayFromInitObject = Object.entries(initialObject);\n\n\tconst filteredArray = arrayFromInitObject.filter(([objectKey]) => keysToPickSet.has(objectKey));\n\n\tconst updatedObject = Object.fromEntries(filteredArray);\n\n\treturn updatedObject as Pick<TObject, TPickArray[number]>;\n};\n\nexport const splitConfig = <TObject extends object>(\n\tconfig: TObject\n): [\"body\" extends keyof TObject ? $RequestOptions : $BaseRequestOptions, ExtraOptions] => [\n\tpickKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n\tomitKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n];\n\nexport const handleResponseType = <TResponse>(\n\tresponse: Response,\n\tparser?: Required<ExtraOptions>[\"responseParser\"]\n) => ({\n\tarrayBuffer: () => response.arrayBuffer() as Promise<TResponse>,\n\tblob: () => response.blob() as Promise<TResponse>,\n\tformData: () => response.formData() as Promise<TResponse>,\n\tjson: async () => {\n\t\tif (parser) {\n\t\t\treturn parser(await response.text());\n\t\t}\n\n\t\treturn response.json() as Promise<TResponse>;\n\t},\n\ttext: () => response.text() as Promise<TResponse>,\n});\n\nexport const getResponseData = <TResponse>(\n\tresponse: Response,\n\tresponseType: keyof ReturnType<typeof handleResponseType>,\n\tparser: ExtraOptions[\"responseParser\"]\n) => {\n\tconst RESPONSE_TYPE_LOOKUP = handleResponseType<TResponse>(response, parser);\n\n\tif (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, responseType)) {\n\t\tthrow new Error(`Invalid response type: ${responseType}`);\n\t}\n\n\treturn RESPONSE_TYPE_LOOKUP[responseType]();\n};\n\ntype data = {\n\toptions: ExtraOptions;\n\tresponse: Response;\n\tsuccessData: unknown;\n};\n\n// == The CallApiResult type is used to cast all return statements due to a design limitation in ts.\n// LINK - See https://www.zhenghao.io/posts/type-functions for more info\nexport const resolveSuccessResult = <CallApiResult>(info: data): CallApiResult => {\n\tconst { options, response, successData } = info;\n\n\tconst apiDetails = {\n\t\tdata: successData,\n\t\terror: null,\n\t\tresponse,\n\t};\n\n\tif (!options.resultMode || options.resultMode === \"all\") {\n\t\treturn apiDetails as CallApiResult;\n\t}\n\n\treturn {\n\t\tonlyError: apiDetails.error,\n\t\tonlyResponse: apiDetails.response,\n\t\tonlySuccess: apiDetails.data,\n\t}[options.resultMode] as CallApiResult;\n};\n\n// == Using curring here so error and options are not required to be passed every time, instead to be captured once by way of closure\nexport const getResolveErrorResultFn = <CallApiResult>($info: {\n\terror?: unknown;\n\toptions: ExtraOptions;\n}) => {\n\tconst { error, options } = $info;\n\n\ttype ErrorInfo = {\n\t\terrorData?: unknown;\n\t\tmessage?: string;\n\t\tresponse?: Response;\n\t};\n\n\tconst resolveErrorResult = (info: ErrorInfo = {}): CallApiResult => {\n\t\tconst { errorData, message, response } = info;\n\n\t\tconst shouldThrowOnError = isFunction(options.throwOnError)\n\t\t\t? options.throwOnError(error as Error)\n\t\t\t: options.throwOnError;\n\n\t\tif (shouldThrowOnError) {\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn {\n\t\t\tdata: null,\n\t\t\terror: {\n\t\t\t\terrorData: errorData ?? error,\n\t\t\t\tmessage: message ?? (error as PossibleErrorObject)?.message ?? options.defaultErrorMessage,\n\t\t\t\tname: (error as PossibleErrorObject)?.name ?? \"UnknownError\",\n\t\t\t},\n\t\t\tresponse: response ?? null,\n\t\t} as CallApiResult;\n\t};\n\n\treturn resolveErrorResult;\n};\n\nexport const isHTTPError = <TErrorData>(error: ApiErrorVariant<TErrorData>[\"error\"] | null) => {\n\treturn isObject(error) && error.name === \"HTTPError\";\n};\n\ntype ErrorDetails<TErrorResponse> = {\n\tdefaultErrorMessage: string;\n\terrorData: TErrorResponse;\n\tresponse: Response;\n};\n\ntype ErrorOptions = {\n\tcause?: unknown;\n};\n\nexport class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {\n\terrorData: ErrorDetails<TErrorResponse>[\"errorData\"];\n\tisHTTPError = true;\n\n\toverride name = \"HTTPError\" as const;\n\n\tresponse: ErrorDetails<TErrorResponse>[\"response\"];\n\n\tconstructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions) {\n\t\tconst { defaultErrorMessage, errorData, response } = errorDetails;\n\n\t\tsuper((errorData as { message?: string }).message ?? defaultErrorMessage, errorOptions);\n\n\t\tthis.errorData = errorData;\n\t\tthis.response = response;\n\t}\n}\n\n// prettier-ignore\nexport const isHTTPErrorInstance = <TErrorResponse>(\n\terror: unknown\n): error is HTTPError<TErrorResponse> => {\n\treturn (\n\t\terror instanceof HTTPError || (isObject(error) && error.name === \"HTTPError\" && error.isHTTPError === true)\n\t);\n};\n\nexport const waitUntil = (delay: number) => {\n\tif (delay === 0) return;\n\n\tconst { promise, resolve } = Promise.withResolvers();\n\n\tsetTimeout(resolve, delay);\n\n\treturn promise;\n};\n"]}
@@ -0,0 +1 @@
1
+ import{splitConfig as e,defaultRetryCodes as r,defaultRetryMethods as o,objectifyHeaders as t,getRequestKey as s,omitKeys as n,mergeUrlWithParams as a,waitUntil as i,getResponseData as u,HTTPError as l,resolveSuccessResult as c,getResolveErrorResultFn as p,isHTTPErrorInstance as d}from"./chunk-F6RUPSGH.js";import{isObject as m,isQueryString as h,isString as y}from"./chunk-AKFUJ4JG.js";var f=R=>{const w=new Map,[b,E]=e(R??{}),{body:g,headers:q,signal:D,...A}=b,$=async(f,R)=>{const[b,M]=e(R??{}),{body:S=g,headers:T,signal:k=D,...j}=b,x={baseURL:"",bodySerializer:JSON.stringify,cancelRedundantRequests:!0,defaultErrorMessage:"Failed to fetch data from server!",responseType:"json",retries:0,retryCodes:r,retryDelay:0,retryMethods:o,...E,...M},C={body:m(S)?x.bodySerializer(S):S,headers:q||T||x.auth||m(S)?{...m(S)&&{Accept:"application/json","Content-Type":"application/json"},...h(S)&&{"Content-Type":"application/x-www-form-urlencoded"},...y(x.auth)&&{Authorization:`Bearer ${x.auth}`},...m(x.auth)&&{Authorization:"bearer"in x.auth?`Bearer ${x.auth.bearer}`:`Token ${x.auth.token}`},...t(q),...t(T)}:void 0,method:"GET",...A,...j},P=s(f,n({...C,...x},["onRequest","onResponse","onResponseError","onError","onRequestError"])),v=w.get(P);if(v&&x.cancelRedundantRequests){const e=new DOMException(`Automatic cancelation of the previous unfinished request to the same url, with the same fetch options: ${f}`,"AbortError");v.abort(e)}const z=new AbortController;w.set(P,z);const O=x.timeout?AbortSignal.timeout(x.timeout):null,U=AbortSignal.any([z.signal,...O?[O]:[],...k?[k]:[]]),F={signal:U,...C};try{await(x.onRequest?.({options:x,request:F}));const e=await fetch(`${x.baseURL}${a(f,x.query)}`,F);if(!e.ok&&!U.aborted&&x.retries>0&&x.retryCodes.includes(e.status)&&x.retryMethods.includes(F.method))return await i(x.retryDelay),await $(f,{...R,retries:x.retries-1});if(!e.ok){const r=await u(x.cloneResponse?e.clone():e,x.responseType,x.responseParser);throw new l({defaultErrorMessage:x.defaultErrorMessage,errorData:r,response:e})}const r=await u(x.cloneResponse?e.clone():e,x.responseType,x.responseParser),o=x.responseValidator?x.responseValidator(r):r;return await(x.onResponse?.({data:o,options:x,request:F,response:x.cloneResponse?e.clone():e})),c({options:x,response:e,successData:o})}catch(e){const r=p({error:e,options:x});if(e instanceof DOMException&&"TimeoutError"===e.name){const o=`Request timed out after ${x.timeout}ms`;return console.error(`${e.name}:`,o),r({message:o})}if(e instanceof DOMException&&"AbortError"===e.name){const o=`Request aborted due to ${e.message}`;return console.error(`${e.name}:`,o),r({message:o})}if(d(e)){const{errorData:o,response:t}=e;return await Promise.allSettled([x.onResponseError?.({errorData:o,options:x,request:F,response:x.cloneResponse?t.clone():t}),x.onError?.({error:null,errorData:o,options:x,request:F,response:t})]),r({errorData:o,message:o?.message,response:t})}return await Promise.allSettled([x.onRequestError?.({error:e,options:x,request:F}),x.onError?.({error:e,errorData:null,options:x,request:F,response:null})]),r()}finally{w.delete(P)}};return $.create=f,$},R=f();export{R as callApi,f as createFetchClient};//# sourceMappingURL=chunk-KQNDKJNJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/createFetchClient.ts"],"names":["callApi"],"mappings":";;;;AA0Ba,IAAA,iBAAA,GAAoB,CAKhC,UACI,KAAA;AACJ,EAAM,MAAA,oBAAA,uBAA2B,GAA6B,EAAA,CAAA;AAE9D,EAAA,MAAM,CAAC,eAAiB,EAAA,gBAAgB,IAAI,WAAY,CAAA,UAAA,IAAc,EAAE,CAAA,CAAA;AAExE,EAAM,MAAA;AAAA,IACL,IAAM,EAAA,QAAA;AAAA,IACN,OAAS,EAAA,WAAA;AAAA,IACT,MAAQ,EAAA,UAAA;AAAA,IACR,GAAG,qBAAA;AAAA,GACA,GAAA,eAAA,CAAA;AAGJ,EAAMA,MAAAA,QAAAA,GAAU,OAKf,GAAA,EACA,MAC+D,KAAA;AAG/D,IAAA,MAAM,CAAC,WAAa,EAAA,YAAY,IAAI,WAAY,CAAA,MAAA,IAAU,EAAE,CAAA,CAAA;AAE5D,IAAM,MAAA,EAAE,OAAO,QAAU,EAAA,OAAA,EAAS,SAAS,UAAY,EAAA,GAAG,mBAAsB,GAAA,WAAA,CAAA;AAGhF,IAAA,MAAM,OAAU,GAAA;AAAA,MACf,OAAS,EAAA,EAAA;AAAA,MACT,gBAAgB,IAAK,CAAA,SAAA;AAAA,MACrB,uBAAyB,EAAA,IAAA;AAAA,MACzB,mBAAqB,EAAA,mCAAA;AAAA,MACrB,YAAc,EAAA,MAAA;AAAA,MACd,OAAS,EAAA,CAAA;AAAA,MACT,UAAY,EAAA,iBAAA;AAAA,MACZ,UAAY,EAAA,CAAA;AAAA,MACZ,YAAc,EAAA,mBAAA;AAAA,MACd,GAAG,gBAAA;AAAA,MACH,GAAG,YAAA;AAAA,KACJ,CAAA;AAGA,IAAA,MAAM,mBAAsB,GAAA;AAAA,MAC3B,MAAM,QAAS,CAAA,IAAI,IAAI,OAAQ,CAAA,cAAA,CAAe,IAAI,CAAI,GAAA,IAAA;AAAA;AAAA,MAGtD,SACC,WAAe,IAAA,OAAA,IAAW,QAAQ,IAAQ,IAAA,QAAA,CAAS,IAAI,CACpD,GAAA;AAAA,QACA,GAAI,QAAS,CAAA,IAAI,CAAK,IAAA;AAAA,UACrB,MAAQ,EAAA,kBAAA;AAAA,UACR,cAAgB,EAAA,kBAAA;AAAA,SACjB;AAAA,QACA,GAAI,aAAc,CAAA,IAAI,CAAK,IAAA;AAAA,UAC1B,cAAgB,EAAA,mCAAA;AAAA,SACjB;AAAA,QACA,GAAI,QAAA,CAAS,OAAQ,CAAA,IAAI,CAAK,IAAA;AAAA,UAC7B,aAAA,EAAe,CAAU,OAAA,EAAA,OAAA,CAAQ,IAAI,CAAA,CAAA;AAAA,SACtC;AAAA,QACA,GAAI,QAAA,CAAS,OAAQ,CAAA,IAAI,CAAK,IAAA;AAAA,UAC7B,aACC,EAAA,QAAA,IAAY,OAAQ,CAAA,IAAA,GACjB,CAAU,OAAA,EAAA,OAAA,CAAQ,IAAK,CAAA,MAAM,CAC7B,CAAA,GAAA,CAAA,MAAA,EAAS,OAAQ,CAAA,IAAA,CAAK,KAAK,CAAA,CAAA;AAAA,SAChC;AAAA,QACA,GAAG,iBAAiB,WAAW,CAAA;AAAA,QAC/B,GAAG,iBAAiB,OAAO,CAAA;AAAA,OAE3B,GAAA,KAAA,CAAA;AAAA;AAAA;AAAA;AAAA,MAKJ,MAAQ,EAAA,KAAA;AAAA,MAER,GAAG,qBAAA;AAAA,MACH,GAAG,iBAAA;AAAA,KACJ,CAAA;AAEA,IAAA,MAAM,UAAa,GAAA,aAAA;AAAA,MAClB,GAAA;AAAA,MACA,SAAS,EAAE,GAAG,mBAAqB,EAAA,GAAG,SAAW,EAAA;AAAA,QAChD,WAAA;AAAA,QACA,YAAA;AAAA,QACA,iBAAA;AAAA,QACA,SAAA;AAAA,QACA,gBAAA;AAAA,OACA,CAAA;AAAA,KACF,CAAA;AAEA,IAAM,MAAA,mBAAA,GAAsB,oBAAqB,CAAA,GAAA,CAAI,UAAU,CAAA,CAAA;AAE/D,IAAI,IAAA,mBAAA,IAAuB,QAAQ,uBAAyB,EAAA;AAC3D,MAAA,MAAM,SAAS,IAAI,YAAA;AAAA,QAClB,0GAA0G,GAAG,CAAA,CAAA;AAAA,QAC7G,YAAA;AAAA,OACD,CAAA;AAEA,MAAA,mBAAA,CAAoB,MAAM,MAAM,CAAA,CAAA;AAAA,KACjC;AAEA,IAAM,MAAA,kBAAA,GAAqB,IAAI,eAAgB,EAAA,CAAA;AAE/C,IAAqB,oBAAA,CAAA,GAAA,CAAI,YAAY,kBAAkB,CAAA,CAAA;AAEvD,IAAA,MAAM,gBAAgB,OAAQ,CAAA,OAAA,GAAU,YAAY,OAAQ,CAAA,OAAA,CAAQ,OAAO,CAAI,GAAA,IAAA,CAAA;AAE/E,IAAM,MAAA,cAAA,GAAiB,YAAY,GAAI,CAAA;AAAA,MACtC,kBAAmB,CAAA,MAAA;AAAA,MACnB,GAAI,aAAA,GAAgB,CAAC,aAAa,IAAI,EAAC;AAAA,MACvC,GAAI,MAAA,GAAS,CAAC,MAAM,IAAI,EAAC;AAAA,KACzB,CAAA,CAAA;AAED,IAAA,MAAM,WAAc,GAAA;AAAA,MACnB,MAAQ,EAAA,cAAA;AAAA,MACR,GAAG,mBAAA;AAAA,KACJ,CAAA;AAEA,IAAI,IAAA;AACH,MAAA,MAAM,QAAQ,SAAY,GAAA,EAAE,OAAS,EAAA,OAAA,EAAS,aAAa,CAAA,CAAA;AAE3D,MAAA,MAAM,WAAW,MAAM,KAAA;AAAA,QACtB,CAAA,EAAG,QAAQ,OAAO,CAAA,EAAG,mBAAmB,GAAK,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA,CAAA;AAAA,QAC3D,WAAA;AAAA,OACD,CAAA;AAEA,MAAM,MAAA,WAAA,GACL,CAAC,QAAS,CAAA,EAAA,IACV,CAAC,cAAe,CAAA,OAAA,IAChB,QAAQ,OAAU,GAAA,CAAA,IAClB,QAAQ,UAAW,CAAA,QAAA,CAAS,SAAS,MAAM,CAAA,IAC3C,QAAQ,YAAa,CAAA,QAAA,CAAS,YAAY,MAAM,CAAA,CAAA;AAEjD,MAAA,IAAI,WAAa,EAAA;AAChB,QAAM,MAAA,SAAA,CAAU,QAAQ,UAAU,CAAA,CAAA;AAElC,QAAO,OAAA,MAAMA,QAAQ,CAAA,GAAA,EAAK,EAAE,GAAG,QAAQ,OAAS,EAAA,OAAA,CAAQ,OAAU,GAAA,CAAA,EAAG,CAAA,CAAA;AAAA,OACtE;AAEA,MAAI,IAAA,CAAC,SAAS,EAAI,EAAA;AACjB,QAAA,MAAM,YAAY,MAAM,eAAA;AAAA,UACvB,OAAQ,CAAA,aAAA,GAAgB,QAAS,CAAA,KAAA,EAAU,GAAA,QAAA;AAAA,UAC3C,OAAQ,CAAA,YAAA;AAAA,UACR,OAAQ,CAAA,cAAA;AAAA,SACT,CAAA;AAGA,QAAA,MAAM,IAAI,SAAU,CAAA;AAAA,UACnB,qBAAqB,OAAQ,CAAA,mBAAA;AAAA,UAC7B,SAAA;AAAA,UACA,QAAA;AAAA,SACA,CAAA,CAAA;AAAA,OACF;AAEA,MAAA,MAAM,cAAc,MAAM,eAAA;AAAA,QACzB,OAAQ,CAAA,aAAA,GAAgB,QAAS,CAAA,KAAA,EAAU,GAAA,QAAA;AAAA,QAC3C,OAAQ,CAAA,YAAA;AAAA,QACR,OAAQ,CAAA,cAAA;AAAA,OACT,CAAA;AAEA,MAAA,MAAM,mBAAmB,OAAQ,CAAA,iBAAA,GAC9B,OAAQ,CAAA,iBAAA,CAAkB,WAAW,CACrC,GAAA,WAAA,CAAA;AAEH,MAAA,MAAM,QAAQ,UAAa,GAAA;AAAA,QAC1B,IAAM,EAAA,gBAAA;AAAA,QACN,OAAA;AAAA,QACA,OAAS,EAAA,WAAA;AAAA,QACT,QAAU,EAAA,OAAA,CAAQ,aAAgB,GAAA,QAAA,CAAS,OAAU,GAAA,QAAA;AAAA,OACrD,CAAA,CAAA;AAED,MAAA,OAAO,qBAAoC,EAAE,OAAA,EAAS,QAAU,EAAA,WAAA,EAAa,kBAAkB,CAAA,CAAA;AAAA,aAGvF,KAAO,EAAA;AACf,MAAA,MAAM,kBAAqB,GAAA,uBAAA,CAAuC,EAAE,KAAA,EAAO,SAAS,CAAA,CAAA;AAEpF,MAAA,IAAI,KAAiB,YAAA,YAAA,IAAgB,KAAM,CAAA,IAAA,KAAS,cAAgB,EAAA;AACnE,QAAM,MAAA,OAAA,GAAU,CAA2B,wBAAA,EAAA,OAAA,CAAQ,OAAO,CAAA,EAAA,CAAA,CAAA;AAE1D,QAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,EAAG,KAAM,CAAA,IAAI,KAAK,OAAO,CAAA,CAAA;AAEvC,QAAO,OAAA,kBAAA,CAAmB,EAAE,OAAA,EAAS,CAAA,CAAA;AAAA,OACtC;AAEA,MAAA,IAAI,KAAiB,YAAA,YAAA,IAAgB,KAAM,CAAA,IAAA,KAAS,YAAc,EAAA;AACjE,QAAM,MAAA,OAAA,GAAU,CAA0B,uBAAA,EAAA,KAAA,CAAM,OAAO,CAAA,CAAA,CAAA;AAEvD,QAAA,OAAA,CAAQ,KAAM,CAAA,CAAA,EAAG,KAAM,CAAA,IAAI,KAAK,OAAO,CAAA,CAAA;AAEvC,QAAO,OAAA,kBAAA,CAAmB,EAAE,OAAA,EAAS,CAAA,CAAA;AAAA,OACtC;AAEA,MAAI,IAAA,mBAAA,CAAgC,KAAK,CAAG,EAAA;AAC3C,QAAM,MAAA,EAAE,SAAW,EAAA,QAAA,EAAa,GAAA,KAAA,CAAA;AAEhC,QAAM,KAAA,MAAM,QAAQ,UAAW,CAAA;AAAA,UAC9B,QAAQ,eAAkB,GAAA;AAAA,YACzB,SAAA;AAAA,YACA,OAAA;AAAA,YACA,OAAS,EAAA,WAAA;AAAA,YACT,QAAU,EAAA,OAAA,CAAQ,aAAgB,GAAA,QAAA,CAAS,OAAU,GAAA,QAAA;AAAA,WACrD,CAAA;AAAA;AAAA,UAGD,QAAQ,OAAU,GAAA;AAAA,YACjB,KAAO,EAAA,IAAA;AAAA,YACP,SAAA;AAAA,YACA,OAAA;AAAA,YACA,OAAS,EAAA,WAAA;AAAA,YACT,QAAA;AAAA,WACA,CAAA;AAAA,SACD,CAAA,CAAA;AAED,QAAA,OAAO,kBAAmB,CAAA;AAAA,UACzB,SAAA;AAAA,UACA,SAAU,SAAmC,EAAA,OAAA;AAAA,UAC7C,QAAA;AAAA,SACA,CAAA,CAAA;AAAA,OACF;AAEA,MAAM,KAAA,MAAM,QAAQ,UAAW,CAAA;AAAA;AAAA,QAE9B,QAAQ,cAAiB,GAAA,EAAE,OAAuB,OAAS,EAAA,OAAA,EAAS,aAAa,CAAA;AAAA;AAAA,QAGjF,QAAQ,OAAU,GAAA;AAAA,UACjB,KAAA;AAAA,UACA,SAAW,EAAA,IAAA;AAAA,UACX,OAAA;AAAA,UACA,OAAS,EAAA,WAAA;AAAA,UACT,QAAU,EAAA,IAAA;AAAA,SACV,CAAA;AAAA,OACD,CAAA,CAAA;AAED,MAAA,OAAO,kBAAmB,EAAA,CAAA;AAAA,KAGzB,SAAA;AACD,MAAA,oBAAA,CAAqB,OAAO,UAAU,CAAA,CAAA;AAAA,KACvC;AAAA,GACD,CAAA;AAEA,EAAAA,SAAQ,MAAS,GAAA,iBAAA,CAAA;AAEjB,EAAOA,OAAAA,QAAAA,CAAAA;AACR,EAAA;AAEO,IAAM,UAAU,iBAAkB","file":"chunk-KQNDKJNJ.js","sourcesContent":["import { isObject, isQueryString, isString } from \"./typeof\";\nimport type {\n\t$RequestOptions,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tGetCallApiResult,\n\tPossibleErrorObject,\n\tResultModeUnion,\n} from \"./types\";\nimport {\n\tHTTPError,\n\tdefaultRetryCodes,\n\tdefaultRetryMethods,\n\tgetRequestKey,\n\tgetResolveErrorResultFn,\n\tgetResponseData,\n\tisHTTPErrorInstance,\n\tmergeUrlWithParams,\n\tobjectifyHeaders,\n\tomitKeys,\n\tresolveSuccessResult,\n\tsplitConfig,\n\twaitUntil,\n} from \"./utils\";\n\nexport const createFetchClient = <\n\tTBaseData,\n\tTBaseErrorData = unknown,\n\tTBaseResultMode extends ResultModeUnion = undefined,\n>(\n\tbaseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>\n) => {\n\tconst abortControllerStore = new Map<string, AbortController>();\n\n\tconst [baseFetchConfig, baseExtraOptions] = splitConfig(baseConfig ?? {});\n\n\tconst {\n\t\tbody: baseBody,\n\t\theaders: baseHeaders,\n\t\tsignal: baseSignal,\n\t\t...restOfBaseFetchConfig\n\t} = baseFetchConfig;\n\n\t/* eslint-disable complexity */\n\tconst callApi = async <\n\t\tTData = TBaseData,\n\t\tTErrorData = TBaseErrorData,\n\t\tTResultMode extends ResultModeUnion = TBaseResultMode,\n\t>(\n\t\turl: string,\n\t\tconfig?: FetchConfig<TData, TErrorData, TResultMode>\n\t): Promise<GetCallApiResult<TData, TErrorData, TResultMode>> => {\n\t\ttype CallApiResult = GetCallApiResult<TData, TErrorData, TResultMode>;\n\n\t\tconst [fetchConfig, extraOptions] = splitConfig(config ?? {});\n\n\t\tconst { body = baseBody, headers, signal = baseSignal, ...restOfFetchConfig } = fetchConfig;\n\n\t\t// == Default Extra Options\n\t\tconst options = {\n\t\t\tbaseURL: \"\",\n\t\t\tbodySerializer: JSON.stringify,\n\t\t\tcancelRedundantRequests: true,\n\t\t\tdefaultErrorMessage: \"Failed to fetch data from server!\",\n\t\t\tresponseType: \"json\",\n\t\t\tretries: 0,\n\t\t\tretryCodes: defaultRetryCodes,\n\t\t\tretryDelay: 0,\n\t\t\tretryMethods: defaultRetryMethods,\n\t\t\t...baseExtraOptions,\n\t\t\t...extraOptions,\n\t\t} satisfies ExtraOptions;\n\n\t\t// == Default Fetch Config\n\t\tconst defaultFetchOptions = {\n\t\t\tbody: isObject(body) ? options.bodySerializer(body) : body,\n\n\t\t\t// - The auth option is provided\n\t\t\theaders:\n\t\t\t\tbaseHeaders || headers || options.auth || isObject(body)\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...(isObject(body) && {\n\t\t\t\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isQueryString(body) && {\n\t\t\t\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isString(options.auth) && {\n\t\t\t\t\t\t\t\tAuthorization: `Bearer ${options.auth}`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isObject(options.auth) && {\n\t\t\t\t\t\t\t\tAuthorization:\n\t\t\t\t\t\t\t\t\t\"bearer\" in options.auth\n\t\t\t\t\t\t\t\t\t\t? `Bearer ${options.auth.bearer}`\n\t\t\t\t\t\t\t\t\t\t: `Token ${options.auth.token}`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...objectifyHeaders(baseHeaders),\n\t\t\t\t\t\t\t...objectifyHeaders(headers),\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\n\t\t\t// == Return undefined if the following conditions are not met (so that native fetch would auto set the correct headers):\n\t\t\t// - headers are provided\n\t\t\t// - The body is an object\n\t\t\tmethod: \"GET\",\n\n\t\t\t...restOfBaseFetchConfig,\n\t\t\t...restOfFetchConfig,\n\t\t} satisfies $RequestOptions;\n\n\t\tconst requestKey = getRequestKey(\n\t\t\turl,\n\t\t\tomitKeys({ ...defaultFetchOptions, ...options }, [\n\t\t\t\t\"onRequest\",\n\t\t\t\t\"onResponse\",\n\t\t\t\t\"onResponseError\",\n\t\t\t\t\"onError\",\n\t\t\t\t\"onRequestError\",\n\t\t\t])\n\t\t);\n\n\t\tconst prevFetchController = abortControllerStore.get(requestKey);\n\n\t\tif (prevFetchController && options.cancelRedundantRequests) {\n\t\t\tconst reason = new DOMException(\n\t\t\t\t`Automatic cancelation of the previous unfinished request to the same url, with the same fetch options: ${url}`,\n\t\t\t\t\"AbortError\"\n\t\t\t);\n\n\t\t\tprevFetchController.abort(reason);\n\t\t}\n\n\t\tconst newFetchController = new AbortController();\n\n\t\tabortControllerStore.set(requestKey, newFetchController);\n\n\t\tconst timeoutSignal = options.timeout ? AbortSignal.timeout(options.timeout) : null;\n\n\t\tconst combinedSignal = AbortSignal.any([\n\t\t\tnewFetchController.signal,\n\t\t\t...(timeoutSignal ? [timeoutSignal] : []),\n\t\t\t...(signal ? [signal] : []),\n\t\t]);\n\n\t\tconst requestInit = {\n\t\t\tsignal: combinedSignal,\n\t\t\t...defaultFetchOptions,\n\t\t} satisfies $RequestOptions;\n\n\t\ttry {\n\t\t\tawait options.onRequest?.({ options, request: requestInit });\n\n\t\t\tconst response = await fetch(\n\t\t\t\t`${options.baseURL}${mergeUrlWithParams(url, options.query)}`,\n\t\t\t\trequestInit\n\t\t\t);\n\n\t\t\tconst shouldRetry =\n\t\t\t\t!response.ok &&\n\t\t\t\t!combinedSignal.aborted &&\n\t\t\t\toptions.retries > 0 &&\n\t\t\t\toptions.retryCodes.includes(response.status) &&\n\t\t\t\toptions.retryMethods.includes(requestInit.method);\n\n\t\t\tif (shouldRetry) {\n\t\t\t\tawait waitUntil(options.retryDelay);\n\n\t\t\t\treturn await callApi(url, { ...config, retries: options.retries - 1 });\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorData = await getResponseData<TErrorData>(\n\t\t\t\t\toptions.cloneResponse ? response.clone() : response,\n\t\t\t\t\toptions.responseType,\n\t\t\t\t\toptions.responseParser\n\t\t\t\t);\n\n\t\t\t\t// == Pushing all error handling responsibilities to the catch block\n\t\t\t\tthrow new HTTPError({\n\t\t\t\t\tdefaultErrorMessage: options.defaultErrorMessage,\n\t\t\t\t\terrorData,\n\t\t\t\t\tresponse,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst successData = await getResponseData<TData>(\n\t\t\t\toptions.cloneResponse ? response.clone() : response,\n\t\t\t\toptions.responseType,\n\t\t\t\toptions.responseParser\n\t\t\t);\n\n\t\t\tconst validSuccessData = options.responseValidator\n\t\t\t\t? options.responseValidator(successData)\n\t\t\t\t: successData;\n\n\t\t\tawait options.onResponse?.({\n\t\t\t\tdata: validSuccessData,\n\t\t\t\toptions,\n\t\t\t\trequest: requestInit,\n\t\t\t\tresponse: options.cloneResponse ? response.clone() : response,\n\t\t\t});\n\n\t\t\treturn resolveSuccessResult<CallApiResult>({ options, response, successData: validSuccessData });\n\n\t\t\t// == Exhaustive Error handling\n\t\t} catch (error) {\n\t\t\tconst resolveErrorResult = getResolveErrorResultFn<CallApiResult>({ error, options });\n\n\t\t\tif (error instanceof DOMException && error.name === \"TimeoutError\") {\n\t\t\t\tconst message = `Request timed out after ${options.timeout}ms`;\n\n\t\t\t\tconsole.error(`${error.name}:`, message);\n\n\t\t\t\treturn resolveErrorResult({ message });\n\t\t\t}\n\n\t\t\tif (error instanceof DOMException && error.name === \"AbortError\") {\n\t\t\t\tconst message = `Request aborted due to ${error.message}`;\n\n\t\t\t\tconsole.error(`${error.name}:`, message);\n\n\t\t\t\treturn resolveErrorResult({ message });\n\t\t\t}\n\n\t\t\tif (isHTTPErrorInstance<TErrorData>(error)) {\n\t\t\t\tconst { errorData, response } = error;\n\n\t\t\t\tvoid (await Promise.allSettled([\n\t\t\t\t\toptions.onResponseError?.({\n\t\t\t\t\t\terrorData,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\trequest: requestInit,\n\t\t\t\t\t\tresponse: options.cloneResponse ? response.clone() : response,\n\t\t\t\t\t}),\n\n\t\t\t\t\t// == Also call the onError interceptor\n\t\t\t\t\toptions.onError?.({\n\t\t\t\t\t\terror: null,\n\t\t\t\t\t\terrorData,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\trequest: requestInit,\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t}),\n\t\t\t\t]));\n\n\t\t\t\treturn resolveErrorResult({\n\t\t\t\t\terrorData,\n\t\t\t\t\tmessage: (errorData as PossibleErrorObject)?.message,\n\t\t\t\t\tresponse,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvoid (await Promise.allSettled([\n\t\t\t\t// == At this point only the request errors exist, so the request error interceptor is called\n\t\t\t\toptions.onRequestError?.({ error: error as Error, options, request: requestInit }),\n\n\t\t\t\t// == Also call the onError interceptor\n\t\t\t\toptions.onError?.({\n\t\t\t\t\terror: error as Error,\n\t\t\t\t\terrorData: null,\n\t\t\t\t\toptions,\n\t\t\t\t\trequest: requestInit,\n\t\t\t\t\tresponse: null,\n\t\t\t\t}),\n\t\t\t]));\n\n\t\t\treturn resolveErrorResult();\n\n\t\t\t// == Removing the now unneeded AbortController from store\n\t\t} finally {\n\t\t\tabortControllerStore.delete(requestKey);\n\t\t}\n\t};\n\n\tcallApi.create = createFetchClient;\n\n\treturn callApi;\n};\n\nexport const callApi = createFetchClient();\n"]}
@@ -1,19 +1,16 @@
1
- import { R as ResultModeUnion, B as BaseConfig, F as FetchConfig, G as GetCallApiResult } from './types-B8FDdcFK.js';
1
+ import { R as ResultModeUnion, B as BaseConfig, F as FetchConfig, G as GetCallApiResult } from './types-CfjkQnRk.js';
2
2
  import './type-helpers-DpDJiTqb.js';
3
3
 
4
- declare const createFetchClient: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all">(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
4
+ declare const createFetchClient: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = undefined>(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
5
5
  <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeUnion = TBaseResultMode>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode>): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
6
6
  create: any;
7
- cancel(url: string, reason?: unknown): void;
8
7
  };
9
8
  declare const callApi: {
10
- <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = "all">(url: string, config?: FetchConfig<TData, TErrorData, TResultMode> | undefined): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
11
- create: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all">(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
9
+ <TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = undefined>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode> | undefined): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
10
+ create: <TBaseData, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = undefined>(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
12
11
  <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeUnion = TBaseResultMode>(url: string, config?: FetchConfig<TData, TErrorData, TResultMode>): Promise<GetCallApiResult<TData, TErrorData, TResultMode>>;
13
12
  create: any;
14
- cancel(url: string, reason?: unknown): void;
15
13
  };
16
- cancel(url: string, reason?: unknown): void;
17
14
  };
18
15
 
19
16
  export { callApi, createFetchClient };
@@ -1 +1 @@
1
- export{callApi,createFetchClient}from"./chunk-5TFO467R.js";import"./chunk-DWIZQKLW.js";import"./chunk-AKFUJ4JG.js";//# sourceMappingURL=createFetchClient.js.map
1
+ export{callApi,createFetchClient}from"./chunk-KQNDKJNJ.js";import"./chunk-F6RUPSGH.js";import"./chunk-AKFUJ4JG.js";//# sourceMappingURL=createFetchClient.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":""}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"createFetchClient.js"}
@@ -1,3 +1,3 @@
1
1
  export { callApi, createFetchClient } from './createFetchClient.js';
2
- export { $ as $RequestOptions, c as ErrorContext, E as ExtraOptions, F as FetchConfig, H as HTTPError, a as ResponseContext, b as ResponseErrorContext, i as isHTTPError, d as isHTTPErrorInstance, t as toQueryString } from './types-B8FDdcFK.js';
2
+ export { $ as $RequestOptions, c as ErrorContext, E as ExtraOptions, F as FetchConfig, a as ResponseContext, b as ResponseErrorContext } from './types-CfjkQnRk.js';
3
3
  import './type-helpers-DpDJiTqb.js';
package/dist/esm/index.js CHANGED
@@ -1 +1 @@
1
- export{callApi,createFetchClient}from"./chunk-5TFO467R.js";export{HTTPError,isHTTPError,isHTTPErrorInstance,toQueryString}from"./chunk-DWIZQKLW.js";import"./chunk-AKFUJ4JG.js";//# sourceMappingURL=index.js.map
1
+ export{callApi,createFetchClient}from"./chunk-KQNDKJNJ.js";import"./chunk-F6RUPSGH.js";import"./chunk-AKFUJ4JG.js";//# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":""}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":""}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"typeof.js"}
@@ -1,7 +1,8 @@
1
1
  import { a as AnyString, b as AnyNumber, P as Prettify } from './type-helpers-DpDJiTqb.js';
2
2
 
3
+ declare const getRequestKey: <TConfig extends Record<string, unknown>>(url: string, config?: TConfig) => string;
3
4
  type ToQueryStringFn = {
4
- (params: ExtraOptions["query"]): string | null;
5
+ (params: ExtraOptions["query"]): null | string;
5
6
  (params: Required<ExtraOptions>["query"]): string;
6
7
  };
7
8
  declare const toQueryString: ToQueryStringFn;
@@ -10,47 +11,48 @@ declare const objectifyHeaders: (headers: RequestInit["headers"]) => Record<stri
10
11
  declare const defaultRetryCodes: Required<BaseConfig>["retryCodes"];
11
12
  declare const defaultRetryMethods: Required<BaseConfig>["retryMethods"];
12
13
  declare const fetchSpecificKeys: ("body" | "method" | "headers" | "cache" | "credentials" | "integrity" | "keepalive" | "mode" | "priority" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window")[];
14
+ declare const omitKeys: <TObject extends Record<string, unknown>, const TOmitArray extends Array<keyof TObject>>(initialObject: TObject, keysToOmit: TOmitArray) => Omit<TObject, keyof TOmitArray>;
13
15
  declare const splitConfig: <TObject extends object>(config: TObject) => ["body" extends keyof TObject ? $RequestOptions : $BaseRequestOptions, ExtraOptions];
14
16
  declare const handleResponseType: <TResponse>(response: Response, parser?: Required<ExtraOptions>["responseParser"]) => {
15
- json: () => Promise<Record<string, unknown> | TResponse>;
16
17
  arrayBuffer: () => Promise<TResponse>;
17
18
  blob: () => Promise<TResponse>;
18
19
  formData: () => Promise<TResponse>;
20
+ json: () => Promise<Record<string, unknown> | TResponse>;
19
21
  text: () => Promise<TResponse>;
20
22
  };
21
23
  declare const getResponseData: <TResponse>(response: Response, responseType: keyof ReturnType<typeof handleResponseType>, parser: ExtraOptions["responseParser"]) => Promise<Record<string, unknown> | TResponse>;
22
24
  type data = {
23
- successData: unknown;
24
25
  options: ExtraOptions;
25
26
  response: Response;
27
+ successData: unknown;
26
28
  };
27
29
  declare const resolveSuccessResult: <CallApiResult>(info: data) => CallApiResult;
28
30
  declare const getResolveErrorResultFn: <CallApiResult>($info: {
29
31
  error?: unknown;
30
32
  options: ExtraOptions;
31
33
  }) => (info?: {
32
- response?: Response;
33
34
  errorData?: unknown;
34
35
  message?: string;
36
+ response?: Response;
35
37
  }) => CallApiResult;
36
38
  declare const isHTTPError: <TErrorData>(error: ApiErrorVariant<TErrorData>["error"] | null) => error is {
37
- name: "HTTPError";
38
39
  errorData: TErrorData;
39
40
  message: string;
41
+ name: "HTTPError";
40
42
  };
41
43
  type ErrorDetails<TErrorResponse> = {
44
+ defaultErrorMessage: string;
42
45
  errorData: TErrorResponse;
43
46
  response: Response;
44
- defaultErrorMessage: string;
45
47
  };
46
48
  type ErrorOptions = {
47
49
  cause?: unknown;
48
50
  };
49
51
  declare class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {
50
- response: ErrorDetails<TErrorResponse>["response"];
51
52
  errorData: ErrorDetails<TErrorResponse>["errorData"];
52
- name: "HTTPError";
53
53
  isHTTPError: boolean;
54
+ name: "HTTPError";
55
+ response: ErrorDetails<TErrorResponse>["response"];
54
56
  constructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions);
55
57
  }
56
58
  declare const isHTTPErrorInstance: <TErrorResponse>(error: unknown) => error is HTTPError<TErrorResponse>;
@@ -61,99 +63,41 @@ interface $RequestOptions extends Pick<FetchConfig, (typeof fetchSpecificKeys)[n
61
63
  interface $BaseRequestOptions extends Omit<$RequestOptions, "body"> {
62
64
  }
63
65
  interface ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = ResultModeUnion> {
64
- /** Optional body of the request, can be a object or any other supported body type. */
65
- body?: Record<string, unknown> | RequestInit["body"];
66
- /**
67
- * @description HTTP method for the request.
68
- * @default "GET"
69
- */
70
- method?: "GET" | "POST" | "PATCH" | "PUT" | "DELETE" | AnyString;
71
- /**
72
- * @description Query parameters to append to the URL.
73
- */
74
- query?: Record<string, string | number | boolean>;
75
66
  /**
76
67
  * @description Authorization header value.
77
68
  */
78
- auth?: string | {
69
+ auth?: {
79
70
  bearer: string;
80
71
  token?: never;
81
72
  } | {
82
- token: string;
83
73
  bearer?: never;
84
- };
74
+ token: string;
75
+ } | string;
85
76
  /**
86
- * @description Custom function to validate the response data.
77
+ * @description Base URL to be prepended to all request URLs
87
78
  */
88
- responseValidator?: (data: unknown) => TData;
79
+ baseURL?: string;
80
+ /** Optional body of the request, can be a object or any other supported body type. */
81
+ body?: Record<string, unknown> | RequestInit["body"];
89
82
  /**
90
83
  * @description Custom function to serialize the body object into a string.
91
84
  */
92
85
  bodySerializer?: (bodyData: Record<string, unknown>) => string;
93
- /**
94
- * @description Custom function to parse the response string into a object.
95
- */
96
- responseParser?: (responseString: string) => Record<string, unknown>;
97
- /**
98
- * @description Mode of the result, can influence how results are handled or returned.
99
- * Can be set to "all" | "onlySuccess" | "onlyError" | "onlyResponse".
100
- * @default "all"
101
- */
102
- resultMode?: TResultMode;
103
86
  /**
104
87
  * @description If true, cancels previous unfinished requests to the same URL.
105
88
  * @default true
106
89
  */
107
90
  cancelRedundantRequests?: boolean;
108
- /**
109
- * @description Base URL to be prepended to all request URLs
110
- */
111
- baseURL?: string;
112
- /**
113
- * @description Request timeout in milliseconds
114
- */
115
- timeout?: number;
116
- /**
117
- * @description Default error message to use if none is provided from a response.
118
- * @default "Failed to fetch data from server!"
119
- */
120
- defaultErrorMessage?: string;
121
91
  /**
122
92
  * @description Whether to clone the response, so response.json and the like can used in the interceptors.
123
93
  * @default false
124
94
  */
125
95
  cloneResponse?: boolean;
126
96
  /**
127
- * If true or the function returns true, throws errors instead of returning them
128
- * The function is passed the error object and can be used to conditionally throw the error
129
- * @default false
130
- */
131
- throwOnError?: boolean | ((error?: Error | HTTPError<TErrorData>) => boolean);
132
- /**
133
- * @description Expected response type, affects how response is parsed
134
- * @default "json"
135
- */
136
- responseType?: keyof ReturnType<typeof handleResponseType>;
137
- /**
138
- * @description Number of retry attempts for failed requests
139
- * @default 0
140
- */
141
- retries?: number;
142
- /**
143
- * @description Delay between retries in milliseconds
144
- * @default 500
145
- */
146
- retryDelay?: number;
147
- /**
148
- * @description HTTP status codes that trigger a retry
149
- * @default [409, 425, 429, 500, 502, 503, 504]
150
- */
151
- retryCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>;
152
- /**
153
- * HTTP methods that are allowed to retry
154
- * @default ["GET", "POST"]
97
+ * @description Default error message to use if none is provided from a response.
98
+ * @default "Failed to fetch data from server!"
155
99
  */
156
- retryMethods?: Array<"GET" | "POST" | AnyString>;
100
+ defaultErrorMessage?: string;
157
101
  /**
158
102
  * @description an optional field you can fill with additional information,
159
103
  * to associate with the request, typically used for logging or tracing.
@@ -177,53 +121,111 @@ interface ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extend
177
121
  * ```
178
122
  */
179
123
  meta?: Record<string, unknown>;
124
+ /**
125
+ * @description HTTP method for the request.
126
+ * @default "GET"
127
+ */
128
+ method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT" | AnyString;
129
+ /**
130
+ * @description Interceptor to be called when an error occurs during the fetch request OR when an error response is received from the api
131
+ * It is basically a combination of `onRequestError` and `onResponseError` interceptors
132
+ */
133
+ onError?: (anyErrorContext: ErrorContext<TErrorData>) => Promise<void> | void;
180
134
  /** @description Interceptor to be called just before the request is made, allowing for modifications or additional operations. */
181
135
  onRequest?: (requestContext: {
182
- request: $RequestOptions;
183
136
  options: ExtraOptions;
184
- }) => void | Promise<void>;
137
+ request: $RequestOptions;
138
+ }) => Promise<void> | void;
185
139
  /** @description Interceptor to be called when an error occurs during the fetch request. */
186
140
  onRequestError?: (requestErrorContext: {
187
141
  error: Error;
188
- request: $RequestOptions;
189
142
  options: ExtraOptions;
190
- }) => void | Promise<void>;
143
+ request: $RequestOptions;
144
+ }) => Promise<void> | void;
191
145
  /** @description Interceptor to be called when a successful response is received from the api. */
192
- onResponse?: (responseContext: ResponseContext<TData>) => void | Promise<void>;
146
+ onResponse?: (responseContext: ResponseContext<TData>) => Promise<void> | void;
193
147
  /** @description Interceptor to be called when an error response is received from the api. */
194
- onResponseError?: (responseErrorContext: ResponseErrorContext<TErrorData>) => void | Promise<void>;
148
+ onResponseError?: (responseErrorContext: ResponseErrorContext<TErrorData>) => Promise<void> | void;
195
149
  /**
196
- * @description Interceptor to be called when an error occurs during the fetch request OR when an error response is received from the api
197
- * It is basically a combination of `onRequestError` and `onResponseError` interceptors
150
+ * @description Query parameters to append to the URL.
151
+ */
152
+ query?: Record<string, boolean | number | string>;
153
+ /**
154
+ * @description Custom function to parse the response string into a object.
155
+ */
156
+ responseParser?: (responseString: string) => Record<string, unknown>;
157
+ /**
158
+ * @description Expected response type, affects how response is parsed
159
+ * @default "json"
160
+ */
161
+ responseType?: keyof ReturnType<typeof handleResponseType>;
162
+ /**
163
+ * @description Custom function to validate the response data.
164
+ */
165
+ responseValidator?: (data: unknown) => TData;
166
+ /**
167
+ * @description Mode of the result, can influence how results are handled or returned.
168
+ * Can be set to "all" | "onlySuccess" | "onlyError" | "onlyResponse".
169
+ * @default "all"
170
+ */
171
+ resultMode?: TResultMode;
172
+ /**
173
+ * @description Number of retry attempts for failed requests
174
+ * @default 0
175
+ */
176
+ retries?: number;
177
+ /**
178
+ * @description HTTP status codes that trigger a retry
179
+ * @default [409, 425, 429, 500, 502, 503, 504]
180
+ */
181
+ retryCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>;
182
+ /**
183
+ * @description Delay between retries in milliseconds
184
+ * @default 500
185
+ */
186
+ retryDelay?: number;
187
+ /**
188
+ * HTTP methods that are allowed to retry
189
+ * @default ["GET", "POST"]
198
190
  */
199
- onError?: (anyErrorContext: ErrorContext<TErrorData>) => void | Promise<void>;
191
+ retryMethods?: Array<"GET" | "POST" | AnyString>;
192
+ /**
193
+ * If true or the function returns true, throws errors instead of returning them
194
+ * The function is passed the error object and can be used to conditionally throw the error
195
+ * @default false
196
+ */
197
+ throwOnError?: ((error?: Error | HTTPError<TErrorData>) => boolean) | boolean;
198
+ /**
199
+ * @description Request timeout in milliseconds
200
+ */
201
+ timeout?: number;
200
202
  }
201
203
  type ResponseContext<TData> = Prettify<{
202
204
  data: TData;
203
- response: Response;
204
- request: $RequestOptions;
205
205
  options: ExtraOptions;
206
+ request: $RequestOptions;
207
+ response: Response;
206
208
  }>;
207
209
  type ResponseErrorContext<TErrorData> = Prettify<{
208
210
  errorData: TErrorData;
209
- response: Response;
210
- request: $RequestOptions;
211
211
  options: ExtraOptions;
212
+ request: $RequestOptions;
213
+ response: Response;
212
214
  }>;
213
215
  type ErrorContext<TErrorData> = Prettify<{
214
- errorData?: TErrorData;
215
- error: null;
216
- response: Response;
217
- request: $RequestOptions;
218
- options: ExtraOptions;
219
- } | {
220
216
  error: Error;
221
217
  errorData?: null;
222
- response: null;
218
+ options: ExtraOptions;
223
219
  request: $RequestOptions;
220
+ response: null;
221
+ } | {
222
+ error: null;
223
+ errorData?: TErrorData;
224
224
  options: ExtraOptions;
225
+ request: $RequestOptions;
226
+ response: Response;
225
227
  }>;
226
- interface FetchConfig<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = "all"> extends Omit<RequestInit, "method" | "body">, ExtraOptions<TData, TErrorData, TResultMode> {
228
+ interface FetchConfig<TData = unknown, TErrorData = unknown, TResultMode extends ResultModeUnion = "all"> extends Omit<RequestInit, "body" | "method">, ExtraOptions<TData, TErrorData, TResultMode> {
227
229
  }
228
230
  type BaseConfig<TBaseData = unknown, TBaseErrorData = unknown, TBaseResultMode extends ResultModeUnion = "all"> = FetchConfig<TBaseData, TBaseErrorData, TBaseResultMode>;
229
231
  type ApiSuccessVariant<TData> = {
@@ -232,36 +234,36 @@ type ApiSuccessVariant<TData> = {
232
234
  response: Response;
233
235
  };
234
236
  type PossibleErrorNames = {
235
- _: "AbortError" | "TimeoutError" | "SyntaxError" | "TypeError" | "Error" | "UnknownError";
237
+ _: "AbortError" | "Error" | "SyntaxError" | "TimeoutError" | "TypeError" | "UnknownError";
236
238
  }["_"];
237
239
  type ApiErrorVariant<TErrorData> = {
238
240
  data: null;
239
241
  error: {
240
- name: "HTTPError";
241
- errorData: TErrorData;
242
+ errorData: Error;
242
243
  message: string;
244
+ name: PossibleErrorNames;
243
245
  };
244
- response: Response;
246
+ response: null;
245
247
  } | {
246
248
  data: null;
247
249
  error: {
248
- name: PossibleErrorNames;
249
- errorData: Error;
250
+ errorData: TErrorData;
250
251
  message: string;
252
+ name: "HTTPError";
251
253
  };
252
- response: null;
254
+ response: Response;
253
255
  };
254
256
  type ResultModeMap<TData = unknown, TErrorData = unknown> = {
255
- all: ApiSuccessVariant<TData> | ApiErrorVariant<TErrorData>;
256
- onlySuccess: ApiSuccessVariant<TData>["data"];
257
+ all: ApiErrorVariant<TErrorData> | ApiSuccessVariant<TData>;
257
258
  onlyError: ApiErrorVariant<TErrorData>["error"];
258
259
  onlyResponse: Response;
260
+ onlySuccess: ApiSuccessVariant<TData>["data"];
259
261
  };
260
262
  type ResultModeUnion = {
261
263
  _: {
262
264
  [Key in keyof ResultModeMap]: Key;
263
- }[keyof ResultModeMap];
265
+ }[keyof ResultModeMap] | undefined;
264
266
  }["_"];
265
- type GetCallApiResult<TData, TErrorData, TResultMode extends ResultModeUnion> = ResultModeMap<TData, TErrorData>[TResultMode];
267
+ type GetCallApiResult<TData, TErrorData, TResultMode> = TResultMode extends NonNullable<ResultModeUnion> ? ResultModeMap<TData, TErrorData>[TResultMode] : ResultModeMap<TData, TErrorData>["all"];
266
268
 
267
- export { type $RequestOptions as $, type BaseConfig as B, type ExtraOptions as E, type FetchConfig as F, type GetCallApiResult as G, HTTPError as H, type ResultModeUnion as R, type ResponseContext as a, type ResponseErrorContext as b, type ErrorContext as c, isHTTPErrorInstance as d, defaultRetryCodes as e, defaultRetryMethods as f, fetchSpecificKeys as g, handleResponseType as h, isHTTPError as i, getResponseData as j, getResolveErrorResultFn as k, mergeUrlWithParams as m, objectifyHeaders as o, resolveSuccessResult as r, splitConfig as s, toQueryString as t, waitUntil as w };
269
+ export { type $RequestOptions as $, type BaseConfig as B, type ExtraOptions as E, type FetchConfig as F, type GetCallApiResult as G, HTTPError as H, type ResultModeUnion as R, type ResponseContext as a, type ResponseErrorContext as b, type ErrorContext as c, defaultRetryCodes as d, defaultRetryMethods as e, fetchSpecificKeys as f, getRequestKey as g, omitKeys as h, handleResponseType as i, getResponseData as j, getResolveErrorResultFn as k, isHTTPError as l, mergeUrlWithParams as m, isHTTPErrorInstance as n, objectifyHeaders as o, resolveSuccessResult as r, splitConfig as s, toQueryString as t, waitUntil as w };
@@ -1,2 +1,2 @@
1
- export { H as HTTPError, e as defaultRetryCodes, f as defaultRetryMethods, g as fetchSpecificKeys, k as getResolveErrorResultFn, j as getResponseData, h as handleResponseType, i as isHTTPError, d as isHTTPErrorInstance, m as mergeUrlWithParams, o as objectifyHeaders, r as resolveSuccessResult, s as splitConfig, t as toQueryString, w as waitUntil } from './types-B8FDdcFK.js';
1
+ export { H as HTTPError, d as defaultRetryCodes, e as defaultRetryMethods, f as fetchSpecificKeys, g as getRequestKey, k as getResolveErrorResultFn, j as getResponseData, i as handleResponseType, l as isHTTPError, n as isHTTPErrorInstance, m as mergeUrlWithParams, o as objectifyHeaders, h as omitKeys, r as resolveSuccessResult, s as splitConfig, t as toQueryString, w as waitUntil } from './types-CfjkQnRk.js';
2
2
  import './type-helpers-DpDJiTqb.js';
package/dist/esm/utils.js CHANGED
@@ -1 +1 @@
1
- export{HTTPError,defaultRetryCodes,defaultRetryMethods,fetchSpecificKeys,getResolveErrorResultFn,getResponseData,handleResponseType,isHTTPError,isHTTPErrorInstance,mergeUrlWithParams,objectifyHeaders,resolveSuccessResult,splitConfig,toQueryString,waitUntil}from"./chunk-DWIZQKLW.js";import"./chunk-AKFUJ4JG.js";//# sourceMappingURL=utils.js.map
1
+ export{HTTPError,defaultRetryCodes,defaultRetryMethods,fetchSpecificKeys,getRequestKey,getResolveErrorResultFn,getResponseData,handleResponseType,isHTTPError,isHTTPErrorInstance,mergeUrlWithParams,objectifyHeaders,omitKeys,resolveSuccessResult,splitConfig,toQueryString,waitUntil}from"./chunk-F6RUPSGH.js";import"./chunk-AKFUJ4JG.js";//# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":""}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"utils.js"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zayne-labs/callapi",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "type": "module",
5
5
  "description": "A lightweight wrapper over fetch with quality of life improvements like built-in request cancellation, retries, interceptors and more",
6
6
  "main": "./dist/esm/index.js",
@@ -39,25 +39,28 @@
39
39
  "node": ">=18.17.x"
40
40
  },
41
41
  "devDependencies": {
42
- "@arethetypeswrong/cli": "^0.15.3",
42
+ "@arethetypeswrong/cli": "^0.15.4",
43
43
  "@changesets/cli": "^2.27.7",
44
- "@eslint/js": "^9.7.0",
44
+ "@eslint/js": "^9.9.0",
45
45
  "@size-limit/preset-small-lib": "^11.1.4",
46
- "@zayne-labs/tsconfig": "^0.0.7",
47
- "eslint": "^9.7.0",
48
- "eslint-plugin-import-x": "^3.0.1",
49
- "eslint-plugin-jsdoc": "^48.7.0",
50
- "eslint-plugin-sonarjs": "^1.0.3",
51
- "eslint-plugin-unicorn": "^54.0.0",
52
- "globals": "^15.8.0",
53
- "husky": "^9.0.11",
54
- "lint-staged": "^15.2.7",
46
+ "@stylistic/eslint-plugin": "^2.6.4",
47
+ "@zayne-labs/tsconfig": "^0.1.1",
48
+ "eslint": "^9.9.0",
49
+ "eslint-plugin-import-x": "^3.1.0",
50
+ "eslint-plugin-jsdoc": "^50.2.2",
51
+ "eslint-plugin-perfectionist": "^3.2.0",
52
+ "eslint-plugin-sonarjs": "^1.0.4",
53
+ "eslint-plugin-unicorn": "^55.0.0",
54
+ "eslint-typegen": "^0.3.1",
55
+ "globals": "^15.9.0",
56
+ "husky": "^9.1.4",
57
+ "lint-staged": "^15.2.9",
55
58
  "prettier": "^3.3.3",
56
59
  "size-limit": "^11.1.4",
57
- "terser": "^5.31.5",
58
- "tsup": "^8.1.0",
60
+ "terser": "^5.31.6",
61
+ "tsup": "^8.2.4",
59
62
  "typescript": "5.5.4",
60
- "typescript-eslint": "^8.0.1"
63
+ "typescript-eslint": "^8.1.0"
61
64
  },
62
65
  "scripts": {
63
66
  "test:check-types": "tsc --pretty --incremental -p tsconfig.json",
@@ -1 +0,0 @@
1
- import{splitConfig as e,defaultRetryCodes as r,defaultRetryMethods as o,objectifyHeaders as t,mergeUrlWithParams as s,waitUntil as n,getResponseData as a,HTTPError as i,resolveSuccessResult as u,getResolveErrorResultFn as l,isHTTPErrorInstance as c}from"./chunk-DWIZQKLW.js";import{isObject as p,isQueryString as d,isString as m}from"./chunk-AKFUJ4JG.js";var h=y=>{const f=new Map,[b,g]=e(y??{}),{headers:w,body:R,signal:q,...E}=b,D=async(h,y)=>{const[b,A]=e(y??{}),{signal:$=q,body:M=R,headers:T,...S}=b,k={bodySerializer:JSON.stringify,responseType:"json",baseURL:"",retries:0,retryDelay:0,retryCodes:r,retryMethods:o,defaultErrorMessage:"Failed to fetch data from server!",cancelRedundantRequests:!0,...g,...A},j=f.get(h);if(j&&k.cancelRedundantRequests){const e=new DOMException(`Automatic cancelation of the previous unfinished request to this same url: ${h}`,"AbortError");j.abort(e)}const x=new AbortController;f.set(h,x);const C=k.timeout?AbortSignal.timeout(k.timeout):null,v=AbortSignal.any([x.signal,...C?[C]:[],...$?[$]:[]]),z={signal:v,method:"GET",body:p(M)?k.bodySerializer(M):M,headers:w||T||k.auth||p(M)?{...p(M)&&{"Content-Type":"application/json",Accept:"application/json"},...d(M)&&{"Content-Type":"application/x-www-form-urlencoded"},...m(k.auth)&&{Authorization:`Bearer ${k.auth}`},...p(k.auth)&&{Authorization:"bearer"in k.auth?`Bearer ${k.auth.bearer}`:`Token ${k.auth.token}`},...t(w),...t(T)}:void 0,...E,...S};try{await(k.onRequest?.({request:z,options:k}));const e=await fetch(`${k.baseURL}${s(h,k.query)}`,z);if(!e.ok&&!v.aborted&&k.retries>0&&k.retryCodes.includes(e.status)&&k.retryMethods.includes(z.method))return await n(k.retryDelay),await D(h,{...y,retries:k.retries-1});if(!e.ok){const r=await a(k.cloneResponse?e.clone():e,k.responseType,k.responseParser);throw new i({errorData:r,response:e,defaultErrorMessage:k.defaultErrorMessage})}const r=await a(k.cloneResponse?e.clone():e,k.responseType,k.responseParser),o=k.responseValidator?k.responseValidator(r):r;return await(k.onResponse?.({data:o,response:k.cloneResponse?e.clone():e,request:z,options:k})),u({successData:o,response:e,options:k})}catch(e){const r=l({error:e,options:k});if(e instanceof DOMException&&"TimeoutError"===e.name){const o=`Request timed out after ${k.timeout}ms`;return console.error(`${e.name}:`,o),r({message:o})}if(e instanceof DOMException&&"AbortError"===e.name){const o=`Request aborted due to ${e.message}`;return console.error(`${e.name}:`,o),r({message:o})}if(c(e)){const{errorData:o,response:t}=e;return await Promise.allSettled([k.onResponseError?.({errorData:o,response:k.cloneResponse?t.clone():t,request:z,options:k}),k.onError?.({errorData:o,response:t,error:null,options:k,request:z})]),r({errorData:o,message:o?.message,response:t})}return await Promise.allSettled([k.onRequestError?.({request:z,error:e,options:k}),k.onError?.({request:z,error:e,options:k,errorData:null,response:null})]),r()}finally{f.delete(h)}};return D.create=h,D.cancel=(e,r)=>{r?f.get(e)?.abort(r):f.get(e)?.abort()},D},y=h();export{y as callApi,h as createFetchClient};//# sourceMappingURL=chunk-5TFO467R.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/createFetchClient.ts"],"names":["callApi"],"mappings":";;;;;;;;;;;;;;;;;;;;AAwBO,IAAM,oBAAoB,CAKhC,eACI;AACJ,QAAM,uBAAuB,oBAAI,IAA6B;AAE9D,QAAM,CAAC,iBAAiB,gBAAgB,IAAI,YAAY,cAAc,CAAC,CAAC;AAExE,QAAM;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,GAAG;AAAA,EACJ,IAAI;AAGJ,QAAMA,WAAU,OAKf,KACA,WAC+D;AAG/D,UAAM,CAAC,aAAa,YAAY,IAAI,YAAY,UAAU,CAAC,CAAC;AAE5D,UAAM,EAAE,SAAS,YAAY,OAAO,UAAU,SAAS,GAAG,kBAAkB,IAAI;AAGhF,UAAM,UAAU;AAAA,MACf,gBAAgB,KAAK;AAAA,MACrB,cAAc;AAAA,MACd,SAAS;AAAA,MACT,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,YAAY;AAAA,MACZ,cAAc;AAAA,MACd,qBAAqB;AAAA,MACrB,yBAAyB;AAAA,MACzB,GAAG;AAAA,MACH,GAAG;AAAA,IACJ;AAEA,UAAM,sBAAsB,qBAAqB,IAAI,GAAG;AAExD,QAAI,uBAAuB,QAAQ,yBAAyB;AAC3D,YAAM,SAAS,IAAI;AAAA,QAClB,8EAA8E,GAAG;AAAA,QACjF;AAAA,MACD;AACA,0BAAoB,MAAM,MAAM;AAAA,IACjC;AAEA,UAAM,qBAAqB,IAAI,gBAAgB;AAE/C,yBAAqB,IAAI,KAAK,kBAAkB;AAEhD,UAAM,gBAAgB,QAAQ,UAAU,YAAY,QAAQ,QAAQ,OAAO,IAAI;AAE/E,UAAM,iBAAiB,YAAY,IAAI;AAAA,MACtC,mBAAmB;AAAA,MACnB,GAAI,gBAAgB,CAAC,aAAa,IAAI,CAAC;AAAA,MACvC,GAAI,SAAS,CAAC,MAAM,IAAI,CAAC;AAAA,IAC1B,CAAC;AAED,UAAM,cAAc;AAAA,MACnB,QAAQ;AAAA,MAER,QAAQ;AAAA,MAER,MAAM,SAAS,IAAI,IAAI,QAAQ,eAAe,IAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,MAMtD,SACC,eAAe,WAAW,QAAQ,QAAQ,SAAS,IAAI,IACpD;AAAA,QACA,GAAI,SAAS,IAAI,KAAK;AAAA,UACrB,gBAAgB;AAAA,UAChB,QAAQ;AAAA,QACT;AAAA,QACA,GAAI,cAAc,IAAI,KAAK;AAAA,UAC1B,gBAAgB;AAAA,QACjB;AAAA,QACA,GAAI,SAAS,QAAQ,IAAI,KAAK;AAAA,UAC7B,eAAe,UAAU,QAAQ,IAAI;AAAA,QACtC;AAAA,QACA,GAAI,SAAS,QAAQ,IAAI,KAAK;AAAA,UAC7B,eACC,YAAY,QAAQ,OACjB,UAAU,QAAQ,KAAK,MAAM,KAC7B,SAAS,QAAQ,KAAK,KAAK;AAAA,QAChC;AAAA,QACA,GAAG,iBAAiB,WAAW;AAAA,QAC/B,GAAG,iBAAiB,OAAO;AAAA,MAC5B,IACC;AAAA,MAEJ,GAAG;AAAA,MACH,GAAG;AAAA,IACJ;AAEA,QAAI;AACH,YAAM,QAAQ,YAAY,EAAE,SAAS,aAAa,QAAQ,CAAC;AAE3D,YAAM,WAAW,MAAM;AAAA,QACtB,GAAG,QAAQ,OAAO,GAAG,mBAAmB,KAAK,QAAQ,KAAK,CAAC;AAAA,QAC3D;AAAA,MACD;AAEA,YAAM,cACL,CAAC,SAAS,MACV,CAAC,eAAe,WAChB,QAAQ,UAAU,KAClB,QAAQ,WAAW,SAAS,SAAS,MAAM,KAC3C,QAAQ,aAAa,SAAS,YAAY,MAAM;AAEjD,UAAI,aAAa;AAChB,cAAM,UAAU,QAAQ,UAAU;AAElC,eAAO,MAAMA,SAAQ,KAAK,EAAE,GAAG,QAAQ,SAAS,QAAQ,UAAU,EAAE,CAAC;AAAA,MACtE;AAEA,UAAI,CAAC,SAAS,IAAI;AACjB,cAAM,YAAY,MAAM;AAAA,UACvB,QAAQ,gBAAgB,SAAS,MAAM,IAAI;AAAA,UAC3C,QAAQ;AAAA,UACR,QAAQ;AAAA,QACT;AAGA,cAAM,IAAI,UAAU;AAAA,UACnB;AAAA,UACA;AAAA,UACA,qBAAqB,QAAQ;AAAA,QAC9B,CAAC;AAAA,MACF;AAEA,YAAM,cAAc,MAAM;AAAA,QACzB,QAAQ,gBAAgB,SAAS,MAAM,IAAI;AAAA,QAC3C,QAAQ;AAAA,QACR,QAAQ;AAAA,MACT;AAEA,YAAM,mBAAmB,QAAQ,oBAC9B,QAAQ,kBAAkB,WAAW,IACrC;AAEH,YAAM,QAAQ,aAAa;AAAA,QAC1B,MAAM;AAAA,QACN,UAAU,QAAQ,gBAAgB,SAAS,MAAM,IAAI;AAAA,QACrD,SAAS;AAAA,QACT;AAAA,MACD,CAAC;AAED,aAAO,qBAAoC,EAAE,aAAa,kBAAkB,UAAU,QAAQ,CAAC;AAAA,IAGhG,SAAS,OAAO;AACf,YAAM,qBAAqB,wBAAuC,EAAE,OAAO,QAAQ,CAAC;AAEpF,UAAI,iBAAiB,gBAAgB,MAAM,SAAS,gBAAgB;AACnE,cAAM,UAAU,2BAA2B,QAAQ,OAAO;AAE1D,gBAAQ,MAAM,GAAG,MAAM,IAAI,KAAK,OAAO;AAEvC,eAAO,mBAAmB,EAAE,QAAQ,CAAC;AAAA,MACtC;AAEA,UAAI,iBAAiB,gBAAgB,MAAM,SAAS,cAAc;AACjE,cAAM,UAAU,0BAA0B,MAAM,OAAO;AAEvD,gBAAQ,MAAM,GAAG,MAAM,IAAI,KAAK,OAAO;AAEvC,eAAO,mBAAmB,EAAE,QAAQ,CAAC;AAAA,MACtC;AAEA,UAAI,oBAAgC,KAAK,GAAG;AAC3C,cAAM,EAAE,WAAW,SAAS,IAAI;AAEhC,aAAM,MAAM,QAAQ,WAAW;AAAA,UAC9B,QAAQ,kBAAkB;AAAA,YACzB;AAAA,YACA,UAAU,QAAQ,gBAAgB,SAAS,MAAM,IAAI;AAAA,YACrD,SAAS;AAAA,YACT;AAAA,UACD,CAAC;AAAA;AAAA,UAGD,QAAQ,UAAU;AAAA,YACjB;AAAA,YACA;AAAA,YACA,OAAO;AAAA,YACP;AAAA,YACA,SAAS;AAAA,UACV,CAAC;AAAA,QACF,CAAC;AAED,eAAO,mBAAmB;AAAA,UACzB;AAAA,UACA,SAAU,WAAmC;AAAA,UAC7C;AAAA,QACD,CAAC;AAAA,MACF;AAEA,WAAM,MAAM,QAAQ,WAAW;AAAA;AAAA,QAE9B,QAAQ,iBAAiB,EAAE,SAAS,aAAa,OAAuB,QAAQ,CAAC;AAAA;AAAA,QAGjF,QAAQ,UAAU;AAAA,UACjB,SAAS;AAAA,UACT;AAAA,UACA;AAAA,UACA,WAAW;AAAA,UACX,UAAU;AAAA,QACX,CAAC;AAAA,MACF,CAAC;AAED,aAAO,mBAAmB;AAAA,IAG3B,UAAE;AACD,2BAAqB,OAAO,GAAG;AAAA,IAChC;AAAA,EACD;AAEA,EAAAA,SAAQ,SAAS;AAEjB,EAAAA,SAAQ,SAAS,CAAC,KAAa,WAAqB;AACnD,aAAS,qBAAqB,IAAI,GAAG,GAAG,MAAM,MAAM,IAAI,qBAAqB,IAAI,GAAG,GAAG,MAAM;AAAA,EAC9F;AAEA,SAAOA;AACR;AAEO,IAAM,UAAU,kBAAkB","sourcesContent":["import { isObject, isQueryString, isString } from \"./typeof\";\nimport type {\n\t$RequestOptions,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tGetCallApiResult,\n\tPossibleErrorObject,\n\tResultModeUnion,\n} from \"./types\";\nimport {\n\tHTTPError,\n\tdefaultRetryCodes,\n\tdefaultRetryMethods,\n\tgetResolveErrorResultFn,\n\tgetResponseData,\n\tisHTTPErrorInstance,\n\tmergeUrlWithParams,\n\tobjectifyHeaders,\n\tresolveSuccessResult,\n\tsplitConfig,\n\twaitUntil,\n} from \"./utils\";\n\nexport const createFetchClient = <\n\tTBaseData,\n\tTBaseErrorData = unknown,\n\tTBaseResultMode extends ResultModeUnion = \"all\",\n>(\n\tbaseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>\n) => {\n\tconst abortControllerStore = new Map<string, AbortController>();\n\n\tconst [baseFetchConfig, baseExtraOptions] = splitConfig(baseConfig ?? {});\n\n\tconst {\n\t\theaders: baseHeaders,\n\t\tbody: baseBody,\n\t\tsignal: baseSignal,\n\t\t...restOfBaseFetchConfig\n\t} = baseFetchConfig;\n\n\t/* eslint-disable complexity */\n\tconst callApi = async <\n\t\tTData = TBaseData,\n\t\tTErrorData = TBaseErrorData,\n\t\tTResultMode extends ResultModeUnion = TBaseResultMode,\n\t>(\n\t\turl: string,\n\t\tconfig?: FetchConfig<TData, TErrorData, TResultMode>\n\t): Promise<GetCallApiResult<TData, TErrorData, TResultMode>> => {\n\t\ttype CallApiResult = GetCallApiResult<TData, TErrorData, TResultMode>;\n\n\t\tconst [fetchConfig, extraOptions] = splitConfig(config ?? {});\n\n\t\tconst { signal = baseSignal, body = baseBody, headers, ...restOfFetchConfig } = fetchConfig;\n\n\t\t// == Default Options\n\t\tconst options = {\n\t\t\tbodySerializer: JSON.stringify,\n\t\t\tresponseType: \"json\",\n\t\t\tbaseURL: \"\",\n\t\t\tretries: 0,\n\t\t\tretryDelay: 0,\n\t\t\tretryCodes: defaultRetryCodes,\n\t\t\tretryMethods: defaultRetryMethods,\n\t\t\tdefaultErrorMessage: \"Failed to fetch data from server!\",\n\t\t\tcancelRedundantRequests: true,\n\t\t\t...baseExtraOptions,\n\t\t\t...extraOptions,\n\t\t} satisfies ExtraOptions;\n\n\t\tconst prevFetchController = abortControllerStore.get(url);\n\n\t\tif (prevFetchController && options.cancelRedundantRequests) {\n\t\t\tconst reason = new DOMException(\n\t\t\t\t`Automatic cancelation of the previous unfinished request to this same url: ${url}`,\n\t\t\t\t\"AbortError\"\n\t\t\t);\n\t\t\tprevFetchController.abort(reason);\n\t\t}\n\n\t\tconst newFetchController = new AbortController();\n\n\t\tabortControllerStore.set(url, newFetchController);\n\n\t\tconst timeoutSignal = options.timeout ? AbortSignal.timeout(options.timeout) : null;\n\n\t\tconst combinedSignal = AbortSignal.any([\n\t\t\tnewFetchController.signal,\n\t\t\t...(timeoutSignal ? [timeoutSignal] : []),\n\t\t\t...(signal ? [signal] : []),\n\t\t]);\n\n\t\tconst requestInit = {\n\t\t\tsignal: combinedSignal,\n\n\t\t\tmethod: \"GET\",\n\n\t\t\tbody: isObject(body) ? options.bodySerializer(body) : body,\n\n\t\t\t// == Return undefined if the following conditions are not met (so that native fetch would auto set the correct headers):\n\t\t\t// - headers are provided\n\t\t\t// - The body is an object\n\t\t\t// - The auth option is provided\n\t\t\theaders:\n\t\t\t\tbaseHeaders || headers || options.auth || isObject(body)\n\t\t\t\t\t? {\n\t\t\t\t\t\t\t...(isObject(body) && {\n\t\t\t\t\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t\t\t\t\t\tAccept: \"application/json\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isQueryString(body) && {\n\t\t\t\t\t\t\t\t\"Content-Type\": \"application/x-www-form-urlencoded\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isString(options.auth) && {\n\t\t\t\t\t\t\t\tAuthorization: `Bearer ${options.auth}`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isObject(options.auth) && {\n\t\t\t\t\t\t\t\tAuthorization:\n\t\t\t\t\t\t\t\t\t\"bearer\" in options.auth\n\t\t\t\t\t\t\t\t\t\t? `Bearer ${options.auth.bearer}`\n\t\t\t\t\t\t\t\t\t\t: `Token ${options.auth.token}`,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...objectifyHeaders(baseHeaders),\n\t\t\t\t\t\t\t...objectifyHeaders(headers),\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined,\n\n\t\t\t...restOfBaseFetchConfig,\n\t\t\t...restOfFetchConfig,\n\t\t} satisfies $RequestOptions;\n\n\t\ttry {\n\t\t\tawait options.onRequest?.({ request: requestInit, options });\n\n\t\t\tconst response = await fetch(\n\t\t\t\t`${options.baseURL}${mergeUrlWithParams(url, options.query)}`,\n\t\t\t\trequestInit\n\t\t\t);\n\n\t\t\tconst shouldRetry =\n\t\t\t\t!response.ok &&\n\t\t\t\t!combinedSignal.aborted &&\n\t\t\t\toptions.retries > 0 &&\n\t\t\t\toptions.retryCodes.includes(response.status) &&\n\t\t\t\toptions.retryMethods.includes(requestInit.method);\n\n\t\t\tif (shouldRetry) {\n\t\t\t\tawait waitUntil(options.retryDelay);\n\n\t\t\t\treturn await callApi(url, { ...config, retries: options.retries - 1 });\n\t\t\t}\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst errorData = await getResponseData<TErrorData>(\n\t\t\t\t\toptions.cloneResponse ? response.clone() : response,\n\t\t\t\t\toptions.responseType,\n\t\t\t\t\toptions.responseParser\n\t\t\t\t);\n\n\t\t\t\t// == Pushing all error handling responsibilities to the catch block\n\t\t\t\tthrow new HTTPError({\n\t\t\t\t\terrorData,\n\t\t\t\t\tresponse,\n\t\t\t\t\tdefaultErrorMessage: options.defaultErrorMessage,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tconst successData = await getResponseData<TData>(\n\t\t\t\toptions.cloneResponse ? response.clone() : response,\n\t\t\t\toptions.responseType,\n\t\t\t\toptions.responseParser\n\t\t\t);\n\n\t\t\tconst validSuccessData = options.responseValidator\n\t\t\t\t? options.responseValidator(successData)\n\t\t\t\t: successData;\n\n\t\t\tawait options.onResponse?.({\n\t\t\t\tdata: validSuccessData,\n\t\t\t\tresponse: options.cloneResponse ? response.clone() : response,\n\t\t\t\trequest: requestInit,\n\t\t\t\toptions,\n\t\t\t});\n\n\t\t\treturn resolveSuccessResult<CallApiResult>({ successData: validSuccessData, response, options });\n\n\t\t\t// == Exhaustive Error handling\n\t\t} catch (error) {\n\t\t\tconst resolveErrorResult = getResolveErrorResultFn<CallApiResult>({ error, options });\n\n\t\t\tif (error instanceof DOMException && error.name === \"TimeoutError\") {\n\t\t\t\tconst message = `Request timed out after ${options.timeout}ms`;\n\n\t\t\t\tconsole.error(`${error.name}:`, message);\n\n\t\t\t\treturn resolveErrorResult({ message });\n\t\t\t}\n\n\t\t\tif (error instanceof DOMException && error.name === \"AbortError\") {\n\t\t\t\tconst message = `Request aborted due to ${error.message}`;\n\n\t\t\t\tconsole.error(`${error.name}:`, message);\n\n\t\t\t\treturn resolveErrorResult({ message });\n\t\t\t}\n\n\t\t\tif (isHTTPErrorInstance<TErrorData>(error)) {\n\t\t\t\tconst { errorData, response } = error;\n\n\t\t\t\tvoid (await Promise.allSettled([\n\t\t\t\t\toptions.onResponseError?.({\n\t\t\t\t\t\terrorData,\n\t\t\t\t\t\tresponse: options.cloneResponse ? response.clone() : response,\n\t\t\t\t\t\trequest: requestInit,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t}),\n\n\t\t\t\t\t// == Also call the onError interceptor\n\t\t\t\t\toptions.onError?.({\n\t\t\t\t\t\terrorData,\n\t\t\t\t\t\tresponse,\n\t\t\t\t\t\terror: null,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\trequest: requestInit,\n\t\t\t\t\t}),\n\t\t\t\t]));\n\n\t\t\t\treturn resolveErrorResult({\n\t\t\t\t\terrorData,\n\t\t\t\t\tmessage: (errorData as PossibleErrorObject)?.message,\n\t\t\t\t\tresponse,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tvoid (await Promise.allSettled([\n\t\t\t\t// == At this point only the request errors exist, so the request error interceptor is called\n\t\t\t\toptions.onRequestError?.({ request: requestInit, error: error as Error, options }),\n\n\t\t\t\t// == Also call the onError interceptor\n\t\t\t\toptions.onError?.({\n\t\t\t\t\trequest: requestInit,\n\t\t\t\t\terror: error as Error,\n\t\t\t\t\toptions,\n\t\t\t\t\terrorData: null,\n\t\t\t\t\tresponse: null,\n\t\t\t\t}),\n\t\t\t]));\n\n\t\t\treturn resolveErrorResult();\n\n\t\t\t// == Removing the now unneeded AbortController from store\n\t\t} finally {\n\t\t\tabortControllerStore.delete(url);\n\t\t}\n\t};\n\n\tcallApi.create = createFetchClient;\n\n\tcallApi.cancel = (url: string, reason?: unknown) => {\n\t\treason ? abortControllerStore.get(url)?.abort(reason) : abortControllerStore.get(url)?.abort();\n\t};\n\n\treturn callApi;\n};\n\nexport const callApi = createFetchClient();\n"]}
@@ -1 +0,0 @@
1
- import{isObject as r,isArray as e,isFunction as o}from"./chunk-AKFUJ4JG.js";var t=r=>r?new URLSearchParams(r).toString():(console.error("toQueryString:","No query params provided!"),null),s=(r,e)=>{if(!e)return r;const o=t(e);return r.endsWith("?")?`${r}${o}`:r.includes("?")?`${r}&${o}`:`${r}?${o}`},n=o=>!o||r(o)?o:Object.fromEntries(e(o)?o:o.entries()),a=Object.keys({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"}).map(Number),i=["GET"],l=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],c=(r,e)=>{const o=Object.entries(r).filter((([r])=>!e.includes(r)));return Object.fromEntries(o)},u=(r,e)=>{const o=new Set(e),t=Object.entries(r).filter((([r])=>o.has(r)));return Object.fromEntries(t)},m=r=>[u(r,l),c(r,l)],d=(r,e)=>({json:async()=>e?e(await r.text()):r.json(),arrayBuffer:()=>r.arrayBuffer(),blob:()=>r.blob(),formData:()=>r.formData(),text:()=>r.text()}),f=(r,e,o)=>{const t=d(r,o);if(!Object.hasOwn(t,e))throw new Error(`Invalid response type: ${e}`);return t[e]()},p=r=>{const{options:e,response:o,successData:t}=r,s={data:t,error:null,response:o};return void 0===e.resultMode||"all"===e.resultMode?s:{onlySuccess:s.data,onlyError:s.error,onlyResponse:s.response}[e.resultMode]},E=r=>{const{error:e,options:t}=r;return(r={})=>{const{errorData:s,message:n,response:a}=r;if(o(t.throwOnError)?t.throwOnError(e):t.throwOnError)throw e;return{data:null,error:{name:e?.name??"UnknownError",errorData:s??e,message:n??e?.message??t.defaultErrorMessage},response:a??null}}},y=e=>r(e)&&"HTTPError"===e.name,h=class extends Error{response;errorData;name="HTTPError";isHTTPError=!0;constructor(r,e){const{defaultErrorMessage:o,response:t,errorData:s}=r;super(s.message??o,e),this.errorData=s,this.response=t}},w=e=>e instanceof h||r(e)&&"HTTPError"===e.name&&!0===e.isHTTPError,T=r=>{if(0===r)return;const{promise:e,resolve:o}=Promise.withResolvers();return setTimeout(o,r),e};export{h as HTTPError,a as defaultRetryCodes,i as defaultRetryMethods,l as fetchSpecificKeys,E as getResolveErrorResultFn,f as getResponseData,d as handleResponseType,y as isHTTPError,w as isHTTPErrorInstance,s as mergeUrlWithParams,n as objectifyHeaders,p as resolveSuccessResult,m as splitConfig,t as toQueryString,T as waitUntil};//# sourceMappingURL=chunk-DWIZQKLW.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { isArray, isFunction, isObject } from \"./typeof\";\nimport type {\n\t$BaseRequestOptions,\n\t$RequestOptions,\n\tApiErrorVariant,\n\tBaseConfig,\n\tExtraOptions,\n\tFetchConfig,\n\tPossibleErrorObject,\n} from \"./types\";\n\ntype ToQueryStringFn = {\n\t(params: ExtraOptions[\"query\"]): string | null;\n\t(params: Required<ExtraOptions>[\"query\"]): string;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"toQueryString:\", \"No query params provided!\");\n\n\t\treturn null as never;\n\t}\n\n\treturn new URLSearchParams(params as Record<string, string>).toString();\n};\n\nexport const mergeUrlWithParams = (url: string, params: ExtraOptions[\"query\"]): string => {\n\tif (!params) {\n\t\treturn url;\n\t}\n\n\tconst paramsString = toQueryString(params);\n\n\tif (url.endsWith(\"?\")) {\n\t\treturn `${url}${paramsString}`;\n\t}\n\n\tif (url.includes(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\treturn `${url}?${paramsString}`;\n};\n\nexport const objectifyHeaders = (headers: RequestInit[\"headers\"]): Record<string, string> | undefined => {\n\tif (!headers || isObject(headers)) {\n\t\treturn headers;\n\t}\n\n\treturn Object.fromEntries(isArray(headers) ? headers : headers.entries());\n};\n\nconst retryCodesLookup = {\n\t408: \"Request Timeout\",\n\t409: \"Conflict\",\n\t425: \"Too Early\",\n\t429: \"Too Many Requests\",\n\t500: \"Internal Server Error\",\n\t502: \"Bad Gateway\",\n\t503: \"Service Unavailable\",\n\t504: \"Gateway Timeout\",\n};\n\nexport const defaultRetryCodes: Required<BaseConfig>[\"retryCodes\"] =\n\tObject.keys(retryCodesLookup).map(Number);\n\nexport const defaultRetryMethods: Required<BaseConfig>[\"retryMethods\"] = [\"GET\"];\n\nexport const fetchSpecificKeys = [\n\t\"body\",\n\t\"integrity\",\n\t\"method\",\n\t\"headers\",\n\t\"signal\",\n\t\"cache\",\n\t\"redirect\",\n\t\"window\",\n\t\"credentials\",\n\t\"keepalive\",\n\t\"referrer\",\n\t\"priority\",\n\t\"mode\",\n\t\"referrerPolicy\",\n] satisfies Array<keyof FetchConfig>;\n\nconst omitKeys = <TObject extends Record<string, unknown>, const TOmitArray extends Array<keyof TObject>>(\n\tinitialObject: TObject,\n\tkeysToOmit: TOmitArray\n) => {\n\tconst arrayFromFilteredObject = Object.entries(initialObject).filter(\n\t\t([key]) => !keysToOmit.includes(key)\n\t);\n\n\tconst updatedObject = Object.fromEntries(arrayFromFilteredObject);\n\n\treturn updatedObject as Omit<TObject, keyof TOmitArray>;\n};\n\nconst pickKeys = <TObject extends Record<string, unknown>, const TPickArray extends Array<keyof TObject>>(\n\tinitialObject: TObject,\n\tkeysToPick: TPickArray\n) => {\n\tconst keysToPickSet = new Set(keysToPick);\n\n\tconst arrayFromInitObject = Object.entries(initialObject);\n\n\tconst filteredArray = arrayFromInitObject.filter(([objectKey]) => keysToPickSet.has(objectKey));\n\n\tconst updatedObject = Object.fromEntries(filteredArray);\n\n\treturn updatedObject as Pick<TObject, TPickArray[number]>;\n};\n\nexport const splitConfig = <TObject extends object>(\n\tconfig: TObject\n): [\"body\" extends keyof TObject ? $RequestOptions : $BaseRequestOptions, ExtraOptions] => [\n\tpickKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n\tomitKeys(config as Record<string, unknown>, fetchSpecificKeys) as never,\n];\n\nexport const handleResponseType = <TResponse>(\n\tresponse: Response,\n\tparser?: Required<ExtraOptions>[\"responseParser\"]\n) => ({\n\tjson: async () => {\n\t\tif (parser) {\n\t\t\treturn parser(await response.text());\n\t\t}\n\n\t\treturn response.json() as Promise<TResponse>;\n\t},\n\tarrayBuffer: () => response.arrayBuffer() as Promise<TResponse>,\n\tblob: () => response.blob() as Promise<TResponse>,\n\tformData: () => response.formData() as Promise<TResponse>,\n\ttext: () => response.text() as Promise<TResponse>,\n});\n\nexport const getResponseData = <TResponse>(\n\tresponse: Response,\n\tresponseType: keyof ReturnType<typeof handleResponseType>,\n\tparser: ExtraOptions[\"responseParser\"]\n) => {\n\tconst RESPONSE_TYPE_LOOKUP = handleResponseType<TResponse>(response, parser);\n\n\tif (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, responseType)) {\n\t\tthrow new Error(`Invalid response type: ${responseType}`);\n\t}\n\n\treturn RESPONSE_TYPE_LOOKUP[responseType]();\n};\n\ntype data = {\n\tsuccessData: unknown;\n\toptions: ExtraOptions;\n\tresponse: Response;\n};\n\n// == The CallApiResult type is used to cast all return statements due to a design limitation in ts.\n// LINK - See https://www.zhenghao.io/posts/type-functions for more info\nexport const resolveSuccessResult = <CallApiResult>(info: data): CallApiResult => {\n\tconst { options, response, successData } = info;\n\n\tconst apiDetails = {\n\t\tdata: successData,\n\t\terror: null,\n\t\tresponse,\n\t};\n\n\tif (options.resultMode === undefined || options.resultMode === \"all\") {\n\t\treturn apiDetails as CallApiResult;\n\t}\n\n\treturn {\n\t\tonlySuccess: apiDetails.data,\n\t\tonlyError: apiDetails.error,\n\t\tonlyResponse: apiDetails.response,\n\t}[options.resultMode] as CallApiResult;\n};\n\n// == Using curring here so error and options are not required to be passed every time, instead to be captured once by way of closure\nexport const getResolveErrorResultFn = <CallApiResult>($info: {\n\terror?: unknown;\n\toptions: ExtraOptions;\n}) => {\n\tconst { error, options } = $info;\n\n\ttype ErrorInfo = {\n\t\tresponse?: Response;\n\t\terrorData?: unknown;\n\t\tmessage?: string;\n\t};\n\n\tconst resolveErrorResult = (info: ErrorInfo = {}): CallApiResult => {\n\t\tconst { errorData, message, response } = info;\n\n\t\tconst shouldThrowOnError = isFunction(options.throwOnError)\n\t\t\t? options.throwOnError(error as Error)\n\t\t\t: options.throwOnError;\n\n\t\tif (shouldThrowOnError) {\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn {\n\t\t\tdata: null,\n\t\t\terror: {\n\t\t\t\tname: (error as PossibleErrorObject)?.name ?? \"UnknownError\",\n\t\t\t\terrorData: errorData ?? error,\n\t\t\t\tmessage: message ?? (error as PossibleErrorObject)?.message ?? options.defaultErrorMessage,\n\t\t\t},\n\t\t\tresponse: response ?? null,\n\t\t} as CallApiResult;\n\t};\n\n\treturn resolveErrorResult;\n};\n\nexport const isHTTPError = <TErrorData>(error: ApiErrorVariant<TErrorData>[\"error\"] | null) => {\n\treturn isObject(error) && error.name === \"HTTPError\";\n};\n\ntype ErrorDetails<TErrorResponse> = {\n\terrorData: TErrorResponse;\n\tresponse: Response;\n\tdefaultErrorMessage: string;\n};\n\ntype ErrorOptions = {\n\tcause?: unknown;\n};\n\nexport class HTTPError<TErrorResponse = Record<string, unknown>> extends Error {\n\tresponse: ErrorDetails<TErrorResponse>[\"response\"];\n\terrorData: ErrorDetails<TErrorResponse>[\"errorData\"];\n\n\toverride name = \"HTTPError\" as const;\n\n\tisHTTPError = true;\n\n\tconstructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions) {\n\t\tconst { defaultErrorMessage, response, errorData } = errorDetails;\n\n\t\tsuper((errorData as { message?: string }).message ?? defaultErrorMessage, errorOptions);\n\n\t\tthis.errorData = errorData;\n\t\tthis.response = response;\n\t}\n}\n\n// prettier-ignore\nexport const isHTTPErrorInstance = <TErrorResponse>(\n\terror: unknown\n): error is HTTPError<TErrorResponse> => {\n\treturn (\n\t\terror instanceof HTTPError || (isObject(error) && error.name === \"HTTPError\" && error.isHTTPError === true)\n\t);\n};\n\nexport const waitUntil = (delay: number) => {\n\tif (delay === 0) return;\n\n\tconst { promise, resolve } = Promise.withResolvers();\n\n\tsetTimeout(resolve, delay);\n\n\treturn promise;\n};\n"]}