@zayne-labs/callapi 1.6.17 → 1.6.18
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/cjs/{error-D4EzEII0.d.cts → error-DH3yCjyX.d.cts} +7 -7
- package/dist/cjs/index.cjs +54 -42
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +2 -2
- package/dist/cjs/utils/index.cjs +0 -37
- package/dist/cjs/utils/index.cjs.map +1 -1
- package/dist/cjs/utils/index.d.cts +1 -2
- package/dist/esm/{chunk-XF6F72SX.js → chunk-KLMWU6K5.js} +19 -3
- package/dist/esm/chunk-KLMWU6K5.js.map +1 -0
- package/dist/esm/{error-D4EzEII0.d.ts → error-DH3yCjyX.d.ts} +7 -7
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +41 -47
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utils/index.d.ts +1 -2
- package/dist/esm/utils/index.js +1 -1
- package/package.json +1 -1
- package/dist/esm/chunk-XF6F72SX.js.map +0 -1
|
@@ -102,7 +102,7 @@ interface CallApiSchemas {
|
|
|
102
102
|
*/
|
|
103
103
|
query?: StandardSchemaV1<Query>;
|
|
104
104
|
}
|
|
105
|
-
interface CallApiValidators<TData =
|
|
105
|
+
interface CallApiValidators<TData = unknown, TErrorData = unknown> {
|
|
106
106
|
/**
|
|
107
107
|
* Custom function to validate the response data.
|
|
108
108
|
*/
|
|
@@ -133,7 +133,7 @@ interface UrlOptions<TSchemas extends CallApiSchemas> {
|
|
|
133
133
|
query?: InferSchemaResult<TSchemas["query"], Query>;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
type RetryCondition<TErrorData> = (context: ErrorContext<TErrorData>) =>
|
|
136
|
+
type RetryCondition<TErrorData> = (context: ErrorContext<TErrorData>) => Awaitable<boolean>;
|
|
137
137
|
interface RetryOptions<TErrorData> {
|
|
138
138
|
/**
|
|
139
139
|
* Keeps track of the number of times the request has already been retried
|
|
@@ -163,12 +163,12 @@ interface RetryOptions<TErrorData> {
|
|
|
163
163
|
* HTTP methods that are allowed to retry
|
|
164
164
|
* @default ["GET", "POST"]
|
|
165
165
|
*/
|
|
166
|
-
retryMethods?: Method[];
|
|
166
|
+
retryMethods?: Method[] | ((context: ErrorContext<TErrorData>) => Method[]);
|
|
167
167
|
/**
|
|
168
168
|
* HTTP status codes that trigger a retry
|
|
169
169
|
* @default [409, 425, 429, 500, 502, 503, 504]
|
|
170
170
|
*/
|
|
171
|
-
retryStatusCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber
|
|
171
|
+
retryStatusCodes?: Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber> | ((context: ErrorContext<TErrorData>) => Array<409 | 425 | 429 | 500 | 502 | 503 | 504 | AnyNumber>);
|
|
172
172
|
/**
|
|
173
173
|
* Strategy to use when retrying
|
|
174
174
|
* @default "linear"
|
|
@@ -203,6 +203,7 @@ type InferPluginOptions<TPluginArray extends CallApiPlugin[]> = UnionToIntersect
|
|
|
203
203
|
type PluginInitContext<TMoreOptions = DefaultMoreOptions> = WithMoreOptions<TMoreOptions> & {
|
|
204
204
|
baseConfig: BaseCallApiExtraOptions & CallApiRequestOptions;
|
|
205
205
|
config: CallApiExtraOptions & CallApiRequestOptions;
|
|
206
|
+
defaultOptions: CallApiExtraOptions;
|
|
206
207
|
initURL: InitURL | undefined;
|
|
207
208
|
options: CombinedCallApiExtraOptions;
|
|
208
209
|
request: CallApiRequestOptionsForHooks;
|
|
@@ -244,8 +245,6 @@ declare const definePlugin: <TPlugin extends CallApiPlugin | AnyFunction<CallApi
|
|
|
244
245
|
type Plugins<TPluginArray extends CallApiPlugin[]> = TPluginArray;
|
|
245
246
|
|
|
246
247
|
declare const fetchSpecificKeys: ("body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "method" | "mode" | "priority" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window")[];
|
|
247
|
-
declare const defaultRetryMethods: ("GET" | "POST")[];
|
|
248
|
-
declare const defaultRetryStatusCodes: Required<BaseCallApiExtraOptions>["retryStatusCodes"];
|
|
249
248
|
|
|
250
249
|
/**
|
|
251
250
|
* @description Makes a type required if TSchema type is undefined or if the output type of TSchema contains undefined, otherwise keeps it as is
|
|
@@ -466,6 +465,7 @@ declare const optionsEnumToOmitFromBase: ("dedupeKey" | "extend")[];
|
|
|
466
465
|
type BaseCallApiExtraOptions<TBaseData = DefaultDataType, TBaseErrorData = DefaultDataType, TBaseResultMode extends ResultModeUnion = ResultModeUnion, TBaseThrowOnError extends boolean = DefaultThrowOnError, TBaseResponseType extends ResponseTypeUnion = ResponseTypeUnion, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TBaseSchemas extends CallApiSchemas = DefaultMoreOptions> = Omit<Partial<CallApiExtraOptions<TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType, TBasePluginArray, TBaseSchemas>>, (typeof optionsEnumToOmitFromBase)[number]>;
|
|
467
466
|
type CombinedCallApiExtraOptions = BaseCallApiExtraOptions & CallApiExtraOptions;
|
|
468
467
|
type BaseCallApiConfig<TBaseData = DefaultDataType, TBaseErrorData = DefaultDataType, TBaseResultMode extends ResultModeUnion = ResultModeUnion, TBaseThrowOnError extends boolean = DefaultThrowOnError, TBaseResponseType extends ResponseTypeUnion = ResponseTypeUnion, TBasePluginArray extends CallApiPlugin[] = DefaultPluginArray, TBaseSchemas extends CallApiSchemas = DefaultMoreOptions> = (CallApiRequestOptions<TBaseSchemas> & BaseCallApiExtraOptions<TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType, TBasePluginArray, TBaseSchemas>) | ((context: {
|
|
468
|
+
defaultOptions: CallApiExtraOptions;
|
|
469
469
|
initURL: string;
|
|
470
470
|
options: CallApiExtraOptions;
|
|
471
471
|
request: CallApiRequestOptions;
|
|
@@ -576,4 +576,4 @@ declare class HTTPError<TErrorResponse = Record<string, unknown>> extends Error
|
|
|
576
576
|
constructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions);
|
|
577
577
|
}
|
|
578
578
|
|
|
579
|
-
export {
|
|
579
|
+
export { type ResponseErrorContext as A, type BaseCallApiConfig as B, type CallApiPlugin as C, type DefaultPluginArray as D, type ErrorContext as E, HTTPError as H, type InferSchemaResult as I, type PluginInitContext as P, type ResultModeUnion as R, type SuccessContext as S, type ResponseTypeUnion as a, type CallApiSchemas as b, type CallApiConfig as c, type CallApiResult as d, type DefaultDataType as e, type DefaultThrowOnError as f, type DefaultMoreOptions as g, type CallApiParameters as h, definePlugin as i, type RetryOptions as j, type BaseCallApiExtraOptions as k, type CallApiExtraOptions as l, type PossibleJavaScriptError as m, type PossibleHTTPError as n, type CallApiRequestOptions as o, type CallApiRequestOptionsForHooks as p, type CallApiResultErrorVariant as q, type CallApiResultSuccessVariant as r, type CombinedCallApiExtraOptions as s, type Interceptors as t, type InterceptorsOrInterceptorArray as u, type PossibleJavascriptErrorNames as v, type Register as w, type RequestContext as x, type RequestErrorContext as y, type ResponseContext as z };
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -205,6 +205,22 @@ var retryStatusCodesLookup = defineEnum({
|
|
|
205
205
|
});
|
|
206
206
|
var defaultRetryMethods = ["GET", "POST"];
|
|
207
207
|
var defaultRetryStatusCodes = Object.keys(retryStatusCodesLookup).map(Number);
|
|
208
|
+
var defaultExtraOptions = {
|
|
209
|
+
baseURL: "",
|
|
210
|
+
bodySerializer: JSON.stringify,
|
|
211
|
+
dedupeStrategy: "cancel",
|
|
212
|
+
defaultErrorMessage: "Failed to fetch data from server!",
|
|
213
|
+
mergedHooksExecutionMode: "parallel",
|
|
214
|
+
mergedHooksExecutionOrder: "mainHooksAfterPlugins",
|
|
215
|
+
responseType: "json",
|
|
216
|
+
resultMode: "all",
|
|
217
|
+
retryAttempts: 0,
|
|
218
|
+
retryDelay: 1e3,
|
|
219
|
+
retryMaxDelay: 1e4,
|
|
220
|
+
retryMethods: defaultRetryMethods,
|
|
221
|
+
retryStatusCodes: defaultRetryStatusCodes,
|
|
222
|
+
retryStrategy: "linear"
|
|
223
|
+
};
|
|
208
224
|
|
|
209
225
|
// src/utils/common.ts
|
|
210
226
|
var omitKeys = (initialObject, keysToOmit) => {
|
|
@@ -375,7 +391,7 @@ var getPluginArray = (plugins) => {
|
|
|
375
391
|
return plugins;
|
|
376
392
|
};
|
|
377
393
|
var initializePlugins = async (context) => {
|
|
378
|
-
const { baseConfig, config, initURL, options, request } = context;
|
|
394
|
+
const { baseConfig, config, defaultOptions, initURL, options, request } = context;
|
|
379
395
|
const hookRegistries = structuredClone(hooksEnum);
|
|
380
396
|
const addMainHooks = () => {
|
|
381
397
|
for (const key of Object.keys(hooksEnum)) {
|
|
@@ -404,6 +420,7 @@ var initializePlugins = async (context) => {
|
|
|
404
420
|
const initResult = await pluginInit({
|
|
405
421
|
baseConfig,
|
|
406
422
|
config,
|
|
423
|
+
defaultOptions,
|
|
407
424
|
initURL,
|
|
408
425
|
options,
|
|
409
426
|
request
|
|
@@ -490,28 +507,30 @@ var getExponentialDelay = (currentAttemptCount, options) => {
|
|
|
490
507
|
const exponentialDelay = (options.retryDelay ?? 1e3) * 2 ** currentAttemptCount;
|
|
491
508
|
return Math.min(exponentialDelay, maxDelay);
|
|
492
509
|
};
|
|
493
|
-
var createRetryStrategy = (
|
|
494
|
-
const currentRetryCount = options["~retryCount"] ?? 0;
|
|
510
|
+
var createRetryStrategy = (ctx) => {
|
|
511
|
+
const currentRetryCount = ctx.options["~retryCount"] ?? 0;
|
|
495
512
|
const getDelay = () => {
|
|
496
|
-
if (options.retryStrategy === "exponential") {
|
|
497
|
-
return getExponentialDelay(currentRetryCount, options);
|
|
513
|
+
if (ctx.options.retryStrategy === "exponential") {
|
|
514
|
+
return getExponentialDelay(currentRetryCount, ctx.options);
|
|
498
515
|
}
|
|
499
|
-
return getLinearDelay(options);
|
|
516
|
+
return getLinearDelay(ctx.options);
|
|
500
517
|
};
|
|
501
518
|
const shouldAttemptRetry = async () => {
|
|
502
|
-
const customRetryCondition = await options.retryCondition?.(ctx) ?? true;
|
|
503
|
-
const maxRetryAttempts = options.retryAttempts ?? 0;
|
|
519
|
+
const customRetryCondition = await ctx.options.retryCondition?.(ctx) ?? true;
|
|
520
|
+
const maxRetryAttempts = ctx.options.retryAttempts ?? 0;
|
|
504
521
|
const baseRetryCondition = maxRetryAttempts > currentRetryCount && customRetryCondition;
|
|
505
522
|
if (ctx.error.name !== "HTTPError") {
|
|
506
523
|
return baseRetryCondition;
|
|
507
524
|
}
|
|
525
|
+
const resolvedRetryMethods = isFunction(ctx.options.retryMethods) ? ctx.options.retryMethods(ctx) : ctx.options.retryMethods;
|
|
526
|
+
const resolvedRetryStatusCodes = isFunction(ctx.options.retryStatusCodes) ? ctx.options.retryStatusCodes(ctx) : ctx.options.retryStatusCodes;
|
|
508
527
|
const includesMethod = (
|
|
509
528
|
// eslint-disable-next-line no-implicit-coercion -- Boolean doesn't narrow
|
|
510
|
-
!!ctx.request.method &&
|
|
529
|
+
!!ctx.request.method && resolvedRetryMethods?.includes(ctx.request.method)
|
|
511
530
|
);
|
|
512
531
|
const includesCodes = (
|
|
513
532
|
// eslint-disable-next-line no-implicit-coercion -- Boolean doesn't narrow
|
|
514
|
-
!!ctx.response?.status &&
|
|
533
|
+
!!ctx.response?.status && resolvedRetryStatusCodes?.includes(ctx.response.status)
|
|
515
534
|
);
|
|
516
535
|
return includesCodes && includesMethod && baseRetryCondition;
|
|
517
536
|
};
|
|
@@ -595,7 +614,12 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
595
614
|
const callApi2 = async (...parameters) => {
|
|
596
615
|
const [initURL, config = {}] = parameters;
|
|
597
616
|
const [fetchOptions, extraOptions] = splitConfig(config);
|
|
598
|
-
const resolvedBaseConfig = isFunction(baseConfig) ? baseConfig({
|
|
617
|
+
const resolvedBaseConfig = isFunction(baseConfig) ? baseConfig({
|
|
618
|
+
defaultOptions: defaultExtraOptions,
|
|
619
|
+
initURL: initURL.toString(),
|
|
620
|
+
options: extraOptions,
|
|
621
|
+
request: fetchOptions
|
|
622
|
+
}) : baseConfig;
|
|
599
623
|
const [baseFetchOptions, baseExtraOptions] = splitBaseConfig(resolvedBaseConfig);
|
|
600
624
|
const initCombinedHooks = {};
|
|
601
625
|
for (const key of Object.keys(hooksEnum)) {
|
|
@@ -605,35 +629,22 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
605
629
|
);
|
|
606
630
|
initCombinedHooks[key] = combinedHook;
|
|
607
631
|
}
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
bodySerializer: JSON.stringify,
|
|
611
|
-
dedupeStrategy: "cancel",
|
|
612
|
-
defaultErrorMessage: "Failed to fetch data from server!",
|
|
613
|
-
mergedHooksExecutionMode: "parallel",
|
|
614
|
-
mergedHooksExecutionOrder: "mainHooksAfterPlugins",
|
|
615
|
-
responseType: "json",
|
|
616
|
-
resultMode: "all",
|
|
617
|
-
retryAttempts: 0,
|
|
618
|
-
retryDelay: 1e3,
|
|
619
|
-
retryMaxDelay: 1e4,
|
|
620
|
-
retryMethods: defaultRetryMethods,
|
|
621
|
-
retryStatusCodes: defaultRetryStatusCodes,
|
|
622
|
-
retryStrategy: "linear",
|
|
632
|
+
const mergedExtraOptions = {
|
|
633
|
+
...defaultExtraOptions,
|
|
623
634
|
...baseExtraOptions,
|
|
624
|
-
...extraOptions
|
|
625
|
-
...initCombinedHooks
|
|
635
|
+
...extraOptions
|
|
626
636
|
};
|
|
627
|
-
const
|
|
637
|
+
const mergedRequestOptions = {
|
|
628
638
|
...baseFetchOptions,
|
|
629
639
|
...fetchOptions
|
|
630
640
|
};
|
|
631
641
|
const { resolvedHooks, resolvedOptions, resolvedRequestOptions, url } = await initializePlugins({
|
|
632
642
|
baseConfig: resolvedBaseConfig,
|
|
633
643
|
config,
|
|
644
|
+
defaultOptions: defaultExtraOptions,
|
|
634
645
|
initURL,
|
|
635
|
-
options:
|
|
636
|
-
request:
|
|
646
|
+
options: mergedExtraOptions,
|
|
647
|
+
request: mergedRequestOptions
|
|
637
648
|
});
|
|
638
649
|
const fullURL = `${resolvedOptions.baseURL}${mergeUrlWithParamsAndQuery(url, resolvedOptions.params, resolvedOptions.query)}`;
|
|
639
650
|
const options = {
|
|
@@ -694,11 +705,7 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
694
705
|
options.responseType,
|
|
695
706
|
options.responseParser
|
|
696
707
|
);
|
|
697
|
-
const validSuccessData = await handleValidation(
|
|
698
|
-
successData,
|
|
699
|
-
schemas?.data,
|
|
700
|
-
validators?.data
|
|
701
|
-
);
|
|
708
|
+
const validSuccessData = await handleValidation(successData, schemas?.data, validators?.data);
|
|
702
709
|
const successContext = {
|
|
703
710
|
data: validSuccessData,
|
|
704
711
|
options,
|
|
@@ -727,9 +734,11 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
727
734
|
request,
|
|
728
735
|
response: apiDetails.response
|
|
729
736
|
};
|
|
730
|
-
const
|
|
731
|
-
const
|
|
732
|
-
|
|
737
|
+
const shouldThrowOnError = isFunction(options.throwOnError) ? options.throwOnError(errorContext) : options.throwOnError;
|
|
738
|
+
const handleRetry = async () => {
|
|
739
|
+
const { getDelay, shouldAttemptRetry } = createRetryStrategy(errorContext);
|
|
740
|
+
const shouldRetry = !combinedSignal.aborted && await shouldAttemptRetry();
|
|
741
|
+
if (!shouldRetry) return;
|
|
733
742
|
await executeHooks(options.onRetry(errorContext));
|
|
734
743
|
const delay = getDelay();
|
|
735
744
|
await waitUntil(delay);
|
|
@@ -737,9 +746,8 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
737
746
|
...config,
|
|
738
747
|
"~retryCount": (options["~retryCount"] ?? 0) + 1
|
|
739
748
|
};
|
|
740
|
-
return
|
|
741
|
-
}
|
|
742
|
-
const shouldThrowOnError = isFunction(options.throwOnError) ? options.throwOnError(errorContext) : options.throwOnError;
|
|
749
|
+
return callApi2(initURL, updatedOptions);
|
|
750
|
+
};
|
|
743
751
|
const handleThrowOnError = () => {
|
|
744
752
|
if (!shouldThrowOnError) return;
|
|
745
753
|
throw apiDetails.error;
|
|
@@ -750,18 +758,21 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
750
758
|
options.onError(errorContext),
|
|
751
759
|
options.onResponse({ ...errorContext, data: null })
|
|
752
760
|
);
|
|
761
|
+
await handleRetry();
|
|
753
762
|
handleThrowOnError();
|
|
754
763
|
return getErrorResult();
|
|
755
764
|
}
|
|
756
765
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
757
766
|
const { message, name } = error;
|
|
758
767
|
console.error(`${name}:`, message);
|
|
768
|
+
await handleRetry();
|
|
759
769
|
handleThrowOnError();
|
|
760
770
|
return getErrorResult();
|
|
761
771
|
}
|
|
762
772
|
if (error instanceof DOMException && error.name === "TimeoutError") {
|
|
763
773
|
const message = `Request timed out after ${options.timeout}ms`;
|
|
764
774
|
console.error(`${error.name}:`, message);
|
|
775
|
+
await handleRetry();
|
|
765
776
|
handleThrowOnError();
|
|
766
777
|
return getErrorResult({ message });
|
|
767
778
|
}
|
|
@@ -771,6 +782,7 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
771
782
|
// == Also call the onError interceptor
|
|
772
783
|
options.onError(errorContext)
|
|
773
784
|
);
|
|
785
|
+
await handleRetry();
|
|
774
786
|
handleThrowOnError();
|
|
775
787
|
return getErrorResult();
|
|
776
788
|
} finally {
|