@zayne-labs/callapi 1.12.6 → 1.14.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/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-IsBgvt90.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-CQmUuQDT.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 = () => {
@@ -148,13 +137,13 @@ const executeHooks = async (...hookResultsOrPromise) => {
148
137
  await Promise.all(validHooks);
149
138
  };
150
139
  const executeHooksInCatchBlock = async (hookResultsOrPromise, hookInfo) => {
151
- const { errorInfo, shouldThrowOnError } = hookInfo;
140
+ const { errorInfoOptions, shouldThrowOnError } = hookInfo;
152
141
  try {
153
142
  await Promise.all(hookResultsOrPromise);
154
143
  return null;
155
144
  } catch (hookError) {
156
145
  if (shouldThrowOnError) throw hookError;
157
- const { errorResult } = resolveErrorResult(hookError, errorInfo);
146
+ const { errorResult } = resolveErrorResult(hookError, errorInfoOptions);
158
147
  return errorResult;
159
148
  }
160
149
  };
@@ -287,10 +276,8 @@ const toStreamableResponse = (context) => {
287
276
  };
288
277
  //#endregion
289
278
  //#region src/dedupe.ts
290
- const createDedupeStrategy = async (context) => {
291
- const { $GlobalRequestInfoCache, $LocalRequestInfoCache, baseConfig, config, newFetchController, options: globalOptions } = context;
292
- const dedupeStrategy = globalOptions.dedupeStrategy ?? extraOptionDefaults.dedupeStrategy;
293
- const resolvedDedupeStrategy = isFunction(dedupeStrategy) ? dedupeStrategy(context) : dedupeStrategy;
279
+ const createDedupeManager = async (context) => {
280
+ const { $GlobalRequestInfoCache, $LocalRequestInfoCache, baseConfig, config, newFetchController, options: globalOptions, resolvedDedupeStrategy } = context;
294
281
  const shouldDisableDedupe = resolvedDedupeStrategy === "none";
295
282
  const getDedupeKey = () => {
296
283
  const dedupeKey = globalOptions.dedupeKey ?? extraOptionDefaults.dedupeKey;
@@ -337,7 +324,6 @@ const createDedupeStrategy = async (context) => {
337
324
  if (!shouldDisableDedupe) await waitFor(.01);
338
325
  const prevRequestInfo = $RequestInfoCache?.get();
339
326
  const getAbortErrorMessage = () => {
340
- if (shouldDisableDedupe) return;
341
327
  return globalOptions.dedupeKey != null ? `Duplicate request detected - Aborted previous request with key '${dedupeKey}'` : `Duplicate request detected - Aborted previous request to '${globalOptions.fullURL}'`;
342
328
  };
343
329
  const handleRequestCancelStrategy = () => {
@@ -365,15 +351,11 @@ const createDedupeStrategy = async (context) => {
365
351
  response: await responsePromise
366
352
  });
367
353
  };
368
- const removeDedupeKeyFromCache = () => {
369
- $RequestInfoCache?.delete();
370
- };
371
354
  return {
372
355
  getAbortErrorMessage,
373
356
  handleRequestCancelStrategy,
374
357
  handleRequestDeferStrategy,
375
- removeDedupeKeyFromCache,
376
- resolvedDedupeStrategy
358
+ removeDedupeCacheEntry: () => $RequestInfoCache?.delete()
377
359
  };
378
360
  };
379
361
  //#endregion
@@ -537,82 +519,82 @@ const setupHooksAndMiddlewares = (context) => {
537
519
  };
538
520
  //#endregion
539
521
  //#region src/refetch.ts
522
+ const shouldAttemptRefetchSymbol = Symbol("shouldAttemptRefetch");
540
523
  const createRefetchManager = (ctx) => {
541
- const { callApi, callApiArgs, options } = ctx;
542
- const currentRefetchCount = options["~refetchCount"] ?? 1;
543
- const refetch = async (refetchOptionOverrides) => {
544
- const maxRefetchAttempts = refetchOptionOverrides?.refetchAttempts ?? options.refetchAttempts ?? extraOptionDefaults.refetchAttempts;
545
- if (!(currentRefetchCount <= maxRefetchAttempts)) {
546
- const message = `Maximum refetch attempts (${maxRefetchAttempts}) exceeded. This prevents infinite loops. Increase 'maxRefetchAttempts' if needed.`;
547
- console.error(message);
548
- 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
+ });
549
538
  }
550
- const updatedConfig = {
551
- ...callApiArgs.config,
552
- ...refetchOptionOverrides,
553
- "~refetchCount": currentRefetchCount + 1
554
- };
555
- return callApi(callApiArgs.initURL, updatedConfig);
539
+ return null;
540
+ };
541
+ return {
542
+ handleRefetch,
543
+ refetch
556
544
  };
557
- return { refetch };
558
545
  };
559
546
  //#endregion
560
547
  //#region src/retry.ts
561
- const getLinearDelay = (currentAttemptCount, options) => {
562
- const retryDelay = options.retryDelay ?? extraOptionDefaults.retryDelay;
563
- return isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay;
564
- };
565
- const getExponentialDelay = (currentAttemptCount, options) => {
566
- const retryDelay = options.retryDelay ?? extraOptionDefaults.retryDelay;
567
- const resolvedRetryDelay = isFunction(retryDelay) ? retryDelay(currentAttemptCount) : retryDelay;
568
- const maxDelay = options.retryMaxDelay ?? extraOptionDefaults.retryMaxDelay;
569
- const exponentialDelay = resolvedRetryDelay * 2 ** currentAttemptCount;
570
- return Math.min(exponentialDelay, maxDelay);
571
- };
572
548
  const createRetryManager = (ctx) => {
573
- const { callApi, callApiArgs, error, errorContext, errorResult, hookInfo } = ctx;
549
+ const { callApi, callApiArgs, error, errorContext, hookInfo, removeDedupeCacheEntry } = ctx;
574
550
  const { options, request } = errorContext;
575
- const currentAttemptCount = options["~retryAttemptCount"] ?? 1;
576
- 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
+ };
577
563
  const getDelay = () => {
564
+ const retryStrategy = options.retryStrategy ?? extraOptionDefaults.retryStrategy;
578
565
  switch (retryStrategy) {
579
- case "exponential": return getExponentialDelay(currentAttemptCount, options);
580
- 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
+ }
581
577
  default: throw new Error(`Invalid retry strategy: ${String(retryStrategy)}`);
582
578
  }
583
579
  };
