@zayne-labs/callapi 1.1.0 → 1.2.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.
@@ -100,6 +100,48 @@ type CallApiPlugin<TData = unknown, TErrorData = unknown> = {
100
100
  };
101
101
  declare const definePlugin: <TPlugin extends CallApiPlugin<never, never> | AnyFunction<CallApiPlugin<never, never>>>(plugin: TPlugin) => TPlugin;
102
102
 
103
+ type RetryCondition<TErrorData> = (context: ErrorContext<TErrorData>) => boolean | Promise<boolean>;
104
+ interface RetryOptions<TErrorData> {
105
+ /**
106
+ * @description Number of allowed retry attempts on HTTP errors
107
+ * @default 0
108
+ */
109
+ retryAttempts?: number;
110
+ /**
111
+ * @description HTTP status codes that trigger a retry
112
+ * @default [409, 425, 429, 500, 502, 503, 504]
113
+ */
114
+ retryCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>;
115
+ /**
116
+ * @description Callback whose return value determines if a request should be retried or not
117
+ */
118
+ retryCondition?: RetryCondition<TErrorData>;
119
+ /**
120
+ * @description Keeps track of the number of times the request has already been retried
121
+ */
122
+ retryCount?: number;
123
+ /**
124
+ * @description Delay between retries in milliseconds
125
+ * @default 1000
126
+ */
127
+ retryDelay?: number;
128
+ /**
129
+ * @description Maximum delay in milliseconds. Only applies to exponential strategy
130
+ * @default 10000
131
+ */
132
+ retryMaxDelay?: number;
133
+ /**
134
+ * HTTP methods that are allowed to retry
135
+ * @default ["GET", "POST"]
136
+ */
137
+ retryMethods?: Array<"GET" | "POST" | AnyString>;
138
+ /**
139
+ * @description Strategy to use when retrying
140
+ * @default "linear"
141
+ */
142
+ retryStrategy?: "exponential" | "linear";
143
+ }
144
+
103
145
  type ToQueryStringFn = {
104
146
  (params: CallApiConfig["query"]): string | null;
105
147
  (params: Required<CallApiConfig>["query"]): string;
@@ -139,6 +181,10 @@ interface CallApiRequestOptions extends Pick<RequestInit, FetchSpecificKeysUnion
139
181
  * @description Optional body of the request, can be a object or any other supported body type.
140
182
  */
141
183
  body?: Record<string, unknown> | RequestInit["body"];
184
+ /**
185
+ * @description Resolved request URL
186
+ */
187
+ readonly fullURL?: string;
142
188
  /**
143
189
  * @description Headers to be used in the request.
144
190
  */
@@ -150,10 +196,6 @@ interface CallApiRequestOptions extends Pick<RequestInit, FetchSpecificKeysUnion
150
196
  method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT" | AnyString;
151
197
  }
152
198
  interface CallApiRequestOptionsForHooks extends CallApiRequestOptions {
153
- /**
154
- * @description Resolved request URL
155
- */
156
- readonly fullURL?: string;
157
199
  headers?: Record<CommonRequestHeaders | AnyString, string>;
158
200
  }
