@zayne-labs/callapi 0.3.4 → 0.4.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.
package/README.md CHANGED
@@ -90,18 +90,18 @@ CallApi provides a unified error handling through an `error` object, which captu
90
90
 
91
91
  The `error` object contains the following properties:
92
92
 
93
- 1. `errorName`: A string indicating the type of error (e.g., 'TypeError', 'SyntaxError', 'HTTPError').
93
+ 1. `name`: A string indicating the type of error (e.g., 'TypeError', 'SyntaxError', 'HTTPError').
94
94
  2. `message`: The error message describing what went wrong.
95
95
  3. `errorData`: The error data, which can be an error response from the API or a standard JavaScript error object.
96
96
 
97
97
  For HTTP errors:
98
98
 
99
- - `errorName` is set to "HTTPError"
99
+ - `name` is set to "HTTPError"
100
100
  - An additional `errorData` property contains the error response data from the API.
101
101
 
102
102
  For non-HTTP errors (e.g., TypeError, SyntaxError):
103
103
 
104
- - `errorName` reflects the specific JavaScript error type (i.e., 'TypeError', 'SyntaxError')
104
+ - `name` reflects the specific JavaScript error type (i.e., 'TypeError', 'SyntaxError')
105
105
  - The `errorData` property contains the original JavaScript Error object.
106
106
 
107
107
  This structure allows you to easily identify and handle different types of errors that may occur during API calls.