584
- const shouldAttemptRetry = async () => {
585
- if (isBoolean(request.signal) && request.signal.aborted) return false;
586
- const retryCondition = options.retryCondition ?? extraOptionDefaults.retryCondition;
587
- const maxRetryAttempts = options.retryAttempts ?? extraOptionDefaults.retryAttempts;
588
- const customRetryCondition = await retryCondition(errorContext);
589
- if (!(currentAttemptCount <= maxRetryAttempts && customRetryCondition)) return false;
590
- const retryMethods = new Set(options.retryMethods ?? extraOptionDefaults.retryMethods);
591
- const includesMethod = isString(request.method) && retryMethods.size > 0 ? retryMethods.has(request.method) : true;
592
- const retryStatusCodes = new Set(options.retryStatusCodes ?? extraOptionDefaults.retryStatusCodes);
593
- const includesStatusCodes = errorContext.response != null && retryStatusCodes.size > 0 ? retryStatusCodes.has(errorContext.response.status) : true;
594
- return includesMethod && includesStatusCodes;
595
- };
596
580
  const handleRetry = async () => {
597
- const retryContext = {
598
- ...errorContext,
599
- retryAttemptCount: currentAttemptCount
600
- };
601
- const hookError = await executeHooksInCatchBlock([options.onRetry?.(retryContext)], hookInfo);
602
- if (hookError) return hookError;
603
- await waitFor(getDelay());
604
- const updatedConfig = {
605
- ...callApiArgs.config,
606
- "~retryAttemptCount": currentAttemptCount + 1
607
- };
608
- return callApi(callApiArgs.initURL, updatedConfig);
609
- };
610
- const handleRetryOrGetErrorResult = async () => {
611
- 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
+ }
612
594
  if (hookInfo.shouldThrowOnError) throw error;
613
- return errorResult;
595
+ return null;
614
596
  };
615
- return { handleRetryOrGetErrorResult };
597
+ return { handleRetry };
616
598
  };
617
599
  //#endregion
618
600
  //#region src/createFetchClient.ts
