@zayne-labs/callapi 1.7.16 → 1.8.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/dist/esm/index.js CHANGED
@@ -1,729 +1,738 @@
1
- import { splitConfig, isFunction, splitBaseConfig, createTimeoutSignal, createCombinedSignal, commonDefaults, getHeaders, isSerializable, HTTPError, isHTTPErrorInstance, waitUntil, hookDefaults, dedupeDefaults, responseDefaults, retryDefaults, isArray, isPlainObject, isString, toQueryString, getFetchImpl, isReadableStream, isHTTPError, requestOptionDefaults, isObject } from './chunk-IXCM5X4X.js';
2
- export { HTTPError } from './chunk-IXCM5X4X.js';
1
+ import { HTTPError, ValidationError, commonDefaults, createCombinedSignal, createTimeoutSignal, dedupeDefaults, defineSchema, getBody, getFetchImpl, getHeaders, handleOptionsValidation, handleValidation, hookDefaults, isArray, isFunction, isHTTPError, isHTTPErrorInstance, isObject, isPlainObject, isReadableStream, isString, isValidationErrorInstance, requestOptionDefaults, responseDefaults, retryDefaults, routeKeyMethods, splitBaseConfig, splitConfig, toQueryString, waitFor } from "./utils-C_6UX70F.js";
3
2
 
