@zayne-labs/callapi 1.12.5 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/constants/index.d.ts +8 -8
- package/dist/constants/index.js +1 -1
- package/dist/{defaults-D0QJmGE5.js → constants-Cj_bGg18.js} +36 -28
- package/dist/constants-Cj_bGg18.js.map +1 -0
- package/dist/{default-types-CswfU2bI.d.ts → default-types-Cn2QRN13.d.ts} +476 -400
- package/dist/{index-DMCchZ0z.d.ts → index-WSyoCGJi.d.ts} +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +169 -170
- package/dist/index.js.map +1 -1
- package/dist/utils/external/index.d.ts +2 -74
- package/dist/utils/external/index.js +1 -1
- package/package.json +6 -6
- package/dist/defaults-D0QJmGE5.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as CallApiConfig, D as ThrowOnErrorBoolean, Et as BaseCallApiSchemaRoutes, F as CallApiResult, Ft as DistributiveOmit, It as NoInferUnMasked, L as GetBaseSchemaConfig, Lt as Writeable, Mt as InferSchemaResult, O as BaseCallApiConfig, Ot as CallApiSchema, Pt as AnyString, R as GetBaseSchemaRoutes, S as GetCurrentRouteSchemaKey, T as InferInitURL, Tt as BaseCallApiSchemaAndConfig, V as GlobalMeta, _ as ResponseTypeType, b as ApplyURLBasedConfig, d as GetResponseType, f as InferCallApiResult, g as ResponseTypeMap, i as CallApiPlugin, j as CallApiContext, jt as InferSchemaOutput, kt as CallApiSchemaConfig, l as CallApiResultSuccessOrErrorVariant, n as DefaultDataType, r as DefaultPluginArray, t as DefaultCallApiContext, u as CallApiResultSuccessVariant, v as ResultModeType, x as GetCurrentRouteSchema, y as ApplyStrictConfig } from "./default-types-Cn2QRN13.js";
|
|
2
2
|
|
|
3
3
|
//#region src/createFetchClient.d.ts
|
|
4
4
|
declare const createFetchClientWithContext: <TOuterCallApiContext extends CallApiContext = DefaultCallApiContext>() => <TBaseCallApiContext extends CallApiContext = TOuterCallApiContext, TBaseData = TBaseCallApiContext["Data"], TBaseErrorData = TBaseCallApiContext["ErrorData"], TBaseResultMode extends ResultModeType = (TBaseCallApiContext["ResultMode"] extends ResultModeType ? TBaseCallApiContext["ResultMode"] : ResultModeType), TBaseThrowOnError extends ThrowOnErrorBoolean = boolean, TBaseResponseType extends ResponseTypeType = ResponseTypeType, const TBaseSchemaAndConfig extends BaseCallApiSchemaAndConfig = BaseCallApiSchemaAndConfig, const TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TComputedBaseSchemaConfig extends CallApiSchemaConfig = GetBaseSchemaConfig<TBaseSchemaAndConfig>, TComputedBaseSchemaRoutes extends BaseCallApiSchemaRoutes = GetBaseSchemaRoutes<TBaseSchemaAndConfig>>(initBaseConfig?: BaseCallApiConfig<TBaseCallApiContext, TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType, TBaseSchemaAndConfig, TBasePluginArray>) => <TData = TBaseData, TErrorData = TBaseErrorData, TResultMode extends ResultModeType = TBaseResultMode, TCallApiContext extends CallApiContext = TBaseCallApiContext, TThrowOnError extends ThrowOnErrorBoolean = TBaseThrowOnError, TResponseType extends ResponseTypeType = TBaseResponseType, const TSchemaConfig extends CallApiSchemaConfig = TComputedBaseSchemaConfig, TInitURL extends InferInitURL<TComputedBaseSchemaRoutes, TSchemaConfig> = InferInitURL<TComputedBaseSchemaRoutes, TSchemaConfig>, TCurrentRouteSchemaKey extends GetCurrentRouteSchemaKey<TSchemaConfig, TInitURL> = GetCurrentRouteSchemaKey<TSchemaConfig, TInitURL>, const TSchema extends CallApiSchema = GetCurrentRouteSchema<TComputedBaseSchemaRoutes, TCurrentRouteSchemaKey>, const TPluginArray extends CallApiPlugin[] = TBasePluginArray, TComputedData = InferSchemaOutput<TSchema["data"], GetResponseType<TData, TResponseType>>, TComputedErrorData = InferSchemaOutput<TSchema["errorData"], GetResponseType<TErrorData, TResponseType>>, TComputedResult = CallApiResult<TComputedData, TComputedErrorData, TResultMode, TThrowOnError>>(initURL: TInitURL, initConfig?: CallApiConfig<TCallApiContext, TComputedData, TComputedErrorData, TResultMode, TThrowOnError, TResponseType, TComputedBaseSchemaRoutes, TSchema, TComputedBaseSchemaConfig, TSchemaConfig, TInitURL, TCurrentRouteSchemaKey, TBasePluginArray, TPluginArray>) => Promise<TComputedResult>;
|
|
@@ -88,4 +88,4 @@ declare const callApi: <TData = unknown, TErrorData = unknown, TResultMode exten
|
|
|
88
88
|
}, TSchema, CallApiSchemaConfig, TSchemaConfig, TInitURL, TCurrentRouteSchemaKey, DefaultPluginArray, TPluginArray>) => Promise<TComputedResult>;
|
|
89
89
|
//#endregion
|
|
90
90
|
export { createFetchClient as n, createFetchClientWithContext as r, callApi as t };
|
|
91
|
-
//# sourceMappingURL=index-
|
|
91
|
+
//# sourceMappingURL=index-WSyoCGJi.d.ts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { n as createFetchClient, r as createFetchClientWithContext, t as callApi } from "./index-
|
|
1
|
+
import { $ as RequestContext, A as CallApiConfig, At as InferSchemaInput, B as GetCallApiContextRequired, C as InferAllMainRouteKeys, Dt as BaseSchemaRouteKeyPrefixes, E as InferParamsFromRoute, Et as BaseCallApiSchemaRoutes, G as FetchMiddlewareContext, H as InstanceContext, I as CallApiResultLoose, J as CallApiExtraOptionsForHooks, K as Middlewares, M as CallApiExtraOptions, N as CallApiParameters, Nt as URLOptions, O as BaseCallApiConfig, Ot as CallApiSchema, P as CallApiRequestOptions, Q as HooksOrHooksArray, S as GetCurrentRouteSchemaKey, T as InferInitURL, U as Register, W as FetchImpl, X as ErrorContext, Y as CallApiRequestOptionsForHooks, Z as Hooks, _ as ResponseTypeType, a as PluginHooks, at as RefetchOptions, c as CallApiResultErrorVariant, et as RequestStreamContext, h as PossibleValidationError, i as CallApiPlugin, it as SuccessContext, jt as InferSchemaOutput, k as BaseCallApiExtraOptions, kt as CallApiSchemaConfig, l as CallApiResultSuccessOrErrorVariant, m as PossibleJavaScriptError, nt as ResponseErrorContext, o as PluginMiddlewares, ot as RetryOptions, p as PossibleHTTPError, q as DedupeOptions, rt as ResponseStreamContext, s as PluginSetupContext, t as DefaultCallApiContext, tt as ResponseContext, u as CallApiResultSuccessVariant, v as ResultModeType, w as InferAllMainRoutes, z as GetCallApiContext } from "./default-types-Cn2QRN13.js";
|
|
2
|
+
import { n as createFetchClient, r as createFetchClientWithContext, t as callApi } from "./index-WSyoCGJi.js";
|
|
3
3
|
export { BaseCallApiConfig, BaseCallApiExtraOptions, BaseCallApiSchemaRoutes, BaseSchemaRouteKeyPrefixes, CallApiConfig, CallApiExtraOptions, CallApiExtraOptionsForHooks, CallApiParameters, CallApiPlugin, CallApiRequestOptions, CallApiRequestOptionsForHooks, CallApiResultLoose as CallApiResult, CallApiResultErrorVariant, CallApiResultSuccessOrErrorVariant, CallApiResultSuccessVariant, CallApiSchema, CallApiSchemaConfig, DedupeOptions, DefaultCallApiContext, ErrorContext, FetchImpl, FetchMiddlewareContext, GetCallApiContext, GetCallApiContextRequired, GetCurrentRouteSchemaKey, Hooks, HooksOrHooksArray, InferAllMainRouteKeys, InferAllMainRoutes, InferInitURL, InferParamsFromRoute, InferSchemaInput, InferSchemaOutput, InstanceContext, Middlewares, PluginHooks, PluginMiddlewares, PluginSetupContext, PossibleHTTPError, PossibleJavaScriptError, PossibleValidationError, RefetchOptions, Register, RequestContext, RequestStreamContext, ResponseContext, ResponseErrorContext, ResponseStreamContext, ResponseTypeType, ResultModeType, RetryOptions, SuccessContext, URLOptions, callApi, createFetchClient, createFetchClientWithContext };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as getCurrentRouteSchemaKeyAndMainInitURL,
|
|
1
|
+
import { A as getCurrentRouteSchemaKeyAndMainInitURL, I as isArray, L as isFunction, M as handleSchemaValidation, N as HTTPError, R as isString, a as getBody, c as getMethod, d as splitConfig, f as waitFor, h as isHTTPErrorInstance, i as createTimeoutSignal, j as handleConfigValidation, k as getFullAndNormalizedURL, l as getResolvedHeaders, o as getFetchImpl, r as createCombinedSignal, s as getHeaders, t as extraOptionDefaults, u as omitKeys, v as isValidationErrorInstance } from "./constants-Cj_bGg18.js";
|
|
2
2
|
//#region src/result.ts
|
|
3
3
|
const getResponseType = (response, responseParser) => ({
|
|
4
4
|
arrayBuffer: () => response.arrayBuffer(),
|
|
@@ -51,8 +51,8 @@ const resolveSuccessResult = (data, info) => {
|
|
|
51
51
|
response
|
|
52
52
|
})[resultMode ?? "all"]();
|
|
53
53
|
};
|
|
54
|
-
const resolveErrorResult = (error,
|
|
55
|
-
const { cloneResponse, message: customErrorMessage, resultMode } =
|
|
54
|
+
const resolveErrorResult = (error, infoOptions) => {
|
|
55
|
+
const { cloneResponse, message: customErrorMessage, resultMode } = infoOptions;
|
|
56
56
|
let errorDetails = {
|
|
57
57
|
data: null,
|
|
58
58
|
error: {
|
|
@@ -96,17 +96,6 @@ const resolveErrorResult = (error, info) => {
|
|
|
96
96
|
errorResult
|
|
97
97
|
};
|
|
98
98
|
};
|
|
99
|
-
const getCustomizedErrorResult = (errorResult, customErrorInfo) => {
|
|
100
|
-
if (!errorResult) return null;
|
|
101
|
-
const { message = errorResult.error.message } = customErrorInfo;
|
|
102
|
-
return {
|
|
103
|
-
...errorResult,
|
|
104
|
-
error: {
|
|
105
|
-
...errorResult.error,
|
|
106
|
-
message
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
};
|
|
110
99
|
//#endregion
|
|
111
100
|
//#region src/hooks.ts
|
|
112
101
|
const getHookRegistriesAndKeys = () => {
|
|
@@ -143,16 +132,18 @@ const composeHooksFromArray = (hooksArray, hooksExecutionMode) => {
|
|
|
143
132
|
return composedHook;
|
|
144
133
|
};
|
|
145
134
|
const executeHooks = async (...hookResultsOrPromise) => {
|
|
146
|
-
|
|
135
|
+
const validHooks = hookResultsOrPromise.filter(Boolean);
|
|
136
|
+
if (validHooks.length === 0) return;
|
|
137
|
+
await Promise.all(validHooks);
|
|
147
138
|
};
|
|
148
139
|
const executeHooksInCatchBlock = async (hookResultsOrPromise, hookInfo) => {
|
|
149
|
-
const {
|
|
140
|
+
const { errorInfoOptions, shouldThrowOnError } = hookInfo;
|
|
150
141
|
try {
|
|
151
142
|
await Promise.all(hookResultsOrPromise);
|
|
152
143
|
return null;
|
|
153
144
|
} catch (hookError) {
|
|
154
145
|
if (shouldThrowOnError) throw hookError;
|
|
155
|
-
const { errorResult } = resolveErrorResult(hookError,
|
|
146
|
+
const { errorResult } = resolveErrorResult(hookError, errorInfoOptions);
|
|
156
147
|
return errorResult;
|
|
157
148
|
}
|
|
158
149
|
};
|
|
@@ -285,25 +276,20 @@ const toStreamableResponse = (context) => {
|
|
|
285
276
|
};
|
|
286
277
|
//#endregion
|
|
287
278
|
//#region src/dedupe.ts
|
|
288
|
-
const
|
|
289
|
-
const { $GlobalRequestInfoCache, $LocalRequestInfoCache, baseConfig, config, newFetchController, options: globalOptions } = context;
|
|
290
|
-
const
|
|
291
|
-
const resolvedDedupeStrategy = isFunction(dedupeStrategy) ? dedupeStrategy(context) : dedupeStrategy;
|
|
279
|
+
const createDedupeManager = async (context) => {
|
|
280
|
+
const { $GlobalRequestInfoCache, $LocalRequestInfoCache, baseConfig, config, newFetchController, options: globalOptions, resolvedDedupeStrategy } = context;
|
|
281
|
+
const shouldDisableDedupe = resolvedDedupeStrategy === "none";
|
|
292
282
|
const getDedupeKey = () => {
|
|
293
|
-
if (!(resolvedDedupeStrategy === "cancel" || resolvedDedupeStrategy === "defer")) return null;
|
|
294
283
|
const dedupeKey = globalOptions.dedupeKey ?? extraOptionDefaults.dedupeKey;
|
|
295
284
|
return isFunction(dedupeKey) ? dedupeKey(context) : dedupeKey;
|
|
296
285
|
};
|
|
297
|
-
const
|
|
298
|
-
const dedupeCacheScopeKey = globalOptions.dedupeCacheScopeKey ?? extraOptionDefaults.dedupeCacheScopeKey;
|
|
299
|
-
return isFunction(dedupeCacheScopeKey) ? dedupeCacheScopeKey(context) : dedupeCacheScopeKey;
|
|
300
|
-
};
|
|
301
|
-
const dedupeKey = getDedupeKey();
|
|
286
|
+
const dedupeKey = shouldDisableDedupe ? null : getDedupeKey();
|
|
302
287
|
const getRequestInfoCache = () => {
|
|
303
|
-
if (
|
|
288
|
+
if (dedupeKey == null) return;
|
|
304
289
|
const dedupeCacheScope = globalOptions.dedupeCacheScope ?? extraOptionDefaults.dedupeCacheScope;
|
|
305
|
-
const dedupeCacheScopeKey =
|
|
306
|
-
const
|
|
290
|
+
const dedupeCacheScopeKey = globalOptions.dedupeCacheScopeKey ?? extraOptionDefaults.dedupeCacheScopeKey;
|
|
291
|
+
const resolvedDedupeCacheScopeKey = isFunction(dedupeCacheScopeKey) ? dedupeCacheScopeKey(context) : dedupeCacheScopeKey;
|
|
292
|
+
const $RequestInfoCache = dedupeCacheScope === "global" ? $GlobalRequestInfoCache.get(resolvedDedupeCacheScopeKey) ?? $GlobalRequestInfoCache.set(resolvedDedupeCacheScopeKey, /* @__PURE__ */ new Map()).get(resolvedDedupeCacheScopeKey) : $LocalRequestInfoCache;
|
|
307
293
|
return {
|
|
308
294
|
delete: () => $RequestInfoCache?.delete(dedupeKey),
|
|
309
295
|
get: () => $RequestInfoCache?.get(dedupeKey),
|
|
@@ -335,28 +321,27 @@ const createDedupeStrategy = async (context) => {
|
|
|
335
321
|
* simultaneously (same problem as microtasks). Any non-zero value (even 0.0000000001) forces
|
|
336
322
|
* proper sequential task queue scheduling, ensuring each request gets its own task slot.
|
|
337
323
|
*/
|
|
338
|
-
if (
|
|
324
|
+
if (!shouldDisableDedupe) await waitFor(.01);
|
|
339
325
|
const prevRequestInfo = $RequestInfoCache?.get();
|
|
340
326
|
const getAbortErrorMessage = () => {
|
|
341
|
-
|
|
342
|
-
return `Duplicate request detected - Aborted previous request to '${globalOptions.fullURL}'`;
|
|
327
|
+
return globalOptions.dedupeKey != null ? `Duplicate request detected - Aborted previous request with key '${dedupeKey}'` : `Duplicate request detected - Aborted previous request to '${globalOptions.fullURL}'`;
|
|
343
328
|
};
|
|
344
329
|
const handleRequestCancelStrategy = () => {
|
|
345
|
-
if (!(prevRequestInfo && resolvedDedupeStrategy === "cancel")) return;
|
|
330
|
+
if (!(!shouldDisableDedupe && prevRequestInfo && resolvedDedupeStrategy === "cancel")) return;
|
|
346
331
|
const message = getAbortErrorMessage();
|
|
347
332
|
const reason = new DOMException(message, "AbortError");
|
|
348
|
-
prevRequestInfo.controller
|
|
333
|
+
prevRequestInfo.controller?.abort(reason);
|
|
349
334
|
};
|
|
350
335
|
const handleRequestDeferStrategy = async (deferContext) => {
|
|
351
336
|
const { fetchApi, options: localOptions, request: localRequest } = deferContext;
|
|
352
|
-
const
|
|
337
|
+
const shouldDeferPromise = !shouldDisableDedupe && prevRequestInfo && resolvedDedupeStrategy === "defer";
|
|
353
338
|
const streamContext = {
|
|
354
339
|
baseConfig,
|
|
355
340
|
config,
|
|
356
341
|
options: localOptions,
|
|
357
342
|
request: localRequest
|
|
358
343
|
};
|
|
359
|
-
const responsePromise =
|
|
344
|
+
const responsePromise = shouldDeferPromise ? prevRequestInfo.responsePromise : fetchApi(localOptions.fullURL, toStreamableRequest(streamContext));
|
|
360
345
|
$RequestInfoCache?.set({
|
|
361
346
|
controller: newFetchController,
|
|
362
347
|
responsePromise
|
|
@@ -366,15 +351,11 @@ const createDedupeStrategy = async (context) => {
|
|
|
366
351
|
response: await responsePromise
|
|
367
352
|
});
|
|
368
353
|
};
|
|
369
|
-
const removeDedupeKeyFromCache = () => {
|
|
370
|
-
$RequestInfoCache?.delete();
|
|
371
|
-
};
|
|
372
354
|
return {
|
|
373
355
|
getAbortErrorMessage,
|
|
374
356
|
handleRequestCancelStrategy,
|
|
375
357
|
handleRequestDeferStrategy,
|
|
376
|
-
|
|
377
|
-
resolvedDedupeStrategy
|
|
358
|
+
removeDedupeCacheEntry: () => $RequestInfoCache?.delete()
|
|
378
359
|
};
|
|
379
360
|
};
|
|
380
361
|
//#endregion
|
|
@@ -411,7 +392,7 @@ const getResolvedPlugins = (context) => {
|
|
|
411
392
|
const { baseConfig, options } = context;
|
|
412
393
|
return isFunction(options.plugins) ? options.plugins({ basePlugins: baseConfig.plugins ?? [] }) : options.plugins ?? [];
|
|
413
394
|
};
|
|
414
|
-
const
|
|
395
|
+
const initializePluginsAndHooks = async (setupContext) => {
|
|
415
396
|
const { baseConfig, config, currentRouteSchemaKey, mainInitURL, options, request } = setupContext;
|
|
416
397
|
const { addMainHooks, addMainMiddlewares, addPluginHooks, addPluginMiddlewares, getResolvedHooks, getResolvedMiddlewares } = setupHooksAndMiddlewares({
|
|
417
398
|
baseConfig,
|
|
@@ -422,35 +403,37 @@ const initializePlugins = async (setupContext) => {
|
|
|
422
403
|
let resolvedInitURL = mainInitURL;
|
|
423
404
|
const resolvedOptions = options;
|
|
424
405
|
const resolvedRequest = request;
|
|
425
|
-
const executePluginSetupFn = async (pluginSetup) => {
|
|
426
|
-
if (!pluginSetup) return;
|
|
427
|
-
const initResult = await pluginSetup(setupContext);
|
|
428
|
-
if (!initResult) return;
|
|
429
|
-
const urlString = initResult.initURL?.toString();
|
|
430
|
-
if (isString(urlString)) {
|
|
431
|
-
const newURLResult = getCurrentRouteSchemaKeyAndMainInitURL({
|
|
432
|
-
baseExtraOptions: baseConfig,
|
|
433
|
-
extraOptions: config,
|
|
434
|
-
initURL: urlString
|
|
435
|
-
});
|
|
436
|
-
resolvedCurrentRouteSchemaKey = newURLResult.currentRouteSchemaKey;
|
|
437
|
-
resolvedInitURL = newURLResult.mainInitURL;
|
|
438
|
-
}
|
|
439
|
-
if (initResult.request) Object.assign(resolvedRequest, initResult.request, initResult.request.extraFetchOptions);
|
|
440
|
-
if (initResult.options) Object.assign(resolvedOptions, initResult.options);
|
|
441
|
-
};
|
|
442
406
|
const resolvedPlugins = getResolvedPlugins({
|
|
443
407
|
baseConfig,
|
|
444
408
|
options
|
|
445
409
|
});
|
|
446
|
-
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
410
|
+
if (resolvedPlugins.length > 0) {
|
|
411
|
+
const executePluginSetupFn = async (pluginSetup) => {
|
|
412
|
+
if (!pluginSetup) return;
|
|
413
|
+
const initResult = await pluginSetup(setupContext);
|
|
414
|
+
if (!initResult) return;
|
|
415
|
+
const urlString = initResult.initURL?.toString();
|
|
416
|
+
if (isString(urlString)) {
|
|
417
|
+
const newURLResult = getCurrentRouteSchemaKeyAndMainInitURL({
|
|
418
|
+
baseExtraOptions: baseConfig,
|
|
419
|
+
extraOptions: config,
|
|
420
|
+
initURL: urlString
|
|
421
|
+
});
|
|
422
|
+
resolvedCurrentRouteSchemaKey = newURLResult.currentRouteSchemaKey;
|
|
423
|
+
resolvedInitURL = newURLResult.mainInitURL;
|
|
424
|
+
}
|
|
425
|
+
if (initResult.request) Object.assign(resolvedRequest, initResult.request, initResult.request.extraFetchOptions);
|
|
426
|
+
if (initResult.options) Object.assign(resolvedOptions, initResult.options);
|
|
427
|
+
};
|
|
428
|
+
for (const plugin of resolvedPlugins) {
|
|
429
|
+
const [, pluginHooks, pluginMiddlewares] = await Promise.all([
|
|
430
|
+
executePluginSetupFn(plugin.setup),
|
|
431
|
+
isFunction(plugin.hooks) ? plugin.hooks(setupContext) : plugin.hooks,
|
|
432
|
+
isFunction(plugin.middlewares) ? plugin.middlewares(setupContext) : plugin.middlewares
|
|
433
|
+
]);
|
|
434
|
+
pluginHooks && addPluginHooks(pluginHooks);
|
|
435
|
+
pluginMiddlewares && addPluginMiddlewares(pluginMiddlewares);
|
|
436
|
+
}
|
|
454
437
|
}
|
|
455
438
|
addMainHooks();
|
|
456
439
|
addMainMiddlewares();
|
|
@@ -501,17 +484,23 @@ const setupHooksAndMiddlewares = (context) => {
|
|
|
501
484
|
};
|
|
502
485
|
const getResolvedHooks = () => {
|
|
503
486
|
const resolvedHooks = {};
|
|
504
|
-
for (const
|
|
487
|
+
for (const hookName of hookRegistryKeys) {
|
|
488
|
+
const hookRegistry = hookRegistries[hookName];
|
|
505
489
|
if (hookRegistry.size === 0) continue;
|
|
506
490
|
const flattenedHookArray = [...hookRegistry].flat();
|
|
507
491
|
if (flattenedHookArray.length === 0) continue;
|
|
492
|
+
if (flattenedHookArray.length === 1) {
|
|
493
|
+
resolvedHooks[hookName] = flattenedHookArray[0];
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
508
496
|
resolvedHooks[hookName] = composeHooksFromArray(flattenedHookArray, options.hooksExecutionMode ?? extraOptionDefaults.hooksExecutionMode);
|
|
509
497
|
}
|
|
510
498
|
return resolvedHooks;
|
|
511
499
|
};
|
|
512
500
|
const getResolvedMiddlewares = () => {
|
|
513
501
|
const resolvedMiddlewares = {};
|
|
514
|
-
for (const
|
|
502
|
+
for (const middlewareName of middlewareRegistryKeys) {
|
|
503
|
+
const middlewareRegistry = middlewareRegistries[middlewareName];
|
|
515
504
|
if (middlewareRegistry.size === 0) continue;
|
|
516
505
|
const middlewareArray = [...middlewareRegistry];
|
|
517
506
|
if (middlewareArray.length === 0) continue;
|
|
@@ -530,82 +519,82 @@ const setupHooksAndMiddlewares = (context) => {
|
|
|
530
519
|
};
|
|
531
520
|
//#endregion
|
|
532
521
|
//#region src/refetch.ts
|
|
522
|
+
const shouldAttemptRefetchSymbol = Symbol("shouldAttemptRefetch");
|
|
533
523
|
const createRefetchManager = (ctx) => {
|
|
534
|
-
const { callApi, callApiArgs, options } = ctx;
|
|
535
|
-
const
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
524
|
+
const { callApi, callApiArgs, options, removeDedupeCacheEntry } = ctx;
|
|
525
|
+
const shouldAttemptRefetch = () => {
|
|
526
|
+
return options[shouldAttemptRefetchSymbol] ?? false;
|
|
527
|
+
};
|
|
528
|
+
const refetch = () => {
|
|
529
|
+
options[shouldAttemptRefetchSymbol] = true;
|
|
530
|
+
};
|
|
531
|
+
const handleRefetch = () => {
|
|
532
|
+
if (shouldAttemptRefetch()) {
|
|
533
|
+
removeDedupeCacheEntry();
|
|
534
|
+
return callApi(callApiArgs.initURL, {
|
|
535
|
+
...callApiArgs.config,
|
|
536
|
+
[shouldAttemptRefetchSymbol]: false
|
|
537
|
+
});
|
|
542
538
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
return callApi(callApiArgs.initURL, updatedConfig);
|
|
539
|
+
return null;
|
|
540
|
+
};
|
|
541
|
+
return {
|
|
542
|
+
handleRefetch,
|
|
543
|
+
refetch
|
|
549
544
|
};
|
|
550
|
-
return { refetch };
|
|
551
545
|
};
|
|
552
546
|
//#endregion
|
|
553
547
|
//#region src/retry.ts
|
|
554
|
-
const getLinearDelay = (currentAttemptCount, options) => {
|
|
555
|
-
const retryDelay = options.retryDelay ?? extraOptionDefaults.retryDelay;
|
|
556
|
-
return isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay;
|
|
557
|
-
};
|
|
558
|
-
const getExponentialDelay = (currentAttemptCount, options) => {
|
|
559
|
-
const retryDelay = options.retryDelay ?? extraOptionDefaults.retryDelay;
|
|
560
|
-
const resolvedRetryDelay = isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay;
|
|
561
|
-
const maxDelay = options.retryMaxDelay ?? extraOptionDefaults.retryMaxDelay;
|
|
562
|
-
const exponentialDelay = resolvedRetryDelay * 2 ** currentAttemptCount;
|
|
563
|
-
return Math.min(exponentialDelay, maxDelay);
|
|
564
|
-
};
|
|
565
548
|
const createRetryManager = (ctx) => {
|
|
566
|
-
const { callApi, callApiArgs, error, errorContext,
|
|
549
|
+
const { callApi, callApiArgs, error, errorContext, hookInfo, removeDedupeCacheEntry } = ctx;
|
|
567
550
|
const { options, request } = errorContext;
|
|
568
|
-
const
|
|
569
|
-
const
|
|
551
|
+
const currentRetryAttemptCount = options["~retryAttemptCount"] ?? 1;
|
|
552
|
+
const shouldAttemptRetry = async () => {
|
|
553
|
+
if (request.signal?.aborted) return false;
|
|
554
|
+
const maxRetryAttempts = options.retryAttempts ?? extraOptionDefaults.retryAttempts;
|
|
555
|
+
const retryCondition = options.retryCondition ?? extraOptionDefaults.retryCondition;
|
|
556
|
+
if (!(currentRetryAttemptCount <= maxRetryAttempts && await retryCondition(errorContext))) return false;
|
|
557
|
+
const retryMethods = options.retryMethods ?? extraOptionDefaults.retryMethods;
|
|
558
|
+
const includesMethod = request.method != null && retryMethods.length > 0 ? retryMethods.includes(request.method) : true;
|
|
559
|
+
const retryStatusCodes = options.retryStatusCodes ?? extraOptionDefaults.retryStatusCodes;
|
|
560
|
+
const includesStatusCodes = errorContext.response != null && retryStatusCodes.length > 0 ? retryStatusCodes.includes(errorContext.response.status) : true;
|
|
561
|
+
return includesMethod && includesStatusCodes;
|
|
562
|
+
};
|
|
570
563
|
const getDelay = () => {
|
|
564
|
+
const retryStrategy = options.retryStrategy ?? extraOptionDefaults.retryStrategy;
|
|
571
565
|
switch (retryStrategy) {
|
|
572
|
-
case "exponential":
|
|
573
|
-
|
|
566
|
+
case "exponential": {
|
|
567
|
+
const retryDelay = options.retryDelay ?? extraOptionDefaults.retryDelay;
|
|
568
|
+
const resolvedRetryDelay = isFunction(retryDelay) ? retryDelay(currentRetryAttemptCount) : retryDelay;
|
|
569
|
+
const maxDelay = options.retryMaxDelay ?? extraOptionDefaults.retryMaxDelay;
|
|
570
|
+
const exponentialDelay = resolvedRetryDelay * 2 ** (currentRetryAttemptCount - 1);
|
|
571
|
+
return Math.min(exponentialDelay, maxDelay);
|
|
572
|
+
}
|
|
573
|
+
case "linear": {
|
|
574
|
+
const retryDelay = options.retryDelay ?? extraOptionDefaults.retryDelay;
|
|
575
|
+
return isFunction(retryDelay) ? retryDelay(currentRetryAttemptCount) : retryDelay;
|
|
576
|
+
}
|
|
574
577
|
default: throw new Error(`Invalid retry strategy: ${String(retryStrategy)}`);
|
|
575
578
|
}
|
|
576
579
|
};
|
|
577
|
-
const shouldAttemptRetry = async () => {
|
|
578
|
-
if (isBoolean(request.signal) && request.signal.aborted) return false;
|
|
579
|
-
const retryCondition = options.retryCondition ?? extraOptionDefaults.retryCondition;
|
|
580
|
-
const maxRetryAttempts = options.retryAttempts ?? extraOptionDefaults.retryAttempts;
|
|
581
|
-
const customRetryCondition = await retryCondition(errorContext);
|
|
582
|
-
if (!(currentAttemptCount <= maxRetryAttempts && customRetryCondition)) return false;
|
|
583
|
-
const retryMethods = new Set(options.retryMethods ?? extraOptionDefaults.retryMethods);
|
|
584
|
-
const includesMethod = isString(request.method) && retryMethods.size > 0 ? retryMethods.has(request.method) : true;
|
|
585
|
-
const retryStatusCodes = new Set(options.retryStatusCodes ?? extraOptionDefaults.retryStatusCodes);
|
|
586
|
-
const includesStatusCodes = errorContext.response != null && retryStatusCodes.size > 0 ? retryStatusCodes.has(errorContext.response.status) : true;
|
|
587
|
-
return includesMethod && includesStatusCodes;
|
|
588
|
-
};
|
|
589
580
|
const handleRetry = async () => {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
const handleRetryOrGetErrorResult = async () => {
|
|
604
|
-
if (await shouldAttemptRetry()) return handleRetry();
|
|
581
|
+
if (await shouldAttemptRetry()) {
|
|
582
|
+
const hookError = await executeHooksInCatchBlock([options.onRetry?.({
|
|
583
|
+
...errorContext,
|
|
584
|
+
retryAttemptCount: currentRetryAttemptCount
|
|
585
|
+
})], hookInfo);
|
|
586
|
+
if (hookError) return hookError;
|
|
587
|
+
await waitFor(getDelay());
|
|
588
|
+
removeDedupeCacheEntry();
|
|
589
|
+
return callApi(callApiArgs.initURL, {
|
|
590
|
+
...callApiArgs.config,
|
|
591
|
+
"~retryAttemptCount": currentRetryAttemptCount + 1
|
|
592
|
+
});
|
|
593
|
+
}
|
|
605
594
|
if (hookInfo.shouldThrowOnError) throw error;
|
|
606
|
-
return
|
|
595
|
+
return null;
|
|
607
596
|
};
|
|
608
|
-
return {
|
|
597
|
+
return { handleRetry };
|
|
609
598
|
};
|
|
610
599
|
//#endregion
|
|
611
600
|
//#region src/createFetchClient.ts
|
|
@@ -640,7 +629,7 @@ const createFetchClientWithContext = () => {
|
|
|
640
629
|
extraOptions: config,
|
|
641
630
|
initURL: initURLString
|
|
642
631
|
});
|
|
643
|
-
const { resolvedCurrentRouteSchemaKey, resolvedHooks, resolvedInitURL, resolvedMiddlewares, resolvedOptions, resolvedRequest } = await
|
|
632
|
+
const { resolvedCurrentRouteSchemaKey, resolvedHooks, resolvedInitURL, resolvedMiddlewares, resolvedOptions, resolvedRequest } = await initializePluginsAndHooks({
|
|
644
633
|
baseConfig,
|
|
645
634
|
config,
|
|
646
635
|
...initURLResult,
|
|
@@ -659,6 +648,7 @@ const createFetchClientWithContext = () => {
|
|
|
659
648
|
});
|
|
660
649
|
const { fullURL, normalizedInitURL } = getFullAndNormalizedURL({
|
|
661
650
|
baseURL: resolvedOptions.baseURL,
|
|
651
|
+
debugMode: resolvedOptions.debugMode,
|
|
662
652
|
initURL: resolvedInitURL,
|
|
663
653
|
params: resolvedOptions.params,
|
|
664
654
|
query: resolvedOptions.query
|
|
@@ -671,33 +661,42 @@ const createFetchClientWithContext = () => {
|
|
|
671
661
|
initURL: resolvedInitURL,
|
|
672
662
|
initURLNormalized: normalizedInitURL
|
|
673
663
|
};
|
|
674
|
-
const
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
const newFetchController = new AbortController();
|
|
684
|
-
const combinedSignal = createCombinedSignal(createTimeoutSignal(options.timeout), resolvedRequest.signal, newFetchController.signal);
|
|
664
|
+
const dedupeStrategy = options.dedupeStrategy ?? extraOptionDefaults.dedupeStrategy;
|
|
665
|
+
const resolvedDedupeStrategy = isFunction(dedupeStrategy) ? dedupeStrategy({
|
|
666
|
+
baseConfig,
|
|
667
|
+
config,
|
|
668
|
+
options,
|
|
669
|
+
request: resolvedRequest
|
|
670
|
+
}) : dedupeStrategy;
|
|
671
|
+
const newFetchController = resolvedDedupeStrategy === "none" ? null : new AbortController();
|
|
672
|
+
const combinedSignal = createCombinedSignal(createTimeoutSignal(options.timeout), resolvedRequest.signal, newFetchController?.signal);
|
|
685
673
|
const request = {
|
|
686
674
|
...resolvedRequest,
|
|
687
675
|
signal: combinedSignal
|
|
688
676
|
};
|
|
689
|
-
const { getAbortErrorMessage, handleRequestCancelStrategy, handleRequestDeferStrategy,
|
|
677
|
+
const { getAbortErrorMessage, handleRequestCancelStrategy, handleRequestDeferStrategy, removeDedupeCacheEntry } = await createDedupeManager({
|
|
690
678
|
$GlobalRequestInfoCache,
|
|
691
679
|
$LocalRequestInfoCache,
|
|
692
680
|
baseConfig,
|
|
693
681
|
config,
|
|
694
682
|
newFetchController,
|
|
695
683
|
options,
|
|
696
|
-
request
|
|
684
|
+
request,
|
|
685
|
+
resolvedDedupeStrategy
|
|
697
686
|
});
|
|
687
|
+
const { handleRefetch, refetch } = createRefetchManager({
|
|
688
|
+
callApi,
|
|
689
|
+
callApiArgs: {
|
|
690
|
+
config,
|
|
691
|
+
initURL
|
|
692
|
+
},
|
|
693
|
+
options,
|
|
694
|
+
removeDedupeCacheEntry
|
|
695
|
+
});
|
|
696
|
+
options.refetch = refetch;
|
|
698
697
|
try {
|
|
699
698
|
handleRequestCancelStrategy();
|
|
700
|
-
await executeHooks(options.onRequest
|
|
699
|
+
if (options.onRequest) await executeHooks(options.onRequest({
|
|
701
700
|
baseConfig,
|
|
702
701
|
config,
|
|
703
702
|
options,
|
|
@@ -711,7 +710,7 @@ const createFetchClientWithContext = () => {
|
|
|
711
710
|
request
|
|
712
711
|
});
|
|
713
712
|
Object.assign(options, extraOptionsValidationResult);
|
|
714
|
-
|
|
713
|
+
Object.assign(request, {
|
|
715
714
|
body: getBody({
|
|
716
715
|
body: requestOptionsValidationResult.body,
|
|
717
716
|
bodySerializer: options.bodySerializer,
|
|
@@ -726,15 +725,14 @@ const createFetchClientWithContext = () => {
|
|
|
726
725
|
initURL: resolvedInitURL,
|
|
727
726
|
method: requestOptionsValidationResult.method
|
|
728
727
|
})
|
|
729
|
-
};
|
|
730
|
-
Object.assign(request, modifiedRequestOptionsValidationResult);
|
|
728
|
+
});
|
|
731
729
|
const readyRequestContext = {
|
|
732
730
|
baseConfig,
|
|
733
731
|
config,
|
|
734
732
|
options,
|
|
735
733
|
request
|
|
736
734
|
};
|
|
737
|
-
await executeHooks(options.onRequestReady
|
|
735
|
+
if (options.onRequestReady) await executeHooks(options.onRequestReady(readyRequestContext));
|
|
738
736
|
const response = await handleRequestDeferStrategy({
|
|
739
737
|
fetchApi: getFetchImpl({
|
|
740
738
|
customFetchImpl: options.customFetchImpl,
|
|
@@ -776,20 +774,17 @@ const createFetchClientWithContext = () => {
|
|
|
776
774
|
request,
|
|
777
775
|
response
|
|
778
776
|
};
|
|
779
|
-
await executeHooks(options.onSuccess?.(successContext), options.onResponse?.({
|
|
777
|
+
if (options.onSuccess || options.onResponse) await executeHooks(options.onSuccess?.(successContext), options.onResponse?.({
|
|
780
778
|
...successContext,
|
|
781
779
|
error: null
|
|
782
780
|
}));
|
|
783
|
-
|
|
781
|
+
const successResult = resolveSuccessResult(successContext.data, {
|
|
784
782
|
response: successContext.response,
|
|
785
783
|
resultMode: options.resultMode
|
|
786
784
|
});
|
|
785
|
+
return await handleRefetch() ?? successResult;
|
|
787
786
|
} catch (error) {
|
|
788
|
-
const
|
|
789
|
-
cloneResponse: options.cloneResponse,
|
|
790
|
-
resultMode: options.resultMode
|
|
791
|
-
};
|
|
792
|
-
const { errorDetails, errorResult } = resolveErrorResult(error, errorInfo);
|
|
787
|
+
const { errorDetails, errorResult } = resolveErrorResult(error, options);
|
|
793
788
|
const errorContext = {
|
|
794
789
|
baseConfig,
|
|
795
790
|
config,
|
|
@@ -800,10 +795,10 @@ const createFetchClientWithContext = () => {
|
|
|
800
795
|
};
|
|
801
796
|
const shouldThrowOnError = Boolean(isFunction(options.throwOnError) ? options.throwOnError(errorContext) : options.throwOnError);
|
|
802
797
|
const hookInfo = {
|
|
803
|
-
|
|
798
|
+
errorInfoOptions: options,
|
|
804
799
|
shouldThrowOnError
|
|
805
800
|
};
|
|
806
|
-
const {
|
|
801
|
+
const { handleRetry } = createRetryManager({
|
|
807
802
|
callApi,
|
|
808
803
|
callApiArgs: {
|
|
809
804
|
config,
|
|
@@ -811,39 +806,43 @@ const createFetchClientWithContext = () => {
|
|
|
811
806
|
},
|
|
812
807
|
error,
|
|
813
808
|
errorContext,
|
|
814
|
-
|
|
815
|
-
|
|
809
|
+
hookInfo,
|
|
810
|
+
removeDedupeCacheEntry
|
|
816
811
|
});
|
|
812
|
+
const handleRefetchThenRetryOrGetResult = async () => {
|
|
813
|
+
return await handleRefetch() ?? await handleRetry() ?? errorResult;
|
|
814
|
+
};
|
|
817
815
|
const responseContext = errorContext.response ? {
|
|
818
816
|
...errorContext,
|
|
819
817
|
data: null
|
|
820
818
|
} : null;
|
|
821
|
-
if (isValidationErrorInstance(error)) return await executeHooksInCatchBlock([
|
|
819
|
+
if (isValidationErrorInstance(error)) return (responseContext && options.onResponse || options.onValidationError || options.onError ? await executeHooksInCatchBlock([
|
|
822
820
|
responseContext && options.onResponse?.(responseContext),
|
|
823
821
|
options.onValidationError?.(errorContext),
|
|
824
822
|
options.onError?.(errorContext)
|
|
825
|
-
], hookInfo) ?? await
|
|
826
|
-
if (isHTTPErrorInstance(error)) return await executeHooksInCatchBlock([
|
|
823
|
+
], hookInfo) : null) ?? await handleRefetchThenRetryOrGetResult();
|
|
824
|
+
if (isHTTPErrorInstance(error)) return (responseContext && options.onResponse || options.onResponseError || options.onError ? await executeHooksInCatchBlock([
|
|
827
825
|
responseContext && options.onResponse?.(responseContext),
|
|
828
826
|
options.onResponseError?.(errorContext),
|
|
829
827
|
options.onError?.(errorContext)
|
|
830
|
-
], hookInfo) ?? await
|
|
831
|
-
let message = error?.message;
|
|
828
|
+
], hookInfo) : null) ?? await handleRefetchThenRetryOrGetResult();
|
|
832
829
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
833
|
-
message = getAbortErrorMessage();
|
|
830
|
+
const message = getAbortErrorMessage();
|
|
831
|
+
errorResult && (errorResult.error.message = message);
|
|
834
832
|
!shouldThrowOnError && console.error(`${error.name}:`, message);
|
|
835
833
|
}
|
|
836
834
|
if (error instanceof DOMException && error.name === "TimeoutError") {
|
|
837
|
-
message = `Request timed out after ${options.timeout}ms`;
|
|
835
|
+
const message = `Request timed out after ${options.timeout}ms`;
|
|
836
|
+
errorResult && (errorResult.error.message = message);
|
|
838
837
|
!shouldThrowOnError && console.error(`${error.name}:`, message);
|
|
839
838
|
}
|
|
840
|
-
return await executeHooksInCatchBlock([
|
|
839
|
+
return (responseContext && options.onResponse || options.onRequestError || options.onError ? await executeHooksInCatchBlock([
|
|
841
840
|
responseContext && options.onResponse?.(responseContext),
|
|
842
841
|
options.onRequestError?.(errorContext),
|
|
843
842
|
options.onError?.(errorContext)
|
|
844
|
-
], hookInfo) ??
|
|
843
|
+
], hookInfo) : null) ?? await handleRefetchThenRetryOrGetResult();
|
|
845
844
|
} finally {
|
|
846
|
-
|
|
845
|
+
removeDedupeCacheEntry();
|
|
847
846
|
}
|
|
848
847
|
};
|
|
849
848
|
return callApi;
|