@@ -109,7 +109,7 @@ This structure allows you to easily identify and handle different types of error
109
109
  ```js
110
110
  const { data, error } = await callApi("some-url");
111
111
 
112
- console.log(error.errorName);
112
+ console.log(error.name);
113
113
  console.log(error.message);
114
114
  // Will reference the would contain the parsed error response data if it is an HTTPError, else it would just reference the corresponding js Error object
115
115
  console.log(error.errorData);
@@ -605,7 +605,7 @@ const { data, error } = await callMainApi("some-url", {
605
605
  });
606
606
 
607
607
  if (isHTTPError(error)) {
608
- console.error(error.errorName); // `HTTPError`
608
+ console.error(error.name); // `HTTPError`
609
609
  console.error(error.message); // contains the parsed error message, if the response from the server contains such a property
610
610
  console.error(error.errorData); // contains the parsed error response
611
611
 
@@ -613,7 +613,7 @@ if (isHTTPError(error)) {
613
613
  }
614
614
 
615
615
  if (error) {
616
- console.error(error.errorName); // contains the name of the error
616
+ console.error(error.name); // contains the name of the error
617
617
  console.error(error.message); // contains the error message
618
618
  console.error(error.errorData); // contains the original error object
619
619
  }
@@ -1,2 +1,2 @@
1
- "use strict";var h=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var X=Object.prototype.hasOwnProperty;var Z=(e,r)=>{for(var o in r)h(e,o,{get:r[o],enumerable:!0})},ee=(e,r,o,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of Y(r))!X.call(e,s)&&s!==o&&h(e,s,{get:()=>r[s],enumerable:!(a=J(r,s))||a.enumerable});return e};var re=e=>ee(h({},"__esModule",{value:!0}),e);var ae={};Z(ae,{HTTPError:()=>d,callApi:()=>N,createFetchClient:()=>g,isHTTPError:()=>G,isHTTPErrorInstance:()=>b,toQueryString:()=>w});module.exports=re(ae);var F=e=>Array.isArray(e),M=e=>e instanceof FormData,c=e=>typeof e=="object"&&e!==null&&!(e instanceof FormData)&&!Array.isArray(e),S=e=>typeof e=="function",x=e=>typeof e=="string";var w=e=>e?new URLSearchParams(e).toString():(console.error("No query params provided"),null),v=(e,r)=>{if(!r)return e;let o=w(r);return e.includes("?")&&!e.endsWith("?")?`${e}&${o}`:e.endsWith("?")?`${e}${o}`:`${e}?${o}`},D=e=>!e||c(e)?e:Object.fromEntries(F(e)?e:e.entries()),te={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"},B=Object.keys(te).map(Number),H=["GET"],$=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],oe=(e,r)=>{let o=Object.entries(e).filter(([s])=>!r.includes(s));return Object.fromEntries(o)},se=(e,r)=>{let o=new Set(r),s=Object.entries(e).filter(([y])=>o.has(y));return Object.fromEntries(s)},A=e=>[se(e,$),oe(e,$)],ne=(e,r)=>({json:async()=>r?r(await e.text()):e.json(),arrayBuffer:()=>e.arrayBuffer(),blob:()=>e.blob(),formData:()=>e.formData(),text:()=>e.text()}),C=(e,r,o)=>{let a=ne(e,o);if(!Object.hasOwn(a,r))throw new Error(`Invalid response type: ${r}`);return a[r]()},I=e=>{let{options:r,response:o,successData:a}=e,s={data:a,errorInfo:null,response:o};return r.resultMode===void 0||r.resultMode==="all"?s:{onlySuccess:s.data,onlyError:s.errorInfo,onlyResponse:s.response}[r.resultMode]},U=e=>{let{error:r,options:o}=e;return(s={})=>{let{errorData:l,message:y,response:O}=s;if(S(o.throwOnError)?o.throwOnError(r):o.throwOnError)throw r;return{data:null,error:{errorName:r?.name??"UnknownError",errorData:l??r,message:y??r?.message??o.defaultErrorMessage},response:O??null}}},G=e=>c(e)&&e.errorName==="HTTPError",d=class extends Error{response;errorData;name="HTTPError";isHTTPError=!0;constructor(r,o){let{defaultErrorMessage:a,response:s,errorData:l}=r;super(l.message??a,o),this.errorData=l,this.response=s}},b=e=>e instanceof d||c(e)&&e.name==="HTTPError"&&e.isHTTPError===!0,z=e=>{if(e===0)return;let{promise:r,resolve:o}=Promise.withResolvers();return setTimeout(o,e),r};var g=e=>{let r=new Map,[o,a]=A(e??{}),{headers:s,body:l,signal:y,...O}=o,T=async(u,j)=>{let[L,K]=A(j??{}),{signal:Q=y,body:p=l,headers:P,...V}=L,t={bodySerializer:JSON.stringify,responseType:"json",baseURL:"",retries:0,retryDelay:0,retryCodes:B,retryMethods:H,defaultErrorMessage:"Failed to fetch data from server!",cancelRedundantRequests:!0,...a,...K},k=r.get(u);if(k&&t.cancelRedundantRequests){let n=new DOMException("Cancelled the previous unfinished request","AbortError");k.abort(n)}let m=new AbortController;r.set(u,m);let W=t.timeout?AbortSignal.timeout(t.timeout):null,q=AbortSignal.any([m.signal,W??m.signal,Q??m.signal]),f={signal:q,method:"GET",body:c(p)?t.bodySerializer(p):p,headers:s||P||t.auth||c(p)?{...c(p)&&{"Content-Type":"application/json",Accept:"application/json"},...M(p)&&{"Content-Type":"multipart/form-data"},...x(p)&&{"Content-Type":"application/x-www-form-urlencoded"},...x(t.auth)&&{Authorization:`Bearer ${t.auth}`},...c(t.auth)&&{Authorization:"bearer"in t.auth?`Bearer ${t.auth.bearer}`:`Token ${t.auth.token}`},...D(s),...D(P)}:void 0,...O,...V};try{await t.onRequest?.({request:f,options:t});let n=await fetch(`${t.baseURL}${v(u,t.query)}`,f);if(!n.ok&&!q.aborted&&t.retries>0&&t.retryCodes.includes(n.status)&&t.retryMethods.includes(f.method))return await z(t.retryDelay),await T(u,{...j,retries:t.retries-1});if(!n.ok){let _=await C(n.clone(),t.responseType,t.responseParser);throw new d({errorData:_,response:n,defaultErrorMessage:t.defaultErrorMessage})}let i=await C(n.clone(),t.responseType,t.responseParser),R=t.responseValidator?t.responseValidator(i):i;return await t.onResponse?.({response:Object.assign(n.clone(),{data:R}),request:f,options:t}),I({successData:R,response:n,options:t})}catch(n){let E=U({error:n,options:t});if(n instanceof DOMException&&n.name==="TimeoutError"){let i=`Request timed out after ${t.timeout}ms`;return console.info(`%cTimeoutError: ${i}`,"color: red; font-weight: 500; font-size: 14px;"),console.trace("TimeoutError"),E({message:i})}if(n instanceof DOMException&&n.name==="AbortError"){let i="Request was cancelled";return console.info(`%AbortError: ${i}`,"color: red; font-weight: 500; font-size: 14px;"),console.trace("AbortError"),E({message:i})}if(b(n)){let{errorData:i,response:R}=n;return await t.onResponseError?.({response:Object.assign(R.clone(),{errorData:i}),request:f,options:t}),E({errorData:i,message:i?.message,response:R})}return await t.onRequestError?.({request:f,error:n,options:t}),E()}finally{r.delete(u)}};return T.create=g,T.cancel=u=>r.get(u)?.abort(),T},N=g();0&&(module.exports={HTTPError,callApi,createFetchClient,isHTTPError,isHTTPErrorInstance,toQueryString});
1
+ "use strict";var h=Object.defineProperty;var J=Object.getOwnPropertyDescriptor;var Y=Object.getOwnPropertyNames;var X=Object.prototype.hasOwnProperty;var Z=(e,r)=>{for(var o in r)h(e,o,{get:r[o],enumerable:!0})},ee=(e,r,o,a)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of Y(r))!X.call(e,s)&&s!==o&&h(e,s,{get:()=>r[s],enumerable:!(a=J(r,s))||a.enumerable});return e};var re=e=>ee(h({},"__esModule",{value:!0}),e);var ae={};Z(ae,{HTTPError:()=>d,callApi:()=>L,createFetchClient:()=>g,isHTTPError:()=>G,isHTTPErrorInstance:()=>b,toQueryString:()=>w});module.exports=re(ae);var F=e=>Array.isArray(e),M=e=>e instanceof FormData,c=e=>typeof e=="object"&&e!==null&&!(e instanceof FormData)&&!Array.isArray(e),S=e=>typeof e=="function",x=e=>typeof e=="string";var w=e=>e?new URLSearchParams(e).toString():(console.error("No query params provided"),null),v=(e,r)=>{if(!r)return e;let o=w(r);return e.includes("?")&&!e.endsWith("?")?`${e}&${o}`:e.endsWith("?")?`${e}${o}`:`${e}?${o}`},D=e=>!e||c(e)?e:Object.fromEntries(F(e)?e:e.entries()),te={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"},B=Object.keys(te).map(Number),H=["GET"],$=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],oe=(e,r)=>{let o=Object.entries(e).filter(([s])=>!r.includes(s));return Object.fromEntries(o)},se=(e,r)=>{let o=new Set(r),s=Object.entries(e).filter(([y])=>o.has(y));return Object.fromEntries(s)},A=e=>[se(e,$),oe(e,$)],ne=(e,r)=>({json:async()=>r?r(await e.text()):e.json(),arrayBuffer:()=>e.arrayBuffer(),blob:()=>e.blob(),formData:()=>e.formData(),text:()=>e.text()}),C=(e,r,o)=>{let a=ne(e,o);if(!Object.hasOwn(a,r))throw new Error(`Invalid response type: ${r}`);return a[r]()},I=e=>{let{options:r,response:o,successData:a}=e,s={data:a,errorInfo:null,response:o};return r.resultMode===void 0||r.resultMode==="all"?s:{onlySuccess:s.data,onlyError:s.errorInfo,onlyResponse:s.response}[r.resultMode]},U=e=>{let{error:r,options:o}=e;return(s={})=>{let{errorData:l,message:y,response:O}=s;if(S(o.throwOnError)?o.throwOnError(r):o.throwOnError)throw r;return{data:null,error:{name:r?.name??"UnknownError",errorData:l??r,message:y??r?.message??o.defaultErrorMessage},response:O??null}}},G=e=>c(e)&&e.name==="HTTPError",d=class extends Error{response;errorData;name="HTTPError";isHTTPError=!0;constructor(r,o){let{defaultErrorMessage:a,response:s,errorData:l}=r;super(l.message??a,o),this.errorData=l,this.response=s}},b=e=>e instanceof d||c(e)&&e.name==="HTTPError"&&e.isHTTPError===!0,z=e=>{if(e===0)return;let{promise:r,resolve:o}=Promise.withResolvers();return setTimeout(o,e),r};var g=e=>{let r=new Map,[o,a]=A(e??{}),{headers:s,body:l,signal:y,...O}=o,T=async(u,j)=>{let[K,N]=A(j??{}),{signal:Q=y,body:p=l,headers:P,...V}=K,t={bodySerializer:JSON.stringify,responseType:"json",baseURL:"",retries:0,retryDelay:0,retryCodes:B,retryMethods:H,defaultErrorMessage:"Failed to fetch data from server!",cancelRedundantRequests:!0,...a,...N},k=r.get(u);if(k&&t.cancelRedundantRequests){let n=new DOMException("Cancelled the previous unfinished request","AbortError");k.abort(n)}let m=new AbortController;r.set(u,m);let W=t.timeout?AbortSignal.timeout(t.timeout):null,q=AbortSignal.any([m.signal,W??m.signal,Q??m.signal]),f={signal:q,method:"GET",body:c(p)?t.bodySerializer(p):p,headers:s||P||t.auth||c(p)?{...c(p)&&{"Content-Type":"application/json",Accept:"application/json"},...M(p)&&{"Content-Type":"multipart/form-data"},...x(p)&&{"Content-Type":"application/x-www-form-urlencoded"},...x(t.auth)&&{Authorization:`Bearer ${t.auth}`},...c(t.auth)&&{Authorization:"bearer"in t.auth?`Bearer ${t.auth.bearer}`:`Token ${t.auth.token}`},...D(s),...D(P)}:void 0,...O,...V};try{await t.onRequest?.({request:f,options:t});let n=await fetch(`${t.baseURL}${v(u,t.query)}`,f);if(!n.ok&&!q.aborted&&t.retries>0&&t.retryCodes.includes(n.status)&&t.retryMethods.includes(f.method))return await z(t.retryDelay),await T(u,{...j,retries:t.retries-1});if(!n.ok){let _=await C(n.clone(),t.responseType,t.responseParser);throw new d({errorData:_,response:n,defaultErrorMessage:t.defaultErrorMessage})}let i=await C(n.clone(),t.responseType,t.responseParser),R=t.responseValidator?t.responseValidator(i):i;return await t.onResponse?.({response:Object.assign(n.clone(),{data:R}),request:f,options:t}),I({successData:R,response:n,options:t})}catch(n){let E=U({error:n,options:t});if(n instanceof DOMException&&n.name==="TimeoutError"){let i=`Request timed out after ${t.timeout}ms`;return console.info(`%cTimeoutError: ${i}`,"color: red; font-weight: 500; font-size: 14px;"),console.trace("TimeoutError"),E({message:i})}if(n instanceof DOMException&&n.name==="AbortError"){let i="Request was cancelled";return console.info(`%AbortError: ${i}`,"color: red; font-weight: 500; font-size: 14px;"),console.trace("AbortError"),E({message:i})}if(b(n)){let{errorData:i,response:R}=n;return await t.onResponseError?.({response:Object.assign(R.clone(),{errorData:i}),request:f,options:t}),E({errorData:i,message:i?.message,response:R})}return await t.onRequestError?.({request:f,error:n,options:t}),E()}finally{r.delete(u)}};return T.create=g,T.cancel=u=>r.get(u)?.abort(),T},L=g();0&&(module.exports={HTTPError,callApi,createFetchClient,isHTTPError,isHTTPErrorInstance,toQueryString});
2
2
  //# 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\tFetchConfig,\n\t$RequestOptions,\n\tExtraOptions,\n\tResponseContext,\n\tResponseErrorContext,\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 isFormData = (value: unknown) => value instanceof FormData;\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","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: Required<ExtraOptions>[\"query\"]): string;\n\t(params: ExtraOptions[\"query\"]): string | null;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"No query params provided\");\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.includes(\"?\") && !url.endsWith(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\tif (url.endsWith(\"?\")) {\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\terrorInfo: 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.errorInfo,\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 $resolveErrorResult = <CallApiResult>($info: { error?: unknown; options: ExtraOptions }) => {\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\terrorName: (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.errorName === \"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 { isFormData, isObject, 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\t$resolveErrorResult,\n\tHTTPError,\n\tdefaultRetryCodes,\n\tdefaultRetryMethods,\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,\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\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(\"Cancelled the previous unfinished request\", \"AbortError\");\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\ttimeoutSignal ?? newFetchController.signal,\n\t\t\tsignal ?? newFetchController.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...(isFormData(body) && {\n\t\t\t\t\t\t\t\t\"Content-Type\": \"multipart/form-data\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isString(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\tresponse.clone(),\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\tresponse.clone(),\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\t// == Workaround as opposed to using the spread operator, as it doesn't work on the response object. So using Object.assign instead on a clone of the response object.\n\t\t\t\tresponse: Object.assign(response.clone(), { data: validSuccessData }),\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 = $resolveErrorResult<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.info(`%cTimeoutError: ${message}`, \"color: red; font-weight: 500; font-size: 14px;\");\n\t\t\t\tconsole.trace(\"TimeoutError\");\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 was cancelled`;\n\n\t\t\t\tconsole.info(`%AbortError: ${message}`, \"color: red; font-weight: 500; font-size: 14px;\");\n\t\t\t\tconsole.trace(\"AbortError\");\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\tawait options.onResponseError?.({\n\t\t\t\t\tresponse: Object.assign(response.clone(), { errorData }),\n\t\t\t\t\trequest: requestInit,\n\t\t\t\t\toptions,\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\t// == At this point only the request errors exist, so the request error interceptor is called\n\t\t\tawait options.onRequestError?.({ request: requestInit, error: error as Error, options });\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) => abortControllerStore.get(url)?.abort();\n\n\treturn callApi;\n};\n\nexport const callApi = createFetchClient();\n"],"mappings":"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","names":["src_exports","__export","HTTPError","callApi","createFetchClient","isHTTPError","isHTTPErrorInstance","toQueryString","__toCommonJS","isArray","value","isFormData","isObject","isFunction","isString","toQueryString","params","mergeUrlWithParams","url","paramsString","objectifyHeaders","headers","isObject","isArray","retryCodesLookup","defaultRetryCodes","defaultRetryMethods","fetchSpecificKeys","omitKeys","initialObject","keysToOmit","arrayFromFilteredObject","key","pickKeys","keysToPick","keysToPickSet","filteredArray","objectKey","splitConfig","config","handleResponseType","response","parser","getResponseData","responseType","RESPONSE_TYPE_LOOKUP","resolveSuccessResult","info","options","successData","apiDetails","$resolveErrorResult","$info","error","errorData","message","isFunction","isHTTPError","HTTPError","errorDetails","errorOptions","defaultErrorMessage","isHTTPErrorInstance","waitUntil","delay","promise","resolve","createFetchClient","baseConfig","abortControllerStore","baseFetchConfig","baseExtraOptions","splitConfig","baseHeaders","baseBody","baseSignal","restOfBaseFetchConfig","callApi","url","config","fetchConfig","extraOptions","signal","body","headers","restOfFetchConfig","options","defaultRetryCodes","defaultRetryMethods","prevFetchController","reason","newFetchController","timeoutSignal","combinedSignal","requestInit","isObject","isFormData","isString","objectifyHeaders","response","mergeUrlWithParams","waitUntil","errorData","getResponseData","HTTPError","successData","validSuccessData","resolveSuccessResult","error","resolveErrorResult","$resolveErrorResult","message","isHTTPErrorInstance"]}
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\tFetchConfig,\n\t$RequestOptions,\n\tExtraOptions,\n\tResponseContext,\n\tResponseErrorContext,\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 isFormData = (value: unknown) => value instanceof FormData;\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","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: Required<ExtraOptions>[\"query\"]): string;\n\t(params: ExtraOptions[\"query\"]): string | null;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"No query params provided\");\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.includes(\"?\") && !url.endsWith(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\tif (url.endsWith(\"?\")) {\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\terrorInfo: 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.errorInfo,\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 $resolveErrorResult = <CallApiResult>($info: { error?: unknown; options: ExtraOptions }) => {\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 { isFormData, isObject, 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\t$resolveErrorResult,\n\tHTTPError,\n\tdefaultRetryCodes,\n\tdefaultRetryMethods,\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,\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\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(\"Cancelled the previous unfinished request\", \"AbortError\");\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\ttimeoutSignal ?? newFetchController.signal,\n\t\t\tsignal ?? newFetchController.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...(isFormData(body) && {\n\t\t\t\t\t\t\t\t\"Content-Type\": \"multipart/form-data\",\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t...(isString(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\tresponse.clone(),\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\tresponse.clone(),\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\t// == Workaround as opposed to using the spread operator, as it doesn't work on the response object. So using Object.assign instead on a clone of the response object.\n\t\t\t\tresponse: Object.assign(response.clone(), { data: validSuccessData }),\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 = $resolveErrorResult<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.info(`%cTimeoutError: ${message}`, \"color: red; font-weight: 500; font-size: 14px;\");\n\t\t\t\tconsole.trace(\"TimeoutError\");\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 was cancelled`;\n\n\t\t\t\tconsole.info(`%AbortError: ${message}`, \"color: red; font-weight: 500; font-size: 14px;\");\n\t\t\t\tconsole.trace(\"AbortError\");\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\tawait options.onResponseError?.({\n\t\t\t\t\tresponse: Object.assign(response.clone(), { errorData }),\n\t\t\t\t\trequest: requestInit,\n\t\t\t\t\toptions,\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\t// == At this point only the request errors exist, so the request error interceptor is called\n\t\t\tawait options.onRequestError?.({ request: requestInit, error: error as Error, options });\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) => abortControllerStore.get(url)?.abort();\n\n\treturn callApi;\n};\n\nexport const callApi = createFetchClient();\n"],"mappings":"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","names":["src_exports","__export","HTTPError","callApi","createFetchClient","isHTTPError","isHTTPErrorInstance","toQueryString","__toCommonJS","isArray","value","isFormData","isObject","isFunction","isString","toQueryString","params","mergeUrlWithParams","url","paramsString","objectifyHeaders","headers","isObject","isArray","retryCodesLookup","defaultRetryCodes","defaultRetryMethods","fetchSpecificKeys","omitKeys","initialObject","keysToOmit","arrayFromFilteredObject","key","pickKeys","keysToPick","keysToPickSet","filteredArray","objectKey","splitConfig","config","handleResponseType","response","parser","getResponseData","responseType","RESPONSE_TYPE_LOOKUP","resolveSuccessResult","info","options","successData","apiDetails","$resolveErrorResult","$info","error","errorData","message","isFunction","isHTTPError","HTTPError","errorDetails","errorOptions","defaultErrorMessage","isHTTPErrorInstance","waitUntil","delay","promise","resolve","createFetchClient","baseConfig","abortControllerStore","baseFetchConfig","baseExtraOptions","splitConfig","baseHeaders","baseBody","baseSignal","restOfBaseFetchConfig","callApi","url","config","fetchConfig","extraOptions","signal","body","headers","restOfFetchConfig","options","defaultRetryCodes","defaultRetryMethods","prevFetchController","reason","newFetchController","timeoutSignal","combinedSignal","requestInit","isObject","isFormData","isString","objectifyHeaders","response","mergeUrlWithParams","waitUntil","errorData","getResponseData","HTTPError","successData","validSuccessData","resolveSuccessResult","error","resolveErrorResult","$resolveErrorResult","message","isHTTPErrorInstance"]}
@@ -19,7 +19,7 @@ declare const handleResponseType: <TResponse>(response: Response, parser?: Requi
19
19
  text: () => Promise<TResponse>;
20
20
  };