4
- // src/result.ts
5
- var getResponseType = (response, parser) => ({
6
- arrayBuffer: () => response.arrayBuffer(),
7
- blob: () => response.blob(),
8
- formData: () => response.formData(),
9
- json: async () => {
10
- const text = await response.text();
11
- return parser(text);
12
- },
13
- stream: () => response.body,
14
- text: () => response.text()
3
+ //#region src/result.ts
4
+ const getResponseType = (response, parser) => ({
5
+ arrayBuffer: () => response.arrayBuffer(),
6
+ blob: () => response.blob(),
7
+ formData: () => response.formData(),
8
+ json: async () => {
9
+ const text = await response.text();
10
+ return parser(text);
11
+ },
12
+ stream: () => response.body,
13
+ text: () => response.text()
15
14
  });
16
- var resolveResponseData = (response, responseType, parser) => {
17
- const selectedParser = parser ?? responseDefaults.responseParser;
18
- const selectedResponseType = responseType ?? responseDefaults.responseType;
19
- const RESPONSE_TYPE_LOOKUP = getResponseType(response, selectedParser);
20
- if (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, selectedResponseType)) {
21
- throw new Error(`Invalid response type: ${responseType}`);
22
- }
23
- return RESPONSE_TYPE_LOOKUP[selectedResponseType]();
15
+ const resolveResponseData = (response, responseType, parser) => {
16
+ const selectedParser = parser ?? responseDefaults.responseParser;
17
+ const selectedResponseType = responseType ?? responseDefaults.responseType;
18
+ const RESPONSE_TYPE_LOOKUP = getResponseType(response, selectedParser);
19
+ if (!Object.hasOwn(RESPONSE_TYPE_LOOKUP, selectedResponseType)) throw new Error(`Invalid response type: ${responseType}`);
20
+ return RESPONSE_TYPE_LOOKUP[selectedResponseType]();
24
21
  };
25
- var getResultModeMap = (details) => {
26
- const resultModeMap = {
27
- all: () => details,
28
- allWithException: () => resultModeMap.all(),
29
- onlySuccess: () => details.data,
30
- onlySuccessWithException: () => resultModeMap.onlySuccess()
31
- };
32
- return resultModeMap;
22
+ const getResultModeMap = (details) => {
23
+ const resultModeMap = {
24
+ all: () => details,
25
+ allWithException: () => resultModeMap.all(),
26
+ onlySuccess: () => details.data,
27
+ onlySuccessWithException: () => resultModeMap.onlySuccess()
28
+ };
29
+ return resultModeMap;
33
30
  };
34
- var resolveSuccessResult = (data, info) => {
35
- const { response, resultMode } = info;
36
- const details = {
37
- data,
38
- error: null,
39
- response
40
- };
41
- const resultModeMap = getResultModeMap(details);
42
- const successResult = resultModeMap[resultMode ?? "all"]();
43
- return successResult;
31
+ const resolveSuccessResult = (data, info) => {
32
+ const { response, resultMode } = info;
33
+ const details = {
34
+ data,
35
+ error: null,
36
+ response
37
+ };
38
+ const resultModeMap = getResultModeMap(details);
39
+ const successResult = resultModeMap[resultMode ?? "all"]();
40
+ return successResult;
44
41
  };
45
- var resolveErrorResult = (error, info) => {
46
- const { cloneResponse, defaultErrorMessage, message: customErrorMessage, resultMode } = info;
47
- let details = {
48
- data: null,
49
- error: {
50
- errorData: error,
51
- message: customErrorMessage ?? error.message,
52
- name: error.name,
53
- originalError: error
54
- },
55
- response: null
56
- };
57
- if (isHTTPErrorInstance(error)) {
58
- const selectedDefaultErrorMessage = defaultErrorMessage ?? commonDefaults.defaultErrorMessage;
59
- const { errorData, message = selectedDefaultErrorMessage, name, response } = error;
60
- details = {
61
- data: null,
62
- error: {
63
- errorData,
64
- message,
65
- name,
66
- originalError: error
67
- },
68
- response: cloneResponse ? response.clone() : response
69
- };
70
- }
71
- const resultModeMap = getResultModeMap(details);
72
- const errorResult = resultModeMap[resultMode ?? "all"]();
73
- return errorResult;
42
+ const resolveErrorResult = (error, info) => {
43
+ const { cloneResponse, defaultErrorMessage, message: customErrorMessage, resultMode } = info;
44
+ let details = {
45
+ data: null,
46
+ error: {
47
+ errorData: error,
48
+ message: customErrorMessage ?? error.message,
49
+ name: error.name,
50
+ originalError: error
51
+ },
52
+ response: null
53
+ };
54
+ if (isValidationErrorInstance(error)) {
55
+ const { issues, message, response } = error;
56
+ details = {
57
+ data: null,
58
+ error: {
59
+ errorData: issues,
60
+ message,
61
+ name: "ValidationError",
62
+ originalError: error
63
+ },
64
+ response
65
+ };
66
+ }
67
+ if (isHTTPErrorInstance(error)) {
68
+ const selectedDefaultErrorMessage = defaultErrorMessage ?? commonDefaults.defaultErrorMessage;
69
+ const { errorData, message = selectedDefaultErrorMessage, name, response } = error;
70
+ details = {
71
+ data: null,
72
+ error: {
73
+ errorData,
74
+ message,
75
+ name,
76
+ originalError: error
77
+ },
78
+ response: cloneResponse ? response.clone() : response
79
+ };
80
+ }
81
+ const resultModeMap = getResultModeMap(details);
82
+ const errorResult = resultModeMap[resultMode ?? "all"]();
83
+ return errorResult;
74
84
  };
75
- var getCustomizedErrorResult = (errorResult, customErrorInfo) => {
76
- if (!errorResult) {
77
- return null;
78
- }
79
- const { message = errorResult.error.message } = customErrorInfo;
80
- return {
81
- ...errorResult,
82
- error: {
83
- ...errorResult.error,
84
- message
85
- }
86
- };
85
+ const getCustomizedErrorResult = (errorResult, customErrorInfo) => {
86
+ if (!errorResult) return null;
87
+ const { message = errorResult.error.message } = customErrorInfo;
88
+ return {
89
+ ...errorResult,
90
+ error: {
91
+ ...errorResult.error,
92
+ message
93
+ }
94
+ };
87
95
  };
88
96
 
89
- // src/hooks.ts
90
- var hookRegistries = {
91
- onError: /* @__PURE__ */ new Set(),
92
- onRequest: /* @__PURE__ */ new Set(),
93
- onRequestError: /* @__PURE__ */ new Set(),
94
- onRequestStream: /* @__PURE__ */ new Set(),
95
- onResponse: /* @__PURE__ */ new Set(),
96
- onResponseError: /* @__PURE__ */ new Set(),
97
- onResponseStream: /* @__PURE__ */ new Set(),
98
- onRetry: /* @__PURE__ */ new Set(),
99
- onSuccess: /* @__PURE__ */ new Set()
97
+ //#endregion
98
+ //#region src/hooks.ts
99
+ const hookRegistries = {
100
+ onError: /* @__PURE__ */ new Set(),
101
+ onRequest: /* @__PURE__ */ new Set(),
102
+ onRequestError: /* @__PURE__ */ new Set(),
103
+ onRequestStream: /* @__PURE__ */ new Set(),
104
+ onResponse: /* @__PURE__ */ new Set(),
105
+ onResponseError: /* @__PURE__ */ new Set(),
106
+ onResponseStream: /* @__PURE__ */ new Set(),
107
+ onRetry: /* @__PURE__ */ new Set(),
108
+ onSuccess: /* @__PURE__ */ new Set(),
109
+ onValidationError: /* @__PURE__ */ new Set()
100
110
  };
101
- var composeTwoHooks = (hooks, mergedHooksExecutionMode) => {
102
- if (hooks.length === 0) return;
103
- const mergedHook = async (ctx) => {
104
- if (mergedHooksExecutionMode === "sequential") {
105
- for (const hook of hooks) {
106
- await hook?.(ctx);
107
- }
108
- return;
109
- }
110
- if (mergedHooksExecutionMode === "parallel") {
111
- const hookArray = [...hooks];
112
- await Promise.all(hookArray.map((uniqueHook) => uniqueHook?.(ctx)));
113
- }
114
- };
115
- return mergedHook;
111
+ const composeTwoHooks = (hooks, mergedHooksExecutionMode) => {
112
+ if (hooks.length === 0) return;
113
+ const mergedHook = async (ctx) => {
114
+ if (mergedHooksExecutionMode === "sequential") {
115
+ for (const hook of hooks) await hook?.(ctx);
116
+ return;
117
+ }
118
+ if (mergedHooksExecutionMode === "parallel") {
119
+ const hookArray = [...hooks];
120
+ await Promise.all(hookArray.map((uniqueHook) => uniqueHook?.(ctx)));
121
+ }
122
+ };
123
+ return mergedHook;
116
124
  };
117
- var executeHooksInTryBlock = async (...hookResultsOrPromise) => {
118
- await Promise.all(hookResultsOrPromise);
125
+ const executeHooksInTryBlock = async (...hookResultsOrPromise) => {
126
+ await Promise.all(hookResultsOrPromise);
119
127
  };
120
- var executeHooksInCatchBlock = async (hookResultsOrPromise, hookInfo) => {
121
- const { errorInfo, shouldThrowOnError } = hookInfo;
122
- try {
123
- await Promise.all(hookResultsOrPromise);
124
- return null;
125
- } catch (hookError) {
126
- const hookErrorResult = resolveErrorResult(hookError, errorInfo);
127
- if (shouldThrowOnError) {
128
- throw hookError;
129
- }
130
- return hookErrorResult;
131
- }
128
+ const executeHooksInCatchBlock = async (hookResultsOrPromise, hookInfo) => {
129
+ const { errorInfo, shouldThrowOnError } = hookInfo;
130
+ try {
131
+ await Promise.all(hookResultsOrPromise);
132
+ return null;
133
+ } catch (hookError) {
134
+ const hookErrorResult = resolveErrorResult(hookError, errorInfo);
135
+ if (shouldThrowOnError) throw hookError;
136
+ return hookErrorResult;
137
+ }
132
138
  };
133
139
 
134
- // src/stream.ts
135
- var createProgressEvent = (options) => {
136
- const { chunk, totalBytes, transferredBytes } = options;
137
- return {
138
- chunk,
139
- progress: Math.round(transferredBytes / totalBytes * 100) || 0,
140
- totalBytes,
141
- transferredBytes
142
- };
140
+ //#endregion
141
+ //#region src/stream.ts
142
+ const createProgressEvent = (options) => {
143
+ const { chunk, totalBytes, transferredBytes } = options;
144
+ return {
145
+ chunk,
146
+ progress: Math.round(transferredBytes / totalBytes * 100) || 0,
147
+ totalBytes,
148
+ transferredBytes
149
+ };
143
150
  };
144
- var calculateTotalBytesFromBody = async (requestBody, existingTotalBytes) => {
145
- let totalBytes = existingTotalBytes;
146
- if (!requestBody) {
147
- return totalBytes;
148
- }
149
- for await (const chunk of requestBody) {
150
- totalBytes += chunk.byteLength;
151
- }
152
- return totalBytes;
151
+ const calculateTotalBytesFromBody = async (requestBody, existingTotalBytes) => {
152
+ let totalBytes = existingTotalBytes;
153
+ if (!requestBody) return totalBytes;
154
+ for await (const chunk of requestBody) totalBytes += chunk.byteLength;
155
+ return totalBytes;
153
156
  };
154
- var toStreamableRequest = async (context) => {
155
- const { baseConfig, config, options, request, requestInstance } = context;
156
- if (!options.onRequestStream || !requestInstance.body) return;
157
- const contentLength = requestInstance.headers.get("content-length") ?? new Headers(request.headers).get("content-length") ?? request.body?.size;
158
- let totalBytes = Number(contentLength ?? 0);
159
- const shouldForceContentLengthCalc = isObject(options.forceCalculateStreamSize) ? options.forceCalculateStreamSize.request : options.forceCalculateStreamSize;
160
- if (!contentLength && shouldForceContentLengthCalc) {
161
- totalBytes = await calculateTotalBytesFromBody(requestInstance.clone().body, totalBytes);
162
- }
163
- let transferredBytes = 0;
164
- await executeHooksInTryBlock(
165
- options.onRequestStream({
166
- baseConfig,
167
- config,
168
- event: createProgressEvent({ chunk: new Uint8Array(), totalBytes, transferredBytes }),
169
- options,
170
- request,
171
- requestInstance
172
- })
173
- );
174
- const body = requestInstance.body;
175
- void new ReadableStream({
176
- start: async (controller) => {
177
- if (!body) return;
178
- for await (const chunk of body) {
179
- transferredBytes += chunk.byteLength;
180
- totalBytes = Math.max(totalBytes, transferredBytes);
181
- await executeHooksInTryBlock(
182
- options.onRequestStream?.({
183
- baseConfig,
184
- config,
185
- event: createProgressEvent({ chunk, totalBytes, transferredBytes }),
186
- options,
187
- request,
188
- requestInstance
189
- })
190
- );
191
- controller.enqueue(chunk);
192
- }
193
- controller.close();
194
- }
195
- });
157
+ const toStreamableRequest = async (context) => {
158
+ const { baseConfig, config, options, request, requestInstance } = context;
159
+ if (!options.onRequestStream || !requestInstance.body) return;
160
+ const contentLength = requestInstance.headers.get("content-length") ?? new Headers(request.headers).get("content-length") ?? request.body?.size;
161
+ let totalBytes = Number(contentLength ?? 0);
162
+ const shouldForceContentLengthCalc = isObject(options.forceCalculateStreamSize) ? options.forceCalculateStreamSize.request : options.forceCalculateStreamSize;
163
+ if (!contentLength && shouldForceContentLengthCalc) totalBytes = await calculateTotalBytesFromBody(requestInstance.clone().body, totalBytes);
164
+ let transferredBytes = 0;
165
+ await executeHooksInTryBlock(options.onRequestStream({
166
+ baseConfig,
167
+ config,
168
+ event: createProgressEvent({
169
+ chunk: new Uint8Array(),
170
+ totalBytes,
171
+ transferredBytes
172
+ }),
173
+ options,
174
+ request,
175
+ requestInstance
176
+ }));
177
+ const body = requestInstance.body;
178
+ new ReadableStream({ start: async (controller) => {
179
+ if (!body) return;
180
+ for await (const chunk of body) {
181
+ transferredBytes += chunk.byteLength;
182
+ totalBytes = Math.max(totalBytes, transferredBytes);
183
+ await executeHooksInTryBlock(options.onRequestStream?.({
184
+ baseConfig,
185
+ config,
186
+ event: createProgressEvent({
187
+ chunk,
188
+ totalBytes,
189
+ transferredBytes
190
+ }),
191
+ options,
192
+ request,
193
+ requestInstance
194
+ }));
195
+ controller.enqueue(chunk);
196
+ }
197
+ controller.close();
198
+ } });
196
199
  };
197
- var toStreamableResponse = async (context) => {
198
- const { baseConfig, config, options, request, response } = context;
199
- if (!options.onResponseStream || !response.body) {
200
- return response;
201
- }
202
- const contentLength = response.headers.get("content-length");
203
- let totalBytes = Number(contentLength ?? 0);
204
- const shouldForceContentLengthCalc = isObject(options.forceCalculateStreamSize) ? options.forceCalculateStreamSize.response : options.forceCalculateStreamSize;
205
- if (!contentLength && shouldForceContentLengthCalc) {
206
- totalBytes = await calculateTotalBytesFromBody(response.clone().body, totalBytes);
207
- }
208
- let transferredBytes = 0;
209
- await executeHooksInTryBlock(
210
- options.onResponseStream({
211
- baseConfig,
212
- config,
213
- event: createProgressEvent({ chunk: new Uint8Array(), totalBytes, transferredBytes }),
214
- options,
215
- request,
216
- response
217
- })
218
- );
219
- const body = response.body;
220
- const stream = new ReadableStream({
221
- start: async (controller) => {
222
- if (!body) return;
223
- for await (const chunk of body) {
224
- transferredBytes += chunk.byteLength;
225
- totalBytes = Math.max(totalBytes, transferredBytes);
226
- await executeHooksInTryBlock(
227
- options.onResponseStream?.({
228
- baseConfig,
229
- config,
230
- event: createProgressEvent({ chunk, totalBytes, transferredBytes }),
231
- options,
232
- request,
233
- response
234
- })
235
- );
236
- controller.enqueue(chunk);
237
- }
238
- controller.close();
239
- }
240
- });
241
- return new Response(stream, response);
200
+ const toStreamableResponse = async (context) => {
201
+ const { baseConfig, config, options, request, response } = context;
202
+ if (!options.onResponseStream || !response.body) return response;
203
+ const contentLength = response.headers.get("content-length");
204
+ let totalBytes = Number(contentLength ?? 0);
205
+ const shouldForceContentLengthCalc = isObject(options.forceCalculateStreamSize) ? options.forceCalculateStreamSize.response : options.forceCalculateStreamSize;
206
+ if (!contentLength && shouldForceContentLengthCalc) totalBytes = await calculateTotalBytesFromBody(response.clone().body, totalBytes);
207
+ let transferredBytes = 0;
208
+ await executeHooksInTryBlock(options.onResponseStream({
209
+ baseConfig,
210
+ config,
211
+ event: createProgressEvent({
212
+ chunk: new Uint8Array(),
213
+ totalBytes,
214
+ transferredBytes
215
+ }),
216
+ options,
217
+ request,
218
+ response
219
+ }));
220
+ const body = response.body;
221
+ const stream = new ReadableStream({ start: async (controller) => {
222
+ if (!body) return;
223
+ for await (const chunk of body) {
224
+ transferredBytes += chunk.byteLength;
225
+ totalBytes = Math.max(totalBytes, transferredBytes);
226
+ await executeHooksInTryBlock(options.onResponseStream?.({
227
+ baseConfig,
228
+ config,
229
+ event: createProgressEvent({
230
+ chunk,
231
+ totalBytes,
232
+ transferredBytes
233
+ }),
234
+ options,
235
+ request,
236
+ response
237
+ }));
238
+ controller.enqueue(chunk);
239
+ }
240
+ controller.close();
241
+ } });
242
+ return new Response(stream, response);
242
243
  };
243
244
 
244
- // src/dedupe.ts
245
- var createDedupeStrategy = async (context) => {
246
- const { $RequestInfoCache, baseConfig, config, newFetchController, options, request } = context;
247
- const dedupeStrategy = options.dedupeStrategy ?? dedupeDefaults.dedupeStrategy;
248
- const generateDedupeKey = () => {
249
- const shouldHaveDedupeKey = dedupeStrategy === "cancel" || dedupeStrategy === "defer";
250
- if (!shouldHaveDedupeKey) {
251
- return null;
252
- }
253
- return `${options.fullURL}-${JSON.stringify({ options, request })}`;
254
- };
255
- const dedupeKey = options.dedupeKey ?? generateDedupeKey();
256
- const $RequestInfoCacheOrNull = dedupeKey !== null ? $RequestInfoCache : null;
257
- if (dedupeKey !== null) {
258
- await waitUntil(0.1);
259
- }
260
- const prevRequestInfo = $RequestInfoCacheOrNull?.get(dedupeKey);
261
- const handleRequestCancelStrategy = () => {
262
- const shouldCancelRequest = prevRequestInfo && dedupeStrategy === "cancel";
263
- if (!shouldCancelRequest) return;
264
- 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`;
265
- const reason = new DOMException(message, "AbortError");
266
- prevRequestInfo.controller.abort(reason);
267
- return Promise.resolve();
268
- };
269
- const handleRequestDeferStrategy = async () => {
270
- const fetchApi = getFetchImpl(options.customFetchImpl);
271
- const shouldUsePromiseFromCache = prevRequestInfo && dedupeStrategy === "defer";
272
- const requestInstance = new Request(
273
- options.fullURL,
274
- isReadableStream(request.body) && !request.duplex ? { ...request, duplex: "half" } : request
275
- );
276
- await toStreamableRequest({
277
- baseConfig,
278
- config,
279
- options,
280
- request,
281
- requestInstance: requestInstance.clone()
282
- });
283
- const getFetchApiPromise = () => {
284
- if (isReadableStream(request.body)) {
285
- return fetchApi(requestInstance.clone());
286
- }
287
- const method = request.method ?? requestOptionDefaults.method;
288
- const modifiedRequest = { ...request, method };
289
- return fetchApi(options.fullURL, modifiedRequest);
290
- };
291
- const responsePromise = shouldUsePromiseFromCache ? prevRequestInfo.responsePromise : getFetchApiPromise();
292
- $RequestInfoCacheOrNull?.set(dedupeKey, { controller: newFetchController, responsePromise });
293
- const streamableResponse = toStreamableResponse({
294
- baseConfig,
295
- config,
296
- options,
297
- request,
298
- response: await responsePromise
299
- });
300
- return streamableResponse;
301
- };
302
- const removeDedupeKeyFromCache = () => {
303
- $RequestInfoCacheOrNull?.delete(dedupeKey);
304
- };
305
- return {
306
- dedupeStrategy,
307
- handleRequestCancelStrategy,
308
- handleRequestDeferStrategy,
309
- removeDedupeKeyFromCache
310
- };
245
+ //#endregion
246
+ //#region src/dedupe.ts
247
+ const getAbortErrorMessage = (dedupeKey, fullURL) => {
248
+ return dedupeKey ? `Duplicate request detected - Aborting previous request with key '${dedupeKey}' as a new request was initiated` : `Duplicate request detected - Aborting previous request to '${fullURL}' as a new request with identical options was initiated`;
249
+ };
250
+ const createDedupeStrategy = async (context) => {
251
+ const { $RequestInfoCache, baseConfig, config, newFetchController, options: globalOptions, request: globalRequest } = context;
252
+ const dedupeStrategy = globalOptions.dedupeStrategy ?? dedupeDefaults.dedupeStrategy;
253
+ const generateDedupeKey = () => {
254
+ const shouldHaveDedupeKey = dedupeStrategy === "cancel" || dedupeStrategy === "defer";
255
+ if (!shouldHaveDedupeKey) return null;
256
+ return `${globalOptions.fullURL}-${JSON.stringify({
257
+ options: globalOptions,
258
+ request: globalRequest
259
+ })}`;
260
+ };
261
+ const dedupeKey = globalOptions.dedupeKey ?? generateDedupeKey();
262
+ const $RequestInfoCacheOrNull = dedupeKey !== null ? $RequestInfoCache : null;
263
+ /******
264
+ * == Add a small delay to the execution to ensure proper request deduplication when multiple requests with the same key start simultaneously.
265
+ * == This gives time for the cache to be updated with the previous request info before the next request checks it.
266
+ ******/
267
+ if (dedupeKey !== null) await waitFor(.1);
268
+ const prevRequestInfo = $RequestInfoCacheOrNull?.get(dedupeKey);
269
+ const handleRequestCancelStrategy = () => {
270
+ const shouldCancelRequest = prevRequestInfo && dedupeStrategy === "cancel";
271
+ if (!shouldCancelRequest) return;
272
+ const message = getAbortErrorMessage(globalOptions.dedupeKey, globalOptions.fullURL);
273
+ const reason = new DOMException(message, "AbortError");
274
+ prevRequestInfo.controller.abort(reason);
275
+ return Promise.resolve();
276
+ };
277
+ const handleRequestDeferStrategy = async (options, request) => {
278
+ const fetchApi = getFetchImpl(options.customFetchImpl);
279
+ const shouldUsePromiseFromCache = prevRequestInfo && dedupeStrategy === "defer";
280
+ const requestObjectForStream = isReadableStream(request.body) ? {
281
+ ...request,
282
+ duplex: request.duplex ?? "half"
283
+ } : request;
284
+ const requestInstance = new Request(options.fullURL, requestObjectForStream);
285
+ await toStreamableRequest({
286
+ baseConfig,
287
+ config,
288
+ options,
289
+ request,
290
+ requestInstance: requestInstance.clone()
291
+ });
292
+ const getFetchApiPromise = () => {
293
+ if (isReadableStream(request.body)) return fetchApi(requestInstance.clone());
294
+ return fetchApi(options.fullURL, request);
295
+ };
296
+ const responsePromise = shouldUsePromiseFromCache ? prevRequestInfo.responsePromise : getFetchApiPromise();
297
+ $RequestInfoCacheOrNull?.set(dedupeKey, {
298
+ controller: newFetchController,
299
+ responsePromise
300
+ });
301
+ const streamableResponse = toStreamableResponse({
302
+ baseConfig,
303
+ config,
304
+ options,
305
+ request,
306
+ response: await responsePromise
307
+ });
308
+ return streamableResponse;
309
+ };
310
+ const removeDedupeKeyFromCache = () => {
311
+ $RequestInfoCacheOrNull?.delete(dedupeKey);
312
+ };
313
+ return {
314
+ dedupeStrategy,
315
+ handleRequestCancelStrategy,
316
+ handleRequestDeferStrategy,
317
+ removeDedupeKeyFromCache
318
+ };
311
319
  };
312
320
 
313
- // src/plugins.ts
314
- var definePlugin = (plugin) => {
315
- return plugin;
321
+ //#endregion
322
+ //#region src/plugins.ts
323
+ const definePlugin = (plugin) => {
324
+ return plugin;
316
325
  };
317
- var resolvePluginArray = (plugins, basePlugins) => {
318
- if (!plugins) {
319
- return [];
320
- }
321
- if (isFunction(plugins)) {
322
- return plugins({ basePlugins: basePlugins ?? [] });
323
- }
324
- return plugins;
326
+ const resolvePluginArray = (plugins, basePlugins) => {
327
+ if (!plugins) return [];
328
+ if (isFunction(plugins)) return plugins({ basePlugins: basePlugins ?? [] });
329
+ return plugins;
325
330
  };
326
- var initializePlugins = async (context) => {
327
- const { baseConfig, config, initURL, options, request } = context;
328
- const clonedHookRegistries = structuredClone(hookRegistries);
329
- const addMainHooks = () => {
330
- for (const key of Object.keys(clonedHookRegistries)) {
331
- const baseHook = baseConfig[key];
332
- const instanceHook = config[key];
333
- const overriddenHook = options[key];
334
- const mainHook = isArray(baseHook) && Boolean(instanceHook) ? [baseHook, instanceHook].flat() : overriddenHook;
335
- if (!mainHook) continue;
336
- clonedHookRegistries[key].add(mainHook);
337
- }
338
- };
339
- const addPluginHooks = (pluginHooks) => {
340
- for (const key of Object.keys(clonedHookRegistries)) {
341
- const pluginHook = pluginHooks[key];
342
- if (!pluginHook) continue;
343
- clonedHookRegistries[key].add(pluginHook);
344
- }
345
- };
346
- const mergedHooksExecutionOrder = options.mergedHooksExecutionOrder ?? hookDefaults.mergedHooksExecutionOrder;
347
- if (mergedHooksExecutionOrder === "mainHooksBeforePlugins") {
348
- addMainHooks();
349
- }
350
- const resolvedPlugins = resolvePluginArray(options.plugins, baseConfig.plugins);
351
- let resolvedUrl = initURL;
352
- let resolvedOptions = options;
353
- let resolvedRequestOptions = request;
354
- const executePluginInit = async (pluginInit) => {
355
- if (!pluginInit) return;
356
- const initResult = await pluginInit({
357
- baseConfig,
358
- config,
359
- initURL,
360
- options,
361
- request
362
- });
363
- if (!isPlainObject(initResult)) return;
364
- if (isString(initResult.initURL)) {
365
- resolvedUrl = initResult.initURL;
366
- }
367
- if (isPlainObject(initResult.request)) {
368
- resolvedRequestOptions = initResult.request;
369
- }
370
- if (isPlainObject(initResult.options)) {
371
- resolvedOptions = initResult.options;
372
- }
373
- };
374
- for (const plugin of resolvedPlugins) {
375
- await executePluginInit(plugin.init);
376
- if (!plugin.hooks) continue;
377
- addPluginHooks(plugin.hooks);
378
- }
379
- if (mergedHooksExecutionOrder === "mainHooksAfterPlugins") {
380
- addMainHooks();
381
- }
382
- const resolvedHooks = {};
383
- for (const [key, hookRegistry] of Object.entries(clonedHookRegistries)) {
384
- const flattenedHookArray = [...hookRegistry].flat();
385
- const mergedHooksExecutionMode = options.mergedHooksExecutionMode ?? hookDefaults.mergedHooksExecutionMode;
386
- const composedHook = composeTwoHooks(flattenedHookArray, mergedHooksExecutionMode);
387
- composedHook && (resolvedHooks[key] = composedHook);
388
- }
389
- return {
390
- resolvedHooks,
391
- resolvedOptions,
392
- resolvedRequestOptions,
393
- url: resolvedUrl?.toString()
394
- };
331
+ const initializePlugins = async (context) => {
332
+ const { baseConfig, config, initURL, options, request } = context;
333
+ const clonedHookRegistries = structuredClone(hookRegistries);
334
+ const addMainHooks = () => {
335
+ for (const key of Object.keys(clonedHookRegistries)) {
336
+ const baseHook = baseConfig[key];
337
+ const instanceHook = config[key];
338
+ const overriddenHook = options[key];
339
+ const mainHook = isArray(baseHook) && Boolean(instanceHook) ? [baseHook, instanceHook].flat() : overriddenHook;
340
+ if (!mainHook) continue;
341
+ clonedHookRegistries[key].add(mainHook);
342
+ }
343
+ };
344
+ const addPluginHooks = (pluginHooks) => {
345
+ for (const key of Object.keys(clonedHookRegistries)) {
346
+ const pluginHook = pluginHooks[key];
347
+ if (!pluginHook) continue;
348
+ clonedHookRegistries[key].add(pluginHook);
349
+ }
350
+ };
351
+ const mergedHooksExecutionOrder = options.mergedHooksExecutionOrder ?? hookDefaults.mergedHooksExecutionOrder;
352
+ if (mergedHooksExecutionOrder === "mainHooksBeforePlugins") addMainHooks();
353
+ const resolvedPlugins = resolvePluginArray(options.plugins, baseConfig.plugins);
354
+ let resolvedInitURL = initURL;
355
+ let resolvedOptions = options;
356
+ let resolvedRequestOptions = request;
357
+ const executePluginInit = async (pluginInit) => {
358
+ if (!pluginInit) return;
359
+ const initResult = await pluginInit({
360
+ baseConfig,
361
+ config,
362
+ initURL,
363
+ options,
364
+ request
365
+ });
366
+ if (!isPlainObject(initResult)) return;
367
+ const urlString = initResult.initURL?.toString();
368
+ if (isString(urlString)) resolvedInitURL = urlString;
369
+ if (isPlainObject(initResult.request)) resolvedRequestOptions = initResult.request;
370
+ if (isPlainObject(initResult.options)) resolvedOptions = initResult.options;
371
+ };
372
+ for (const plugin of resolvedPlugins) {
373
+ await executePluginInit(plugin.init);
374
+ if (!plugin.hooks) continue;
375
+ addPluginHooks(plugin.hooks);
376
+ }
377
+ if (mergedHooksExecutionOrder === "mainHooksAfterPlugins") addMainHooks();
378
+ const resolvedHooks = {};
379
+ for (const [key, hookRegistry] of Object.entries(clonedHookRegistries)) {
380
+ const flattenedHookArray = [...hookRegistry].flat();
381
+ const mergedHooksExecutionMode = options.mergedHooksExecutionMode ?? hookDefaults.mergedHooksExecutionMode;
382
+ const composedHook = composeTwoHooks(flattenedHookArray, mergedHooksExecutionMode);
383
+ composedHook && (resolvedHooks[key] = composedHook);
384
+ }
385
+ return {
386
+ resolvedHooks,
387
+ resolvedInitURL: resolvedInitURL.toString(),
388
+ resolvedOptions,
389
+ resolvedRequestOptions
390
+ };
395
391
  };
396
392
 
397
- // src/retry.ts
398
- var getLinearDelay = (currentAttemptCount, options) => {
399
- const retryDelay = options.retryDelay ?? options.retry?.delay;
400
- const resolveRetryDelay = (isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay) ?? retryDefaults.delay;
401
- return resolveRetryDelay;
393
+ //#endregion
394
+ //#region src/retry.ts
395
+ const getLinearDelay = (currentAttemptCount, options) => {
396
+ const retryDelay = options.retryDelay ?? options.retry?.delay;
397
+ const resolveRetryDelay = (isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay) ?? retryDefaults.delay;
398
+ return resolveRetryDelay;
402
399
  };
403
- var getExponentialDelay = (currentAttemptCount, options) => {
404
- const retryDelay = options.retryDelay ?? options.retry?.delay ?? retryDefaults.delay;
405
- const resolvedRetryDelay = Number(
406
- isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay
407
- );
408
- const maxDelay = Number(options.retryMaxDelay ?? options.retry?.maxDelay ?? retryDefaults.maxDelay);
409
- const exponentialDelay = resolvedRetryDelay * 2 ** currentAttemptCount;
410
- return Math.min(exponentialDelay, maxDelay);
400
+ const getExponentialDelay = (currentAttemptCount, options) => {
401
+ const retryDelay = options.retryDelay ?? options.retry?.delay ?? retryDefaults.delay;
402
+ const resolvedRetryDelay = Number(isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay);
403
+ const maxDelay = Number(options.retryMaxDelay ?? options.retry?.maxDelay ?? retryDefaults.maxDelay);
404
+ const exponentialDelay = resolvedRetryDelay * 2 ** currentAttemptCount;
405
+ return Math.min(exponentialDelay, maxDelay);
411
406
  };
412
- var createRetryStrategy = (ctx) => {
413
- const { options } = ctx;
414
- const currentAttemptCount = options["~retryAttemptCount"] ?? 1;
415
- const retryStrategy = options.retryStrategy ?? options.retry?.strategy ?? retryDefaults.strategy;
416
- const getDelay = () => {
417
- switch (retryStrategy) {
418
- case "exponential": {
419
- return getExponentialDelay(currentAttemptCount, options);
420
- }
421
- case "linear": {
422
- return getLinearDelay(currentAttemptCount, options);
423
- }
424
- default: {
425
- throw new Error(`Invalid retry strategy: ${String(retryStrategy)}`);
426
- }
427
- }
428
- };
429
- const shouldAttemptRetry = async () => {
430
- const retryCondition = options.retryCondition ?? options.retry?.condition ?? retryDefaults.condition;
431
- const maximumRetryAttempts = options.retryAttempts ?? options.retry?.attempts ?? retryDefaults.attempts;
432
- const customRetryCondition = await retryCondition(ctx);
433
- const baseShouldRetry = maximumRetryAttempts >= currentAttemptCount && customRetryCondition;
434
- if (!baseShouldRetry) {
435
- return false;
436
- }
437
- if (!isHTTPError(ctx.error)) {
438
- return true;
439
- }
440
- const selectedMethodArray = options.retryMethods ?? options.retry?.methods ?? retryDefaults.methods;
441
- const retryMethods = new Set(selectedMethodArray);
442
- const method = ctx.request.method ?? requestOptionDefaults.method;
443
- const includesMethod = Boolean(method) && retryMethods.has(method);
444
- const selectedStatusCodeArray = options.retryStatusCodes ?? options.retry?.statusCodes;
445
- const retryStatusCodes = selectedStatusCodeArray ? new Set(selectedStatusCodeArray) : null;
446
- const includesStatusCodes = Boolean(ctx.response?.status) && (retryStatusCodes?.has(ctx.response.status) ?? true);
447
- const shouldRetry = includesMethod && includesStatusCodes;
448
- return shouldRetry;
449
- };
450
- return {
451
- currentAttemptCount,
452
- getDelay,
453
- shouldAttemptRetry
454
- };
407
+ const createRetryStrategy = (ctx) => {
408
+ const { options } = ctx;
409
+ const currentAttemptCount = options["~retryAttemptCount"] ?? 1;
410
+ const retryStrategy = options.retryStrategy ?? options.retry?.strategy ?? retryDefaults.strategy;
411
+ const getDelay = () => {
412
+ switch (retryStrategy) {
413
+ case "exponential": return getExponentialDelay(currentAttemptCount, options);
414
+ case "linear": return getLinearDelay(currentAttemptCount, options);
415
+ default: throw new Error(`Invalid retry strategy: ${String(retryStrategy)}`);
416
+ }
417
+ };
418
+ const shouldAttemptRetry = async () => {
419
+ const retryCondition = options.retryCondition ?? options.retry?.condition ?? retryDefaults.condition;
420
+ const maximumRetryAttempts = options.retryAttempts ?? options.retry?.attempts ?? retryDefaults.attempts;
421
+ const customRetryCondition = await retryCondition(ctx);
422
+ const baseShouldRetry = maximumRetryAttempts >= currentAttemptCount && customRetryCondition;
423
+ if (!baseShouldRetry) return false;
424
+ if (!isHTTPError(ctx.error)) return true;
425
+ const selectedMethodArray = options.retryMethods ?? options.retry?.methods ?? retryDefaults.methods;
426
+ const retryMethods = new Set(selectedMethodArray);
427
+ const method = ctx.request.method ?? requestOptionDefaults.method;
428
+ const includesMethod = Boolean(method) && retryMethods.has(method);
429
+ const selectedStatusCodeArray = options.retryStatusCodes ?? options.retry?.statusCodes;
430
+ const retryStatusCodes = selectedStatusCodeArray ? new Set(selectedStatusCodeArray) : null;
431
+ const includesStatusCodes = Boolean(ctx.response?.status) && (retryStatusCodes?.has(ctx.response.status) ?? true);
432
+ const shouldRetry = includesMethod && includesStatusCodes;
433
+ return shouldRetry;
434
+ };
435
+ return {
436
+ currentAttemptCount,
437
+ getDelay,
438
+ shouldAttemptRetry
439
+ };
455
440
  };
456
441
 
457
- // src/url.ts
458
- var slash = "/";
459
- var column = ":";
460
- var mergeUrlWithParams = (url, params) => {
461
- if (!params) {
462
- return url;
463
- }
464
- let newUrl = url;
465
- if (isArray(params)) {
466
- const matchedParamArray = newUrl.split(slash).filter((param) => param.startsWith(column));
467
- for (const [index, matchedParam] of matchedParamArray.entries()) {
468
- const realParam = params[index];
469
- newUrl = newUrl.replace(matchedParam, realParam);
470
- }
471
- return newUrl;
472
- }
473
- for (const [key, value] of Object.entries(params)) {
474
- newUrl = newUrl.replace(`${column}${key}`, String(value));
475
- }
476
- return newUrl;
442
+ //#endregion
443
+ //#region src/url.ts
444
+ const slash = "/";
445
+ const column = ":";
446
+ const mergeUrlWithParams = (url, params) => {
447
+ if (!params) return url;
448
+ let newUrl = url;
449
+ if (isArray(params)) {
450
+ const matchedParamArray = newUrl.split(slash).filter((param) => param.startsWith(column));
451
+ for (const [index, matchedParam] of matchedParamArray.entries()) {
452
+ const realParam = params[index];
453
+ newUrl = newUrl.replace(matchedParam, realParam);
454
+ }
455
+ return newUrl;
456
+ }
457
+ for (const [key, value] of Object.entries(params)) newUrl = newUrl.replace(`${column}${key}`, String(value));
458
+ return newUrl;
477
459
  };
478
- var questionMark = "?";
479
- var ampersand = "&";
480
- var mergeUrlWithQuery = (url, query) => {
481
- if (!query) {
482
- return url;
483
- }
484
- const queryString = toQueryString(query);
485
- if (queryString?.length === 0) {
486
- return url;
487
- }
488
- if (url.endsWith(questionMark)) {
489
- return `${url}${queryString}`;
490
- }
491
- if (url.includes(questionMark)) {
492
- return `${url}${ampersand}${queryString}`;
493
- }
494
- return `${url}${questionMark}${queryString}`;
460
+ const questionMark = "?";
461
+ const ampersand = "&";
462
+ const mergeUrlWithQuery = (url, query) => {
463
+ if (!query) return url;
464
+ const queryString = toQueryString(query);
465
+ if (queryString?.length === 0) return url;
466
+ if (url.endsWith(questionMark)) return `${url}${queryString}`;
467
+ if (url.includes(questionMark)) return `${url}${ampersand}${queryString}`;
468
+ return `${url}${questionMark}${queryString}`;
495
469
  };
496
- var mergeUrlWithParamsAndQuery = (url, params, query) => {
497
- if (!url) return;
498
- const urlWithMergedParams = mergeUrlWithParams(url, params);
499
- return mergeUrlWithQuery(urlWithMergedParams, query);
470
+ const getCurrentRouteKey = (url, schemaConfig) => {
471
+ let currentRouteKey = url;
472
+ if (schemaConfig?.baseURL && currentRouteKey.startsWith(schemaConfig.baseURL)) currentRouteKey = currentRouteKey.replace(schemaConfig.baseURL, "");
473
+ return currentRouteKey;
500
474
  };
501
-
502
- // src/validation.ts
503
- var standardSchemaParser = async (schema, inputData) => {
504
- const result = await schema["~standard"].validate(inputData);
505
- if (result.issues) {
506
- throw new Error(JSON.stringify(result.issues, null, 2), { cause: result.issues });
507
- }
508
- return result.value;
475
+ /**
476
+ * @description
477
+ * Extracts the method from the URL if it is a schema modifier.
478
+ *
479
+ * @param initURL - The URL to extract the method from.
480
+ * @returns The method if it is a schema modifier, otherwise undefined.
481
+ */
482
+ const extractMethodFromURL = (initURL) => {
483
+ if (!initURL?.startsWith("@")) return;
484
+ const method = initURL.split("@")[1]?.split("/")[0];
485
+ if (!method || !routeKeyMethods.includes(method)) return;
486
+ return method;
487
+ };
488
+ const getMethod = (options) => {
489
+ const { initURL, method, schemaConfig } = options;
490
+ if (schemaConfig?.requireHttpMethodProvision === true) return method?.toUpperCase() ?? requestOptionDefaults.method;
491
+ return method?.toUpperCase() ?? extractMethodFromURL(initURL)?.toUpperCase() ?? requestOptionDefaults.method;
492
+ };
493
+ const normalizeURL = (initURL) => {
494
+ const methodFromURL = extractMethodFromURL(initURL);
495
+ if (!methodFromURL) return initURL;
496
+ const normalizedURL = initURL.replace(`@${methodFromURL}/`, "/");
497
+ return normalizedURL;
509
498
  };
510
- var handleValidation = async (responseData, schema, validator) => {
511
- const validResponseData = validator ? validator(responseData) : responseData;
512
- const schemaValidResponseData = schema ? await standardSchemaParser(schema, validResponseData) : validResponseData;
513
- return schemaValidResponseData;
499
+ const getFullURL = (options) => {
500
+ const { baseURL, initURL, params, query } = options;
501
+ const normalizedURL = normalizeURL(initURL);
502
+ const urlWithMergedParams = mergeUrlWithParams(normalizedURL, params);
503
+ const urlWithMergedQueryAndParams = mergeUrlWithQuery(urlWithMergedParams, query);
504
+ if (urlWithMergedQueryAndParams.startsWith("http") || !baseURL) return urlWithMergedQueryAndParams;
505
+ return `${baseURL}${urlWithMergedQueryAndParams}`;
514
506
  };
515
507
 
516
- // src/createFetchClient.ts
517
- var createFetchClient = (initBaseConfig = {}) => {
518
- const $RequestInfoCache = /* @__PURE__ */ new Map();
519
- const callApi2 = async (...parameters) => {
520
- const [initURL, initConfig = {}] = parameters;
521
- const [fetchOptions, extraOptions] = splitConfig(initConfig);
522
- const resolvedBaseConfig = isFunction(initBaseConfig) ? initBaseConfig({ initURL: initURL.toString(), options: extraOptions, request: fetchOptions }) : initBaseConfig;
523
- const [baseFetchOptions, baseExtraOptions] = splitBaseConfig(resolvedBaseConfig);
524
- const mergedExtraOptions = {
525
- ...baseExtraOptions,
526
- ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "options" && extraOptions
527
- };
528
- const mergedRequestOptions = {
529
- ...baseFetchOptions,
530
- ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "request" && fetchOptions
531
- };
532
- const baseConfig = resolvedBaseConfig;
533
- const config = initConfig;
534
- const { resolvedHooks, resolvedOptions, resolvedRequestOptions, url } = await initializePlugins({
535
- baseConfig,
536
- config,
537
- initURL,
538
- options: mergedExtraOptions,
539
- request: mergedRequestOptions
540
- });
541
- const fullURL = `${resolvedOptions.baseURL ?? ""}${mergeUrlWithParamsAndQuery(url, resolvedOptions.params, resolvedOptions.query)}`;
542
- const options = {
543
- ...resolvedOptions,
544
- ...resolvedHooks,
545
- fullURL,
546
- initURL: initURL.toString()
547
- };
548
- const newFetchController = new AbortController();
549
- const timeoutSignal = options.timeout != null ? createTimeoutSignal(options.timeout) : null;
550
- const combinedSignal = createCombinedSignal(
551
- resolvedRequestOptions.signal,
552
- timeoutSignal,
553
- newFetchController.signal
554
- );
555
- const bodySerializer = options.bodySerializer ?? commonDefaults.bodySerializer;
556
- const request = {
557
- ...resolvedRequestOptions,
558
- body: isSerializable(resolvedRequestOptions.body) ? bodySerializer(resolvedRequestOptions.body) : resolvedRequestOptions.body,
559
- headers: await getHeaders({
560
- auth: options.auth,
561
- baseHeaders: baseFetchOptions.headers,
562
- body: resolvedRequestOptions.body,
563
- headers: fetchOptions.headers
564
- }),
565
- signal: combinedSignal
566
- };
567
- const {
568
- dedupeStrategy,
569
- handleRequestCancelStrategy,
570
- handleRequestDeferStrategy,
571
- removeDedupeKeyFromCache
572
- } = await createDedupeStrategy({
573
- $RequestInfoCache,
574
- baseConfig,
575
- config,
576
- newFetchController,
577
- options,
578
- request
579
- });
580
- await handleRequestCancelStrategy();
581
- try {
582
- await executeHooksInTryBlock(options.onRequest?.({ baseConfig, config, options, request }));
583
- request.headers = await getHeaders({
584
- auth: options.auth,
585
- body: request.body,
586
- headers: request.headers
587
- });
588
- const response = await handleRequestDeferStrategy();
589
- const shouldCloneResponse = dedupeStrategy === "defer" || options.cloneResponse;
590
- const schemas = isFunction(options.schemas) ? options.schemas({ baseSchemas: baseExtraOptions.schemas }) : options.schemas;
591
- const validators = isFunction(options.validators) ? options.validators({ baseValidators: baseExtraOptions.validators }) : options.validators;
592
- if (!response.ok) {
593
- const errorData = await resolveResponseData(
594
- shouldCloneResponse ? response.clone() : response,
595
- options.responseType,
596
- options.responseParser
597
- );
598
- const validErrorData = await handleValidation(
599
- errorData,
600
- schemas?.errorData,
601
- validators?.errorData
602
- );
603
- throw new HTTPError(
604
- {
605
- defaultErrorMessage: options.defaultErrorMessage,
606
- errorData: validErrorData,
607
- response
608
- },
609
- { cause: validErrorData }
610
- );
611
- }
612
- const successData = await resolveResponseData(
613
- shouldCloneResponse ? response.clone() : response,
614
- options.responseType,
615
- options.responseParser
616
- );
617
- const validSuccessData = await handleValidation(successData, schemas?.data, validators?.data);
618
- const successContext = {
619
- baseConfig,
620
- config,
621
- data: validSuccessData,
622
- options,
623
- request,
624
- response
625
- };
626
- await executeHooksInTryBlock(
627
- options.onSuccess?.(successContext),
628
- options.onResponse?.({ ...successContext, error: null })
629
- );
630
- const successResult = resolveSuccessResult(successContext.data, {
631
- response: successContext.response,
632
- resultMode: options.resultMode
633
- });
634
- return successResult;
635
- } catch (error) {
636
- const errorInfo = {
637
- cloneResponse: options.cloneResponse,
638
- defaultErrorMessage: options.defaultErrorMessage,
639
- resultMode: options.resultMode
640
- };
641
- const generalErrorResult = resolveErrorResult(error, errorInfo);
642
- const errorContext = {
643
- baseConfig,
644
- config,
645
- error: generalErrorResult?.error,
646
- options,
647
- request,
648
- response: generalErrorResult?.response
649
- };
650
- const shouldThrowOnError = isFunction(options.throwOnError) ? options.throwOnError(errorContext) : options.throwOnError;
651
- const hookInfo = {
652
- errorInfo,
653
- shouldThrowOnError
654
- };
655
- const handleRetryOrGetErrorResult = async () => {
656
- const { currentAttemptCount, getDelay, shouldAttemptRetry } = createRetryStrategy(errorContext);
657
- const shouldRetry = !combinedSignal.aborted && await shouldAttemptRetry();
658
- if (shouldRetry) {
659
- const retryContext = {
660
- ...errorContext,
661
- retryAttemptCount: currentAttemptCount
662
- };
663
- const hookError2 = await executeHooksInCatchBlock(
664
- [options.onRetry?.(retryContext)],
665
- hookInfo
666
- );
667
- if (hookError2) {
668
- return hookError2;
669
- }
670
- const delay = getDelay();
671
- await waitUntil(delay);
672
- const updatedOptions = {
673
- ...config,
674
- "~retryAttemptCount": currentAttemptCount + 1
675
- };
676
- return callApi2(initURL, updatedOptions);
677
- }
678
- if (shouldThrowOnError) {
679
- throw error;
680
- }
681
- return generalErrorResult;
682
- };
683
- if (isHTTPErrorInstance(error)) {
684
- const hookError2 = await executeHooksInCatchBlock(
685
- [
686
- options.onResponseError?.(errorContext),
687
- options.onError?.(errorContext),
688
- options.onResponse?.({ ...errorContext, data: null })
689
- ],
690
- hookInfo
691
- );
692
- if (hookError2) {
693
- return hookError2;
694
- }
695
- return await handleRetryOrGetErrorResult();
696
- }
697
- if (error instanceof DOMException && error.name === "AbortError") {
698
- !shouldThrowOnError && console.error(`${error.name}:`, error.message);
699
- }
700
- let timeoutMessage;
701
- if (error instanceof DOMException && error.name === "TimeoutError") {
702
- timeoutMessage = `Request timed out after ${options.timeout}ms`;
703
- !shouldThrowOnError && console.error(`${error.name}:`, timeoutMessage);
704
- }
705
- const hookError = await executeHooksInCatchBlock(
706
- [options.onRequestError?.(errorContext), options.onError?.(errorContext)],
707
- hookInfo
708
- );
709
- if (hookError) {
710
- return hookError;
711
- }
712
- const errorResult = await handleRetryOrGetErrorResult();
713
- return timeoutMessage ? getCustomizedErrorResult(errorResult, { message: timeoutMessage }) : errorResult;
714
- } finally {
715
- removeDedupeKeyFromCache();
716
- }
717
- };
718
- return callApi2;
508
+ //#endregion
509
+ //#region src/createFetchClient.ts
510
+ const createFetchClient = (initBaseConfig = {}) => {
511
+ const $RequestInfoCache = /* @__PURE__ */ new Map();
512
+ const callApi$1 = async (...parameters) => {
513
+ const [initURLOrURLObject, initConfig = {}] = parameters;
514
+ const [fetchOptions, extraOptions] = splitConfig(initConfig);
515
+ const resolvedBaseConfig = isFunction(initBaseConfig) ? initBaseConfig({
516
+ initURL: initURLOrURLObject.toString(),
517
+ options: extraOptions,
518
+ request: fetchOptions
519
+ }) : initBaseConfig;
520
+ const [baseFetchOptions, baseExtraOptions] = splitBaseConfig(resolvedBaseConfig);
521
+ const mergedExtraOptions = {
522
+ ...baseExtraOptions,
523
+ ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "options" && extraOptions
524
+ };
525
+ const mergedRequestOptions = {
526
+ ...baseFetchOptions,
527
+ ...baseExtraOptions.skipAutoMergeFor !== "all" && baseExtraOptions.skipAutoMergeFor !== "request" && fetchOptions
528
+ };
529
+ const baseConfig = resolvedBaseConfig;
530
+ const config = initConfig;
531
+ const { resolvedHooks, resolvedInitURL, resolvedOptions, resolvedRequestOptions } = await initializePlugins({
532
+ baseConfig,
533
+ config,
534
+ initURL: initURLOrURLObject.toString(),
535
+ options: mergedExtraOptions,
536
+ request: mergedRequestOptions
537
+ });
538
+ const fullURL = getFullURL({
539
+ baseURL: resolvedOptions.baseURL,
540
+ initURL: resolvedInitURL,
541
+ params: resolvedOptions.params,
542
+ query: resolvedOptions.query
543
+ });
544
+ const resolvedSchemaConfig = isFunction(extraOptions.schemaConfig) ? extraOptions.schemaConfig({ baseSchemaConfig: baseExtraOptions.schemaConfig ?? {} }) : extraOptions.schemaConfig ?? baseExtraOptions.schemaConfig;
545
+ const currentRouteKey = getCurrentRouteKey(resolvedInitURL, resolvedSchemaConfig);
546
+ const routeSchema = baseExtraOptions.schema?.[currentRouteKey];
547
+ const resolvedSchema = isFunction(extraOptions.schema) ? extraOptions.schema({
548
+ baseSchema: baseExtraOptions.schema ?? {},
549
+ routeSchema: routeSchema ?? {}
550
+ }) : extraOptions.schema ?? routeSchema;
551
+ let options = {
552
+ ...resolvedOptions,
553
+ ...resolvedHooks,
554
+ fullURL,
555
+ initURL: resolvedInitURL,
556
+ initURLNormalized: normalizeURL(resolvedInitURL)
557
+ };
558
+ const newFetchController = new AbortController();
559
+ const timeoutSignal = options.timeout != null ? createTimeoutSignal(options.timeout) : null;
560
+ const combinedSignal = createCombinedSignal(resolvedRequestOptions.signal, timeoutSignal, newFetchController.signal);
561
+ let request = {
562
+ ...resolvedRequestOptions,
563
+ signal: combinedSignal
564
+ };
565
+ const { dedupeStrategy, handleRequestCancelStrategy, handleRequestDeferStrategy, removeDedupeKeyFromCache } = await createDedupeStrategy({
566
+ $RequestInfoCache,
567
+ baseConfig,
568
+ config,
569
+ newFetchController,
570
+ options,
571
+ request
572
+ });
573
+ try {
574
+ await handleRequestCancelStrategy();
575
+ await executeHooksInTryBlock(options.onRequest?.({
576
+ baseConfig,
577
+ config,
578
+ options,
579
+ request
580
+ }));
581
+ const { extraOptionsValidationResult, requestOptionsValidationResult } = await handleOptionsValidation({
582
+ extraOptions: options,
583
+ requestOptions: request,
584
+ schema: resolvedSchema,
585
+ schemaConfig: resolvedSchemaConfig
586
+ });
587
+ const shouldApplySchemaOutput = Boolean(extraOptionsValidationResult) || Boolean(requestOptionsValidationResult) || !resolvedSchemaConfig?.disableValidationOutputApplication;
588
+ if (shouldApplySchemaOutput) options = {
589
+ ...options,
590
+ ...extraOptionsValidationResult
591
+ };
592
+ const validBody = getBody({
593
+ body: shouldApplySchemaOutput ? requestOptionsValidationResult?.body : request.body,
594
+ bodySerializer: options.bodySerializer
595
+ });
596
+ const validHeaders = await getHeaders({
597
+ auth: options.auth,
598
+ baseHeaders: request.headers,
599
+ body: request.body,
600
+ headers: shouldApplySchemaOutput ? requestOptionsValidationResult?.headers : request.headers
601
+ });
602
+ const validMethod = getMethod({
603
+ initURL: resolvedInitURL,
604
+ method: shouldApplySchemaOutput ? requestOptionsValidationResult?.method : request.method,
605
+ schemaConfig: resolvedSchemaConfig
606
+ });
607
+ request = {
608
+ ...request,
609
+ ...Boolean(validBody) && { body: validBody },
610
+ ...Boolean(validHeaders) && { headers: validHeaders },
611
+ ...Boolean(validMethod) && { method: validMethod }
612
+ };
613
+ const response = await handleRequestDeferStrategy(options, request);
614
+ const shouldCloneResponse = dedupeStrategy === "defer" || options.cloneResponse;
615
+ if (!response.ok) {
616
+ const errorData = await resolveResponseData(shouldCloneResponse ? response.clone() : response, options.responseType, options.responseParser);
617
+ const validErrorData = await handleValidation(resolvedSchema?.errorData, {
618
+ inputValue: errorData,
619
+ response,
620
+ schemaConfig: resolvedSchemaConfig
621
+ });
622
+ throw new HTTPError({
623
+ defaultErrorMessage: options.defaultErrorMessage,
624
+ errorData: validErrorData,
625
+ response
626
+ }, { cause: validErrorData });
627
+ }
628
+ const successData = await resolveResponseData(shouldCloneResponse ? response.clone() : response, options.responseType, options.responseParser);
629
+ const validSuccessData = await handleValidation(resolvedSchema?.data, {
630
+ inputValue: successData,
631
+ response,
632
+ schemaConfig: resolvedSchemaConfig
633
+ });
634
+ const successContext = {
635
+ baseConfig,
636
+ config,
637
+ data: validSuccessData,
638
+ options,
639
+ request,
640
+ response
641
+ };
642
+ await executeHooksInTryBlock(options.onSuccess?.(successContext), options.onResponse?.({
643
+ ...successContext,
644
+ error: null
645
+ }));
646
+ const successResult = resolveSuccessResult(successContext.data, {
647
+ response: successContext.response,
648
+ resultMode: options.resultMode
649
+ });
650
+ return successResult;
651
+ } catch (error) {
652
+ const errorInfo = {
653
+ cloneResponse: options.cloneResponse,
654
+ defaultErrorMessage: options.defaultErrorMessage,
655
+ resultMode: options.resultMode
656
+ };
657
+ const generalErrorResult = resolveErrorResult(error, errorInfo);
658
+ const errorContext = {
659
+ baseConfig,
660
+ config,
661
+ error: generalErrorResult?.error,
662
+ options,
663
+ request,
664
+ response: generalErrorResult?.response
665
+ };
666
+ const shouldThrowOnError = isFunction(options.throwOnError) ? options.throwOnError(errorContext) : options.throwOnError;
667
+ const hookInfo = {
668
+ errorInfo,
669
+ shouldThrowOnError
670
+ };
671
+ const handleRetryOrGetErrorResult = async () => {
672
+ const { currentAttemptCount, getDelay, shouldAttemptRetry } = createRetryStrategy(errorContext);
673
+ const shouldRetry = !combinedSignal.aborted && await shouldAttemptRetry();
674
+ if (shouldRetry) {
675
+ const retryContext = {
676
+ ...errorContext,
677
+ retryAttemptCount: currentAttemptCount
678
+ };
679
+ const hookError$1 = await executeHooksInCatchBlock([options.onRetry?.(retryContext)], hookInfo);
680
+ if (hookError$1) return hookError$1;
681
+ const delay = getDelay();
682
+ await waitFor(delay);
683
+ const updatedOptions = {
684
+ ...config,
685
+ "~retryAttemptCount": currentAttemptCount + 1
686
+ };
687
+ return callApi$1(initURLOrURLObject, updatedOptions);
688
+ }
689
+ if (shouldThrowOnError) throw error;
690
+ return generalErrorResult;
691
+ };
692
+ if (isHTTPErrorInstance(error)) {
693
+ const hookError$1 = await executeHooksInCatchBlock([
694
+ options.onResponseError?.(errorContext),
695
+ options.onError?.(errorContext),
696
+ options.onResponse?.({
697
+ ...errorContext,
698
+ data: null
699
+ })
700
+ ], hookInfo);
701
+ return hookError$1 ?? await handleRetryOrGetErrorResult();
702
+ }
703
+ if (isValidationErrorInstance(error)) {
704
+ const hookError$1 = await executeHooksInCatchBlock([
705
+ options.onValidationError?.(errorContext),
706
+ options.onRequestError?.(errorContext),
707
+ options.onError?.(errorContext)
708
+ ], hookInfo);
709
+ return hookError$1 ?? await handleRetryOrGetErrorResult();
710
+ }
711
+ let message = error?.message;
712
+ if (error instanceof DOMException && error.name === "AbortError") {
713
+ message = getAbortErrorMessage(options.dedupeKey, options.fullURL);
714
+ !shouldThrowOnError && console.error(`${error.name}:`, message);
715
+ }
716
+ if (error instanceof DOMException && error.name === "TimeoutError") {
717
+ message = `Request timed out after ${options.timeout}ms`;
718
+ !shouldThrowOnError && console.error(`${error.name}:`, message);
719
+ }
720
+ const hookError = await executeHooksInCatchBlock([options.onRequestError?.(errorContext), options.onError?.(errorContext)], hookInfo);
721
+ return hookError ?? getCustomizedErrorResult(await handleRetryOrGetErrorResult(), { message });
722
+ } finally {
723
+ removeDedupeKeyFromCache();
724
+ }
725
+ };
726
+ return callApi$1;
719
727
  };
720
- var callApi = createFetchClient();
728
+ const callApi = createFetchClient();
721
729
 
722
- // src/defineParameters.ts
723
- var defineParameters = (...parameters) => {
724
- return parameters;
730
+ //#endregion
731
+ //#region src/defineParameters.ts
732
+ const defineParameters = (...parameters) => {
733
+ return parameters;
725
734
  };
726
735
 
727
- export { callApi, createFetchClient, defineParameters, definePlugin };
728
- //# sourceMappingURL=index.js.map
736
+ //#endregion
737
+ export { HTTPError, ValidationError, callApi, createFetchClient, defineParameters, definePlugin, defineSchema };
729
738
  //# sourceMappingURL=index.js.map