@zayne-labs/callapi 1.0.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.
package/README.md CHANGED
@@ -44,4 +44,3 @@ To do this, you first need to set your `script`'s type to `module`, then import
44
44
  import { callApi } from "https://esm.run/@zayne-labs/callapi@0.3.2";
45
45
  </script>
46
46
  ```
47
-
@@ -1,3 +1,52 @@
1
+ type ValueOrFunctionResult<TValue> = TValue | (() => TValue);
2
+ /**
3
+ * Bearer Or Token authentication
4
+ *
5
+ * The value of `bearer` will be added to a header as
6
+ * `auth: Bearer some-auth-token`,
7
+ *
8
+ * The value of `token` will be added to a header as
9
+ * `auth: Token some-auth-token`,
10
+ */
11
+ type BearerOrTokenAuth = {
12
+ type?: never;
13
+ bearer?: never;
14
+ token?: ValueOrFunctionResult<string | null>;
15
+ } | {
16
+ type?: never;
17
+ bearer?: ValueOrFunctionResult<string | null>;
18
+ token?: never;
19
+ };
20
+ /**
21
+ * Basic auth
22
+ */
23
+ type BasicAuth = {
24
+ type: "Basic";
25
+ username: ValueOrFunctionResult<string | null | undefined>;
26
+ password: ValueOrFunctionResult<string | null | undefined>;
27
+ };
28
+ /**
29
+ * Custom auth
30
+ *
31
+ * @param prefix - prefix of the header
32
+ * @param authValue - value of the header
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * {
37
+ * type: "Custom",
38
+ * prefix: "Token",
39
+ * authValue: "token"
40
+ * }
41
+ * ```
42
+ */
43
+ type CustomAuth = {
44
+ type: "Custom";
45
+ prefix: ValueOrFunctionResult<string | null | undefined>;
46
+ value: ValueOrFunctionResult<string | null | undefined>;
47
+ };
48
+ type Auth = BearerOrTokenAuth | BasicAuth | CustomAuth;
49
+
1
50
  type AnyString = string & {
2
51
  placeholder?: never;
3
52
  };
@@ -51,6 +100,48 @@ type CallApiPlugin<TData = unknown, TErrorData = unknown> = {
51
100
  };
52
101
  declare const definePlugin: <TPlugin extends CallApiPlugin<never, never> | AnyFunction<CallApiPlugin<never, never>>>(plugin: TPlugin) => TPlugin;
53
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
+
54
145
  type ToQueryStringFn = {
55
146
  (params: CallApiConfig["query"]): string | null;
56
147
  (params: Required<CallApiConfig>["query"]): string;
@@ -90,6 +181,10 @@ interface CallApiRequestOptions extends Pick<RequestInit, FetchSpecificKeysUnion
90
181
  * @description Optional body of the request, can be a object or any other supported body type.
91
182
  */
92
183
  body?: Record<string, unknown> | RequestInit["body"];
184
+ /**
185
+ * @description Resolved request URL
186
+ */
187
+ readonly fullURL?: string;
93
188
  /**
94
189
  * @description Headers to be used in the request.
95
190
  */
@@ -101,10 +196,6 @@ interface CallApiRequestOptions extends Pick<RequestInit, FetchSpecificKeysUnion
101
196
  method?: "DELETE" | "GET" | "PATCH" | "POST" | "PUT" | AnyString;
102
197
  }
103
198
  interface CallApiRequestOptionsForHooks extends CallApiRequestOptions {
104
- /**
105
- * @description Resolved request URL
106
- */
107
- readonly fullURL?: string;
108
199
  headers?: Record<CommonRequestHeaders | AnyString, string>;
109
200
  }