159
201
  interface Register {
@@ -163,62 +205,42 @@ type R_Meta = Register extends {
163
205
  } ? TMeta : never;
164
206
  interface Interceptors<TData = unknown, TErrorData = unknown> {
165
207
  /**
166
- * @description Interceptor to be called when any error occurs within the request/response lifecyle, regardless of whether the error is from the api or not.
208
+ * @description Interceptor that will be called when any error occurs within the request/response lifecyle, regardless of whether the error is from the api or not.
167
209
  * It is basically a combination of `onRequestError` and `onResponseError` interceptors
168
210
  */
169
211
  onError?: (context: ErrorContext<TErrorData>) => Awaitable<unknown>;
170
212
  /**
171
- * @description Interceptor to be called just before the request is made, allowing for modifications or additional operations.
213
+ * @description Interceptor that will be called just before the request is made, allowing for modifications or additional operations.
172
214
  */
173
215
  onRequest?: (context: RequestContext) => Awaitable<unknown>;
174
216
  /**
175
- * @description Interceptor to be called when an error occurs during the fetch request.
217
+ * @description Interceptor that will be called when an error occurs during the fetch request.
176
218
  */
177
219
  onRequestError?: (context: RequestErrorContext) => Awaitable<unknown>;
178
220
  /**
179
- * @description Interceptor to be called when any response is received from the api, whether successful or not
221
+ * @description Interceptor that will be called when any response is received from the api, whether successful or not
180
222
  */
181
223
  onResponse?: (context: ResponseContext<TData, TErrorData>) => Awaitable<unknown>;
182
224
  /**
183
- * @description Interceptor to be called when an error response is received from the api.
225
+ * @description Interceptor that will be called when an error response is received from the api.
184
226
  */
185
227
  onResponseError?: (context: ResponseErrorContext<TErrorData>) => Awaitable<unknown>;
186
228
  /**
187
- * @description Interceptor to be called when a successful response is received from the api.
188
- */
189
- onSuccess?: (context: SuccessContext<TData>) => Awaitable<unknown>;
190
- }
191
- interface InterceptorsArray<TData = unknown, TErrorData = unknown> {
192
- /**
193
- * @description Interceptor to be called when any error occurs within the request/response lifecyle, regardless of whether the error is from the api or not.
194
- * It is basically a combination of `onRequestError` and `onResponseError` interceptors
195
- */
196
- onError?: Array<Interceptors<TData, TErrorData>["onError"]>;
197
- /**
198
- * @description Interceptor to be called just before the request is made, allowing for modifications or additional operations.
199
- */
200
- onRequest?: Array<Interceptors<TData, TErrorData>["onRequest"]>;
201
- /**
202
- * @description Interceptor to be called when an error occurs during the fetch request.
203
- */
204
- onRequestError?: Array<Interceptors<TData, TErrorData>["onRequestError"]>;
205
- /**
206
- * @description Interceptor to be called when any response is received from the api, whether successful or not
229
+ * @description Interceptor that will be called when a request is retried.
207
230
  */
208
- onResponse?: Array<Interceptors<TData, TErrorData>["onResponse"]>;
231
+ onRetry?: (response: ErrorContext<TErrorData>) => Awaitable<unknown>;
209
232
  /**
210
- * @description Interceptor to be called when an error response is received from the api.
233
+ * @description Interceptor that will be called when a successful response is received from the api.
211
234
  */
212
- onResponseError?: Array<Interceptors<TData, TErrorData>["onResponseError"]>;
213
- /**
214
- * @description Interceptor to be called when a successful response is received from the api.
215
- */
216
- onSuccess?: Array<Interceptors<TData, TErrorData>["onSuccess"]>;
235
+ onSuccess?: (context: SuccessContext<TData>) => Awaitable<unknown>;
217
236
  }
237
+ type InterceptorsArray<TData = unknown, TErrorData = unknown> = {
238
+ [Key in keyof Interceptors<TData, TErrorData>]: Array<Interceptors<TData, TErrorData>[Key]>;
239
+ };
240
+ type InterceptorsOrInterceptorsArray<TData, TErrorData> = Interceptors<TData, TErrorData> | InterceptorsArray<TData, TErrorData>;
218
241
  type FetchImpl = UnmaskType<(input: string | Request | URL, init?: RequestInit) => Promise<Response>>;
219
242
  type CallApiPluginArray<TData, TErrorData> = Array<CallApiPlugin<TData, TErrorData>>;
220
- type CallApiPluginFn<TData, TErrorData> = (context: PluginInitContext<TData, TErrorData>) => Array<CallApiPlugin<TData, TErrorData>>;
221
- type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends CallApiResultModeUnion = CallApiResultModeUnion> = (Interceptors<TData, TErrorData> | InterceptorsArray<TData, TErrorData>) & {
243
+ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends CallApiResultModeUnion = CallApiResultModeUnion> = InterceptorsOrInterceptorsArray<TData, TErrorData> & RetryOptions<TErrorData> & {
222
244
  /**
223
245
  * @description Authorization header value.
224
246
  */
@@ -266,17 +288,17 @@ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends Cal
266
288
  */
267
289
  readonly initURL?: string;
268
290
  /**
269
- * @description Defines the mode in which the merged interceptors are executed, can be set to "parallel" | "sequential".
270
- * - If set to "parallel", both plugin and main interceptors will be executed in parallel.
271
- * - If set to "sequential", the plugin interceptors will be executed first, followed by the main interceptor.
291
+ * @description Defines the mode in which the merged hooks are executed, can be set to "parallel" | "sequential".
292
+ * - If set to "parallel", main and plugin hooks will be executed in parallel.
293
+ * - If set to "sequential", the plugin hooks will be executed first, followed by the main hook.
272
294
  * @default "parallel"
273
295
  */
274
- mergedInterceptorsExecutionMode?: "parallel" | "sequential";
296
+ mergedHooksExecutionMode?: "parallel" | "sequential";
275
297
  /**
276
- * @description - Controls what order in which the mergedInterceptors execute
277
- * @default "mainInterceptorLast"
298
+ * @description - Controls what order in which the merged hooks execute
299
+ * @default "mainHooksLast"
278
300
  */
279
- mergedInterceptorsExecutionOrder?: "mainInterceptorFirst" | "mainInterceptorLast";
301
+ mergedHooksExecutionOrder?: "mainHooksFirst" | "mainHooksLast";
280
302
  /**
281
303
  * @description - An optional field you can fill with additional information,
282
304
  * to associate with the request, typically used for logging or tracing.
@@ -308,7 +330,7 @@ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends Cal
308
330
  /**
309
331
  * @description An array of CallApi plugins. It allows you to extend the behavior of the library.
310
332
  */
311
- plugins?: CallApiPluginArray<TData, TErrorData>;
333
+ plugins?: CallApiPluginArray<TData, TErrorData> | ((context: PluginInitContext<TData, TErrorData>) => CallApiPluginArray<TData, TErrorData>);
312
334
  /**
313
335
  * @description Query parameters to append to the URL.
314
336
  */
@@ -336,27 +358,7 @@ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends Cal
336
358
  * Can be set to "all" | "onlySuccess" | "onlyError" | "onlyResponse".
337
359
  * @default "all"
338
360
  */
339
- resultMode?: TResultMode;
340
- /**
341
- * @description Number of retry attempts for failed requests
342
- * @default 0
343
- */
344
- retryAttempts?: number;
345
- /**
346
- * @description HTTP status codes that trigger a retry
347
- * @default [409, 425, 429, 500, 502, 503, 504]
348
- */
349
- retryCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>;
350
- /**
351
- * @description Delay between retries in milliseconds
352
- * @default 500
353
- */
354
- retryDelay?: number;
355
- /**
356
- * HTTP methods that are allowed to retry
357
- * @default ["GET", "POST"]
358
- */
359
- retryMethods?: Array<"GET" | "POST" | AnyString>;
361
+ resultMode?: TErrorData extends false ? "onlySuccessWithException" : TResultMode | undefined;
360
362
  /**
361
363
  * If true or the function returns true, throws errors instead of returning them
362
364
  * The function is passed the error object and can be used to conditionally throw the error
@@ -368,23 +370,15 @@ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends Cal
368
370
  */
369
371
  timeout?: number;
370
372
  };
371
- declare const optionsEnumToOmitFromBase: ["extend", "override", "dedupeKey"];
373
+ declare const optionsEnumToOmitFromBase: ["extend", "dedupeKey"];
372
374
  interface BaseCallApiExtraOptions<TBaseData = unknown, TBaseErrorData = unknown, TBaseResultMode extends CallApiResultModeUnion = CallApiResultModeUnion> extends Omit<CallApiExtraOptions<TBaseData, TBaseErrorData, TBaseResultMode>, typeof optionsEnumToOmitFromBase[number]> {
373
- /**
374
- * @description An array of CallApi plugins. It allows you to extend the behavior of the library.
375
- */
376
- plugins?: CallApiPluginArray<TBaseData, TBaseErrorData> | CallApiPluginFn<TBaseData, TBaseErrorData>;
377
375
  }
378
- declare const optionsEnumToOmitFromInstance: ["plugins"];
379
- interface CallApiExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends CallApiResultModeUnion = CallApiResultModeUnion> extends Omit<ExtraOptions<TData, TErrorData, TResultMode>, (typeof optionsEnumToOmitFromInstance)[number]> {
376
+ declare const optionsEnumToExtendFromBase: "plugins"[];
377
+ interface CallApiExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends CallApiResultModeUnion = CallApiResultModeUnion> extends Omit<ExtraOptions<TData, TErrorData, TResultMode>, never> {
380
378
  /**
381
379
  * @description Options that should extend the base options.
382
380
  */
383
- extend?: Pick<ExtraOptions<TData, TErrorData, TResultMode>, (typeof optionsEnumToOmitFromInstance)[number]>;
384
- /**
385
- * @description Options that should override the base options.
386
- */
387
- override?: Pick<ExtraOptions<TData, TErrorData, TResultMode>, (typeof optionsEnumToOmitFromInstance)[number]>;
381
+ extend?: Pick<ExtraOptions<TData, TErrorData, TResultMode>, typeof optionsEnumToExtendFromBase[number]>;
388
382
  }
389
383
  interface CombinedCallApiExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends CallApiResultModeUnion = CallApiResultModeUnion> extends BaseCallApiExtraOptions<TData, TErrorData, TResultMode>, CallApiExtraOptions<TData, TErrorData, TResultMode> {
390
384
  }
@@ -466,9 +460,9 @@ type CallApiResultErrorVariant<TErrorData> = {
466
460
  };
467
461
  type ResultModeMap<TData = unknown, TErrorData = unknown> = {
468
462
  all: CallApiResultSuccessVariant<TData> | CallApiResultErrorVariant<TErrorData>;
469
- onlyError: CallApiResultErrorVariant<TErrorData>["error"] | null;
470
- onlyResponse: CallApiResultSuccessVariant<TData>["response"] | null;
471
- onlySuccess: CallApiResultSuccessVariant<TData>["data"] | null;
463
+ onlyError: CallApiResultErrorVariant<TErrorData>["error"] | CallApiResultSuccessVariant<TData>["error"];
464
+ onlyResponse: CallApiResultErrorVariant<TErrorData>["response"] | CallApiResultSuccessVariant<TData>["response"];
465
+ onlySuccess: CallApiResultErrorVariant<TErrorData>["data"] | CallApiResultSuccessVariant<TData>["data"];
472
466
  onlySuccessWithException: CallApiResultSuccessVariant<TData>["data"];
473
467
  };
474
468
  type CallApiResultModeUnion = {
@@ -1 +1 @@
1
- "use strict";var e,r=Object.defineProperty,o=Object.getOwnPropertyDescriptor,t=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,n={};((e,o)=>{for(var t in o)r(e,t,{get:o[t],enumerable:!0})})(n,{callApi:()=>I,createFetchClient:()=>P,definePlugin:()=>p}),module.exports=(e=n,((e,n,a,i)=>{if(n&&"object"==typeof n||"function"==typeof n)for(let u of t(n))s.call(e,u)||u===a||r(e,u,{get:()=>n[u],enumerable:!(i=o(n,u))||i.enumerable});return e})(r({},"__esModule",{value:!0}),e));var a=e=>Array.isArray(e),i=e=>{if(!(e=>"object"==typeof e&&null!==e)(e))return!1;const r=Object.getPrototypeOf(e);return(null==r||r===Object.prototype||null===Object.getPrototypeOf(r))&&!(Symbol.toStringTag in e)},u=e=>"function"==typeof e,l=e=>"string"==typeof e,c=async e=>{const{initURL:r,options:o,request:t}=e,s={onError:new Set([]),onRequest:new Set([]),onRequestError:new Set([]),onResponse:new Set([]),onResponseError:new Set([]),onSuccess:new Set([])},n=()=>{s.onRequest.add(o.onRequest),s.onRequestError.add(o.onRequestError),s.onResponse.add(o.onResponse),s.onResponseError.add(o.onResponseError),s.onSuccess.add(o.onSuccess),s.onError.add(o.onError)};"mainInterceptorFirst"===o.mergedInterceptorsExecutionOrder&&n();const a=u(o.plugins)?[o.plugins({initURL:r,options:o,request:t}),o.extend?.plugins??[]].flat():[o.plugins??[],o.extend?.plugins??[]].flat();let c=r,p=o,d=t;const f=async e=>{if(!e)return;const s=await e({initURL:r,options:o,request:t});i(s)&&(l(s.url)&&(c=s.url),i(s.request)&&(d=s.request),i(s.options)&&(p=s.options))};for(const e of o.override?.plugins??a)await f(e.init),e.hooks&&(y=e.hooks,s.onRequest.add(y.onRequest),s.onRequestError.add(y.onRequestError),s.onResponse.add(y.onResponse),s.onResponseError.add(y.onResponseError),s.onSuccess.add(y.onSuccess),s.onError.add(y.onError));var y;o.mergedInterceptorsExecutionOrder&&"mainInterceptorLast"!==o.mergedInterceptorsExecutionOrder||n();const m=e=>{const r=((e,r)=>async o=>{if("sequential"!==r){if("parallel"===r){const r=[...e];await Promise.all(r.map((e=>e?.(o))))}}else for(const r of e)await(r?.(o))})(e,o.mergedInterceptorsExecutionMode);return r};return{interceptors:{onError:m([...s.onError].flat()),onRequest:m([...s.onRequest].flat()),onRequestError:m([...s.onRequestError].flat()),onResponse:m([...s.onResponse].flat()),onResponseError:m([...s.onResponseError].flat()),onSuccess:m([...s.onSuccess].flat())},resolvedOptions:p,resolvedRequestOptions:d,url:c}},p=e=>e,d=e=>u(e)?e():e,f=e=>{if(void 0!==e){if(l(e)||null===e)return{Authorization:`Bearer ${e}`};switch(e.type){case"Basic":{const r=d(e.username),o=d(e.password);if(void 0===r||void 0===o)return;return{Authorization:`Basic ${globalThis.btoa(`${r}:${o}`)}`}}case"Custom":{const r=d(e.value);if(void 0===r)return;return{Authorization:`${d(e.prefix)} ${r}`}}default:{const r=d(e.bearer),o=d(e.token);return"token"in e&&void 0!==o?{Authorization:`Token ${o}`}:void 0!==r&&{Authorization:`Bearer ${r}`}}}}},y=["extend","override","dedupeKey"],m=["plugins"],E=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],R={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"},g=["GET"],h=Object.keys(R).map(Number),w=(e,r)=>{const o={},t=new Set(r);for(const[r,s]of Object.entries(e))t.has(r)||(o[r]=s);return o},b=(e,r)=>{const o={},t=new Set(r);for(const[r,s]of Object.entries(e))t.has(r)&&(o[r]=s);return o},q=e=>!e||i(e)?e:Object.fromEntries(e),S=e=>{const{auth:r,baseHeaders:o,body:t,headers:s}=e;if(!Boolean(o||s||t||r))return;const n={...f(r),...q(o),...q(s)};return l(a=t)&&a.includes("=")?(n["Content-Type"]="application/x-www-form-urlencoded",n):((i(t)||l(t)&&t.startsWith("{"))&&(n["Content-Type"]="application/json",n.Accept="application/json"),n);var a},v=(e,r)=>a(e)?[e,r].flat():r??e,O=(...e)=>Promise.all(e),T=async(e,r,o,t)=>{const s=((e,r)=>({arrayBuffer:()=>e.arrayBuffer(),blob:()=>e.blob(),formData:()=>e.formData(),json:async()=>{if(r){const o=await e.text();return r(o)}return e.json()},stream:()=>e.body,text:()=>e.text()}))(e,o);if(!Object.hasOwn(s,r))throw new Error(`Invalid response type: ${r}`);const n=await s[r]();return t?t(n):n},M=e=>{const{defaultErrorMessage:r,error:o,message:t,resultMode:s}=e;let n={data:null,error:{errorData:o,message:t??o.message,name:o.name},response:null};if(j(o)){const{errorData:e,message:t=r,name:s,response:a}=o;n={data:null,error:{errorData:e,message:t,name:s},response:a}}return{apiDetails:n,generalErrorResult:{all:n,onlyError:n.error,onlyResponse:n.response,onlySuccess:n.data,onlySuccessWithException:n.data}[s??"all"],resolveCustomErrorInfo:({message:r})=>M({...e,message:r}).generalErrorResult}},$=class extends Error{errorData;isHTTPError=!0;name="HTTPError";response;constructor(e,r){const{defaultErrorMessage:o,errorData:t,response:s}=e;super(t?.message??o,r),this.errorData=t,this.response=s,Error.captureStackTrace(this,this.constructor)}},j=e=>e instanceof $||i(e)&&"HTTPError"===e.name&&!0===e.isHTTPError,x=e=>{if(0===e)return;const{promise:r,resolve:o}=(()=>{let e,r;return{promise:new Promise(((o,t)=>{r=o,e=t})),reject:e,resolve:r}})();return setTimeout(o,e),r},D=(e,r)=>{if(!r)return e;const o=(t=r)?new URLSearchParams(t).toString():(console.error("toQueryString:","No query params provided!"),null);var t;return 0===o?.length?e:e.endsWith("?")?`${e}${o}`:e.includes("?")?`${e}&${o}`:`${e}?${o}`},A=(e,r,o)=>{const t=((e,r)=>{if(!r)return e;let o=e;if(a(r)){const e=o.split("/").filter((e=>e.startsWith(":")));for(const[t,s]of e.entries()){const e=r[t];o=o.replace(s,e)}return o}for(const[e,t]of Object.entries(r))o=o.replace(`:${e}`,String(t));return o})(e,r);return D(t,o)},P=(e={})=>{const[r,o]=(e=>[b(e,E),w(e,[...E,...y])])(e),{body:t,headers:s,signal:n,...a}=r,l=new Map,p=async(...e)=>{const[r,d]=e,[f,y]=(e=>[b(e,E),w(e,[...E,...m])])(d??{}),{body:R=t,headers:q,signal:D=n,...P}=f,I={baseURL:"",bodySerializer:JSON.stringify,dedupeStrategy:"cancel",defaultErrorMessage:"Failed to fetch data from server!",mergedInterceptorsExecutionMode:"parallel",mergedInterceptorsExecutionOrder:"mainInterceptorLast",responseType:"json",resultMode:"all",retryAttempts:0,retryCodes:h,retryDelay:0,retryMethods:g,...o,...y,onError:v(o.onError,y.onError),onRequest:v(o.onRequest,y.onRequest),onRequestError:v(o.onRequestError,y.onRequestError),onResponse:v(o.onResponse,y.onResponse),onResponseError:v(o.onResponseError,y.onResponseError),onSuccess:v(o.onSuccess,y.onSuccess)},{interceptors:k,resolvedOptions:L,resolvedRequestOptions:C,url:U}=await c({initURL:r,options:I,request:{...a,...P}}),B={...L,...k,initURL:r},H={body:i(R)?B.bodySerializer(R):R,method:"GET",...C},z=`${B.baseURL}${A(U,B.params,B.query)}`,N="cancel"===B.dedupeStrategy||"defer"===B.dedupeStrategy,K=B.dedupeKey??((e,r)=>r.shouldHaveDedupeKey?`${e}-${JSON.stringify(r)}`:null)(z,{shouldHaveDedupeKey:N,...C,...B});null!=K&&await x(.1);const W=null!=K?l:null,F=W?.get(K);if(F&&"cancel"===B.dedupeStrategy){const e=B.dedupeKey?`Duplicate request detected - Aborting previous request with key '${K}' as a new request was initiated`:`Duplicate request detected - Aborting previous request to '${z}' as a new request with identical options was initiated`,r=new DOMException(e,"AbortError");F.controller.abort(r)}const G=new AbortController,J=null!=B.timeout?(V=B.timeout,AbortSignal.timeout(V)):null;var V;const _=((...e)=>AbortSignal.any(e.filter(Boolean)))(G.signal,J,D),Q={fullURL:z,signal:_,...H},X=(e=>{if(e)return e;if("undefined"!=typeof globalThis&&u(globalThis.fetch))return globalThis.fetch;throw new Error("No fetch implementation found")})(B.customFetchImpl);try{await O(B.onRequest({options:B,request:Q})),Q.headers=S({auth:B.auth,baseHeaders:s??q,body:R,headers:Q.headers});const e=F&&"defer"===B.dedupeStrategy?F.responsePromise:X(z,Q);W?.set(K,{controller:G,responsePromise:e});const o=await e;if(!o.ok&&!_.aborted&&B.retryAttempts>0&&B.retryCodes.includes(o.status)&&B.retryMethods.includes(Q.method))return await x(B.retryDelay),await p(r,{...d,retryAttempts:B.retryAttempts-1});const t="defer"===B.dedupeStrategy||"onlyResponse"===B.resultMode||B.cloneResponse;if(!o.ok){const e=await T(t?o.clone():o,B.responseType,B.responseParser,B.responseErrorValidator);throw new $({defaultErrorMessage:B.defaultErrorMessage,errorData:e,response:o})}const n=await T(t?o.clone():o,B.responseType,B.responseParser,B.responseValidator);return await O(B.onSuccess({data:n,options:B,request:Q,response:B.cloneResponse?o.clone():o}),B.onResponse({data:n,error:null,options:B,request:Q,response:B.cloneResponse?o.clone():o})),(e=>{const{data:r,response:o,resultMode:t}=e,s={data:r,error:null,response:o};return t?{all:s,onlyError:s.error,onlyResponse:s.response,onlySuccess:s.data,onlySuccessWithException:s.data}[t]:s})({data:n,response:o,resultMode:B.resultMode})}catch(e){const{apiDetails:r,generalErrorResult:o,resolveCustomErrorInfo:t}=M({defaultErrorMessage:B.defaultErrorMessage,error:e,resultMode:B.resultMode}),s=u(B.throwOnError)?B.throwOnError({error:r.error,options:B,request:Q,response:r.response}):B.throwOnError,n=()=>{if(s)throw r.error};if(j(e)){const{response:r}=e,t=o.error;return await O(B.onResponseError({error:t,options:B,request:Q,response:B.cloneResponse?r.clone():r}),B.onError({error:t,options:B,request:Q,response:B.cloneResponse?r.clone():r}),B.onResponse({data:null,error:t,options:B,request:Q,response:B.cloneResponse?r.clone():r})),n(),o}if(e instanceof DOMException&&"TimeoutError"===e.name){const r=`Request timed out after ${B.timeout}ms`;return console.error(`${e.name}:`,r),n(),t({message:r})}if(e instanceof DOMException&&"AbortError"===e.name){const{message:r,name:t}=e;return console.error(`${t}:`,r),n(),o}const a=o.error;return await O(B.onRequestError({error:a,options:B,request:Q}),B.onError({error:a,options:B,request:Q,response:null})),n(),o}finally{W?.delete(K)}};return p.create=P,p},I=P();//# 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:()=>H,createFetchClient:()=>A,definePlugin:()=>k}),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=>Array.isArray(e),i=e=>{if(!(e=>"object"==typeof e&&null!==e)(e))return!1;const r=Object.getPrototypeOf(e);return(null==r||r===Object.prototype||null===Object.getPrototypeOf(r))&&!(Symbol.toStringTag in e)},l=e=>"function"==typeof e,u=e=>"string"==typeof e,c=e=>l(e)?e():e,p=e=>{if(void 0!==e){if(u(e)||null===e)return{Authorization:`Bearer ${e}`};switch(e.type){case"Basic":{const r=c(e.username),t=c(e.password);if(void 0===r||void 0===t)return;return{Authorization:`Basic ${globalThis.btoa(`${r}:${t}`)}`}}case"Custom":{const r=c(e.value);if(void 0===r)return;return{Authorization:`${c(e.prefix)} ${r}`}}default:{const r=c(e.bearer),t=c(e.token);return"token"in e&&void 0!==t?{Authorization:`Token ${t}`}:void 0!==r&&{Authorization:`Bearer ${r}`}}}}},d=["extend","dedupeKey"],y=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],f={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"},m=["GET"],g=Object.keys(f).map(Number),w=(e,r)=>{const t={},o=new Set(r);for(const[r,s]of Object.entries(e))o.has(r)||(t[r]=s);return t},h=(e,r)=>{const t={},o=new Set(r);for(const[r,s]of Object.entries(e))o.has(r)&&(t[r]=s);return t},b=e=>!e||i(e)?e:Object.fromEntries(e),E=e=>{const{auth:r,baseHeaders:t,body:o,headers:s}=e;if(!Boolean(t||s||o||r))return;const n={...p(r),...b(t),...b(s)};return u(a=o)&&a.includes("=")?(n["Content-Type"]="application/x-www-form-urlencoded",n):((i(o)||u(o)&&o.startsWith("{"))&&(n["Content-Type"]="application/json",n.Accept="application/json"),n);var a},O=(...e)=>Promise.all(e),R=async(e,r,t,o)=>{const s=((e,r)=>({arrayBuffer:()=>e.arrayBuffer(),blob:()=>e.blob(),formData:()=>e.formData(),json:async()=>{if(r){const t=await e.text();return r(t)}return e.json()},stream:()=>e.body,text:()=>e.text()}))(e,t);if(!Object.hasOwn(s,r))throw new Error(`Invalid response type: ${r}`);const n=await s[r]();return o?o(n):n},S=e=>{const{defaultErrorMessage:r,error:t,message:o,resultMode:s}=e;let n={data:null,error:{errorData:t,message:o??t.message,name:t.name},response:null};if(v(t)){const{errorData:e,message:o=r,name:s,response:a}=t;n={data:null,error:{errorData:e,message:o,name:s},response:a}}return{apiDetails:n,generalErrorResult:{all:n,onlyError:n.error,onlyResponse:n.response,onlySuccess:n.data,onlySuccessWithException:n.data}[s??"all"],resolveCustomErrorInfo:({message:r})=>S({...e,message:r}).generalErrorResult}},q=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,Error.captureStackTrace(this,this.constructor)}},v=e=>e instanceof q||i(e)&&"HTTPError"===e.name&&!0===e.isHTTPError,T=e=>{if(0===e)return;const{promise:r,resolve:t}=(()=>{let e,r;return{promise:new Promise(((t,o)=>{r=t,e=o})),reject:e,resolve:r}})();return setTimeout(t,e),r},M=(e,r,t,o)=>{const s=(e=>{if(e)return e;if("undefined"!=typeof globalThis&&l(globalThis.fetch))return globalThis.fetch;throw new Error("No fetch implementation found")})(r.customFetchImpl);return o&&"defer"===r.dedupeStrategy?o.responsePromise:s(e,t)},j=(e,r)=>async t=>{if("sequential"!==r){if("parallel"===r){const r=[...e];await Promise.all(r.map((e=>e?.(t))))}}else for(const r of e)await(r?.(t))},$={onError:new Set,onRequest:new Set,onRequestError:new Set,onResponse:new Set,onResponseError:new Set,onRetry:new Set,onSuccess:new Set},k=e=>e,D=(e,r)=>{const t=e.retryCount??0;return{getDelay:()=>"exponential"===e.retryStrategy?((e,r)=>{const t=r.retryMaxDelay??1e4,o=(r.retryDelay??1e3)*2**e;return Math.min(o,t)})(t,e):(e=>e.retryDelay??1e3)(e),shouldAttemptRetry:async()=>{const o=await(e.retryCondition?.(r))??!0,s=(e.retryAttempts??0)>t&&o;if("HTTPError"!==r.error.name)return s;const n=!!r.request.method&&e.retryMethods?.includes(r.request.method);return!!r.response?.status&&e.retryCodes?.includes(r.response.status)&&n&&s}}},x=(e,r)=>{if(!r)return e;const t=(o=r)?new URLSearchParams(o).toString():(console.error("toQueryString:","No query params provided!"),null);var o;return 0===t?.length?e:e.endsWith("?")?`${e}${t}`:e.includes("?")?`${e}&${t}`:`${e}?${t}`},P=(e,r,t)=>{const o=((e,r)=>{if(!r)return e;let t=e;if(a(r)){const e=t.split("/").filter((e=>e.startsWith(":")));for(const[o,s]of e.entries()){const e=r[o];t=t.replace(s,e)}return t}for(const[e,o]of Object.entries(r))t=t.replace(`:${e}`,String(o));return t})(e,r);return x(o,t)},A=(e={})=>{const[r,t]=(e=>[h(e,y),w(e,[...y,...d])])(e),{body:o,headers:s,signal:n,...c}=r,p=new Map,f=async(...e)=>{const[r,d]=e,[b,k]=(e=>[h(e,y),w(e,y)])(d??{}),{body:x=o,headers:A,signal:H=n,...C}=b,L={};for(const e of Object.keys($)){const r=(U=t[e],B=k[e],a(U)?[U,B].flat():B??U);L[e]=r}var U,B;const z={baseURL:"",bodySerializer:JSON.stringify,dedupeStrategy:"cancel",defaultErrorMessage:"Failed to fetch data from server!",mergedHooksExecutionMode:"parallel",mergedHooksExecutionOrder:"mainHooksLast",responseType:"json",resultMode:"all",retryAttempts:0,retryCodes:g,retryDelay:1e3,retryMaxDelay:1e4,retryMethods:m,retryStrategy:"linear",...t,...k,...L},{resolvedHooks:N,resolvedOptions:I,resolvedRequestOptions:W,url:F}=await(async e=>{const{initURL:r,options:t,request:o}=e,s=structuredClone($),n=()=>{for(const e of Object.keys($)){const r=t[e];s[e].add(r)}},a=e=>{for(const r of Object.keys($)){const t=e[r];s[r].add(t)}};"mainHooksFirst"===t.mergedHooksExecutionOrder&&n();const c=e=>e?l(e)?e({initURL:r,options:t,request:o}):e:[],p=[...c(t.plugins),...c(t.extend?.plugins)];let d=r,y=t,f=o;const m=async e=>{if(!e)return;const s=await e({initURL:r,options:t,request:o});i(s)&&(u(s.url)&&(d=s.url),i(s.request)&&(f=s.request),i(s.options)&&(y=s.options))};for(const e of p)await m(e.init),e.hooks&&a(e.hooks);t.mergedHooksExecutionOrder&&"mainHooksLast"!==t.mergedHooksExecutionOrder||n();const g={};for(const[e,r]of Object.entries(s)){const o=[...r].flat(),s=j(o,t.mergedHooksExecutionMode);g[e]=s}return{resolvedHooks:g,resolvedOptions:y,resolvedRequestOptions:f,url:d}})({initURL:r,options:z,request:{...c,...C}}),G={...I,...N,initURL:r},K={body:i(x)?G.bodySerializer(x):x,method:"GET",...W},J=new AbortController,V=null!=G.timeout?(_=G.timeout,AbortSignal.timeout(_)):null;var _;const Q=((...e)=>AbortSignal.any(e.filter(Boolean)))(J.signal,V,H),X=`${G.baseURL}${P(F,G.params,G.query)}`,Y={...K,fullURL:X,signal:Q},Z=G.dedupeKey??((e,r,t)=>"cancel"===t.dedupeStrategy||"defer"===t.dedupeStrategy?`${r.fullURL}-${JSON.stringify({options:t,request:r})}`:null)(0,Y,G);null!==Z&&await T(.1);const ee=null!==Z?p:null,re=ee?.get(Z);((e,r,t)=>{if(t&&"cancel"===r.dedupeStrategy){const o=r.dedupeKey?`Duplicate request detected - Aborting previous request with key '${r.dedupeKey}' as a new request was initiated`:`Duplicate request detected - Aborting previous request to '${e}' as a new request with identical options was initiated`,s=new DOMException(o,"AbortError");t.controller.abort(s)}})(X,G,re);try{await O(G.onRequest({options:G,request:Y})),Y.headers=E({auth:G.auth,baseHeaders:s??A,body:x,headers:Y.headers});const e=M(X,G,Y,re);ee?.set(Z,{controller:J,responsePromise:e});const r=await e,t="defer"===G.dedupeStrategy||G.cloneResponse;if(!r.ok){const e=await R(t?r.clone():r,G.responseType,G.responseParser,G.responseErrorValidator);throw new q({defaultErrorMessage:G.defaultErrorMessage,errorData:e,response:r})}const o=await R(t?r.clone():r,G.responseType,G.responseParser,G.responseValidator);return await O(G.onSuccess({data:o,options:G,request:Y,response:G.cloneResponse?r.clone():r}),G.onResponse({data:o,error:null,options:G,request:Y,response:G.cloneResponse?r.clone():r})),await(e=>{const{data:r,response:t,resultMode:o}=e,s={data:r,error:null,response:t};return o?{all:s,onlyError:s.error,onlyResponse:s.response,onlySuccess:s.data,onlySuccessWithException:s.data}[o]:s})({data:o,response:r,resultMode:G.resultMode})}catch(e){const{apiDetails:t,generalErrorResult:o,resolveCustomErrorInfo:s}=S({defaultErrorMessage:G.defaultErrorMessage,error:e,resultMode:G.resultMode}),n={error:t.error,options:G,request:Y,response:t.response},{getDelay:a,shouldAttemptRetry:i}=D(G,n);if(!Q.aborted&&await i()){await O(G.onRetry(n));const e=a();return await T(e),await f(r,{...d,retryCount:(G.retryCount??0)+1})}const u=l(G.throwOnError)?G.throwOnError(n):G.throwOnError,c=()=>{if(u)throw t.error};if(v(e)){const{response:r}=e,t=o.error;return await O(G.onResponseError({error:t,options:G,request:Y,response:G.cloneResponse?r.clone():r}),G.onError({error:t,options:G,request:Y,response:G.cloneResponse?r.clone():r}),G.onResponse({data:null,error:t,options:G,request:Y,response:G.cloneResponse?r.clone():r})),c(),o}if(e instanceof DOMException&&"TimeoutError"===e.name){const r=`Request timed out after ${G.timeout}ms`;return console.error(`${e.name}:`,r),c(),s({message:r})}if(e instanceof DOMException&&"AbortError"===e.name){const{message:r,name:t}=e;return console.error(`${t}:`,r),c(),o}const p=o.error;return await O(G.onRequestError({error:p,options:G,request:Y}),G.onError({error:p,options:G,request:Y,response:null})),c(),o}finally{ee?.delete(Z)}};return f.create=A,f},H=A();//# sourceMappingURL=index.cjs.map