@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.
@@ -1,4 +1,4 @@
1
- import { Ct as DistributiveOmit, E as CallApiResult, Et as Writeable, M as GlobalMeta, O as GetBaseSchemaConfig, S as CallApiContext, St as AnyString, _ as ResponseTypeType, _t as InferSchemaOutput, ct as ThrowOnErrorBoolean, d as GetResponseType, dt as BaseCallApiSchemaRoutes, et as ApplyStrictConfig, f as InferCallApiResult, g as ResponseTypeMap, i as CallApiPlugin, k as GetBaseSchemaRoutes, l as CallApiResultSuccessOrErrorVariant, mt as CallApiSchemaConfig, n as DefaultDataType, nt as GetCurrentRouteSchema, ot as InferInitURL, pt as CallApiSchema, r as DefaultPluginArray, rt as GetCurrentRouteSchemaKey, t as DefaultCallApiContext, tt as ApplyURLBasedConfig, u as CallApiResultSuccessVariant, ut as BaseCallApiSchemaAndConfig, v as ResultModeType, vt as InferSchemaResult, wt as NoInferUnMasked, x as CallApiConfig, y as BaseCallApiConfig } from "./default-types-CswfU2bI.js";
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-DMCchZ0z.d.ts.map
91
+ //# sourceMappingURL=index-WSyoCGJi.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { $ as RetryOptions, A as GetCallApiContext, B as DedupeOptions, C as CallApiExtraOptions, D as CallApiResultLoose, G as HooksOrHooksArray, H as CallApiRequestOptionsForHooks, J as ResponseContext, K as RequestContext, L as FetchImpl, N as InstanceContext, P as Register, Q as RefetchOptions, R as FetchMiddlewareContext, T as CallApiRequestOptions, U as ErrorContext, V as CallApiExtraOptionsForHooks, W as Hooks, X as ResponseStreamContext, Y as ResponseErrorContext, Z as SuccessContext, _ as ResponseTypeType, _t as InferSchemaOutput, a as PluginHooks, at as InferAllMainRoutes, b as BaseCallApiExtraOptions, c as CallApiResultErrorVariant, dt as BaseCallApiSchemaRoutes, ft as BaseSchemaRouteKeyPrefixes, gt as InferSchemaInput, h as PossibleValidationError, i as CallApiPlugin, it as InferAllMainRouteKeys, j as GetCallApiContextRequired, l as CallApiResultSuccessOrErrorVariant, lt as URLOptions, m as PossibleJavaScriptError, mt as CallApiSchemaConfig, o as PluginMiddlewares, ot as InferInitURL, p as PossibleHTTPError, pt as CallApiSchema, q as RequestStreamContext, rt as GetCurrentRouteSchemaKey, s as PluginSetupContext, st as InferParamsFromRoute, t as DefaultCallApiContext, u as CallApiResultSuccessVariant, v as ResultModeType, w as CallApiParameters, x as CallApiConfig, y as BaseCallApiConfig, z as Middlewares } from "./default-types-CswfU2bI.js";
2
- import { n as createFetchClient, r as createFetchClientWithContext, t as callApi } from "./index-DMCchZ0z.js";
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, B as isString, L as isArray, M as handleSchemaValidation, N as HTTPError, R as isBoolean, 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, z as isFunction } from "./defaults-D0QJmGE5.js";
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, info) => {
55
- const { cloneResponse, message: customErrorMessage, resultMode } = info;
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
- await Promise.all(hookResultsOrPromise);
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 { errorInfo, shouldThrowOnError } = hookInfo;
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, errorInfo);
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 createDedupeStrategy = async (context) => {
289
- const { $GlobalRequestInfoCache, $LocalRequestInfoCache, baseConfig, config, newFetchController, options: globalOptions } = context;
290
- const dedupeStrategy = globalOptions.dedupeStrategy ?? extraOptionDefaults.dedupeStrategy;
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 getDedupeCacheScopeKey = () => {
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 (!dedupeKey) return;
288
+ if (dedupeKey == null) return;
304
289
  const dedupeCacheScope = globalOptions.dedupeCacheScope ?? extraOptionDefaults.dedupeCacheScope;
305
- const dedupeCacheScopeKey = getDedupeCacheScopeKey();
306
- const $RequestInfoCache = dedupeCacheScope === "global" ? $GlobalRequestInfoCache.get(dedupeCacheScopeKey) ?? $GlobalRequestInfoCache.set(dedupeCacheScopeKey, /* @__PURE__ */ new Map()).get(dedupeCacheScopeKey) : $LocalRequestInfoCache;
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 (dedupeKey !== null) await waitFor(.01);
324
+ if (!shouldDisableDedupe) await waitFor(.01);
339
325
  const prevRequestInfo = $RequestInfoCache?.get();
340
326
  const getAbortErrorMessage = () => {
341
- if (globalOptions.dedupeKey) return `Duplicate request detected - Aborted previous request with key '${dedupeKey}'`;
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.abort(reason);
333
+ prevRequestInfo.controller?.abort(reason);
349
334
  };
350
335
  const handleRequestDeferStrategy = async (deferContext) => {
351
336
  const { fetchApi, options: localOptions, request: localRequest } = deferContext;
352
- const shouldUsePromiseFromCache = prevRequestInfo && resolvedDedupeStrategy === "defer";
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 = shouldUsePromiseFromCache ? prevRequestInfo.responsePromise : fetchApi(localOptions.fullURL, toStreamableRequest(streamContext));
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
- removeDedupeKeyFromCache,
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 initializePlugins = async (setupContext) => {
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
- for (const plugin of resolvedPlugins) {
447
- const [, pluginHooks, pluginMiddlewares] = await Promise.all([
448
- executePluginSetupFn(plugin.setup),
449
- isFunction(plugin.hooks) ? plugin.hooks(setupContext) : plugin.hooks,
450
- isFunction(plugin.middlewares) ? plugin.middlewares(setupContext) : plugin.middlewares
451
- ]);
452
- pluginHooks && addPluginHooks(pluginHooks);
453
- pluginMiddlewares && addPluginMiddlewares(pluginMiddlewares);
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 [hookName, hookRegistry] of Object.entries(hookRegistries)) {
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 [middlewareName, middlewareRegistry] of Object.entries(middlewareRegistries)) {
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 currentRefetchCount = options["~refetchCount"] ?? 1;
536
- const refetch = async (refetchOptionOverrides) => {
537
- const maxRefetchAttempts = refetchOptionOverrides?.refetchAttempts ?? options.refetchAttempts ?? extraOptionDefaults.refetchAttempts;
538
- if (!(currentRefetchCount <= maxRefetchAttempts)) {
539
- const message = `Maximum refetch attempts (${maxRefetchAttempts}) exceeded. This prevents infinite loops. Increase 'maxRefetchAttempts' if needed.`;
540
- console.error(message);
541
- return null;
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
- const updatedConfig = {
544
- ...callApiArgs.config,
545
- ...refetchOptionOverrides,
546
- "~refetchCount": currentRefetchCount + 1
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, errorResult, hookInfo } = ctx;
549
+ const { callApi, callApiArgs, error, errorContext, hookInfo, removeDedupeCacheEntry } = ctx;
567
550
  const { options, request } = errorContext;
568
- const currentAttemptCount = options["~retryAttemptCount"] ?? 1;
569
- const retryStrategy = options.retryStrategy ?? extraOptionDefaults.retryStrategy;
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": return getExponentialDelay(currentAttemptCount, options);
573
- case "linear": return getLinearDelay(currentAttemptCount, options);
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
- const retryContext = {
591
- ...errorContext,
592
- retryAttemptCount: currentAttemptCount
593
- };
594
- const hookError = await executeHooksInCatchBlock([options.onRetry?.(retryContext)], hookInfo);
595
- if (hookError) return hookError;
596
- await waitFor(getDelay());
597
- const updatedConfig = {
598
- ...callApiArgs.config,
599
- "~retryAttemptCount": currentAttemptCount + 1
600
- };
601
- return callApi(callApiArgs.initURL, updatedConfig);
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 errorResult;
595
+ return null;
607
596
  };
608
- return { handleRetryOrGetErrorResult };
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 initializePlugins({
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 refetchFnResult = createRefetchManager({
675
- callApi,
676
- callApiArgs: {
677
- config,
678
- initURL
679
- },
680
- options
681
- });
682
- Object.assign(options, refetchFnResult);
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, removeDedupeKeyFromCache, resolvedDedupeStrategy } = await createDedupeStrategy({
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
- const modifiedRequestOptionsValidationResult = {
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?.(readyRequestContext));
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
- return resolveSuccessResult(successContext.data, {
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 errorInfo = {
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
- errorInfo,
798
+ errorInfoOptions: options,
804
799
  shouldThrowOnError
805
800
  };
806
- const { handleRetryOrGetErrorResult } = createRetryManager({
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
- errorResult,
815
- hookInfo
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 handleRetryOrGetErrorResult();
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 handleRetryOrGetErrorResult();
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) ?? getCustomizedErrorResult(await handleRetryOrGetErrorResult(), { message });
843
+ ], hookInfo) : null) ?? await handleRefetchThenRetryOrGetResult();
845
844
  } finally {
846
- removeDedupeKeyFromCache();
845
+ removeDedupeCacheEntry();
847
846
  }
848
847
  };
849
848
  return callApi;