110
201
  interface Register {
@@ -114,72 +205,46 @@ type R_Meta = Register extends {
114
205
  } ? TMeta : never;
115
206
  interface Interceptors<TData = unknown, TErrorData = unknown> {
116
207
  /**
117
- * @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.
118
209
  * It is basically a combination of `onRequestError` and `onResponseError` interceptors
119
210
  */
120
211
  onError?: (context: ErrorContext<TErrorData>) => Awaitable<unknown>;
121
212
  /**
122
- * @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.
123
214
  */
124
215
  onRequest?: (context: RequestContext) => Awaitable<unknown>;
125
216
  /**
126
- * @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.
127
218
  */
128
219
  onRequestError?: (context: RequestErrorContext) => Awaitable<unknown>;
129
220
  /**
130
- * @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
131
222
  */
132
223
  onResponse?: (context: ResponseContext<TData, TErrorData>) => Awaitable<unknown>;
133
224
  /**
134
- * @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.
135
226
  */
136
227
  onResponseError?: (context: ResponseErrorContext<TErrorData>) => Awaitable<unknown>;
137
228
  /**
138
- * @description Interceptor to be called when a successful response is received from the api.
229
+ * @description Interceptor that will be called when a request is retried.
139
230
  */
140
- onSuccess?: (context: SuccessContext<TData>) => Awaitable<unknown>;
141
- }
142
- interface InterceptorsArray<TData = unknown, TErrorData = unknown> {
231
+ onRetry?: (response: ErrorContext<TErrorData>) => Awaitable<unknown>;
143
232
  /**
144
- * @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.
145
- * It is basically a combination of `onRequestError` and `onResponseError` interceptors
233
+ * @description Interceptor that will be called when a successful response is received from the api.
146
234
  */
147
- onError?: Array<Interceptors<TData, TErrorData>["onError"]>;
148
- /**
149
- * @description Interceptor to be called just before the request is made, allowing for modifications or additional operations.
150
- */
151
- onRequest?: Array<Interceptors<TData, TErrorData>["onRequest"]>;
152
- /**
153
- * @description Interceptor to be called when an error occurs during the fetch request.
154
- */
155
- onRequestError?: Array<Interceptors<TData, TErrorData>["onRequestError"]>;
156
- /**
157
- * @description Interceptor to be called when any response is received from the api, whether successful or not
158
- */
159
- onResponse?: Array<Interceptors<TData, TErrorData>["onResponse"]>;
160
- /**
161
- * @description Interceptor to be called when an error response is received from the api.
162
- */
163
- onResponseError?: Array<Interceptors<TData, TErrorData>["onResponseError"]>;
164
- /**
165
- * @description Interceptor to be called when a successful response is received from the api.
166
- */
167
- onSuccess?: Array<Interceptors<TData, TErrorData>["onSuccess"]>;
235
+ onSuccess?: (context: SuccessContext<TData>) => Awaitable<unknown>;
168
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>;
169
241
  type FetchImpl = UnmaskType<(input: string | Request | URL, init?: RequestInit) => Promise<Response>>;
170
242
  type CallApiPluginArray<TData, TErrorData> = Array<CallApiPlugin<TData, TErrorData>>;
171
- type CallApiPluginFn<TData, TErrorData> = (context: PluginInitContext<TData, TErrorData>) => Array<CallApiPlugin<TData, TErrorData>>;
172
- 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> & {
173
244
  /**
174
245
  * @description Authorization header value.
175
246
  */
176
- auth?: string | {
177
- bearer: string | null;
178
- token?: never;
179
- } | {
180
- bearer?: never;
181
- token: string | null;
182
- } | null;
247
+ auth?: string | Auth | null;
183
248
  /**
184
249
  * @description Base URL to be prepended to all request URLs
185
250
  */
@@ -198,6 +263,11 @@ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends Cal
198
263
  * @description Custom fetch implementation
199
264
  */
200
265
  customFetchImpl?: FetchImpl;
266
+ /**
267
+ * @description Custom request key to be used to identify a request in the fetch deduplication strategy.
268
+ * @default the full request url + string formed from the request options
269
+ */
270
+ dedupeKey?: string;
201
271
  /**
202
272
  * @description Defines the deduplication strategy for the request, can be set to "none" | "defer" | "cancel".
203
273
  * - If set to "none", deduplication is disabled.
@@ -218,17 +288,17 @@ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends Cal
218
288
  */
219
289
  readonly initURL?: string;
220
290
  /**
221
- * @description Defines the mode in which the merged interceptors are executed, can be set to "parallel" | "sequential".
222
- * - If set to "parallel", both plugin and main interceptors will be executed in parallel.
223
- * - 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.
224
294
  * @default "parallel"
225
295
  */
226
- mergedInterceptorsExecutionMode?: "parallel" | "sequential";
296
+ mergedHooksExecutionMode?: "parallel" | "sequential";
227
297
  /**
228
- * @description - Controls what order in which the mergedInterceptors execute
229
- * @default "mainInterceptorLast"
298
+ * @description - Controls what order in which the merged hooks execute
299
+ * @default "mainHooksLast"
230
300
  */
231
- mergedInterceptorsExecutionOrder?: "mainInterceptorFirst" | "mainInterceptorLast";
301
+ mergedHooksExecutionOrder?: "mainHooksFirst" | "mainHooksLast";
232
302
  /**
233
303
  * @description - An optional field you can fill with additional information,
234
304
  * to associate with the request, typically used for logging or tracing.
@@ -260,16 +330,11 @@ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends Cal
260
330
  /**
261
331
  * @description An array of CallApi plugins. It allows you to extend the behavior of the library.
262
332
  */
263
- plugins?: CallApiPluginArray<TData, TErrorData>;
333
+ plugins?: CallApiPluginArray<TData, TErrorData> | ((context: PluginInitContext<TData, TErrorData>) => CallApiPluginArray<TData, TErrorData>);
264
334
  /**
265
335
  * @description Query parameters to append to the URL.
266
336
  */
267
337
  query?: Record<string, boolean | number | string>;
268
- /**
269
- * @description Custom request key to be used to identify a request in the fetch deduplication strategy.
270
- * @default the full request url + string formed from the request options
271
- */
272
- requestKey?: string;
273
338
  /**
274
339
  * @description Custom function to validate the response error data, stemming from the api.
275
340
  * This only runs if the api actually sends back error status codes, else it will be ignored, in which case you should only use the `responseValidator` option.
@@ -293,27 +358,7 @@ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends Cal
293
358
  * Can be set to "all" | "onlySuccess" | "onlyError" | "onlyResponse".
294
359
  * @default "all"
295
360
  */
296
- resultMode?: TResultMode;
297
- /**
298
- * @description Number of retry attempts for failed requests
299
- * @default 0
300
- */
301
- retryAttempts?: number;
302
- /**
303
- * @description HTTP status codes that trigger a retry
304
- * @default [409, 425, 429, 500, 502, 503, 504]
305
- */
306
- retryCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>;
307
- /**
308
- * @description Delay between retries in milliseconds
309
- * @default 500
310
- */
311
- retryDelay?: number;
312
- /**
313
- * HTTP methods that are allowed to retry
314
- * @default ["GET", "POST"]
315
- */
316
- retryMethods?: Array<"GET" | "POST" | AnyString>;
361
+ resultMode?: TErrorData extends false ? "onlySuccessWithException" : TResultMode | undefined;
317
362
  /**
318
363
  * If true or the function returns true, throws errors instead of returning them
319
364
  * The function is passed the error object and can be used to conditionally throw the error
@@ -325,23 +370,15 @@ type ExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends Cal
325
370
  */
326
371
  timeout?: number;
327
372
  };
328
- declare const optionsEnumToOmitFromBase: ["extend", "override", "requestKey"];
373
+ declare const optionsEnumToOmitFromBase: ["extend", "dedupeKey"];
329
374
  interface BaseCallApiExtraOptions<TBaseData = unknown, TBaseErrorData = unknown, TBaseResultMode extends CallApiResultModeUnion = CallApiResultModeUnion> extends Omit<CallApiExtraOptions<TBaseData, TBaseErrorData, TBaseResultMode>, typeof optionsEnumToOmitFromBase[number]> {
330
- /**
331
- * @description An array of CallApi plugins. It allows you to extend the behavior of the library.
332
- */
333
- plugins?: CallApiPluginArray<TBaseData, TBaseErrorData> | CallApiPluginFn<TBaseData, TBaseErrorData>;
334
375
  }
335
- declare const optionsEnumToOmitFromInstance: ["plugins"];
336
- 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> {
337
378
  /**
338
379
  * @description Options that should extend the base options.
339
380
  */
340
- extend?: Pick<ExtraOptions<TData, TErrorData, TResultMode>, (typeof optionsEnumToOmitFromInstance)[number]>;
341
- /**
342
- * @description Options that should override the base options.
343
- */
344
- override?: Pick<ExtraOptions<TData, TErrorData, TResultMode>, (typeof optionsEnumToOmitFromInstance)[number]>;
381
+ extend?: Pick<ExtraOptions<TData, TErrorData, TResultMode>, typeof optionsEnumToExtendFromBase[number]>;
345
382
  }
346
383
  interface CombinedCallApiExtraOptions<TData = unknown, TErrorData = unknown, TResultMode extends CallApiResultModeUnion = CallApiResultModeUnion> extends BaseCallApiExtraOptions<TData, TErrorData, TResultMode>, CallApiExtraOptions<TData, TErrorData, TResultMode> {
347
384
  }
@@ -423,9 +460,9 @@ type CallApiResultErrorVariant<TErrorData> = {
423
460
  };
424
461
  type ResultModeMap<TData = unknown, TErrorData = unknown> = {
425
462
  all: CallApiResultSuccessVariant<TData> | CallApiResultErrorVariant<TErrorData>;
426
- onlyError: CallApiResultErrorVariant<TErrorData>["error"] | null;
427
- onlyResponse: CallApiResultSuccessVariant<TData>["response"] | null;
428
- 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"];
429
466
  onlySuccessWithException: CallApiResultSuccessVariant<TData>["data"];
430
467
  };
431
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:()=>D,createFetchClient:()=>$,definePlugin:()=>p}),module.exports=(e=n,((e,n,a,i)=>{if(n&&"object"==typeof n||"function"==typeof n)for(let l of t(n))s.call(e,l)||l===a||r(e,l,{get:()=>n[l],enumerable:!(i=o(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=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=l(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)&&(u(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 E=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:E([...s.onError].flat()),onRequest:E([...s.onRequest].flat()),onRequestError:E([...s.onRequestError].flat()),onResponse:E([...s.onResponse].flat()),onResponseError:E([...s.onResponseError].flat()),onSuccess:E([...s.onSuccess].flat())},resolvedOptions:p,resolvedRequestOptions:d,url:c}},p=e=>e,d=["extend","override","requestKey"],f=["plugins"],y=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],E={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"],R=Object.keys(E).map(Number),g=(e,r)=>{const o={},t=new Set(r);for(const[r,s]of Object.entries(e))t.has(r)||(o[r]=s);return o},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},h=e=>!e||i(e)?e:Object.fromEntries(e),q=e=>{const{auth:r,baseHeaders:o,body:t,headers:s}=e;if(!Boolean(o||s||t||r))return;const n={...(u(r)||null===r)&&{Authorization:`Bearer ${r}`},...i(r)&&{Authorization:"bearer"in r?`Bearer ${r.bearer}`:`Token ${r.token}`},...h(o),...h(s)};return u(a=t)&&a.includes("=")?(n["Content-Type"]="application/x-www-form-urlencoded",n):((i(t)||u(t)&&t.startsWith("{"))&&(n["Content-Type"]="application/json",n.Accept="application/json"),n);var a},b=(e,r)=>a(e)?[e,r].flat():r??e,S=(...e)=>Promise.all(e),O=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},v=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(M(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})=>v({...e,message:r}).generalErrorResult}},T=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)}},M=e=>e instanceof T||i(e)&&"HTTPError"===e.name&&!0===e.isHTTPError,j=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},x=(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}`},P=(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 x(t,o)},$=(e={})=>{const[r,o]=(e=>[w(e,y),g(e,[...y,...d])])(e),{body:t,headers:s,signal:n,...a}=r,u=new Map,p=async(...e)=>{const[r,d]=e,[E,h]=(e=>[w(e,y),g(e,[...y,...f])])(d??{}),{body:x=t,headers:$,signal:D=n,...A}=E,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:R,retryDelay:0,retryMethods:m,...o,...h,onError:b(o.onError,h.onError),onRequest:b(o.onRequest,h.onRequest),onRequestError:b(o.onRequestError,h.onRequestError),onResponse:b(o.onResponse,h.onResponse),onResponseError:b(o.onResponseError,h.onResponseError),onSuccess:b(o.onSuccess,h.onSuccess)},{interceptors:L,resolvedOptions:k,resolvedRequestOptions:U,url:C}=await c({initURL:r,options:I,request:{...a,...A}}),H={...k,...L,initURL:r},B={body:i(x)?H.bodySerializer(x):x,method:"GET",...U},N=`${H.baseURL}${P(C,H.params,H.query)}`,K="cancel"===H.dedupeStrategy||"defer"===H.dedupeStrategy,W=H.requestKey??((e,r)=>r.shouldHaveRequestKey?`${e}-${JSON.stringify(r)}`:null)(N,{shouldHaveRequestKey:K,...U,...H});null!=W&&await j(.1);const z=null!=W?u:null,F=z?.get(W);if(F&&"cancel"===H.dedupeStrategy){const e=H.requestKey?`Duplicate request detected - Aborting previous request with key '${W}' as a new request was initiated`:`Duplicate request detected - Aborting previous request to '${N}' as a new request with identical options was initiated`,r=new DOMException(e,"AbortError");F.controller.abort(r)}const G=new AbortController,J=null!=H.timeout?(V=H.timeout,AbortSignal.timeout(V)):null;var V;const _=((...e)=>AbortSignal.any(e.filter(Boolean)))(G.signal,J,D),Q={fullURL:N,signal:_,...B},X=(e=>{if(e)return e;if("undefined"!=typeof globalThis&&l(globalThis.fetch))return globalThis.fetch;throw new Error("No fetch implementation found")})(H.customFetchImpl);try{await S(H.onRequest({options:H,request:Q})),Q.headers=q({auth:H.auth,baseHeaders:s??$,body:x,headers:Q.headers});const e=F&&"defer"===H.dedupeStrategy?F.responsePromise:X(N,Q);z?.set(W,{controller:G,responsePromise:e});const o=await e;if(!o.ok&&!_.aborted&&H.retryAttempts>0&&H.retryCodes.includes(o.status)&&H.retryMethods.includes(Q.method))return await j(H.retryDelay),await p(r,{...d,retryAttempts:H.retryAttempts-1});const t="defer"===H.dedupeStrategy||"onlyResponse"===H.resultMode||H.cloneResponse;if(!o.ok){const e=await O(t?o.clone():o,H.responseType,H.responseParser,H.responseErrorValidator);throw new T({defaultErrorMessage:H.defaultErrorMessage,errorData:e,response:o})}const n=await O(t?o.clone():o,H.responseType,H.responseParser,H.responseValidator);return await S(H.onSuccess({data:n,options:H,request:Q,response:H.cloneResponse?o.clone():o}),H.onResponse({data:n,error:null,options:H,request:Q,response:H.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:H.resultMode})}catch(e){const{apiDetails:r,generalErrorResult:o,resolveCustomErrorInfo:t}=v({defaultErrorMessage:H.defaultErrorMessage,error:e,resultMode:H.resultMode}),s=l(H.throwOnError)?H.throwOnError({error:r.error,options:H,request:Q,response:r.response}):H.throwOnError,n=()=>{if(s)throw r.error};if(M(e)){const{response:r}=e,t=o.error;return await S(H.onResponseError({error:t,options:H,request:Q,response:H.cloneResponse?r.clone():r}),H.onError({error:t,options:H,request:Q,response:H.cloneResponse?r.clone():r}),H.onResponse({data:null,error:t,options:H,request:Q,response:H.cloneResponse?r.clone():r})),n(),o}if(e instanceof DOMException&&"TimeoutError"===e.name){const r=`Request timed out after ${H.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 S(H.onRequestError({error:a,options:H,request:Q}),H.onError({error:a,options:H,request:Q,response:null})),n(),o}finally{z?.delete(W)}};return p.create=$,p},D=$();//# 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