@@ -679,33 +661,42 @@ const createFetchClientWithContext = () => {
679
661
  initURL: resolvedInitURL,
680
662
  initURLNormalized: normalizedInitURL
681
663
  };
682
- const refetchFnResult = createRefetchManager({
683
- callApi,
684
- callApiArgs: {
685
- config,
686
- initURL
687
- },
688
- options
689
- });
690
- Object.assign(options, refetchFnResult);
691
- const newFetchController = options.dedupeStrategy === "none" ? null : new AbortController();
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();
692
672
  const combinedSignal = createCombinedSignal(createTimeoutSignal(options.timeout), resolvedRequest.signal, newFetchController?.signal);
693
673
  const request = {
694
674
  ...resolvedRequest,
695
675
  signal: combinedSignal
696
676
  };
697
- const { getAbortErrorMessage, handleRequestCancelStrategy, handleRequestDeferStrategy, removeDedupeKeyFromCache, resolvedDedupeStrategy } = await createDedupeStrategy({
677
+ const { getAbortErrorMessage, handleRequestCancelStrategy, handleRequestDeferStrategy, removeDedupeCacheEntry } = await createDedupeManager({
698
678
  $GlobalRequestInfoCache,
699
679
  $LocalRequestInfoCache,
700
680
  baseConfig,
701
681
  config,
702
682
  newFetchController,
703
683
  options,
704
- request
684
+ request,
685
+ resolvedDedupeStrategy
686
+ });
687
+ const { handleRefetch, refetch } = createRefetchManager({
688
+ callApi,
689
+ callApiArgs: {
690
+ config,
691
+ initURL
692
+ },
693
+ options,
694
+ removeDedupeCacheEntry
705
695
  });
696
+ options.refetch = refetch;
706
697
  try {
707
698
  handleRequestCancelStrategy();
708
- await executeHooks(options.onRequest?.({
699
+ if (options.onRequest) await executeHooks(options.onRequest({
709
700
  baseConfig,
710
701
  config,
711
702
  options,
@@ -719,30 +710,31 @@ const createFetchClientWithContext = () => {
719
710
  request
720
711
  });
721
712
  Object.assign(options, extraOptionsValidationResult);
722
- const modifiedRequestOptionsValidationResult = {
723
- body: getBody({
724
- body: requestOptionsValidationResult.body,
725
- bodySerializer: options.bodySerializer,
726
- resolvedHeaders: requestOptionsValidationResult.headers
727
- }),
713
+ const resolvedBody = getBody({
714
+ body: requestOptionsValidationResult.body,
715
+ bodySerializer: options.bodySerializer,
716
+ bodyTransformer: options.bodyTransformer,
717
+ resolvedHeaders: requestOptionsValidationResult.headers
718
+ });
719
+ Object.assign(request, {
720
+ body: resolvedBody,
728
721
  headers: await getHeaders({
729
722
  auth: options.auth,
730
- body: requestOptionsValidationResult.body,
723
+ body: resolvedBody,
731
724
  resolvedHeaders: requestOptionsValidationResult.headers
732
725
  }),
733
726
  method: getMethod({
734
727
  initURL: resolvedInitURL,
735
728
  method: requestOptionsValidationResult.method
736
729
  })
737
- };
738
- Object.assign(request, modifiedRequestOptionsValidationResult);
730
+ });
739
731
  const readyRequestContext = {
740
732
  baseConfig,
741
733
  config,
742
734
  options,
743
735
  request
744
736
  };
745
- await executeHooks(options.onRequestReady?.(readyRequestContext));
737
+ if (options.onRequestReady) await executeHooks(options.onRequestReady(readyRequestContext));
746
738
  const response = await handleRequestDeferStrategy({
747
739
  fetchApi: getFetchImpl({
748
740
  customFetchImpl: options.customFetchImpl,
@@ -784,20 +776,17 @@ const createFetchClientWithContext = () => {
784
776
  request,
785
777
  response
786
778
  };
787
- await executeHooks(options.onSuccess?.(successContext), options.onResponse?.({
779
+ if (options.onSuccess || options.onResponse) await executeHooks(options.onSuccess?.(successContext), options.onResponse?.({
788
780
  ...successContext,
789
781
  error: null
790
782
  }));
791
- return resolveSuccessResult(successContext.data, {
783
+ const successResult = resolveSuccessResult(successContext.data, {
792
784
  response: successContext.response,
793
785
  resultMode: options.resultMode
794
786
  });
787
+ return await handleRefetch() ?? successResult;
795
788
  } catch (error) {
796
- const errorInfo = {
797
- cloneResponse: options.cloneResponse,
798
- resultMode: options.resultMode
799
- };
800
- const { errorDetails, errorResult } = resolveErrorResult(error, errorInfo);
789
+ const { errorDetails, errorResult } = resolveErrorResult(error, options);
801
790
  const errorContext = {
802
791
  baseConfig,
803
792
  config,
@@ -808,10 +797,10 @@ const createFetchClientWithContext = () => {
808
797
  };
809
798
  const shouldThrowOnError = Boolean(isFunction(options.throwOnError) ? options.throwOnError(errorContext) : options.throwOnError);
810
799
  const hookInfo = {
811
- errorInfo,
800
+ errorInfoOptions: options,
812
801
  shouldThrowOnError
813
802
  };
814
- const { handleRetryOrGetErrorResult } = createRetryManager({
803
+ const { handleRetry } = createRetryManager({
815
804
  callApi,
816
805
  callApiArgs: {
817
806
  config,
@@ -819,39 +808,43 @@ const createFetchClientWithContext = () => {
819
808
  },
820
809
  error,
821
810
  errorContext,
822
- errorResult,
823
- hookInfo
811
+ hookInfo,
812
+ removeDedupeCacheEntry
824
813
  });
814
+ const handleRefetchThenRetryOrGetResult = async () => {
815
+ return await handleRefetch() ?? await handleRetry() ?? errorResult;
816
+ };
825
817
  const responseContext = errorContext.response ? {
826
818
  ...errorContext,
827
819
  data: null
828
820
  } : null;
829
- if (isValidationErrorInstance(error)) return await executeHooksInCatchBlock([
821
+ if (isValidationErrorInstance(error)) return (responseContext && options.onResponse || options.onValidationError || options.onError ? await executeHooksInCatchBlock([
830
822
  responseContext && options.onResponse?.(responseContext),
831
823
  options.onValidationError?.(errorContext),
832
824
  options.onError?.(errorContext)
833
- ], hookInfo) ?? await handleRetryOrGetErrorResult();
834
- if (isHTTPErrorInstance(error)) return await executeHooksInCatchBlock([
825
+ ], hookInfo) : null) ?? await handleRefetchThenRetryOrGetResult();
826
+ if (isHTTPErrorInstance(error)) return (responseContext && options.onResponse || options.onResponseError || options.onError ? await executeHooksInCatchBlock([
835
827
  responseContext && options.onResponse?.(responseContext),
836
828
  options.onResponseError?.(errorContext),
837
829
  options.onError?.(errorContext)
838
- ], hookInfo) ?? await handleRetryOrGetErrorResult();
839
- let message = error?.message;
830
+ ], hookInfo) : null) ?? await handleRefetchThenRetryOrGetResult();
840
831
  if (error instanceof DOMException && error.name === "AbortError") {
841
- message = getAbortErrorMessage();
832
+ const message = getAbortErrorMessage();
833
+ errorResult && (errorResult.error.message = message);
842
834
  !shouldThrowOnError && console.error(`${error.name}:`, message);
843
835
  }
844
836
  if (error instanceof DOMException && error.name === "TimeoutError") {
845
- message = `Request timed out after ${options.timeout}ms`;
837
+ const message = `Request timed out after ${options.timeout}ms`;
838
+ errorResult && (errorResult.error.message = message);
846
839
  !shouldThrowOnError && console.error(`${error.name}:`, message);
847
840
  }
848
- return await executeHooksInCatchBlock([
841
+ return (responseContext && options.onResponse || options.onRequestError || options.onError ? await executeHooksInCatchBlock([
849
842
  responseContext && options.onResponse?.(responseContext),
850
843
  options.onRequestError?.(errorContext),
851
844
  options.onError?.(errorContext)
852
- ], hookInfo) ?? getCustomizedErrorResult(await handleRetryOrGetErrorResult(), { message });
845
+ ], hookInfo) : null) ?? await handleRefetchThenRetryOrGetResult();
853
846
  } finally {
854
- removeDedupeKeyFromCache();
847
+ removeDedupeCacheEntry();
855
848
  }
856
849
  };
857
850
  return callApi;