21
21
  declare const isHTTPError: <TErrorData>(error: ApiErrorVariant<TErrorData>["error"] | null) => error is {
22
- errorName: "HTTPError";
22
+ name: "HTTPError";
23
23
  errorData: TErrorData;
24
24
  message: string;
25
25
  };
@@ -196,11 +196,13 @@ type ApiSuccessVariant<TData> = {
196
196
  error: null;
197
197
  response: Response;
198
198
  };
199
- type PossibleErrorNames = "AbortError" | "TimeoutError" | "SyntaxError" | "TypeError" | "Error" | "UnknownError";
199
+ type PossibleErrorNames = {
200
+ _: "AbortError" | "TimeoutError" | "SyntaxError" | "TypeError" | "Error" | "UnknownError";
201
+ }["_"];
200
202
  type ApiErrorVariant<TErrorData> = {
201
203
  data: null;
202
204
  error: {
203
- errorName: "HTTPError";
205
+ name: "HTTPError";
204
206
  errorData: TErrorData;
205
207
  message: string;
206
208
  };
@@ -208,7 +210,7 @@ type ApiErrorVariant<TErrorData> = {
208
210
  } | {
209
211
  data: null;
210
212
  error: {
211
- errorName: PossibleErrorNames;
213
+ name: PossibleErrorNames;
212
214
  errorData: Error;
213
215
  message: string;
214
216
  };
@@ -1,8 +1,8 @@
1
- import { g, d, e, c as c$1, b as b$1, o, i, m, j, k, n } from './chunk-W6T7K2ZN.js';
1
+ import { g, d, e, c as c$1, b as b$1, o, i, m, j, k, n } from './chunk-ON3SY4EX.js';
2
2
  import { c, b, e as e$1 } from './chunk-3E33QJL5.js';
3
3
 
4
4
  var x=S=>{let c$2=new Map,[$,F]=g(S??{}),{headers:R,body:j$1,signal:P,...v}=$,u=async(o$1,h)=>{let[U,z]=g(h??{}),{signal:k$1=P,body:s=j$1,headers:b$2,...G}=U,e$2={bodySerializer:JSON.stringify,responseType:"json",baseURL:"",retries:0,retryDelay:0,retryCodes:d,retryMethods:e,defaultErrorMessage:"Failed to fetch data from server!",cancelRedundantRequests:!0,...F,...z},E=c$2.get(o$1);if(E&&e$2.cancelRedundantRequests){let t=new DOMException("Cancelled the previous unfinished request","AbortError");E.abort(t);}let d$1=new AbortController;c$2.set(o$1,d$1);let H=e$2.timeout?AbortSignal.timeout(e$2.timeout):null,y=AbortSignal.any([d$1.signal,H??d$1.signal,k$1??d$1.signal]),a={signal:y,method:"GET",body:c(s)?e$2.bodySerializer(s):s,headers:R||b$2||e$2.auth||c(s)?{...c(s)&&{"Content-Type":"application/json",Accept:"application/json"},...b(s)&&{"Content-Type":"multipart/form-data"},...e$1(s)&&{"Content-Type":"application/x-www-form-urlencoded"},...e$1(e$2.auth)&&{Authorization:`Bearer ${e$2.auth}`},...c(e$2.auth)&&{Authorization:"bearer"in e$2.auth?`Bearer ${e$2.auth.bearer}`:`Token ${e$2.auth.token}`},...c$1(R),...c$1(b$2)}:void 0,...v,...G};try{await e$2.onRequest?.({request:a,options:e$2});let t=await fetch(`${e$2.baseURL}${b$1(o$1,e$2.query)}`,a);if(!t.ok&&!y.aborted&&e$2.retries>0&&e$2.retryCodes.includes(t.status)&&e$2.retryMethods.includes(a.method))return await o(e$2.retryDelay),await u(o$1,{...h,retries:e$2.retries-1});if(!t.ok){let I=await i(t.clone(),e$2.responseType,e$2.responseParser);throw new m({errorData:I,response:t,defaultErrorMessage:e$2.defaultErrorMessage})}let r=await i(t.clone(),e$2.responseType,e$2.responseParser),i$1=e$2.responseValidator?e$2.responseValidator(r):r;return await e$2.onResponse?.({response:Object.assign(t.clone(),{data:i$1}),request:a,options:e$2}),j({successData:i$1,response:t,options:e$2})}catch(t){let n$1=k({error:t,options:e$2});if(t instanceof DOMException&&t.name==="TimeoutError"){let r=`Request timed out after ${e$2.timeout}ms`;return console.info(`%cTimeoutError: ${r}`,"color: red; font-weight: 500; font-size: 14px;"),console.trace("TimeoutError"),n$1({message:r})}if(t instanceof DOMException&&t.name==="AbortError"){let r="Request was cancelled";return console.info(`%AbortError: ${r}`,"color: red; font-weight: 500; font-size: 14px;"),console.trace("AbortError"),n$1({message:r})}if(n(t)){let{errorData:r,response:i}=t;return await e$2.onResponseError?.({response:Object.assign(i.clone(),{errorData:r}),request:a,options:e$2}),n$1({errorData:r,message:r?.message,response:i})}return await e$2.onRequestError?.({request:a,error:t,options:e$2}),n$1()}finally{c$2.delete(o$1);}};return u.create=x,u.cancel=o=>c$2.get(o)?.abort(),u},J=x();
5
5
 
6
6
  export { x as a, J as b };
7
7
  //# sourceMappingURL=out.js.map
8
- //# sourceMappingURL=chunk-LO64E2L2.js.map
8
+ //# sourceMappingURL=chunk-FIQCUJN4.js.map
@@ -1,7 +1,7 @@
1
1
  import { c as c$1, a, d } from './chunk-3E33QJL5.js';
2
2
 
3
- var E=r=>r?new URLSearchParams(r).toString():(console.error("No query params provided"),null),b=(r,e)=>{if(!e)return r;let t=E(e);return r.includes("?")&&!r.endsWith("?")?`${r}&${t}`:r.endsWith("?")?`${r}${t}`:`${r}?${t}`},g=r=>!r||c$1(r)?r:Object.fromEntries(a(r)?r:r.entries()),y={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"},x=Object.keys(y).map(Number),j=["GET"],l=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],T=(r,e)=>{let t=Object.entries(r).filter(([s])=>!e.includes(s));return Object.fromEntries(t)},R=(r,e)=>{let t=new Set(e),s=Object.entries(r).filter(([i])=>t.has(i));return Object.fromEntries(s)},w=r=>[R(r,l),T(r,l)],O=(r,e)=>({json:async()=>e?e(await r.text()):r.json(),arrayBuffer:()=>r.arrayBuffer(),blob:()=>r.blob(),formData:()=>r.formData(),text:()=>r.text()}),P=(r,e,t)=>{let o=O(r,t);if(!Object.hasOwn(o,e))throw new Error(`Invalid response type: ${e}`);return o[e]()},k=r=>{let{options:e,response:t,successData:o}=r,s={data:o,errorInfo:null,response:t};return e.resultMode===void 0||e.resultMode==="all"?s:{onlySuccess:s.data,onlyError:s.errorInfo,onlyResponse:s.response}[e.resultMode]},h=r=>{let{error:e,options:t}=r;return (s={})=>{let{errorData:n,message:i,response:d$1}=s;if(d(t.throwOnError)?t.throwOnError(e):t.throwOnError)throw e;return {data:null,error:{errorName:e?.name??"UnknownError",errorData:n??e,message:i??e?.message??t.defaultErrorMessage},response:d$1??null}}},A=r=>c$1(r)&&r.errorName==="HTTPError",c=class extends Error{response;errorData;name="HTTPError";isHTTPError=!0;constructor(e,t){let{defaultErrorMessage:o,response:s,errorData:n}=e;super(n.message??o,t),this.errorData=n,this.response=s;}},D=r=>r instanceof c||c$1(r)&&r.name==="HTTPError"&&r.isHTTPError===!0,C=r=>{if(r===0)return;let{promise:e,resolve:t}=Promise.withResolvers();return setTimeout(t,r),e};
3
+ var E=r=>r?new URLSearchParams(r).toString():(console.error("No query params provided"),null),b=(r,e)=>{if(!e)return r;let t=E(e);return r.includes("?")&&!r.endsWith("?")?`${r}&${t}`:r.endsWith("?")?`${r}${t}`:`${r}?${t}`},g=r=>!r||c$1(r)?r:Object.fromEntries(a(r)?r:r.entries()),y={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"},x=Object.keys(y).map(Number),j=["GET"],l=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],T=(r,e)=>{let t=Object.entries(r).filter(([s])=>!e.includes(s));return Object.fromEntries(t)},R=(r,e)=>{let t=new Set(e),s=Object.entries(r).filter(([i])=>t.has(i));return Object.fromEntries(s)},w=r=>[R(r,l),T(r,l)],O=(r,e)=>({json:async()=>e?e(await r.text()):r.json(),arrayBuffer:()=>r.arrayBuffer(),blob:()=>r.blob(),formData:()=>r.formData(),text:()=>r.text()}),P=(r,e,t)=>{let o=O(r,t);if(!Object.hasOwn(o,e))throw new Error(`Invalid response type: ${e}`);return o[e]()},k=r=>{let{options:e,response:t,successData:o}=r,s={data:o,errorInfo:null,response:t};return e.resultMode===void 0||e.resultMode==="all"?s:{onlySuccess:s.data,onlyError:s.errorInfo,onlyResponse:s.response}[e.resultMode]},h=r=>{let{error:e,options:t}=r;return (s={})=>{let{errorData:n,message:i,response:d$1}=s;if(d(t.throwOnError)?t.throwOnError(e):t.throwOnError)throw e;return {data:null,error:{name:e?.name??"UnknownError",errorData:n??e,message:i??e?.message??t.defaultErrorMessage},response:d$1??null}}},A=r=>c$1(r)&&r.name==="HTTPError",c=class extends Error{response;errorData;name="HTTPError";isHTTPError=!0;constructor(e,t){let{defaultErrorMessage:o,response:s,errorData:n}=e;super(n.message??o,t),this.errorData=n,this.response=s;}},D=r=>r instanceof c||c$1(r)&&r.name==="HTTPError"&&r.isHTTPError===!0,C=r=>{if(r===0)return;let{promise:e,resolve:t}=Promise.withResolvers();return setTimeout(t,r),e};
4
4
 
5
5
  export { E as a, b, g as c, x as d, j as e, l as f, w as g, O as h, P as i, k as j, h as k, A as l, c as m, D as n, C as o };
6
6
  //# sourceMappingURL=out.js.map
7
- //# sourceMappingURL=chunk-W6T7K2ZN.js.map
7
+ //# sourceMappingURL=chunk-ON3SY4EX.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils.ts"],"names":["toQueryString","params","mergeUrlWithParams","url","paramsString","objectifyHeaders","headers","isObject","isArray","retryCodesLookup","defaultRetryCodes","defaultRetryMethods","fetchSpecificKeys","omitKeys","initialObject","keysToOmit","arrayFromFilteredObject","key","pickKeys","keysToPick","keysToPickSet","filteredArray","objectKey","splitConfig","config","handleResponseType","response","parser","getResponseData","responseType","RESPONSE_TYPE_LOOKUP","resolveSuccessResult","info","options","successData","apiDetails","$resolveErrorResult","$info","error","errorData","message","isFunction","isHTTPError","HTTPError","errorDetails","errorOptions","defaultErrorMessage","isHTTPErrorInstance","waitUntil","delay","promise","resolve"],"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: Required<ExtraOptions>[\"query\"]): string;\n\t(params: ExtraOptions[\"query\"]): string | null;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"No query params provided\");\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.includes(\"?\") && !url.endsWith(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\tif (url.endsWith(\"?\")) {\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\terrorInfo: 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.errorInfo,\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 $resolveErrorResult = <CallApiResult>($info: { error?: unknown; options: ExtraOptions }) => {\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\terrorName: (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.errorName === \"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"]}
1
+ {"version":3,"sources":["../../src/utils.ts"],"names":["toQueryString","params","mergeUrlWithParams","url","paramsString","objectifyHeaders","headers","isObject","isArray","retryCodesLookup","defaultRetryCodes","defaultRetryMethods","fetchSpecificKeys","omitKeys","initialObject","keysToOmit","arrayFromFilteredObject","key","pickKeys","keysToPick","keysToPickSet","filteredArray","objectKey","splitConfig","config","handleResponseType","response","parser","getResponseData","responseType","RESPONSE_TYPE_LOOKUP","resolveSuccessResult","info","options","successData","apiDetails","$resolveErrorResult","$info","error","errorData","message","isFunction","isHTTPError","HTTPError","errorDetails","errorOptions","defaultErrorMessage","isHTTPErrorInstance","waitUntil","delay","promise","resolve"],"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: Required<ExtraOptions>[\"query\"]): string;\n\t(params: ExtraOptions[\"query\"]): string | null;\n};\n\nexport const toQueryString: ToQueryStringFn = (params) => {\n\tif (!params) {\n\t\tconsole.error(\"No query params provided\");\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.includes(\"?\") && !url.endsWith(\"?\")) {\n\t\treturn `${url}&${paramsString}`;\n\t}\n\n\tif (url.endsWith(\"?\")) {\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\terrorInfo: 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.errorInfo,\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 $resolveErrorResult = <CallApiResult>($info: { error?: unknown; options: ExtraOptions }) => {\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"]}
@@ -1,4 +1,4 @@
1
- import { R as ResultModeUnion, B as BaseConfig, F as FetchConfig, G as GetCallApiResult } from './types-BbqJOcbJ.js';
1
+ import { R as ResultModeUnion, B as BaseConfig, F as FetchConfig, G as GetCallApiResult } from './types-Bjfr6g7f.js';
2
2
  import './type-helpers-Dibitydy.js';
3
3
 
4
4
  declare const createFetchClient: <TBaseData, TBaseErrorData, TBaseResultMode extends ResultModeUnion = undefined>(baseConfig?: BaseConfig<TBaseData, TBaseErrorData, TBaseResultMode>) => {
@@ -1,5 +1,5 @@
1
- export { b as callApi, a as createFetchClient } from './chunk-LO64E2L2.js';
2
- import './chunk-W6T7K2ZN.js';
1
+ export { b as callApi, a as createFetchClient } from './chunk-FIQCUJN4.js';
2
+ import './chunk-ON3SY4EX.js';
3
3
  import './chunk-3E33QJL5.js';
4
4
  //# sourceMappingURL=out.js.map
5
5
  //# sourceMappingURL=createFetchClient.js.map
@@ -1,3 +1,3 @@
1
1
  export { callApi, createFetchClient } from './createFetchClient.js';
2
- export { $ as $RequestOptions, E as ExtraOptions, F as FetchConfig, H as HTTPError, a as ResponseContext, b as ResponseErrorContext, i as isHTTPError, c as isHTTPErrorInstance, t as toQueryString } from './types-BbqJOcbJ.js';
2
+ export { $ as $RequestOptions, E as ExtraOptions, F as FetchConfig, H as HTTPError, a as ResponseContext, b as ResponseErrorContext, i as isHTTPError, c as isHTTPErrorInstance, t as toQueryString } from './types-Bjfr6g7f.js';
3
3
  import './type-helpers-Dibitydy.js';
package/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { b as callApi, a as createFetchClient } from './chunk-LO64E2L2.js';
2
- export { m as HTTPError, l as isHTTPError, n as isHTTPErrorInstance, a as toQueryString } from './chunk-W6T7K2ZN.js';
1
+ export { b as callApi, a as createFetchClient } from './chunk-FIQCUJN4.js';
2
+ export { m as HTTPError, l as isHTTPError, n as isHTTPErrorInstance, a as toQueryString } from './chunk-ON3SY4EX.js';
3
3
  import './chunk-3E33QJL5.js';
4
4
  //# sourceMappingURL=out.js.map
5
5
  //# sourceMappingURL=index.js.map
@@ -34,7 +34,7 @@ declare const $resolveErrorResult: <CallApiResult>($info: {
34
34
  message?: string;
35
35
  }) => CallApiResult;
36
36
  declare const isHTTPError: <TErrorData>(error: ApiErrorVariant<TErrorData>["error"] | null) => error is {
37
- errorName: "HTTPError";
37
+ name: "HTTPError";
38
38
  errorData: TErrorData;
39
39
  message: string;
40
40
  };
@@ -213,11 +213,13 @@ type ApiSuccessVariant<TData> = {
213
213
  error: null;
214
214
  response: Response;
215
215
  };
216
- type PossibleErrorNames = "AbortError" | "TimeoutError" | "SyntaxError" | "TypeError" | "Error" | "UnknownError";
216
+ type PossibleErrorNames = {
217
+ _: "AbortError" | "TimeoutError" | "SyntaxError" | "TypeError" | "Error" | "UnknownError";
218
+ }["_"];
217
219
  type ApiErrorVariant<TErrorData> = {
218
220
  data: null;
219
221
  error: {
220
- errorName: "HTTPError";
222
+ name: "HTTPError";
221
223
  errorData: TErrorData;
222
224
  message: string;
223
225
  };
@@ -225,7 +227,7 @@ type ApiErrorVariant<TErrorData> = {
225
227
  } | {
226
228
  data: null;
227
229
  error: {
228
- errorName: PossibleErrorNames;
230
+ name: PossibleErrorNames;
229
231
  errorData: Error;
230
232
  message: string;
231
233
  };
@@ -1,2 +1,2 @@
1
- export { j as $resolveErrorResult, H as HTTPError, d as defaultRetryCodes, e as defaultRetryMethods, f as fetchSpecificKeys, g as getResponseData, h as handleResponseType, i as isHTTPError, c as isHTTPErrorInstance, m as mergeUrlWithParams, o as objectifyHeaders, r as resolveSuccessResult, s as splitConfig, t as toQueryString, w as waitUntil } from './types-BbqJOcbJ.js';
1
+ export { j as $resolveErrorResult, H as HTTPError, d as defaultRetryCodes, e as defaultRetryMethods, f as fetchSpecificKeys, g as getResponseData, h as handleResponseType, i as isHTTPError, c as isHTTPErrorInstance, m as mergeUrlWithParams, o as objectifyHeaders, r as resolveSuccessResult, s as splitConfig, t as toQueryString, w as waitUntil } from './types-Bjfr6g7f.js';
2
2
  import './type-helpers-Dibitydy.js';
package/dist/esm/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- export { k as $resolveErrorResult, m as HTTPError, d as defaultRetryCodes, e as defaultRetryMethods, f as fetchSpecificKeys, i as getResponseData, h as handleResponseType, l as isHTTPError, n as isHTTPErrorInstance, b as mergeUrlWithParams, c as objectifyHeaders, j as resolveSuccessResult, g as splitConfig, a as toQueryString, o as waitUntil } from './chunk-W6T7K2ZN.js';
1
+ export { k as $resolveErrorResult, m as HTTPError, d as defaultRetryCodes, e as defaultRetryMethods, f as fetchSpecificKeys, i as getResponseData, h as handleResponseType, l as isHTTPError, n as isHTTPErrorInstance, b as mergeUrlWithParams, c as objectifyHeaders, j as resolveSuccessResult, g as splitConfig, a as toQueryString, o as waitUntil } from './chunk-ON3SY4EX.js';
2
2
  import './chunk-3E33QJL5.js';
3
3
  //# sourceMappingURL=out.js.map
4
4
  //# sourceMappingURL=utils.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zayne-labs/callapi",
3
- "version": "0.3.4",
3
+ "version": "0.4.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/cjs/index.cjs",
@@ -50,7 +50,7 @@
50
50
  "lint-staged": "^15.2.7",
51
51
  "prettier": "^3.3.2",
52
52
  "tsup": "^8.1.0",
53
- "typescript": "5.5.2",
53
+ "typescript": "5.5.3",
54
54
  "typescript-eslint": "^7.13.1"
55
55
  },
56
56
  "scripts": {