@zayne-labs/callapi 1.6.16 → 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-BokQ-iQX.d.cts → error-DH3yCjyX.d.cts} +89 -87
- package/dist/cjs/index.cjs +53 -38
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +6 -114
- 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-JG2BPHMX.js → chunk-KLMWU6K5.js} +19 -3
- package/dist/esm/chunk-KLMWU6K5.js.map +1 -0
- package/dist/esm/{error-BokQ-iQX.d.ts → error-DH3yCjyX.d.ts} +89 -87
- package/dist/esm/index.d.ts +6 -114
- package/dist/esm/index.js +40 -43
- 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-JG2BPHMX.js.map +0 -1
|
@@ -115,77 +115,25 @@ interface CallApiValidators<TData = unknown, TErrorData = unknown> {
|
|
|
115
115
|
}
|
|
116
116
|
type InferSchemaResult<TSchema, TData> = TSchema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<TSchema> : TData;
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
type JsonPrimitive = boolean | number | string | null | undefined;
|
|
123
|
-
type SerializableObject = Record<keyof object, unknown>;
|
|
124
|
-
type SerializableArray = Array<JsonPrimitive | SerializableArray | SerializableObject> | ReadonlyArray<JsonPrimitive | SerializableArray | SerializableObject>;
|
|
125
|
-
type Body = UnmaskType<RequestInit["body"] | SerializableArray | SerializableObject>;
|
|
126
|
-
type BodyOption<TSchemas extends CallApiSchemas> = MakeSchemaOptionRequired<TSchemas["body"], {
|
|
118
|
+
type Params = UnmaskType<Record<string, boolean | number | string> | Array<boolean | number | string>>;
|
|
119
|
+
type Query = UnmaskType<Record<string, boolean | number | string>>;
|
|
120
|
+
type InitURL = UnmaskType<string | URL>;
|
|
121
|
+
interface UrlOptions<TSchemas extends CallApiSchemas> {
|
|
127
122
|
/**
|
|
128
|
-
*
|
|
123
|
+
* URL to be used in the request.
|
|
129
124
|
*/
|
|
130
|
-
|
|
131
|
-
}>;
|
|
132
|
-
type Method = UnmaskType<"CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE" | AnyString>;
|
|
133
|
-
type MethodOption<TSchemas extends CallApiSchemas> = MakeSchemaOptionRequired<TSchemas["method"], {
|
|
125
|
+
readonly initURL?: string;
|
|
134
126
|
/**
|
|
135
|
-
*
|
|
136
|
-
* @default "GET"
|
|
127
|
+
* Parameters to be appended to the URL (i.e: /:id)
|
|
137
128
|
*/
|
|
138
|
-
|
|
139
|
-
}>;
|
|
140
|
-
type Headers = UnmaskType<Record<"Authorization", CommonAuthorizationHeaders> | Record<"Content-Type", CommonContentTypes> | Record<CommonRequestHeaders, string | undefined> | Record<string, string | undefined> | RequestInit["headers"]>;
|
|
141
|
-
type HeadersOption<TSchemas extends CallApiSchemas> = MakeSchemaOptionRequired<TSchemas["headers"], {
|
|
129
|
+
params?: InferSchemaResult<TSchemas["params"], Params>;
|
|
142
130
|
/**
|
|
143
|
-
*
|
|
131
|
+
* Query parameters to append to the URL.
|
|
144
132
|
*/
|
|
145
|
-
|
|
146
|
-
}>;
|
|
147
|
-
interface Register {
|
|
133
|
+
query?: InferSchemaResult<TSchemas["query"], Query>;
|
|
148
134
|
}
|
|
149
|
-
type GlobalMeta = Register extends {
|
|
150
|
-
meta?: infer TMeta extends Record<string, unknown>;
|
|
151
|
-
} ? TMeta : never;
|
|
152
|
-
type MetaOption<TSchemas extends CallApiSchemas> = {
|
|
153
|
-
/**
|
|
154
|
-
* - An optional field you can fill with additional information,
|
|
155
|
-
* to associate with the request, typically used for logging or tracing.
|
|
156
|
-
*
|
|
157
|
-
* - A good use case for this, would be to use the info to handle specific cases in any of the shared interceptors.
|
|
158
|
-
*
|
|
159
|
-
* @example
|
|
160
|
-
* ```ts
|
|
161
|
-
* const callMainApi = callApi.create({
|
|
162
|
-
* baseURL: "https://main-api.com",
|
|
163
|
-
* onResponseError: ({ response, options }) => {
|
|
164
|
-
* if (options.meta?.userId) {
|
|
165
|
-
* console.error(`User ${options.meta.userId} made an error`);
|
|
166
|
-
* }
|
|
167
|
-
* },
|
|
168
|
-
* });
|
|
169
|
-
*
|
|
170
|
-
* const response = await callMainApi({
|
|
171
|
-
* url: "https://example.com/api/data",
|
|
172
|
-
* meta: { userId: "123" },
|
|
173
|
-
* });
|
|
174
|
-
* ```
|
|
175
|
-
*/
|
|
176
|
-
meta?: InferSchemaResult<TSchemas["meta"], GlobalMeta>;
|
|
177
|
-
};
|
|
178
|
-
type ResultModeOption<TErrorData, TResultMode extends ResultModeUnion> = TErrorData extends false ? {
|
|
179
|
-
resultMode: "onlySuccessWithException";
|
|
180
|
-
} : TErrorData extends false | undefined ? {
|
|
181
|
-
resultMode?: "onlySuccessWithException";
|
|
182
|
-
} : undefined extends TResultMode ? {
|
|
183
|
-
resultMode?: TResultMode;
|
|
184
|
-
} : {
|
|
185
|
-
resultMode: TResultMode;
|
|
186
|
-
};
|
|
187
135
|
|
|
188
|
-
type RetryCondition<TErrorData> = (context: ErrorContext<TErrorData>) =>
|
|
136
|
+
type RetryCondition<TErrorData> = (context: ErrorContext<TErrorData>) => Awaitable<boolean>;
|
|
189
137
|
interface RetryOptions<TErrorData> {
|
|
190
138
|
/**
|
|
191
139
|
* Keeps track of the number of times the request has already been retried
|
|
@@ -215,12 +163,12 @@ interface RetryOptions<TErrorData> {
|
|
|
215
163
|
* HTTP methods that are allowed to retry
|
|
216
164
|
* @default ["GET", "POST"]
|
|
217
165
|
*/
|
|
218
|
-
retryMethods?: Method[];
|
|
166
|
+
retryMethods?: Method[] | ((context: ErrorContext<TErrorData>) => Method[]);
|
|
219
167
|
/**
|
|
220
168
|
* HTTP status codes that trigger a retry
|
|
221
169
|
* @default [409, 425, 429, 500, 502, 503, 504]
|
|
222
170
|
*/
|
|
223
|
-
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>);
|
|
224
172
|
/**
|
|
225
173
|
* Strategy to use when retrying
|
|
226
174
|
* @default "linear"
|
|
@@ -255,6 +203,7 @@ type InferPluginOptions<TPluginArray extends CallApiPlugin[]> = UnionToIntersect
|
|
|
255
203
|
type PluginInitContext<TMoreOptions = DefaultMoreOptions> = WithMoreOptions<TMoreOptions> & {
|
|
256
204
|
baseConfig: BaseCallApiExtraOptions & CallApiRequestOptions;
|
|
257
205
|
config: CallApiExtraOptions & CallApiRequestOptions;
|
|
206
|
+
defaultOptions: CallApiExtraOptions;
|
|
258
207
|
initURL: InitURL | undefined;
|
|
259
208
|
options: CombinedCallApiExtraOptions;
|
|
260
209
|
request: CallApiRequestOptionsForHooks;
|
|
@@ -296,8 +245,76 @@ declare const definePlugin: <TPlugin extends CallApiPlugin | AnyFunction<CallApi
|
|
|
296
245
|
type Plugins<TPluginArray extends CallApiPlugin[]> = TPluginArray;
|
|
297
246
|
|
|
298
247
|
declare const fetchSpecificKeys: ("body" | "cache" | "credentials" | "headers" | "integrity" | "keepalive" | "method" | "mode" | "priority" | "redirect" | "referrer" | "referrerPolicy" | "signal" | "window")[];
|
|
299
|
-
|
|
300
|
-
|
|
248
|
+
|
|
249
|
+
/**
|
|
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
|
|
251
|
+
*/
|
|
252
|
+
type MakeSchemaOptionRequired<TSchema extends StandardSchemaV1 | undefined, TObject> = undefined extends TSchema ? TObject : undefined extends InferSchemaResult<TSchema, NonNullable<unknown>> ? TObject : Required<TObject>;
|
|
253
|
+
type JsonPrimitive = boolean | number | string | null | undefined;
|
|
254
|
+
type SerializableObject = Record<keyof object, unknown>;
|
|
255
|
+
type SerializableArray = Array<JsonPrimitive | SerializableArray | SerializableObject> | ReadonlyArray<JsonPrimitive | SerializableArray | SerializableObject>;
|
|
256
|
+
type Body = UnmaskType<RequestInit["body"] | SerializableArray | SerializableObject>;
|
|
257
|
+
type BodyOption<TSchemas extends CallApiSchemas> = MakeSchemaOptionRequired<TSchemas["body"], {
|
|
258
|
+
/**
|
|
259
|
+
* Body of the request, can be a object or any other supported body type.
|
|
260
|
+
*/
|
|
261
|
+
body?: InferSchemaResult<TSchemas["body"], Body>;
|
|
262
|
+
}>;
|
|
263
|
+
type Method = UnmaskType<"CONNECT" | "DELETE" | "GET" | "HEAD" | "OPTIONS" | "PATCH" | "POST" | "PUT" | "TRACE" | AnyString>;
|
|
264
|
+
type MethodOption<TSchemas extends CallApiSchemas> = MakeSchemaOptionRequired<TSchemas["method"], {
|
|
265
|
+
/**
|
|
266
|
+
* HTTP method for the request.
|
|
267
|
+
* @default "GET"
|
|
268
|
+
*/
|
|
269
|
+
method?: InferSchemaResult<TSchemas["method"], Method>;
|
|
270
|
+
}>;
|
|
271
|
+
type Headers = UnmaskType<Record<"Authorization", CommonAuthorizationHeaders> | Record<"Content-Type", CommonContentTypes> | Record<CommonRequestHeaders, string | undefined> | Record<string, string | undefined> | RequestInit["headers"]>;
|
|
272
|
+
type HeadersOption<TSchemas extends CallApiSchemas> = MakeSchemaOptionRequired<TSchemas["headers"], {
|
|
273
|
+
/**
|
|
274
|
+
* Headers to be used in the request.
|
|
275
|
+
*/
|
|
276
|
+
headers?: InferSchemaResult<TSchemas["headers"], Headers>;
|
|
277
|
+
}>;
|
|
278
|
+
interface Register {
|
|
279
|
+
}
|
|
280
|
+
type GlobalMeta = Register extends {
|
|
281
|
+
meta?: infer TMeta extends Record<string, unknown>;
|
|
282
|
+
} ? TMeta : never;
|
|
283
|
+
type MetaOption<TSchemas extends CallApiSchemas> = {
|
|
284
|
+
/**
|
|
285
|
+
* - An optional field you can fill with additional information,
|
|
286
|
+
* to associate with the request, typically used for logging or tracing.
|
|
287
|
+
*
|
|
288
|
+
* - A good use case for this, would be to use the info to handle specific cases in any of the shared interceptors.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* ```ts
|
|
292
|
+
* const callMainApi = callApi.create({
|
|
293
|
+
* baseURL: "https://main-api.com",
|
|
294
|
+
* onResponseError: ({ response, options }) => {
|
|
295
|
+
* if (options.meta?.userId) {
|
|
296
|
+
* console.error(`User ${options.meta.userId} made an error`);
|
|
297
|
+
* }
|
|
298
|
+
* },
|
|
299
|
+
* });
|
|
300
|
+
*
|
|
301
|
+
* const response = await callMainApi({
|
|
302
|
+
* url: "https://example.com/api/data",
|
|
303
|
+
* meta: { userId: "123" },
|
|
304
|
+
* });
|
|
305
|
+
* ```
|
|
306
|
+
*/
|
|
307
|
+
meta?: InferSchemaResult<TSchemas["meta"], GlobalMeta>;
|
|
308
|
+
};
|
|
309
|
+
type ResultModeOption<TErrorData, TResultMode extends ResultModeUnion> = TErrorData extends false ? {
|
|
310
|
+
resultMode: "onlySuccessWithException";
|
|
311
|
+
} : TErrorData extends false | undefined ? {
|
|
312
|
+
resultMode?: "onlySuccessWithException";
|
|
313
|
+
} : undefined extends TResultMode ? {
|
|
314
|
+
resultMode?: TResultMode;
|
|
315
|
+
} : {
|
|
316
|
+
resultMode: TResultMode;
|
|
317
|
+
};
|
|
301
318
|
|
|
302
319
|
type FetchSpecificKeysUnion = Exclude<(typeof fetchSpecificKeys)[number], "body" | "headers" | "method">;
|
|
303
320
|
type CallApiRequestOptions<TSchemas extends CallApiSchemas = DefaultMoreOptions> = BodyOption<TSchemas> & HeadersOption<TSchemas> & MethodOption<TSchemas> & Pick<RequestInit, FetchSpecificKeysUnion>;
|
|
@@ -448,13 +465,15 @@ declare const optionsEnumToOmitFromBase: ("dedupeKey" | "extend")[];
|
|
|
448
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]>;
|
|
449
466
|
type CombinedCallApiExtraOptions = BaseCallApiExtraOptions & CallApiExtraOptions;
|
|
450
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;
|
|
451
469
|
initURL: string;
|
|
452
470
|
options: CallApiExtraOptions;
|
|
453
471
|
request: CallApiRequestOptions;
|
|
454
472
|
}) => CallApiRequestOptions<TBaseSchemas> & BaseCallApiExtraOptions<TBaseData, TBaseErrorData, TBaseResultMode, TBaseThrowOnError, TBaseResponseType, TBasePluginArray, TBaseSchemas>);
|
|
473
|
+
type CallApiConfig<TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeUnion = ResultModeUnion, TThrowOnError extends boolean = DefaultThrowOnError, TResponseType extends ResponseTypeUnion = ResponseTypeUnion, TPluginArray extends CallApiPlugin[] = DefaultPluginArray, TSchemas extends CallApiSchemas = DefaultMoreOptions> = CallApiRequestOptions<TSchemas> & CallApiExtraOptions<TData, TErrorData, TResultMode, TThrowOnError, TResponseType, TPluginArray, TSchemas>;
|
|
455
474
|
type CallApiParameters<TData = DefaultDataType, TErrorData = DefaultDataType, TResultMode extends ResultModeUnion = ResultModeUnion, TThrowOnError extends boolean = DefaultThrowOnError, TResponseType extends ResponseTypeUnion = ResponseTypeUnion, TPluginArray extends CallApiPlugin[] = DefaultPluginArray, TSchemas extends CallApiSchemas = DefaultMoreOptions> = [
|
|
456
475
|
initURL: InferSchemaResult<TSchemas["initURL"], InitURL>,
|
|
457
|
-
config?:
|
|
476
|
+
config?: CallApiConfig<TData, TErrorData, TResultMode, TThrowOnError, TResponseType, TPluginArray, TSchemas>
|
|
458
477
|
];
|
|
459
478
|
type RequestContext = UnmaskType<{
|
|
460
479
|
options: CombinedCallApiExtraOptions;
|
|
@@ -539,24 +558,7 @@ type ResultModeMap<TData = DefaultDataType, TErrorData = DefaultDataType, TRespo
|
|
|
539
558
|
}>;
|
|
540
559
|
type ResultModeUnion = keyof ResultModeMap | undefined;
|
|
541
560
|
type GetCallApiResult<TData, TErrorData, TResultMode extends ResultModeUnion, TThrowOnError extends boolean, TResponseType extends ResponseTypeUnion> = TErrorData extends false | undefined ? ResultModeMap<TData, TErrorData, TResponseType>["onlySuccessWithException"] : ResultModeUnion | undefined extends TResultMode ? TThrowOnError extends true ? ResultModeMap<TData, TErrorData, TResponseType>["allWithException"] : ResultModeMap<TData, TErrorData, TResponseType>["all"] : TResultMode extends NonNullable<ResultModeUnion> ? TResultMode extends "onlySuccess" ? ResultModeMap<TData, TErrorData, TResponseType>["onlySuccessWithException"] : TResultMode extends "onlyResponse" ? ResultModeMap<TData, TErrorData, TResponseType>["onlyResponseWithException"] : ResultModeMap<TData, TErrorData, TResponseType>[TResultMode] : never;
|
|
542
|
-
|
|
543
|
-
type Params = UnmaskType<Record<string, boolean | number | string> | Array<boolean | number | string>>;
|
|
544
|
-
type Query = UnmaskType<Record<string, boolean | number | string>>;
|
|
545
|
-
type InitURL = UnmaskType<string | URL>;
|
|
546
|
-
interface UrlOptions<TSchemas extends CallApiSchemas> {
|
|
547
|
-
/**
|
|
548
|
-
* URL to be used in the request.
|
|
549
|
-
*/
|
|
550
|
-
readonly initURL?: string;
|
|
551
|
-
/**
|
|
552
|
-
* Parameters to be appended to the URL (i.e: /:id)
|
|
553
|
-
*/
|
|
554
|
-
params?: InferSchemaResult<TSchemas["params"], Params>;
|
|
555
|
-
/**
|
|
556
|
-
* Query parameters to append to the URL.
|
|
557
|
-
*/
|
|
558
|
-
query?: InferSchemaResult<TSchemas["query"], Query>;
|
|
559
|
-
}
|
|
561
|
+
type CallApiResult<TData, TErrorData, TResultMode extends ResultModeUnion, TThrowOnError extends boolean, TResponseType extends ResponseTypeUnion> = Promise<GetCallApiResult<TData, TErrorData, TResultMode, TThrowOnError, TResponseType>>;
|
|
560
562
|
|
|
561
563
|
type ErrorDetails<TErrorResponse> = {
|
|
562
564
|
defaultErrorMessage: string;
|
|
@@ -574,4 +576,4 @@ declare class HTTPError<TErrorResponse = Record<string, unknown>> extends Error
|
|
|
574
576
|
constructor(errorDetails: ErrorDetails<TErrorResponse>, errorOptions?: ErrorOptions);
|
|
575
577
|
}
|
|
576
578
|
|
|
577
|
-
export { type
|
|
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 = {
|
|
@@ -666,7 +677,6 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
666
677
|
await executeHooks(options.onRequest({ options, request }));
|
|
667
678
|
request.headers = mergeAndResolveHeaders({
|
|
668
679
|
auth: options.auth,
|
|
669
|
-
baseHeaders: baseFetchOptions.headers,
|
|
670
680
|
body: request.body,
|
|
671
681
|
headers: request.headers
|
|
672
682
|
});
|
|
@@ -724,9 +734,11 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
724
734
|
request,
|
|
725
735
|
response: apiDetails.response
|
|
726
736
|
};
|
|
727
|
-
const
|
|
728
|
-
const
|
|
729
|
-
|
|
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;
|
|
730
742
|
await executeHooks(options.onRetry(errorContext));
|
|
731
743
|
const delay = getDelay();
|
|
732
744
|
await waitUntil(delay);
|
|
@@ -734,9 +746,8 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
734
746
|
...config,
|
|
735
747
|
"~retryCount": (options["~retryCount"] ?? 0) + 1
|
|
736
748
|
};
|
|
737
|
-
return
|
|
738
|
-
}
|
|
739
|
-
const shouldThrowOnError = isFunction(options.throwOnError) ? options.throwOnError(errorContext) : options.throwOnError;
|
|
749
|
+
return callApi2(initURL, updatedOptions);
|
|
750
|
+
};
|
|
740
751
|
const handleThrowOnError = () => {
|
|
741
752
|
if (!shouldThrowOnError) return;
|
|
742
753
|
throw apiDetails.error;
|
|
@@ -747,18 +758,21 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
747
758
|
options.onError(errorContext),
|
|
748
759
|
options.onResponse({ ...errorContext, data: null })
|
|
749
760
|
);
|
|
761
|
+
await handleRetry();
|
|
750
762
|
handleThrowOnError();
|
|
751
763
|
return getErrorResult();
|
|
752
764
|
}
|
|
753
765
|
if (error instanceof DOMException && error.name === "AbortError") {
|
|
754
766
|
const { message, name } = error;
|
|
755
767
|
console.error(`${name}:`, message);
|
|
768
|
+
await handleRetry();
|
|
756
769
|
handleThrowOnError();
|
|
757
770
|
return getErrorResult();
|
|
758
771
|
}
|
|
759
772
|
if (error instanceof DOMException && error.name === "TimeoutError") {
|
|
760
773
|
const message = `Request timed out after ${options.timeout}ms`;
|
|
761
774
|
console.error(`${error.name}:`, message);
|
|
775
|
+
await handleRetry();
|
|
762
776
|
handleThrowOnError();
|
|
763
777
|
return getErrorResult({ message });
|
|
764
778
|
}
|
|
@@ -768,6 +782,7 @@ var createFetchClient = (baseConfig = {}) => {
|
|
|
768
782
|
// == Also call the onError interceptor
|
|
769
783
|
options.onError(errorContext)
|
|
770
784
|
);
|
|
785
|
+
await handleRetry();
|
|
771
786
|
handleThrowOnError();
|
|
772
787
|
return getErrorResult();
|
|
773
788
|
} finally {
|