@fetchkit/ffetch 5.0.1 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +182 -39
- package/dist/index.cjs +223 -212
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -48
- package/dist/index.d.ts +9 -48
- package/dist/index.js +225 -214
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/plugins/circuit.d.cts +1 -1
- package/dist/plugins/circuit.d.ts +1 -1
- package/dist/plugins/dedupe.d.cts +1 -1
- package/dist/plugins/dedupe.d.ts +1 -1
- package/dist/plugins/request-shortcuts.cjs +76 -0
- package/dist/plugins/request-shortcuts.cjs.map +1 -0
- package/dist/plugins/request-shortcuts.d.cts +16 -0
- package/dist/plugins/request-shortcuts.d.ts +16 -0
- package/dist/plugins/request-shortcuts.js +51 -0
- package/dist/plugins/request-shortcuts.js.map +1 -0
- package/dist/plugins/response-shortcuts.cjs +91 -0
- package/dist/plugins/response-shortcuts.cjs.map +1 -0
- package/dist/plugins/response-shortcuts.d.cts +12 -0
- package/dist/plugins/response-shortcuts.d.ts +12 -0
- package/dist/plugins/response-shortcuts.js +66 -0
- package/dist/plugins/response-shortcuts.js.map +1 -0
- package/dist/{plugins-9qcU31nU.d.cts → plugins-DqBQVM4I.d.cts} +6 -2
- package/dist/{plugins-9qcU31nU.d.ts → plugins-DqBQVM4I.d.ts} +6 -2
- package/dist/types-DbmivXba.d.cts +48 -0
- package/dist/types-DpHoyvhy.d.ts +48 -0
- package/package.json +11 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,51 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { F as FFetchOptions, a as FFetch } from './types-DbmivXba.cjs';
|
|
2
|
+
export { H as Hooks } from './types-DbmivXba.cjs';
|
|
3
|
+
import { C as ClientPlugin, P as PluginExtensionBase, a as PluginRequestPromiseExtensionBase, b as PluginExtensions, c as PluginRequestPromiseExtensions } from './plugins-DqBQVM4I.cjs';
|
|
4
|
+
export { e as PluginDispatch, d as PluginRequestContext, f as PluginSetupContext } from './plugins-DqBQVM4I.cjs';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
before?: (req: Request) => void | Promise<void>;
|
|
6
|
-
after?: (req: Request, res: Response) => void | Promise<void>;
|
|
7
|
-
onError?: (req: Request, err: unknown) => void | Promise<void>;
|
|
8
|
-
onRetry?: (req: Request, attempt: number, err?: unknown, res?: Response) => void | Promise<void>;
|
|
9
|
-
onTimeout?: (req: Request) => void | Promise<void>;
|
|
10
|
-
onAbort?: (req: Request) => void | Promise<void>;
|
|
11
|
-
onComplete?: (req: Request, res?: Response, err?: unknown) => void | Promise<void>;
|
|
12
|
-
transformRequest?: (req: Request) => Request | Promise<Request>;
|
|
13
|
-
transformResponse?: (res: Response, req: Request) => Response | Promise<Response>;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
interface RetryContext {
|
|
17
|
-
attempt: number;
|
|
18
|
-
request: Request;
|
|
19
|
-
response?: Response;
|
|
20
|
-
error?: unknown;
|
|
21
|
-
}
|
|
22
|
-
interface CoreClientOptions {
|
|
23
|
-
timeout?: number;
|
|
24
|
-
retries?: number;
|
|
25
|
-
retryDelay?: number | ((ctx: RetryContext) => number);
|
|
26
|
-
shouldRetry?: (ctx: RetryContext) => boolean;
|
|
27
|
-
throwOnHttpError?: boolean;
|
|
28
|
-
hooks?: Hooks;
|
|
29
|
-
fetchHandler?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
30
|
-
}
|
|
31
|
-
interface FFetchOptions<TPlugins extends readonly ClientPlugin<PluginExtensionBase>[] = readonly ClientPlugin<PluginExtensionBase>[]> extends CoreClientOptions {
|
|
32
|
-
plugins?: TPlugins;
|
|
33
|
-
}
|
|
34
|
-
type FFetchRequestOptions = CoreClientOptions;
|
|
35
|
-
type FFetch<TExtensions extends object = Record<never, never>> = {
|
|
36
|
-
(input: RequestInfo | URL, init?: FFetchRequestInit): Promise<Response>;
|
|
37
|
-
pendingRequests: PendingRequest[];
|
|
38
|
-
abortAll: () => void;
|
|
39
|
-
} & TExtensions;
|
|
40
|
-
interface FFetchRequestInit extends RequestInit, FFetchRequestOptions {
|
|
41
|
-
}
|
|
42
|
-
type PendingRequest = {
|
|
43
|
-
promise: Promise<Response>;
|
|
44
|
-
request: Request;
|
|
45
|
-
controller?: AbortController;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
declare function createClient<TPlugins extends readonly ClientPlugin<PluginExtensionBase>[] = readonly ClientPlugin<PluginExtensionBase>[]>(opts?: FFetchOptions<TPlugins>): FFetch<PluginExtensions<TPlugins>>;
|
|
6
|
+
declare function createClient<TPlugins extends readonly ClientPlugin<PluginExtensionBase, PluginRequestPromiseExtensionBase>[] = readonly ClientPlugin<PluginExtensionBase, PluginRequestPromiseExtensionBase>[]>(opts?: FFetchOptions<TPlugins>): FFetch<PluginExtensions<TPlugins>, PluginRequestPromiseExtensions<TPlugins>>;
|
|
49
7
|
|
|
50
8
|
declare class BaseError extends Error {
|
|
51
9
|
cause?: unknown;
|
|
@@ -66,5 +24,8 @@ declare class RetryLimitError extends BaseError {
|
|
|
66
24
|
declare class NetworkError extends BaseError {
|
|
67
25
|
constructor(message?: string, cause?: unknown);
|
|
68
26
|
}
|
|
27
|
+
declare class HttpError extends BaseError {
|
|
28
|
+
constructor(message?: string, cause?: unknown);
|
|
29
|
+
}
|
|
69
30
|
|
|
70
|
-
export { AbortError, CircuitOpenError, ClientPlugin,
|
|
31
|
+
export { AbortError, CircuitOpenError, ClientPlugin, FFetch, FFetchOptions, HttpError, NetworkError, RetryLimitError, TimeoutError, createClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,51 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export {
|
|
1
|
+
import { F as FFetchOptions, a as FFetch } from './types-DpHoyvhy.js';
|
|
2
|
+
export { H as Hooks } from './types-DpHoyvhy.js';
|
|
3
|
+
import { C as ClientPlugin, P as PluginExtensionBase, a as PluginRequestPromiseExtensionBase, b as PluginExtensions, c as PluginRequestPromiseExtensions } from './plugins-DqBQVM4I.js';
|
|
4
|
+
export { e as PluginDispatch, d as PluginRequestContext, f as PluginSetupContext } from './plugins-DqBQVM4I.js';
|
|
3
5
|
|
|
4
|
-
|
|
5
|
-
before?: (req: Request) => void | Promise<void>;
|
|
6
|
-
after?: (req: Request, res: Response) => void | Promise<void>;
|
|
7
|
-
onError?: (req: Request, err: unknown) => void | Promise<void>;
|
|
8
|
-
onRetry?: (req: Request, attempt: number, err?: unknown, res?: Response) => void | Promise<void>;
|
|
9
|
-
onTimeout?: (req: Request) => void | Promise<void>;
|
|
10
|
-
onAbort?: (req: Request) => void | Promise<void>;
|
|
11
|
-
onComplete?: (req: Request, res?: Response, err?: unknown) => void | Promise<void>;
|
|
12
|
-
transformRequest?: (req: Request) => Request | Promise<Request>;
|
|
13
|
-
transformResponse?: (res: Response, req: Request) => Response | Promise<Response>;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
interface RetryContext {
|
|
17
|
-
attempt: number;
|
|
18
|
-
request: Request;
|
|
19
|
-
response?: Response;
|
|
20
|
-
error?: unknown;
|
|
21
|
-
}
|
|
22
|
-
interface CoreClientOptions {
|
|
23
|
-
timeout?: number;
|
|
24
|
-
retries?: number;
|
|
25
|
-
retryDelay?: number | ((ctx: RetryContext) => number);
|
|
26
|
-
shouldRetry?: (ctx: RetryContext) => boolean;
|
|
27
|
-
throwOnHttpError?: boolean;
|
|
28
|
-
hooks?: Hooks;
|
|
29
|
-
fetchHandler?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
30
|
-
}
|
|
31
|
-
interface FFetchOptions<TPlugins extends readonly ClientPlugin<PluginExtensionBase>[] = readonly ClientPlugin<PluginExtensionBase>[]> extends CoreClientOptions {
|
|
32
|
-
plugins?: TPlugins;
|
|
33
|
-
}
|
|
34
|
-
type FFetchRequestOptions = CoreClientOptions;
|
|
35
|
-
type FFetch<TExtensions extends object = Record<never, never>> = {
|
|
36
|
-
(input: RequestInfo | URL, init?: FFetchRequestInit): Promise<Response>;
|
|
37
|
-
pendingRequests: PendingRequest[];
|
|
38
|
-
abortAll: () => void;
|
|
39
|
-
} & TExtensions;
|
|
40
|
-
interface FFetchRequestInit extends RequestInit, FFetchRequestOptions {
|
|
41
|
-
}
|
|
42
|
-
type PendingRequest = {
|
|
43
|
-
promise: Promise<Response>;
|
|
44
|
-
request: Request;
|
|
45
|
-
controller?: AbortController;
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
declare function createClient<TPlugins extends readonly ClientPlugin<PluginExtensionBase>[] = readonly ClientPlugin<PluginExtensionBase>[]>(opts?: FFetchOptions<TPlugins>): FFetch<PluginExtensions<TPlugins>>;
|
|
6
|
+
declare function createClient<TPlugins extends readonly ClientPlugin<PluginExtensionBase, PluginRequestPromiseExtensionBase>[] = readonly ClientPlugin<PluginExtensionBase, PluginRequestPromiseExtensionBase>[]>(opts?: FFetchOptions<TPlugins>): FFetch<PluginExtensions<TPlugins>, PluginRequestPromiseExtensions<TPlugins>>;
|
|
49
7
|
|
|
50
8
|
declare class BaseError extends Error {
|
|
51
9
|
cause?: unknown;
|
|
@@ -66,5 +24,8 @@ declare class RetryLimitError extends BaseError {
|
|
|
66
24
|
declare class NetworkError extends BaseError {
|
|
67
25
|
constructor(message?: string, cause?: unknown);
|
|
68
26
|
}
|
|
27
|
+
declare class HttpError extends BaseError {
|
|
28
|
+
constructor(message?: string, cause?: unknown);
|
|
29
|
+
}
|
|
69
30
|
|
|
70
|
-
export { AbortError, CircuitOpenError, ClientPlugin,
|
|
31
|
+
export { AbortError, CircuitOpenError, ClientPlugin, FFetch, FFetchOptions, HttpError, NetworkError, RetryLimitError, TimeoutError, createClient };
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AbortError,
|
|
3
3
|
CircuitOpenError,
|
|
4
|
+
HttpError,
|
|
4
5
|
NetworkError,
|
|
5
6
|
RetryLimitError,
|
|
6
7
|
TimeoutError
|
|
@@ -129,251 +130,260 @@ function createClient(opts = {}) {
|
|
|
129
130
|
entry.controller?.abort();
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
|
-
const client =
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
await effectiveHooks.before?.(request);
|
|
139
|
-
const effectiveRetries = init.retries ?? clientDefaultRetries;
|
|
140
|
-
const effectiveRetryDelay = typeof init.retryDelay !== "undefined" ? init.retryDelay : clientDefaultRetryDelay;
|
|
141
|
-
const effectiveShouldRetry = init.shouldRetry ?? clientDefaultShouldRetry;
|
|
142
|
-
const effectiveTimeout = init.timeout ?? clientDefaultTimeout;
|
|
143
|
-
const userSignal = init.signal;
|
|
144
|
-
const transformedSignal = request.signal;
|
|
145
|
-
const pluginContext = {
|
|
146
|
-
request,
|
|
147
|
-
init,
|
|
148
|
-
state: /* @__PURE__ */ Object.create(null),
|
|
149
|
-
metadata: {
|
|
150
|
-
startedAt: Date.now(),
|
|
151
|
-
timeoutMs: effectiveTimeout,
|
|
152
|
-
signals: {
|
|
153
|
-
user: userSignal === void 0 || userSignal === null ? void 0 : userSignal,
|
|
154
|
-
transformed: transformedSignal
|
|
155
|
-
},
|
|
156
|
-
retry: {
|
|
157
|
-
configuredRetries: effectiveRetries,
|
|
158
|
-
configuredDelay: effectiveRetryDelay,
|
|
159
|
-
attempt: 0
|
|
160
|
-
}
|
|
133
|
+
const client = (input, init = {}) => {
|
|
134
|
+
const execute = async () => {
|
|
135
|
+
let request = new Request(input, init);
|
|
136
|
+
const effectiveHooks = { ...clientDefaultHooks, ...init.hooks || {} };
|
|
137
|
+
if (effectiveHooks.transformRequest) {
|
|
138
|
+
request = await effectiveHooks.transformRequest(request);
|
|
161
139
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
140
|
+
await effectiveHooks.before?.(request);
|
|
141
|
+
const effectiveRetries = init.retries ?? clientDefaultRetries;
|
|
142
|
+
const effectiveRetryDelay = typeof init.retryDelay !== "undefined" ? init.retryDelay : clientDefaultRetryDelay;
|
|
143
|
+
const effectiveShouldRetry = init.shouldRetry ?? clientDefaultShouldRetry;
|
|
144
|
+
const effectiveTimeout = init.timeout ?? clientDefaultTimeout;
|
|
145
|
+
const userSignal = init.signal;
|
|
146
|
+
const transformedSignal = request.signal;
|
|
147
|
+
const pluginContext = {
|
|
148
|
+
request,
|
|
149
|
+
init,
|
|
150
|
+
state: /* @__PURE__ */ Object.create(null),
|
|
151
|
+
metadata: {
|
|
152
|
+
startedAt: Date.now(),
|
|
153
|
+
timeoutMs: effectiveTimeout,
|
|
154
|
+
signals: {
|
|
155
|
+
user: userSignal === void 0 || userSignal === null ? void 0 : userSignal,
|
|
156
|
+
transformed: transformedSignal
|
|
157
|
+
},
|
|
158
|
+
retry: {
|
|
159
|
+
configuredRetries: effectiveRetries,
|
|
160
|
+
configuredDelay: effectiveRetryDelay,
|
|
161
|
+
attempt: 0
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
for (const plugin of plugins) {
|
|
166
|
+
await plugin.preRequest?.(pluginContext);
|
|
170
167
|
}
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
let controller = void 0;
|
|
183
|
-
if (effectiveTimeout > 0) {
|
|
184
|
-
timeoutSignal = createTimeoutSignal(effectiveTimeout);
|
|
185
|
-
pluginContext.metadata.signals.timeout = timeoutSignal;
|
|
186
|
-
}
|
|
187
|
-
const signals = [];
|
|
188
|
-
if (userSignal) signals.push(userSignal);
|
|
189
|
-
if (transformedSignal && transformedSignal !== userSignal) {
|
|
190
|
-
signals.push(transformedSignal);
|
|
191
|
-
}
|
|
192
|
-
if (timeoutSignal) signals.push(timeoutSignal);
|
|
193
|
-
if (signals.length === 1) {
|
|
194
|
-
combinedSignal = signals[0];
|
|
195
|
-
controller = new AbortController();
|
|
196
|
-
} else {
|
|
197
|
-
if (typeof AbortSignal.any !== "function") {
|
|
198
|
-
throw new Error(
|
|
199
|
-
"AbortSignal.any is required for combining multiple signals. Please install a polyfill for environments that do not support it."
|
|
168
|
+
const effectiveThrowOnHttpError = typeof init.throwOnHttpError !== "undefined" ? init.throwOnHttpError : opts.throwOnHttpError ?? false;
|
|
169
|
+
function createTimeoutSignal(timeout) {
|
|
170
|
+
if (typeof AbortSignal?.timeout === "function") {
|
|
171
|
+
return AbortSignal.timeout(timeout);
|
|
172
|
+
}
|
|
173
|
+
const controller2 = new AbortController();
|
|
174
|
+
const timeoutId = setTimeout(() => controller2.abort(), timeout);
|
|
175
|
+
controller2.signal.addEventListener(
|
|
176
|
+
"abort",
|
|
177
|
+
() => clearTimeout(timeoutId),
|
|
178
|
+
{ once: true }
|
|
200
179
|
);
|
|
180
|
+
return controller2.signal;
|
|
201
181
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
182
|
+
let timeoutSignal = void 0;
|
|
183
|
+
let combinedSignal = void 0;
|
|
184
|
+
let controller = void 0;
|
|
185
|
+
if (effectiveTimeout > 0) {
|
|
186
|
+
timeoutSignal = createTimeoutSignal(effectiveTimeout);
|
|
187
|
+
pluginContext.metadata.signals.timeout = timeoutSignal;
|
|
188
|
+
}
|
|
189
|
+
const signals = [];
|
|
190
|
+
if (userSignal) signals.push(userSignal);
|
|
191
|
+
if (transformedSignal && transformedSignal !== userSignal) {
|
|
192
|
+
signals.push(transformedSignal);
|
|
193
|
+
}
|
|
194
|
+
if (timeoutSignal) signals.push(timeoutSignal);
|
|
195
|
+
if (signals.length === 1) {
|
|
196
|
+
combinedSignal = signals[0];
|
|
197
|
+
controller = new AbortController();
|
|
198
|
+
} else {
|
|
199
|
+
if (typeof AbortSignal.any !== "function") {
|
|
200
|
+
throw new Error(
|
|
201
|
+
"AbortSignal.any is required for combining multiple signals. Please install a polyfill for environments that do not support it."
|
|
221
202
|
);
|
|
222
203
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
204
|
+
combinedSignal = AbortSignal.any(signals);
|
|
205
|
+
controller = new AbortController();
|
|
206
|
+
}
|
|
207
|
+
pluginContext.metadata.signals.combined = combinedSignal;
|
|
208
|
+
const retryWithHooks = async () => {
|
|
209
|
+
let attempt = 0;
|
|
210
|
+
const shouldRetryWithHook = (ctx) => {
|
|
211
|
+
attempt = ctx.attempt;
|
|
212
|
+
pluginContext.metadata.retry.attempt = attempt;
|
|
213
|
+
pluginContext.metadata.retry.lastError = ctx.error;
|
|
214
|
+
pluginContext.metadata.retry.lastResponse = ctx.response;
|
|
215
|
+
const retrying = effectiveShouldRetry(ctx);
|
|
216
|
+
pluginContext.metadata.retry.shouldRetryResult = retrying;
|
|
217
|
+
if (retrying && attempt <= effectiveRetries) {
|
|
218
|
+
effectiveHooks.onRetry?.(
|
|
219
|
+
request,
|
|
220
|
+
attempt - 1,
|
|
221
|
+
ctx.error,
|
|
222
|
+
ctx.response
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
return retrying;
|
|
226
|
+
};
|
|
227
|
+
let lastResponse = void 0;
|
|
228
|
+
try {
|
|
229
|
+
let res = await retry(
|
|
230
|
+
async () => {
|
|
240
231
|
if (userSignal?.aborted) {
|
|
241
232
|
effectiveHooks.onAbort?.(request);
|
|
242
233
|
throw new AbortError("Request was aborted by user");
|
|
243
|
-
}
|
|
234
|
+
}
|
|
235
|
+
if (timeoutSignal?.aborted) {
|
|
244
236
|
effectiveHooks.onTimeout?.(request);
|
|
245
237
|
throw new TimeoutError("signal timed out");
|
|
246
|
-
} else {
|
|
247
|
-
throw new AbortError(
|
|
248
|
-
"Request was aborted",
|
|
249
|
-
new DOMException("Aborted", "AbortError")
|
|
250
|
-
);
|
|
251
238
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
try {
|
|
257
|
-
const handler = init.fetchHandler ?? fetchHandler ?? fetch;
|
|
258
|
-
const response = await handler(reqWithSignal);
|
|
259
|
-
lastResponse = response;
|
|
260
|
-
pluginContext.metadata.retry.lastResponse = response;
|
|
261
|
-
return response;
|
|
262
|
-
} catch (err) {
|
|
263
|
-
pluginContext.metadata.retry.lastError = err;
|
|
264
|
-
if (err instanceof DOMException && err.name === "AbortError") {
|
|
265
|
-
if (timeoutSignal?.aborted && (!userSignal || !userSignal.aborted)) {
|
|
266
|
-
effectiveHooks.onTimeout?.(request);
|
|
267
|
-
throw new TimeoutError("signal timed out", err);
|
|
268
|
-
} else if (userSignal?.aborted) {
|
|
239
|
+
if (typeof combinedSignal?.throwIfAborted === "function") {
|
|
240
|
+
combinedSignal.throwIfAborted();
|
|
241
|
+
} else if (combinedSignal?.aborted) {
|
|
242
|
+
if (userSignal?.aborted) {
|
|
269
243
|
effectiveHooks.onAbort?.(request);
|
|
270
244
|
throw new AbortError("Request was aborted by user");
|
|
245
|
+
} else if (timeoutSignal?.aborted) {
|
|
246
|
+
effectiveHooks.onTimeout?.(request);
|
|
247
|
+
throw new TimeoutError("signal timed out");
|
|
271
248
|
} else {
|
|
272
249
|
throw new AbortError(
|
|
273
250
|
"Request was aborted",
|
|
274
251
|
new DOMException("Aborted", "AbortError")
|
|
275
252
|
);
|
|
276
253
|
}
|
|
277
|
-
} else if (err instanceof TypeError && /NetworkError|network error|failed to fetch|lost connection|NetworkError when attempting to fetch resource/i.test(
|
|
278
|
-
err.message
|
|
279
|
-
)) {
|
|
280
|
-
throw new NetworkError(err.message, err);
|
|
281
254
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
255
|
+
const reqWithSignal = new Request(request, {
|
|
256
|
+
signal: combinedSignal
|
|
257
|
+
});
|
|
258
|
+
try {
|
|
259
|
+
const handler = init.fetchHandler ?? fetchHandler ?? fetch;
|
|
260
|
+
const response = await handler(reqWithSignal);
|
|
261
|
+
lastResponse = response;
|
|
262
|
+
pluginContext.metadata.retry.lastResponse = response;
|
|
263
|
+
return response;
|
|
264
|
+
} catch (err) {
|
|
265
|
+
pluginContext.metadata.retry.lastError = err;
|
|
266
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
267
|
+
if (timeoutSignal?.aborted && (!userSignal || !userSignal.aborted)) {
|
|
268
|
+
effectiveHooks.onTimeout?.(request);
|
|
269
|
+
throw new TimeoutError("signal timed out", err);
|
|
270
|
+
} else if (userSignal?.aborted) {
|
|
271
|
+
effectiveHooks.onAbort?.(request);
|
|
272
|
+
throw new AbortError("Request was aborted by user");
|
|
273
|
+
} else {
|
|
274
|
+
throw new AbortError(
|
|
275
|
+
"Request was aborted",
|
|
276
|
+
new DOMException("Aborted", "AbortError")
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
} else if (err instanceof TypeError && /NetworkError|network error|failed to fetch|lost connection|NetworkError when attempting to fetch resource/i.test(
|
|
280
|
+
err.message
|
|
281
|
+
)) {
|
|
282
|
+
throw new NetworkError(err.message, err);
|
|
283
|
+
}
|
|
284
|
+
throw err;
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
effectiveRetries,
|
|
288
|
+
effectiveRetryDelay,
|
|
289
|
+
shouldRetryWithHook,
|
|
290
|
+
request,
|
|
291
|
+
combinedSignal
|
|
301
292
|
);
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
resp
|
|
293
|
+
if (effectiveHooks.transformResponse) {
|
|
294
|
+
res = await effectiveHooks.transformResponse(res, request);
|
|
295
|
+
}
|
|
296
|
+
await effectiveHooks.after?.(request, res);
|
|
297
|
+
await effectiveHooks.onComplete?.(request, res, void 0);
|
|
298
|
+
if (effectiveThrowOnHttpError && (res.status >= 400 && res.status < 500 && res.status !== 429 || res.status >= 500 || res.status === 429)) {
|
|
299
|
+
const { HttpError: HttpError2 } = await import("./error-XBHPSMAQ.js");
|
|
300
|
+
throw new HttpError2(
|
|
301
|
+
`HTTP error: ${res.status} ${res.statusText}`,
|
|
302
|
+
res
|
|
313
303
|
);
|
|
314
304
|
}
|
|
315
|
-
return
|
|
305
|
+
return res;
|
|
306
|
+
} catch (err) {
|
|
307
|
+
pluginContext.metadata.retry.lastError = err;
|
|
308
|
+
if (lastResponse) {
|
|
309
|
+
const resp = lastResponse;
|
|
310
|
+
if (effectiveThrowOnHttpError && (resp.status >= 400 && resp.status < 500 && resp.status !== 429 || resp.status >= 500 || resp.status === 429)) {
|
|
311
|
+
const { HttpError: HttpError2 } = await import("./error-XBHPSMAQ.js");
|
|
312
|
+
throw new HttpError2(
|
|
313
|
+
`HTTP error: ${resp.status} ${resp.statusText}`,
|
|
314
|
+
resp
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
return resp;
|
|
318
|
+
}
|
|
319
|
+
if (err instanceof TimeoutError) {
|
|
320
|
+
await effectiveHooks.onTimeout?.(request);
|
|
321
|
+
await effectiveHooks.onError?.(request, err);
|
|
322
|
+
await effectiveHooks.onComplete?.(request, void 0, err);
|
|
323
|
+
throw err;
|
|
324
|
+
}
|
|
325
|
+
if (err instanceof AbortError) {
|
|
326
|
+
await effectiveHooks.onAbort?.(request);
|
|
327
|
+
await effectiveHooks.onError?.(request, err);
|
|
328
|
+
await effectiveHooks.onComplete?.(request, void 0, err);
|
|
329
|
+
throw err;
|
|
330
|
+
}
|
|
331
|
+
if (err instanceof NetworkError) {
|
|
332
|
+
await effectiveHooks.onError?.(request, err);
|
|
333
|
+
await effectiveHooks.onComplete?.(request, void 0, err);
|
|
334
|
+
throw err;
|
|
335
|
+
}
|
|
336
|
+
const retryErr = new RetryLimitError(
|
|
337
|
+
typeof err === "object" && err && "message" in err && typeof err.message === "string" ? err.message : "Retry limit reached",
|
|
338
|
+
err
|
|
339
|
+
);
|
|
340
|
+
await effectiveHooks.onError?.(request, retryErr);
|
|
341
|
+
await effectiveHooks.onComplete?.(request, void 0, retryErr);
|
|
342
|
+
throw retryErr;
|
|
316
343
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
344
|
+
};
|
|
345
|
+
const baseDispatch = async () => retryWithHooks();
|
|
346
|
+
let dispatch = baseDispatch;
|
|
347
|
+
for (let i = plugins.length - 1; i >= 0; i--) {
|
|
348
|
+
const plugin = plugins[i];
|
|
349
|
+
if (plugin.wrapDispatch) {
|
|
350
|
+
dispatch = plugin.wrapDispatch(dispatch);
|
|
322
351
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
await
|
|
327
|
-
throw err;
|
|
352
|
+
}
|
|
353
|
+
const actualPromise = dispatch(pluginContext).then(async (response) => {
|
|
354
|
+
for (const plugin of plugins) {
|
|
355
|
+
await plugin.onSuccess?.(pluginContext, response);
|
|
328
356
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
357
|
+
return response;
|
|
358
|
+
}).catch(async (err) => {
|
|
359
|
+
for (const plugin of plugins) {
|
|
360
|
+
await plugin.onError?.(pluginContext, err);
|
|
333
361
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
362
|
+
throw err;
|
|
363
|
+
});
|
|
364
|
+
const pendingEntry = {
|
|
365
|
+
promise: actualPromise,
|
|
366
|
+
request,
|
|
367
|
+
controller
|
|
368
|
+
};
|
|
369
|
+
pendingRequests.push(pendingEntry);
|
|
370
|
+
return actualPromise.finally(async () => {
|
|
371
|
+
for (const plugin of plugins) {
|
|
372
|
+
await plugin.onFinally?.(pluginContext);
|
|
373
|
+
}
|
|
374
|
+
const index = pendingRequests.indexOf(pendingEntry);
|
|
375
|
+
if (index > -1) {
|
|
376
|
+
pendingRequests.splice(index, 1);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
342
379
|
};
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
if (plugin.wrapDispatch) {
|
|
348
|
-
dispatch = plugin.wrapDispatch(dispatch);
|
|
380
|
+
let promise = execute();
|
|
381
|
+
for (const plugin of plugins) {
|
|
382
|
+
if (plugin.decoratePromise) {
|
|
383
|
+
promise = plugin.decoratePromise(promise);
|
|
349
384
|
}
|
|
350
385
|
}
|
|
351
|
-
|
|
352
|
-
for (const plugin of plugins) {
|
|
353
|
-
await plugin.onSuccess?.(pluginContext, response);
|
|
354
|
-
}
|
|
355
|
-
return response;
|
|
356
|
-
}).catch(async (err) => {
|
|
357
|
-
for (const plugin of plugins) {
|
|
358
|
-
await plugin.onError?.(pluginContext, err);
|
|
359
|
-
}
|
|
360
|
-
throw err;
|
|
361
|
-
});
|
|
362
|
-
const pendingEntry = {
|
|
363
|
-
promise: actualPromise,
|
|
364
|
-
request,
|
|
365
|
-
controller
|
|
366
|
-
};
|
|
367
|
-
pendingRequests.push(pendingEntry);
|
|
368
|
-
return actualPromise.finally(async () => {
|
|
369
|
-
for (const plugin of plugins) {
|
|
370
|
-
await plugin.onFinally?.(pluginContext);
|
|
371
|
-
}
|
|
372
|
-
const index = pendingRequests.indexOf(pendingEntry);
|
|
373
|
-
if (index > -1) {
|
|
374
|
-
pendingRequests.splice(index, 1);
|
|
375
|
-
}
|
|
376
|
-
});
|
|
386
|
+
return promise;
|
|
377
387
|
};
|
|
378
388
|
Object.defineProperty(client, "pendingRequests", {
|
|
379
389
|
get() {
|
|
@@ -394,6 +404,7 @@ function createClient(opts = {}) {
|
|
|
394
404
|
export {
|
|
395
405
|
AbortError,
|
|
396
406
|
CircuitOpenError,
|
|
407
|
+
HttpError,
|
|
397
408
|
NetworkError,
|
|
398
409
|
RetryLimitError,
|
|
399
410
|
TimeoutError,
|