@zayne-labs/callapi 1.6.14 → 1.6.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1,773 @@
1
- "use strict";var e,r=Object.defineProperty,t=Object.getOwnPropertyDescriptor,o=Object.getOwnPropertyNames,s=Object.prototype.hasOwnProperty,n={};((e,t)=>{for(var o in t)r(e,o,{get:t[o],enumerable:!0})})(n,{HTTPError:()=>a,callApi:()=>L,createFetchClient:()=>U,definePlugin:()=>x}),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=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)}},i=e=>e instanceof a||d(e)&&"HTTPError"===e.name&&!0===e.isHTTPError,l=e=>Array.isArray(e),u=e=>"object"==typeof e&&null!==e,c=e=>"[object Object]"===Object.prototype.toString.call(e),d=e=>{if(!c(e))return!1;const r=e?.constructor;if(void 0===r)return!0;const t=r.prototype;return!!c(t)&&(!!Object.hasOwn(t,"isPrototypeOf")&&Object.getPrototypeOf(e)===Object.prototype)},p=e=>"function"==typeof e,y=e=>"string"==typeof e,f=e=>p(e)?e():e,h=e=>{if(void 0!==e){if(y(e)||null===e)return{Authorization:`Bearer ${e}`};switch(e.type){case"Basic":{const r=f(e.username),t=f(e.password);if(void 0===r||void 0===t)return;return{Authorization:`Basic ${globalThis.btoa(`${r}:${t}`)}`}}case"Custom":{const r=f(e.value);if(void 0===r)return;return{Authorization:`${f(e.prefix)} ${r}`}}default:{const r=f(e.bearer),t=f(e.token);return"token"in e&&void 0!==t?{Authorization:`Token ${t}`}:void 0!==r&&{Authorization:`Bearer ${r}`}}}}},m=["extend","dedupeKey"],g=["body","integrity","method","headers","signal","cache","redirect","window","credentials","keepalive","referrer","priority","mode","referrerPolicy"],w={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=["GET","POST"],E=Object.keys(w).map(Number),R=(e,r)=>{const t={},o=new Set(r);for(const[r,s]of Object.entries(e))o.has(r)||(t[r]=s);return t},S=(e,r)=>{const t={},o=new Set(r);for(const[r,s]of Object.entries(e))o.has(r)&&(t[r]=s);return t},O=e=>!e||d(e)?e:Object.fromEntries(e),v=e=>{const{auth:r,baseHeaders:t,body:o,headers:s}=e;if(!Boolean(t||s||o||r))return;const n={...h(r),...O(t),...O(s)};return y(a=o)&&a.includes("=")?(n["Content-Type"]="application/x-www-form-urlencoded",n):((d(o)||y(o)&&o.startsWith("{"))&&(n["Content-Type"]="application/json",n.Accept="application/json"),n);var a},q=(...e)=>Promise.all(e),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},D=async e=>{const{$RequestInfoCache:r,newFetchController:t,options:o,request:s}=e,n=o.dedupeKey??("cancel"===o.dedupeStrategy||"defer"===o.dedupeStrategy?`${o.fullURL}-${JSON.stringify({options:o,request:s})}`:null),a=null!==n?r:null;null!==n&&await T(.1);const i=a?.get(n);return{handleRequestCancelStrategy:()=>{if(!(i&&"cancel"===o.dedupeStrategy))return;const e=o.dedupeKey?`Duplicate request detected - Aborting previous request with key '${o.dedupeKey}' as a new request was initiated`:`Duplicate request detected - Aborting previous request to '${o.fullURL}' as a new request with identical options was initiated`,r=new DOMException(e,"AbortError");return i.controller.abort(r),Promise.resolve()},handleRequestDeferStrategy:()=>{const e=(e=>{if(e)return e;if("undefined"!=typeof globalThis&&p(globalThis.fetch))return globalThis.fetch;throw new Error("No fetch implementation found")})(o.customFetchImpl),r=i&&"defer"===o.dedupeStrategy?i.responsePromise:e(o.fullURL,s);return a?.set(n,{controller:t,responsePromise:r}),r},removeDedupeKeyFromCache:()=>a?.delete(n)}},x=e=>e,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))},M={onError:new Set,onRequest:new Set,onRequestError:new Set,onResponse:new Set,onResponseError:new Set,onRetry:new Set,onSuccess:new Set},P=(e,r)=>e?p(e)?e(r):e:[],$=async(e,r,t)=>{const o=((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(o,r))throw new Error(`Invalid response type: ${r}`);return await o[r]()},k=(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.retryStatusCodes?.includes(r.response.status)&&n&&s}}},A=(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}`},C=(e,r,t)=>{if(!e)return;const o=((e,r)=>{if(!r)return e;let t=e;if(l(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 A(o,t)},H=async(e,r,t)=>{const o=t?t(e):e,s=r?await(async(e,r)=>{const t=await e["~standard"].validate(r);if(t.issues)throw new Error(JSON.stringify(t.issues,null,2),{cause:t.issues});return t.value})(r,o):o;return s},U=e=>{const[r,t]=(e=>[S(e,g),R(e,[...g,...m])])(e??{}),o=new Map,s=async(...e)=>{const[n,c={}]=e,[f,h]=(e=>[S(e,g),R(e,g)])(c),m={};for(const e of Object.keys(M)){const r=(w=t[e],O=h[e],l(w)?[w,O].flat():O??w);m[e]=r}var w,O;const x={baseURL:"",bodySerializer:JSON.stringify,dedupeStrategy:"cancel",defaultErrorMessage:"Failed to fetch data from server!",mergedHooksExecutionMode:"parallel",mergedHooksExecutionOrder:"mainHooksAfterPlugins",responseType:"json",resultMode:"all",retryAttempts:0,retryDelay:1e3,retryMaxDelay:1e4,retryMethods:b,retryStatusCodes:E,retryStrategy:"linear",...t,...h,...m},A=f.body??r.body,U={...r,...f,body:d(A)?x.bodySerializer(A):A,headers:v({auth:x.auth,baseHeaders:r.headers,body:A,headers:f.headers}),signal:f.signal??r.signal},{resolvedHooks:L,resolvedOptions:W,resolvedRequestOptions:B,url:z}=await(async e=>{const{initURL:r,options:t,request:o}=e,s=structuredClone(M),n=()=>{for(const e of Object.keys(M)){const r=t[e];s[e].add(r)}},a=e=>{for(const r of Object.keys(M)){const t=e[r];s[r].add(t)}};"mainHooksBeforePlugins"===t.mergedHooksExecutionOrder&&n();const i=[...P(t.plugins,e),...P(t.extend?.plugins,e)];let l=r,u=t,c=o;const p=async e=>{if(!e)return;const s=await e({initURL:r,options:t,request:o});d(s)&&(y(s.initURL)&&(l=s.initURL),d(s.request)&&(c=s.request),d(s.options)&&(u=s.options))};for(const e of i)await p(e.init),e.hooks&&a(e.hooks);t.mergedHooksExecutionOrder&&"mainHooksAfterPlugins"!==t.mergedHooksExecutionOrder||n();const f={};for(const[e,r]of Object.entries(s)){const o=[...r].flat(),s=j(o,t.mergedHooksExecutionMode);f[e]=s}return{resolvedHooks:f,resolvedOptions:u,resolvedRequestOptions:c,url:l?.toString()}})({initURL:n,options:x,request:U}),F=`${W.baseURL}${C(z,W.params,W.query)}`,N={...W,...L,fullURL:F,initURL:n.toString()},K=new AbortController,I=null!=N.timeout?(G=N.timeout,AbortSignal.timeout(G)):null;var G;const J=((...e)=>AbortSignal.any(e.filter(Boolean)))(B.signal,I,K.signal),_={...B,signal:J},{handleRequestCancelStrategy:Q,handleRequestDeferStrategy:V,removeDedupeKeyFromCache:X}=await D({$RequestInfoCache:o,newFetchController:K,options:N,request:_});await Q();try{await q(N.onRequest({options:N,request:_})),_.headers=v({auth:N.auth,baseHeaders:r.headers,body:A,headers:_.headers});const e=await V(),t="defer"===N.dedupeStrategy||N.cloneResponse,{schemas:o,validators:s}=(e=>({schemas:e.schemas&&{...e.schemas,...e.extend?.schemas},validators:e.validators&&{...e.validators,...e.extend?.validators}}))(N);if(!e.ok){const r=await $(t?e.clone():e,N.responseType,N.responseParser),n=await H(r,o?.errorData,s?.errorData);throw new a({defaultErrorMessage:N.defaultErrorMessage,errorData:n,response:e})}const n=await $(t?e.clone():e,N.responseType,N.responseParser),i={data:await H(n,o?.data,s?.data),options:N,request:_,response:N.cloneResponse?e.clone():e};return await q(N.onSuccess(i),N.onResponse({...i,error:null})),await(e=>{const{data:r,response:t,resultMode:o}=e,s={data:r,error:null,response:t};return o?{all:s,allWithException:s,allWithoutResponse:R(s,["response"]),onlyError:s.error,onlyResponse:s.response,onlyResponseWithException:s.response,onlySuccess:s.data,onlySuccessWithException:s.data}[o]:s})({data:i.data,response:i.response,resultMode:N.resultMode})}catch(e){const{apiDetails:r,getErrorResult:t}=(e=>{const{cloneResponse:r,defaultErrorMessage:t,error:o,message:s,resultMode:n}=e;let a={data:null,error:{errorData:o,message:s??o.message,name:o.name},response:null};if(i(o)){const{errorData:e,message:s=t,name:n,response:i}=o;a={data:null,error:{errorData:e,message:s,name:n},response:r?i.clone():i}}const l={all:a,allWithException:a,allWithoutResponse:R(a,["response"]),onlyError:a.error,onlyResponse:a.response,onlyResponseWithException:a.response,onlySuccess:a.data,onlySuccessWithException:a.data};return{apiDetails:a,getErrorResult:e=>{const r=l[n??"all"];return u(e)?{...r,...e}:r}}})({cloneResponse:N.cloneResponse,defaultErrorMessage:N.defaultErrorMessage,error:e,resultMode:N.resultMode}),o={error:r.error,options:N,request:_,response:r.response},{getDelay:a,shouldAttemptRetry:l}=k(N,o);if(!J.aborted&&await l()){await q(N.onRetry(o));const e=a();await T(e);const r={...c,"~retryCount":(N["~retryCount"]??0)+1};return await s(n,r)}const d=p(N.throwOnError)?N.throwOnError(o):N.throwOnError,y=()=>{if(d)throw r.error};if(i(e))return await q(N.onResponseError(o),N.onError(o),N.onResponse({...o,data:null})),y(),t();if(e instanceof DOMException&&"AbortError"===e.name){const{message:r,name:o}=e;return console.error(`${o}:`,r),y(),t()}if(e instanceof DOMException&&"TimeoutError"===e.name){const r=`Request timed out after ${N.timeout}ms`;return console.error(`${e.name}:`,r),y(),t({message:r})}return await q(N.onRequestError(o),N.onError(o)),y(),t()}finally{X()}};return s.create=U,s},L=U();//# sourceMappingURL=index.cjs.map
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ HTTPError: () => HTTPError,
24
+ callApi: () => callApi,
25
+ createFetchClient: () => createFetchClient,
26
+ defineParameters: () => defineParameters,
27
+ definePlugin: () => definePlugin
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+
31
+ // src/error.ts
32
+ var resolveErrorResult = (info) => {
33
+ const { cloneResponse, defaultErrorMessage, error, message: customErrorMessage, resultMode } = info;
34
+ let apiDetails = {
35
+ data: null,
36
+ error: {
37
+ errorData: error,
38
+ message: customErrorMessage ?? error.message,
39
+ name: error.name
40
+ },
41
+ response: null
42
+ };
43
+ if (isHTTPErrorInstance(error)) {
44
+ const { errorData, message = defaultErrorMessage, name, response } = error;
45
+ apiDetails = {
46
+ data: null,
47
+ error: {
48
+ errorData,
49
+ message,
50
+ name
51
+ },
52
+ response: cloneResponse ? response.clone() : response
53
+ };
54
+ }
55
+ const resultModeMap = {
56
+ all: apiDetails,
57
+ allWithException: apiDetails,
58
+ allWithoutResponse: omitKeys(apiDetails, ["response"]),
59
+ onlyError: apiDetails.error,
60
+ onlyResponse: apiDetails.response,
61
+ onlyResponseWithException: apiDetails.response,
62
+ onlySuccess: apiDetails.data,
63
+ onlySuccessWithException: apiDetails.data
64
+ };
65
+ const getErrorResult = (customInfo) => {
66
+ const errorResult = resultModeMap[resultMode ?? "all"];
67
+ return isObject(customInfo) ? { ...errorResult, ...customInfo } : errorResult;
68
+ };
69
+ return { apiDetails, getErrorResult };
70
+ };
71
+ var HTTPError = class extends Error {
72
+ errorData;
73
+ isHTTPError = true;
74
+ name = "HTTPError";
75
+ response;
76
+ constructor(errorDetails, errorOptions) {
77
+ const { defaultErrorMessage, errorData, response } = errorDetails;
78
+ super(errorData?.message ?? defaultErrorMessage, errorOptions);
79
+ this.errorData = errorData;
80
+ this.response = response;
81
+ Error.captureStackTrace(this, this.constructor);
82
+ }
83
+ };
84
+
85
+ // src/utils/type-guards.ts
86
+ var isHTTPErrorInstance = (error) => {
87
+ return (
88
+ // prettier-ignore
89
+ error instanceof HTTPError || isPlainObject(error) && error.name === "HTTPError" && error.isHTTPError === true
90
+ );
91
+ };
92
+ var isArray = (value) => Array.isArray(value);
93
+ var isObject = (value) => typeof value === "object" && value !== null;
94
+ var hasObjectPrototype = (value) => {
95
+ return Object.prototype.toString.call(value) === "[object Object]";
96
+ };
97
+ var isPlainObject = (value) => {
98
+ if (!hasObjectPrototype(value)) {
99
+ return false;
100
+ }
101
+ const constructor = value?.constructor;
102
+ if (constructor === void 0) {
103
+ return true;
104
+ }
105
+ const prototype = constructor.prototype;
106
+ if (!hasObjectPrototype(prototype)) {
107
+ return false;
108
+ }
109
+ if (!Object.hasOwn(prototype, "isPrototypeOf")) {
110
+ return false;
111
+ }
112
+ if (Object.getPrototypeOf(value) !== Object.prototype) {
113
+ return false;
114
+ }
115
+ return true;
116
+ };
117
+ var isFunction = (value) => typeof value === "function";
118
+ var isQueryString = (value) => isString(value) && value.includes("=");
119
+ var isString = (value) => typeof value === "string";
120
+
121
+ // src/auth.ts
122
+ var getValue = (value) => {
123
+ return isFunction(value) ? value() : value;
124
+ };
125
+ var getAuthHeader = (auth) => {
126
+ if (auth === void 0) return;
127
+ if (isString(auth) || auth === null) {
128
+ return { Authorization: `Bearer ${auth}` };
129
+ }
130
+ switch (auth.type) {
131
+ case "Basic": {
132
+ const username = getValue(auth.username);
133
+ const password = getValue(auth.password);
134
+ if (username === void 0 || password === void 0) return;
135
+ return {
136
+ Authorization: `Basic ${globalThis.btoa(`${username}:${password}`)}`
137
+ };
138
+ }
139
+ case "Custom": {
140
+ const value = getValue(auth.value);
141
+ if (value === void 0) return;
142
+ const prefix = getValue(auth.prefix);
143
+ return {
144
+ Authorization: `${prefix} ${value}`
145
+ };
146
+ }
147
+ default: {
148
+ const bearer = getValue(auth.bearer);
149
+ const token = getValue(auth.token);
150
+ if ("token" in auth && token !== void 0) {
151
+ return { Authorization: `Token ${token}` };
152
+ }
153
+ return bearer !== void 0 && { Authorization: `Bearer ${bearer}` };
154
+ }
155
+ }
156
+ };
157
+
158
+ // src/utils/type-helpers.ts
159
+ var defineEnum = (value) => value;
160
+
161
+ // src/types/common.ts
162
+ var optionsEnumToExtendFromBase = defineEnum(["plugins", "validators", "schemas"]);
163
+ var optionsEnumToOmitFromBase = defineEnum(["extend", "dedupeKey"]);
164
+
165
+ // src/utils/constants.ts
166
+ var fetchSpecificKeys = defineEnum([
167
+ "body",
168
+ "integrity",
169
+ "method",
170
+ "headers",
171
+ "signal",
172
+ "cache",
173
+ "redirect",
174
+ "window",
175
+ "credentials",
176
+ "keepalive",
177
+ "referrer",
178
+ "priority",
179
+ "mode",
180
+ "referrerPolicy"
181
+ ]);
182
+ var retryStatusCodesLookup = defineEnum({
183
+ 408: "Request Timeout",
184
+ 409: "Conflict",
185
+ 425: "Too Early",
186
+ 429: "Too Many Requests",
187
+ 500: "Internal Server Error",
188
+ 502: "Bad Gateway",
189
+ 503: "Service Unavailable",
190
+ 504: "Gateway Timeout"
191
+ });
192
+ var defaultRetryMethods = ["GET", "POST"];
193
+ var defaultRetryStatusCodes = Object.keys(retryStatusCodesLookup).map(Number);
194
+
195
+ // src/utils/common.ts
196
+ var omitKeys = (initialObject, keysToOmit) => {
197
+ const updatedObject = {};
198
+ const keysToOmitSet = new Set(keysToOmit);
199
+ for (const [key, value] of Object.entries(initialObject)) {
200
+ if (!keysToOmitSet.has(key)) {
201
+ updatedObject[key] = value;
202
+ }
203
+ }
204
+ return updatedObject;
205
+ };
206
+ var pickKeys = (initialObject, keysToPick) => {
207
+ const updatedObject = {};
208
+ const keysToPickSet = new Set(keysToPick);
209
+ for (const [key, value] of Object.entries(initialObject)) {
210
+ if (keysToPickSet.has(key)) {
211
+ updatedObject[key] = value;
212
+ }
213
+ }
214
+ return updatedObject;
215
+ };
216
+ var splitBaseConfig = (baseConfig) => [
217
+ pickKeys(baseConfig, fetchSpecificKeys),
218
+ omitKeys(baseConfig, [
219
+ ...fetchSpecificKeys,
220
+ ...optionsEnumToOmitFromBase
221
+ ])
222
+ ];
223
+ var splitConfig = (config) => [
224
+ pickKeys(config, fetchSpecificKeys),
225
+ omitKeys(config, fetchSpecificKeys)
226
+ ];
227
+ var objectifyHeaders = (headers) => {
228
+ if (!headers || isPlainObject(headers)) {
229
+ return headers;
230
+ }
231
+ return Object.fromEntries(headers);
232
+ };
233
+ var toQueryString = (params) => {
234
+ if (!params) {
235
+ console.error("toQueryString:", "No query params provided!");
236
+ return null;
237
+ }
238
+ return new URLSearchParams(params).toString();
239
+ };
240
+ var mergeAndResolveHeaders = (options) => {
241
+ const { auth, baseHeaders, body, headers } = options;
242
+ const shouldResolveHeaders = Boolean(baseHeaders || headers || body || auth);
243
+ if (!shouldResolveHeaders) return;
244
+ const headersObject = {
245
+ ...getAuthHeader(auth),
246
+ ...objectifyHeaders(baseHeaders),
247
+ ...objectifyHeaders(headers)
248
+ };
249
+ if (isQueryString(body)) {
250
+ headersObject["Content-Type"] = "application/x-www-form-urlencoded";
251
+ return headersObject;
252
+ }
253
+ if (isPlainObject(body) || isString(body) && body.startsWith("{")) {
254
+ headersObject["Content-Type"] = "application/json";
255
+ headersObject.Accept = "application/json";
256
+ }
257
+ return headersObject;
258
+ };
259
+ var combineHooks = (baseInterceptor, interceptor) => {
260
+ if (isArray(baseInterceptor)) {
261
+ return [baseInterceptor, interceptor].flat();
262
+ }
263
+ return interceptor ?? baseInterceptor;
264
+ };
265
+ var getFetchImpl = (customFetchImpl) => {
266
+ if (customFetchImpl) {
267
+ return customFetchImpl;
268
+ }
269
+ if (typeof globalThis !== "undefined" && isFunction(globalThis.fetch)) {
270
+ return globalThis.fetch;
271
+ }
272
+ throw new Error("No fetch implementation found");
273
+ };
274
+ var executeHooks = (...interceptors) => Promise.all(interceptors);
275
+ var PromiseWithResolvers = () => {
276
+ let reject;
277
+ let resolve;
278
+ const promise = new Promise((res, rej) => {
279
+ resolve = res;
280
+ reject = rej;
281
+ });
282
+ return { promise, reject, resolve };
283
+ };
284
+ var waitUntil = (delay) => {
285
+ if (delay === 0) return;
286
+ const { promise, resolve } = PromiseWithResolvers();
287
+ setTimeout(resolve, delay);
288
+ return promise;
289
+ };
290
+
291
+ // src/dedupe.ts
292
+ var createDedupeStrategy = async (context) => {
293
+ const { $RequestInfoCache, newFetchController, options, request } = context;
294
+ const generateDedupeKey = () => {
295
+ const shouldHaveDedupeKey = options.dedupeStrategy === "cancel" || options.dedupeStrategy === "defer";
296
+ if (!shouldHaveDedupeKey) {
297
+ return null;
298
+ }
299
+ return `${options.fullURL}-${JSON.stringify({ options, request })}`;
300
+ };
301
+ const dedupeKey = options.dedupeKey ?? generateDedupeKey();
302
+ const $RequestInfoCacheOrNull = dedupeKey !== null ? $RequestInfoCache : null;
303
+ if (dedupeKey !== null) {
304
+ await waitUntil(0.1);
305
+ }
306
+ const prevRequestInfo = $RequestInfoCacheOrNull?.get(dedupeKey);
307
+ const handleRequestCancelStrategy = () => {
308
+ const shouldCancelRequest = prevRequestInfo && options.dedupeStrategy === "cancel";
309
+ if (!shouldCancelRequest) return;
310
+ const message = options.dedupeKey ? `Duplicate request detected - Aborting previous request with key '${options.dedupeKey}' as a new request was initiated` : `Duplicate request detected - Aborting previous request to '${options.fullURL}' as a new request with identical options was initiated`;
311
+ const reason = new DOMException(message, "AbortError");
312
+ prevRequestInfo.controller.abort(reason);
313
+ return Promise.resolve();
314
+ };
315
+ const handleRequestDeferStrategy = () => {
316
+ const fetchApi = getFetchImpl(options.customFetchImpl);
317
+ const shouldUsePromiseFromCache = prevRequestInfo && options.dedupeStrategy === "defer";
318
+ const responsePromise = shouldUsePromiseFromCache ? prevRequestInfo.responsePromise : fetchApi(options.fullURL, request);
319
+ $RequestInfoCacheOrNull?.set(dedupeKey, { controller: newFetchController, responsePromise });
320
+ return responsePromise;
321
+ };
322
+ const removeDedupeKeyFromCache = () => $RequestInfoCacheOrNull?.delete(dedupeKey);
323
+ return {
324
+ handleRequestCancelStrategy,
325
+ handleRequestDeferStrategy,
326
+ removeDedupeKeyFromCache
327
+ };
328
+ };
329
+
330
+ // src/plugins.ts
331
+ var definePlugin = (plugin) => {
332
+ return plugin;
333
+ };
334
+ var createMergedHook = (hooks, mergedHooksExecutionMode) => {
335
+ return async (ctx) => {
336
+ if (mergedHooksExecutionMode === "sequential") {
337
+ for (const hook of hooks) {
338
+ await hook?.(ctx);
339
+ }
340
+ return;
341
+ }
342
+ if (mergedHooksExecutionMode === "parallel") {
343
+ const hookArray = [...hooks];
344
+ await Promise.all(hookArray.map((uniqueHook) => uniqueHook?.(ctx)));
345
+ }
346
+ };
347
+ };
348
+ var hooksEnum = {
349
+ onError: /* @__PURE__ */ new Set(),
350
+ onRequest: /* @__PURE__ */ new Set(),
351
+ onRequestError: /* @__PURE__ */ new Set(),
352
+ onResponse: /* @__PURE__ */ new Set(),
353
+ onResponseError: /* @__PURE__ */ new Set(),
354
+ onRetry: /* @__PURE__ */ new Set(),
355
+ onSuccess: /* @__PURE__ */ new Set()
356
+ };
357
+ var getPluginArray = (plugins, context) => {
358
+ if (!plugins) {
359
+ return [];
360
+ }
361
+ return isFunction(plugins) ? plugins(context) : plugins;
362
+ };
363
+ var initializePlugins = async (context) => {
364
+ const { initURL, options, request } = context;
365
+ const hookRegistries = structuredClone(hooksEnum);
366
+ const addMainHooks = () => {
367
+ for (const key of Object.keys(hooksEnum)) {
368
+ const mainHook = options[key];
369
+ hookRegistries[key].add(mainHook);
370
+ }
371
+ };
372
+ const addPluginHooks = (pluginHooks) => {
373
+ for (const key of Object.keys(hooksEnum)) {
374
+ const pluginHook = pluginHooks[key];
375
+ hookRegistries[key].add(pluginHook);
376
+ }
377
+ };
378
+ if (options.mergedHooksExecutionOrder === "mainHooksBeforePlugins") {
379
+ addMainHooks();
380
+ }
381
+ const resolvedPlugins = [
382
+ ...getPluginArray(options.plugins, context),
383
+ ...getPluginArray(options.extend?.plugins, context)
384
+ ];
385
+ let resolvedUrl = initURL;
386
+ let resolvedOptions = options;
387
+ let resolvedRequestOptions = request;
388
+ const executePluginInit = async (pluginInit) => {
389
+ if (!pluginInit) return;
390
+ const initResult = await pluginInit({ initURL, options, request });
391
+ if (!isPlainObject(initResult)) return;
392
+ if (isString(initResult.initURL)) {
393
+ resolvedUrl = initResult.initURL;
394
+ }
395
+ if (isPlainObject(initResult.request)) {
396
+ resolvedRequestOptions = initResult.request;
397
+ }
398
+ if (isPlainObject(initResult.options)) {
399
+ resolvedOptions = initResult.options;
400
+ }
401
+ };
402
+ for (const plugin of resolvedPlugins) {
403
+ await executePluginInit(plugin.init);
404
+ if (!plugin.hooks) continue;
405
+ addPluginHooks(plugin.hooks);
406
+ }
407
+ if (!options.mergedHooksExecutionOrder || options.mergedHooksExecutionOrder === "mainHooksAfterPlugins") {
408
+ addMainHooks();
409
+ }
410
+ const resolvedHooks = {};
411
+ for (const [key, hookRegistry] of Object.entries(hookRegistries)) {
412
+ const flattenedHookArray = [...hookRegistry].flat();
413
+ const mergedHook = createMergedHook(flattenedHookArray, options.mergedHooksExecutionMode);
414
+ resolvedHooks[key] = mergedHook;
415
+ }
416
+ return {
417
+ resolvedHooks,
418
+ resolvedOptions,
419
+ resolvedRequestOptions,
420
+ url: resolvedUrl?.toString()
421
+ };
422
+ };
423
+
424
+ // src/response.ts
425
+ var getResponseType = (response, parser) => ({
426
+ arrayBuffer: () => response.arrayBuffer(),
427
+ blob: () => response.blob(),
428
+ formData: () => response.formData(),
429
+ json: async () => {
430
+ if (parser) {
431
+ const text = await response.text();
432
+ return parser(text);
433
+ }
434
+ return response.json();
435
+ },
436
+ stream: () => response.body,
437
+ text: () => response.text()
438
+ });
439
+ var resolveResponseData = async (response, responseType, parser) => {
440
+ const RESPONSE_TYPE_LOOKUP = getResponseType(response, parser);
441
+ if (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, responseType)) {
442
+ throw new Error(`Invalid response type: ${responseType}`);
443
+ }
444
+ const responseData = await RESPONSE_TYPE_LOOKUP[responseType]();
445
+ return responseData;
446
+ };
447
+ var resolveSuccessResult = (info) => {
448
+ const { data, response, resultMode } = info;
449
+ const apiDetails = { data, error: null, response };
450
+ if (!resultMode) {
451
+ return apiDetails;
452
+ }
453
+ const resultModeMap = {
454
+ all: apiDetails,
455
+ allWithException: apiDetails,
456
+ allWithoutResponse: omitKeys(apiDetails, ["response"]),
457
+ onlyError: apiDetails.error,
458
+ onlyResponse: apiDetails.response,
459
+ onlyResponseWithException: apiDetails.response,
460
+ onlySuccess: apiDetails.data,
461
+ onlySuccessWithException: apiDetails.data
462
+ };
463
+ return resultModeMap[resultMode];
464
+ };
465
+
466
+ // src/retry.ts
467
+ var getLinearDelay = (options) => options.retryDelay ?? 1e3;
468
+ var getExponentialDelay = (currentAttemptCount, options) => {
469
+ const maxDelay = options.retryMaxDelay ?? 1e4;
470
+ const exponentialDelay = (options.retryDelay ?? 1e3) * 2 ** currentAttemptCount;
471
+ return Math.min(exponentialDelay, maxDelay);
472
+ };
473
+ var createRetryStrategy = (options, ctx) => {
474
+ const currentRetryCount = options["~retryCount"] ?? 0;
475
+ const getDelay = () => {
476
+ if (options.retryStrategy === "exponential") {
477
+ return getExponentialDelay(currentRetryCount, options);
478
+ }
479
+ return getLinearDelay(options);
480
+ };
481
+ const shouldAttemptRetry = async () => {
482
+ const customRetryCondition = await options.retryCondition?.(ctx) ?? true;
483
+ const maxRetryAttempts = options.retryAttempts ?? 0;
484
+ const baseRetryCondition = maxRetryAttempts > currentRetryCount && customRetryCondition;
485
+ if (ctx.error.name !== "HTTPError") {
486
+ return baseRetryCondition;
487
+ }
488
+ const includesMethod = (
489
+ // eslint-disable-next-line no-implicit-coercion -- Boolean doesn't narrow
490
+ !!ctx.request.method && options.retryMethods?.includes(ctx.request.method)
491
+ );
492
+ const includesCodes = (
493
+ // eslint-disable-next-line no-implicit-coercion -- Boolean doesn't narrow
494
+ !!ctx.response?.status && options.retryStatusCodes?.includes(ctx.response.status)
495
+ );
496
+ return includesCodes && includesMethod && baseRetryCondition;
497
+ };
498
+ return {
499
+ getDelay,
500
+ shouldAttemptRetry
501
+ };
502
+ };
503
+
504
+ // src/url.ts
505
+ var slash = "/";
506
+ var column = ":";
507
+ var mergeUrlWithParams = (url, params) => {
508
+ if (!params) {
509
+ return url;
510
+ }
511
+ let newUrl = url;
512
+ if (isArray(params)) {
513
+ const matchedParamArray = newUrl.split(slash).filter((param) => param.startsWith(column));
514
+ for (const [index, matchedParam] of matchedParamArray.entries()) {
515
+ const realParam = params[index];
516
+ newUrl = newUrl.replace(matchedParam, realParam);
517
+ }
518
+ return newUrl;
519
+ }
520
+ for (const [key, value] of Object.entries(params)) {
521
+ newUrl = newUrl.replace(`${column}${key}`, String(value));
522
+ }
523
+ return newUrl;
524
+ };
525
+ var questionMark = "?";
526
+ var ampersand = "&";
527
+ var mergeUrlWithQuery = (url, query) => {
528
+ if (!query) {
529
+ return url;
530
+ }
531
+ const queryString = toQueryString(query);
532
+ if (queryString?.length === 0) {
533
+ return url;
534
+ }
535
+ if (url.endsWith(questionMark)) {
536
+ return `${url}${queryString}`;
537
+ }
538
+ if (url.includes(questionMark)) {
539
+ return `${url}${ampersand}${queryString}`;
540
+ }
541
+ return `${url}${questionMark}${queryString}`;
542
+ };
543
+ var mergeUrlWithParamsAndQuery = (url, params, query) => {
544
+ if (!url) return;
545
+ const urlWithMergedParams = mergeUrlWithParams(url, params);
546
+ return mergeUrlWithQuery(urlWithMergedParams, query);
547
+ };
548
+
549
+ // src/utils/polyfills.ts
550
+ var createCombinedSignal = (...signals) => AbortSignal.any(signals.filter(Boolean));
551
+ var createTimeoutSignal = (milliseconds) => AbortSignal.timeout(milliseconds);
552
+
553
+ // src/validation.ts
554
+ var standardSchemaParser = async (schema, inputData) => {
555
+ const result = await schema["~standard"].validate(inputData);
556
+ if (result.issues) {
557
+ throw new Error(JSON.stringify(result.issues, null, 2), { cause: result.issues });
558
+ }
559
+ return result.value;
560
+ };
561
+ var createExtensibleSchemasAndValidators = (options) => {
562
+ const schemas = options.schemas && { ...options.schemas, ...options.extend?.schemas };
563
+ const validators = options.validators && { ...options.validators, ...options.extend?.validators };
564
+ return { schemas, validators };
565
+ };
566
+ var handleValidation = async (responseData, schema, validator) => {
567
+ const validResponseData = validator ? validator(responseData) : responseData;
568
+ const schemaValidResponseData = schema ? await standardSchemaParser(schema, validResponseData) : validResponseData;
569
+ return schemaValidResponseData;
570
+ };
571
+
572
+ // src/createFetchClient.ts
573
+ var createFetchClient = (baseConfig) => {
574
+ const [baseFetchOptions, baseExtraOptions] = splitBaseConfig(baseConfig ?? {});
575
+ const $RequestInfoCache = /* @__PURE__ */ new Map();
576
+ const callApi2 = async (...parameters) => {
577
+ const [initURL, config = {}] = parameters;
578
+ const [fetchOptions, extraOptions] = splitConfig(config);
579
+ const initCombinedHooks = {};
580
+ for (const key of Object.keys(hooksEnum)) {
581
+ const combinedHook = combineHooks(
582
+ baseExtraOptions[key],
583
+ extraOptions[key]
584
+ );
585
+ initCombinedHooks[key] = combinedHook;
586
+ }
587
+ const defaultExtraOptions = {
588
+ baseURL: "",
589
+ bodySerializer: JSON.stringify,
590
+ dedupeStrategy: "cancel",
591
+ defaultErrorMessage: "Failed to fetch data from server!",
592
+ mergedHooksExecutionMode: "parallel",
593
+ mergedHooksExecutionOrder: "mainHooksAfterPlugins",
594
+ responseType: "json",
595
+ resultMode: "all",
596
+ retryAttempts: 0,
597
+ retryDelay: 1e3,
598
+ retryMaxDelay: 1e4,
599
+ retryMethods: defaultRetryMethods,
600
+ retryStatusCodes: defaultRetryStatusCodes,
601
+ retryStrategy: "linear",
602
+ ...baseExtraOptions,
603
+ ...extraOptions,
604
+ ...initCombinedHooks
605
+ };
606
+ const body = fetchOptions.body ?? baseFetchOptions.body;
607
+ const defaultRequestOptions = {
608
+ ...baseFetchOptions,
609
+ ...fetchOptions,
610
+ body: isPlainObject(body) ? defaultExtraOptions.bodySerializer(body) : body,
611
+ headers: mergeAndResolveHeaders({
612
+ auth: defaultExtraOptions.auth,
613
+ baseHeaders: baseFetchOptions.headers,
614
+ body,
615
+ headers: fetchOptions.headers
616
+ }),
617
+ signal: fetchOptions.signal ?? baseFetchOptions.signal
618
+ };
619
+ const { resolvedHooks, resolvedOptions, resolvedRequestOptions, url } = await initializePlugins({
620
+ initURL,
621
+ options: defaultExtraOptions,
622
+ request: defaultRequestOptions
623
+ });
624
+ const fullURL = `${resolvedOptions.baseURL}${mergeUrlWithParamsAndQuery(url, resolvedOptions.params, resolvedOptions.query)}`;
625
+ const options = {
626
+ ...resolvedOptions,
627
+ ...resolvedHooks,
628
+ fullURL,
629
+ initURL: initURL.toString()
630
+ };
631
+ const newFetchController = new AbortController();
632
+ const timeoutSignal = options.timeout != null ? createTimeoutSignal(options.timeout) : null;
633
+ const combinedSignal = createCombinedSignal(
634
+ resolvedRequestOptions.signal,
635
+ timeoutSignal,
636
+ newFetchController.signal
637
+ );
638
+ const request = {
639
+ ...resolvedRequestOptions,
640
+ signal: combinedSignal
641
+ };
642
+ const { handleRequestCancelStrategy, handleRequestDeferStrategy, removeDedupeKeyFromCache } = await createDedupeStrategy({ $RequestInfoCache, newFetchController, options, request });
643
+ await handleRequestCancelStrategy();
644
+ try {
645
+ await executeHooks(options.onRequest({ options, request }));
646
+ request.headers = mergeAndResolveHeaders({
647
+ auth: options.auth,
648
+ baseHeaders: baseFetchOptions.headers,
649
+ body,
650
+ headers: request.headers
651
+ });
652
+ const response = await handleRequestDeferStrategy();
653
+ const shouldCloneResponse = options.dedupeStrategy === "defer" || options.cloneResponse;
654
+ const { schemas, validators } = createExtensibleSchemasAndValidators(options);
655
+ if (!response.ok) {
656
+ const errorData = await resolveResponseData(
657
+ shouldCloneResponse ? response.clone() : response,
658
+ options.responseType,
659
+ options.responseParser
660
+ );
661
+ const validErrorData = await handleValidation(
662
+ errorData,
663
+ schemas?.errorData,
664
+ validators?.errorData
665
+ );
666
+ throw new HTTPError({
667
+ defaultErrorMessage: options.defaultErrorMessage,
668
+ errorData: validErrorData,
669
+ response
670
+ });
671
+ }
672
+ const successData = await resolveResponseData(
673
+ shouldCloneResponse ? response.clone() : response,
674
+ options.responseType,
675
+ options.responseParser
676
+ );
677
+ const validSuccessData = await handleValidation(successData, schemas?.data, validators?.data);
678
+ const successContext = {
679
+ data: validSuccessData,
680
+ options,
681
+ request,
682
+ response: options.cloneResponse ? response.clone() : response
683
+ };
684
+ await executeHooks(
685
+ options.onSuccess(successContext),
686
+ options.onResponse({ ...successContext, error: null })
687
+ );
688
+ return await resolveSuccessResult({
689
+ data: successContext.data,
690
+ response: successContext.response,
691
+ resultMode: options.resultMode
692
+ });
693
+ } catch (error) {
694
+ const { apiDetails, getErrorResult } = resolveErrorResult({
695
+ cloneResponse: options.cloneResponse,
696
+ defaultErrorMessage: options.defaultErrorMessage,
697
+ error,
698
+ resultMode: options.resultMode
699
+ });
700
+ const errorContext = {
701
+ error: apiDetails.error,
702
+ options,
703
+ request,
704
+ response: apiDetails.response
705
+ };
706
+ const { getDelay, shouldAttemptRetry } = createRetryStrategy(options, errorContext);
707
+ const shouldRetry = !combinedSignal.aborted && await shouldAttemptRetry();
708
+ if (shouldRetry) {
709
+ await executeHooks(options.onRetry(errorContext));
710
+ const delay = getDelay();
711
+ await waitUntil(delay);
712
+ const updatedOptions = {
713
+ ...config,
714
+ "~retryCount": (options["~retryCount"] ?? 0) + 1
715
+ };
716
+ return await callApi2(initURL, updatedOptions);
717
+ }
718
+ const shouldThrowOnError = isFunction(options.throwOnError) ? options.throwOnError(errorContext) : options.throwOnError;
719
+ const handleThrowOnError = () => {
720
+ if (!shouldThrowOnError) return;
721
+ throw apiDetails.error;
722
+ };
723
+ if (isHTTPErrorInstance(error)) {
724
+ await executeHooks(
725
+ options.onResponseError(errorContext),
726
+ options.onError(errorContext),
727
+ options.onResponse({ ...errorContext, data: null })
728
+ );
729
+ handleThrowOnError();
730
+ return getErrorResult();
731
+ }
732
+ if (error instanceof DOMException && error.name === "AbortError") {
733
+ const { message, name } = error;
734
+ console.error(`${name}:`, message);
735
+ handleThrowOnError();
736
+ return getErrorResult();
737
+ }
738
+ if (error instanceof DOMException && error.name === "TimeoutError") {
739
+ const message = `Request timed out after ${options.timeout}ms`;
740
+ console.error(`${error.name}:`, message);
741
+ handleThrowOnError();
742
+ return getErrorResult({ message });
743
+ }
744
+ await executeHooks(
745
+ // == At this point only the request errors exist, so the request error interceptor is called
746
+ options.onRequestError(errorContext),
747
+ // == Also call the onError interceptor
748
+ options.onError(errorContext)
749
+ );
750
+ handleThrowOnError();
751
+ return getErrorResult();
752
+ } finally {
753
+ removeDedupeKeyFromCache();
754
+ }
755
+ };
756
+ callApi2.create = createFetchClient;
757
+ return callApi2;
758
+ };
759
+ var callApi = createFetchClient();
760
+
761
+ // src/defineParameters.ts
762
+ var defineParameters = (...parameters) => {
763
+ return parameters;
764
+ };
765
+ // Annotate the CommonJS export names for ESM import in node:
766
+ 0 && (module.exports = {
767
+ HTTPError,
768
+ callApi,
769
+ createFetchClient,
770
+ defineParameters,
771
+ definePlugin
772
+ });
773
+ //# sourceMappingURL=index.cjs.map