@fetchkit/ffetch 4.2.0 → 5.0.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 +230 -211
- package/dist/index.cjs +91 -206
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -25
- package/dist/index.d.ts +13 -25
- package/dist/index.js +91 -207
- 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.cjs +122 -0
- package/dist/plugins/circuit.cjs.map +1 -0
- package/dist/plugins/circuit.d.cts +15 -0
- package/dist/plugins/circuit.d.ts +15 -0
- package/dist/plugins/circuit.js +85 -0
- package/dist/plugins/circuit.js.map +1 -0
- package/dist/plugins/dedupe.cjs +167 -0
- package/dist/plugins/dedupe.cjs.map +1 -0
- package/dist/plugins/dedupe.d.cts +22 -0
- package/dist/plugins/dedupe.d.ts +22 -0
- package/dist/plugins/dedupe.js +139 -0
- package/dist/plugins/dedupe.js.map +1 -0
- package/dist/plugins-9qcU31nU.d.cts +58 -0
- package/dist/plugins-9qcU31nU.d.ts +58 -0
- package/package.json +11 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { C as ClientPlugin, P as PluginExtensionBase, a as PluginExtensions } from './plugins-9qcU31nU.js';
|
|
2
|
+
export { c as PluginDispatch, b as PluginRequestContext, d as PluginSetupContext } from './plugins-9qcU31nU.js';
|
|
3
|
+
|
|
1
4
|
type Hooks = {
|
|
2
5
|
before?: (req: Request) => void | Promise<void>;
|
|
3
6
|
after?: (req: Request, res: Response) => void | Promise<void>;
|
|
@@ -5,51 +8,36 @@ type Hooks = {
|
|
|
5
8
|
onRetry?: (req: Request, attempt: number, err?: unknown, res?: Response) => void | Promise<void>;
|
|
6
9
|
onTimeout?: (req: Request) => void | Promise<void>;
|
|
7
10
|
onAbort?: (req: Request) => void | Promise<void>;
|
|
8
|
-
onCircuitOpen?: (req: Request) => void | Promise<void>;
|
|
9
|
-
onCircuitClose?: (req: Request) => void | Promise<void>;
|
|
10
11
|
onComplete?: (req: Request, res?: Response, err?: unknown) => void | Promise<void>;
|
|
11
12
|
transformRequest?: (req: Request) => Request | Promise<Request>;
|
|
12
13
|
transformResponse?: (res: Response, req: Request) => Response | Promise<Response>;
|
|
13
14
|
};
|
|
14
15
|
|
|
15
|
-
type DedupeHashParams = {
|
|
16
|
-
method: string;
|
|
17
|
-
url: string;
|
|
18
|
-
body: string | FormData | URLSearchParams | Blob | ArrayBuffer | BufferSource | null | ReadableStream<unknown>;
|
|
19
|
-
headers?: Headers | Record<string, string>;
|
|
20
|
-
signal?: AbortSignal;
|
|
21
|
-
requestInit?: RequestInit;
|
|
22
|
-
request?: Request;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
16
|
interface RetryContext {
|
|
26
17
|
attempt: number;
|
|
27
18
|
request: Request;
|
|
28
19
|
response?: Response;
|
|
29
20
|
error?: unknown;
|
|
30
21
|
}
|
|
31
|
-
interface
|
|
22
|
+
interface CoreClientOptions {
|
|
32
23
|
timeout?: number;
|
|
33
24
|
retries?: number;
|
|
34
25
|
retryDelay?: number | ((ctx: RetryContext) => number);
|
|
35
26
|
shouldRetry?: (ctx: RetryContext) => boolean;
|
|
36
27
|
throwOnHttpError?: boolean;
|
|
37
|
-
circuit?: {
|
|
38
|
-
threshold: number;
|
|
39
|
-
reset: number;
|
|
40
|
-
};
|
|
41
28
|
hooks?: Hooks;
|
|
42
29
|
fetchHandler?: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
|
|
43
|
-
dedupe?: boolean;
|
|
44
|
-
dedupeHashFn?: (params: DedupeHashParams) => string | undefined;
|
|
45
30
|
}
|
|
46
|
-
|
|
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>> = {
|
|
47
36
|
(input: RequestInfo | URL, init?: FFetchRequestInit): Promise<Response>;
|
|
48
37
|
pendingRequests: PendingRequest[];
|
|
49
38
|
abortAll: () => void;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
interface FFetchRequestInit extends RequestInit, FFetchOptions {
|
|
39
|
+
} & TExtensions;
|
|
40
|
+
interface FFetchRequestInit extends RequestInit, FFetchRequestOptions {
|
|
53
41
|
}
|
|
54
42
|
type PendingRequest = {
|
|
55
43
|
promise: Promise<Response>;
|
|
@@ -57,7 +45,7 @@ type PendingRequest = {
|
|
|
57
45
|
controller?: AbortController;
|
|
58
46
|
};
|
|
59
47
|
|
|
60
|
-
declare function createClient(opts?: FFetchOptions): FFetch
|
|
48
|
+
declare function createClient<TPlugins extends readonly ClientPlugin<PluginExtensionBase>[] = readonly ClientPlugin<PluginExtensionBase>[]>(opts?: FFetchOptions<TPlugins>): FFetch<PluginExtensions<TPlugins>>;
|
|
61
49
|
|
|
62
50
|
declare class BaseError extends Error {
|
|
63
51
|
cause?: unknown;
|
|
@@ -79,4 +67,4 @@ declare class NetworkError extends BaseError {
|
|
|
79
67
|
constructor(message?: string, cause?: unknown);
|
|
80
68
|
}
|
|
81
69
|
|
|
82
|
-
export { AbortError, CircuitOpenError,
|
|
70
|
+
export { AbortError, CircuitOpenError, ClientPlugin, type FFetch, type FFetchOptions, type Hooks, NetworkError, RetryLimitError, TimeoutError, createClient };
|
package/dist/index.js
CHANGED
|
@@ -6,38 +6,6 @@ import {
|
|
|
6
6
|
TimeoutError
|
|
7
7
|
} from "./chunk-RV6LC73N.js";
|
|
8
8
|
|
|
9
|
-
// src/dedupeRequestHash.ts
|
|
10
|
-
function dedupeRequestHash(params) {
|
|
11
|
-
const { method, url, body } = params;
|
|
12
|
-
let bodyString = "";
|
|
13
|
-
if (body instanceof FormData) {
|
|
14
|
-
return void 0;
|
|
15
|
-
}
|
|
16
|
-
if (typeof ReadableStream !== "undefined" && body instanceof ReadableStream) {
|
|
17
|
-
return void 0;
|
|
18
|
-
}
|
|
19
|
-
if (typeof body === "string") {
|
|
20
|
-
bodyString = body;
|
|
21
|
-
} else if (body instanceof URLSearchParams) {
|
|
22
|
-
bodyString = body.toString();
|
|
23
|
-
} else if (body instanceof ArrayBuffer) {
|
|
24
|
-
bodyString = Buffer.from(body).toString("base64");
|
|
25
|
-
} else if (body instanceof Uint8Array) {
|
|
26
|
-
bodyString = Buffer.from(body).toString("base64");
|
|
27
|
-
} else if (body instanceof Blob) {
|
|
28
|
-
bodyString = `[blob:${body.type}:${body.size}]`;
|
|
29
|
-
} else if (body == null) {
|
|
30
|
-
bodyString = "";
|
|
31
|
-
} else {
|
|
32
|
-
try {
|
|
33
|
-
bodyString = JSON.stringify(body);
|
|
34
|
-
} catch {
|
|
35
|
-
bodyString = "[unserializable-body]";
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return `${method.toUpperCase()}|${url}|${bodyString}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
9
|
// src/retry.ts
|
|
42
10
|
var defaultDelay = (ctx) => {
|
|
43
11
|
const retryAfter = ctx.response?.headers.get("Retry-After");
|
|
@@ -89,102 +57,48 @@ function shouldRetry(ctx) {
|
|
|
89
57
|
return response.status >= 500 || response.status === 429;
|
|
90
58
|
}
|
|
91
59
|
|
|
92
|
-
// src/circuit.ts
|
|
93
|
-
var CircuitBreaker = class {
|
|
94
|
-
constructor(threshold, resetTimeout) {
|
|
95
|
-
this.threshold = threshold;
|
|
96
|
-
this.resetTimeout = resetTimeout;
|
|
97
|
-
this.failures = 0;
|
|
98
|
-
this.nextAttempt = 0;
|
|
99
|
-
this.isOpen = false;
|
|
100
|
-
}
|
|
101
|
-
// Returns true if the circuit breaker is currently open (blocking requests).
|
|
102
|
-
get open() {
|
|
103
|
-
return this.isOpen;
|
|
104
|
-
}
|
|
105
|
-
// Call this after each request to record the result and update circuit state.
|
|
106
|
-
// Returns true if the result was counted as a failure.
|
|
107
|
-
recordResult(response, error, req) {
|
|
108
|
-
if (error && !(error instanceof RetryLimitError)) {
|
|
109
|
-
this.setLastOpenRequest(req);
|
|
110
|
-
this.onFailure();
|
|
111
|
-
return true;
|
|
112
|
-
}
|
|
113
|
-
if (response && (response.status >= 500 || response.status === 429)) {
|
|
114
|
-
this.setLastOpenRequest(req);
|
|
115
|
-
this.onFailure();
|
|
116
|
-
return true;
|
|
117
|
-
}
|
|
118
|
-
if (req) this.setLastSuccessRequest(req);
|
|
119
|
-
this.onSuccess();
|
|
120
|
-
return false;
|
|
121
|
-
}
|
|
122
|
-
setHooks(hooks) {
|
|
123
|
-
this.hooks = hooks;
|
|
124
|
-
}
|
|
125
|
-
setLastOpenRequest(req) {
|
|
126
|
-
this.lastOpenRequest = req;
|
|
127
|
-
}
|
|
128
|
-
setLastSuccessRequest(req) {
|
|
129
|
-
this.lastSuccessRequest = req;
|
|
130
|
-
}
|
|
131
|
-
async invoke(fn) {
|
|
132
|
-
if (Date.now() < this.nextAttempt)
|
|
133
|
-
throw new CircuitOpenError("Circuit is open");
|
|
134
|
-
try {
|
|
135
|
-
const res = await fn();
|
|
136
|
-
this.onSuccess();
|
|
137
|
-
return res;
|
|
138
|
-
} catch (err) {
|
|
139
|
-
this.onFailure();
|
|
140
|
-
throw err;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
onSuccess() {
|
|
144
|
-
const wasOpen = this.isOpen;
|
|
145
|
-
this.failures = 0;
|
|
146
|
-
if (wasOpen) {
|
|
147
|
-
this.isOpen = false;
|
|
148
|
-
if (this.hooks?.onCircuitClose && this.lastSuccessRequest) {
|
|
149
|
-
this.hooks.onCircuitClose(this.lastSuccessRequest);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
this.lastSuccessRequest = void 0;
|
|
153
|
-
}
|
|
154
|
-
onFailure() {
|
|
155
|
-
this.failures++;
|
|
156
|
-
if (this.failures >= this.threshold) {
|
|
157
|
-
this.nextAttempt = Date.now() + this.resetTimeout;
|
|
158
|
-
this.isOpen = true;
|
|
159
|
-
if (this.hooks?.onCircuitOpen && this.lastOpenRequest) {
|
|
160
|
-
this.hooks.onCircuitOpen(this.lastOpenRequest);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
|
|
166
60
|
// src/client.ts
|
|
167
61
|
function createClient(opts = {}) {
|
|
168
|
-
const dedupeMap = /* @__PURE__ */ new Map();
|
|
169
62
|
const {
|
|
170
63
|
timeout: clientDefaultTimeout = 5e3,
|
|
171
64
|
retries: clientDefaultRetries = 0,
|
|
172
65
|
retryDelay: clientDefaultRetryDelay = defaultDelay,
|
|
173
66
|
shouldRetry: clientDefaultShouldRetry = shouldRetry,
|
|
174
67
|
hooks: clientDefaultHooks = {},
|
|
175
|
-
circuit: clientDefaultCircuit,
|
|
176
68
|
fetchHandler,
|
|
177
|
-
|
|
178
|
-
dedupeHashFn = dedupeRequestHash
|
|
69
|
+
plugins: inputPlugins = []
|
|
179
70
|
} = opts;
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
71
|
+
const extensionDescriptors = /* @__PURE__ */ Object.create(null);
|
|
72
|
+
const plugins = inputPlugins.map((plugin, index) => ({ plugin, index })).sort((a, b) => {
|
|
73
|
+
const aOrder = a.plugin.order ?? 0;
|
|
74
|
+
const bOrder = b.plugin.order ?? 0;
|
|
75
|
+
if (aOrder !== bOrder) return aOrder - bOrder;
|
|
76
|
+
return a.index - b.index;
|
|
77
|
+
}).map((entry) => entry.plugin);
|
|
78
|
+
for (const plugin of plugins) {
|
|
79
|
+
plugin.setup?.({
|
|
80
|
+
defineExtension: (key, descriptor) => {
|
|
81
|
+
const propertyKey = key;
|
|
82
|
+
if (propertyKey in extensionDescriptors) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`Plugin extension collision for property "${String(propertyKey)}"`
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
if ("get" in descriptor) {
|
|
88
|
+
extensionDescriptors[propertyKey] = {
|
|
89
|
+
get: descriptor.get,
|
|
90
|
+
enumerable: descriptor.enumerable ?? true,
|
|
91
|
+
configurable: false
|
|
92
|
+
};
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
extensionDescriptors[propertyKey] = {
|
|
96
|
+
value: descriptor.value,
|
|
97
|
+
writable: false,
|
|
98
|
+
enumerable: descriptor.enumerable ?? true,
|
|
99
|
+
configurable: false
|
|
100
|
+
};
|
|
101
|
+
}
|
|
188
102
|
});
|
|
189
103
|
}
|
|
190
104
|
const pendingRequests = [];
|
|
@@ -194,53 +108,39 @@ function createClient(opts = {}) {
|
|
|
194
108
|
}
|
|
195
109
|
}
|
|
196
110
|
const client = async (input, init = {}) => {
|
|
197
|
-
const effectiveDedupe = typeof init.dedupe !== "undefined" ? init.dedupe : dedupe;
|
|
198
|
-
const effectiveDedupeHashFn = init.dedupeHashFn || dedupeHashFn;
|
|
199
|
-
let dedupeKey;
|
|
200
111
|
let request = new Request(input, init);
|
|
201
|
-
if (effectiveDedupe) {
|
|
202
|
-
dedupeKey = effectiveDedupeHashFn({
|
|
203
|
-
method: request.method,
|
|
204
|
-
url: request.url,
|
|
205
|
-
body: init.body ?? null,
|
|
206
|
-
headers: request.headers,
|
|
207
|
-
signal: init.signal === void 0 || init.signal === null ? void 0 : init.signal,
|
|
208
|
-
requestInit: init,
|
|
209
|
-
request
|
|
210
|
-
});
|
|
211
|
-
if (dedupeKey) {
|
|
212
|
-
if (dedupeMap.has(dedupeKey)) {
|
|
213
|
-
return dedupeMap.get(dedupeKey).promise;
|
|
214
|
-
}
|
|
215
|
-
let settled = false;
|
|
216
|
-
let resolveFn;
|
|
217
|
-
let rejectFn;
|
|
218
|
-
const inFlightPromise = new Promise((resolve, reject) => {
|
|
219
|
-
resolveFn = (value) => {
|
|
220
|
-
if (!settled) {
|
|
221
|
-
settled = true;
|
|
222
|
-
resolve(value);
|
|
223
|
-
}
|
|
224
|
-
};
|
|
225
|
-
rejectFn = (reason) => {
|
|
226
|
-
if (!settled) {
|
|
227
|
-
settled = true;
|
|
228
|
-
reject(reason);
|
|
229
|
-
}
|
|
230
|
-
};
|
|
231
|
-
});
|
|
232
|
-
dedupeMap.set(dedupeKey, {
|
|
233
|
-
promise: inFlightPromise,
|
|
234
|
-
resolve: resolveFn,
|
|
235
|
-
reject: rejectFn
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
112
|
const effectiveHooks = { ...clientDefaultHooks, ...init.hooks || {} };
|
|
240
113
|
if (effectiveHooks.transformRequest) {
|
|
241
114
|
request = await effectiveHooks.transformRequest(request);
|
|
242
115
|
}
|
|
243
116
|
await effectiveHooks.before?.(request);
|
|
117
|
+
const effectiveRetries = init.retries ?? clientDefaultRetries;
|
|
118
|
+
const effectiveRetryDelay = typeof init.retryDelay !== "undefined" ? init.retryDelay : clientDefaultRetryDelay;
|
|
119
|
+
const effectiveShouldRetry = init.shouldRetry ?? clientDefaultShouldRetry;
|
|
120
|
+
const effectiveTimeout = init.timeout ?? clientDefaultTimeout;
|
|
121
|
+
const userSignal = init.signal;
|
|
122
|
+
const transformedSignal = request.signal;
|
|
123
|
+
const pluginContext = {
|
|
124
|
+
request,
|
|
125
|
+
init,
|
|
126
|
+
state: /* @__PURE__ */ Object.create(null),
|
|
127
|
+
metadata: {
|
|
128
|
+
startedAt: Date.now(),
|
|
129
|
+
timeoutMs: effectiveTimeout,
|
|
130
|
+
signals: {
|
|
131
|
+
user: userSignal === void 0 || userSignal === null ? void 0 : userSignal,
|
|
132
|
+
transformed: transformedSignal
|
|
133
|
+
},
|
|
134
|
+
retry: {
|
|
135
|
+
configuredRetries: effectiveRetries,
|
|
136
|
+
configuredDelay: effectiveRetryDelay,
|
|
137
|
+
attempt: 0
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
for (const plugin of plugins) {
|
|
142
|
+
await plugin.preRequest?.(pluginContext);
|
|
143
|
+
}
|
|
244
144
|
const effectiveThrowOnHttpError = typeof init.throwOnHttpError !== "undefined" ? init.throwOnHttpError : opts.throwOnHttpError ?? false;
|
|
245
145
|
function createTimeoutSignal(timeout) {
|
|
246
146
|
if (typeof AbortSignal?.timeout === "function") {
|
|
@@ -255,14 +155,12 @@ function createClient(opts = {}) {
|
|
|
255
155
|
);
|
|
256
156
|
return controller2.signal;
|
|
257
157
|
}
|
|
258
|
-
const effectiveTimeout = init.timeout ?? clientDefaultTimeout;
|
|
259
|
-
const userSignal = init.signal;
|
|
260
|
-
const transformedSignal = request.signal;
|
|
261
158
|
let timeoutSignal = void 0;
|
|
262
159
|
let combinedSignal = void 0;
|
|
263
160
|
let controller = void 0;
|
|
264
161
|
if (effectiveTimeout > 0) {
|
|
265
162
|
timeoutSignal = createTimeoutSignal(effectiveTimeout);
|
|
163
|
+
pluginContext.metadata.signals.timeout = timeoutSignal;
|
|
266
164
|
}
|
|
267
165
|
const signals = [];
|
|
268
166
|
if (userSignal) signals.push(userSignal);
|
|
@@ -282,14 +180,16 @@ function createClient(opts = {}) {
|
|
|
282
180
|
combinedSignal = AbortSignal.any(signals);
|
|
283
181
|
controller = new AbortController();
|
|
284
182
|
}
|
|
183
|
+
pluginContext.metadata.signals.combined = combinedSignal;
|
|
285
184
|
const retryWithHooks = async () => {
|
|
286
|
-
const effectiveRetries = init.retries ?? clientDefaultRetries;
|
|
287
|
-
const effectiveRetryDelay = typeof init.retryDelay !== "undefined" ? init.retryDelay : clientDefaultRetryDelay;
|
|
288
|
-
const effectiveShouldRetry = init.shouldRetry ?? clientDefaultShouldRetry;
|
|
289
185
|
let attempt = 0;
|
|
290
186
|
const shouldRetryWithHook = (ctx) => {
|
|
291
187
|
attempt = ctx.attempt;
|
|
188
|
+
pluginContext.metadata.retry.attempt = attempt;
|
|
189
|
+
pluginContext.metadata.retry.lastError = ctx.error;
|
|
190
|
+
pluginContext.metadata.retry.lastResponse = ctx.response;
|
|
292
191
|
const retrying = effectiveShouldRetry(ctx);
|
|
192
|
+
pluginContext.metadata.retry.shouldRetryResult = retrying;
|
|
293
193
|
if (retrying && attempt <= effectiveRetries) {
|
|
294
194
|
effectiveHooks.onRetry?.(
|
|
295
195
|
request,
|
|
@@ -335,12 +235,10 @@ function createClient(opts = {}) {
|
|
|
335
235
|
const handler = init.fetchHandler ?? fetchHandler ?? fetch;
|
|
336
236
|
const response = await handler(reqWithSignal);
|
|
337
237
|
lastResponse = response;
|
|
338
|
-
|
|
339
|
-
breaker.recordResult(response, void 0, request);
|
|
340
|
-
}
|
|
238
|
+
pluginContext.metadata.retry.lastResponse = response;
|
|
341
239
|
return response;
|
|
342
240
|
} catch (err) {
|
|
343
|
-
|
|
241
|
+
pluginContext.metadata.retry.lastError = err;
|
|
344
242
|
if (err instanceof DOMException && err.name === "AbortError") {
|
|
345
243
|
if (timeoutSignal?.aborted && (!userSignal || !userSignal.aborted)) {
|
|
346
244
|
effectiveHooks.onTimeout?.(request);
|
|
@@ -381,6 +279,7 @@ function createClient(opts = {}) {
|
|
|
381
279
|
}
|
|
382
280
|
return res;
|
|
383
281
|
} catch (err) {
|
|
282
|
+
pluginContext.metadata.retry.lastError = err;
|
|
384
283
|
if (lastResponse) {
|
|
385
284
|
const resp = lastResponse;
|
|
386
285
|
if (effectiveThrowOnHttpError && (resp.status >= 400 && resp.status < 500 && resp.status !== 429 || resp.status >= 500 || resp.status === 429)) {
|
|
@@ -418,45 +317,39 @@ function createClient(opts = {}) {
|
|
|
418
317
|
throw retryErr;
|
|
419
318
|
}
|
|
420
319
|
};
|
|
421
|
-
const
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
await effectiveHooks.onError?.(request, err);
|
|
428
|
-
await effectiveHooks.onComplete?.(request, void 0, err);
|
|
429
|
-
}
|
|
430
|
-
throw err;
|
|
431
|
-
}) : retryWithHooks();
|
|
432
|
-
if (effectiveDedupe && dedupeKey && dedupeMap.has(dedupeKey)) {
|
|
433
|
-
const entry = dedupeMap.get(dedupeKey);
|
|
434
|
-
if (entry) {
|
|
435
|
-
actualPromise.then(
|
|
436
|
-
(result) => entry.resolve(result),
|
|
437
|
-
(error) => entry.reject(error)
|
|
438
|
-
);
|
|
439
|
-
dedupeMap.set(dedupeKey, {
|
|
440
|
-
promise: actualPromise,
|
|
441
|
-
resolve: entry.resolve,
|
|
442
|
-
reject: entry.reject
|
|
443
|
-
});
|
|
320
|
+
const baseDispatch = async () => retryWithHooks();
|
|
321
|
+
let dispatch = baseDispatch;
|
|
322
|
+
for (let i = plugins.length - 1; i >= 0; i--) {
|
|
323
|
+
const plugin = plugins[i];
|
|
324
|
+
if (plugin.wrapDispatch) {
|
|
325
|
+
dispatch = plugin.wrapDispatch(dispatch);
|
|
444
326
|
}
|
|
445
327
|
}
|
|
328
|
+
const actualPromise = dispatch(pluginContext).then(async (response) => {
|
|
329
|
+
for (const plugin of plugins) {
|
|
330
|
+
await plugin.onSuccess?.(pluginContext, response);
|
|
331
|
+
}
|
|
332
|
+
return response;
|
|
333
|
+
}).catch(async (err) => {
|
|
334
|
+
for (const plugin of plugins) {
|
|
335
|
+
await plugin.onError?.(pluginContext, err);
|
|
336
|
+
}
|
|
337
|
+
throw err;
|
|
338
|
+
});
|
|
446
339
|
const pendingEntry = {
|
|
447
340
|
promise: actualPromise,
|
|
448
341
|
request,
|
|
449
342
|
controller
|
|
450
343
|
};
|
|
451
344
|
pendingRequests.push(pendingEntry);
|
|
452
|
-
return actualPromise.finally(() => {
|
|
345
|
+
return actualPromise.finally(async () => {
|
|
346
|
+
for (const plugin of plugins) {
|
|
347
|
+
await plugin.onFinally?.(pluginContext);
|
|
348
|
+
}
|
|
453
349
|
const index = pendingRequests.indexOf(pendingEntry);
|
|
454
350
|
if (index > -1) {
|
|
455
351
|
pendingRequests.splice(index, 1);
|
|
456
352
|
}
|
|
457
|
-
if (effectiveDedupe && dedupeKey && dedupeMap.get(dedupeKey)?.promise === actualPromise) {
|
|
458
|
-
dedupeMap.delete(dedupeKey);
|
|
459
|
-
}
|
|
460
353
|
});
|
|
461
354
|
};
|
|
462
355
|
Object.defineProperty(client, "pendingRequests", {
|
|
@@ -472,24 +365,15 @@ function createClient(opts = {}) {
|
|
|
472
365
|
enumerable: false,
|
|
473
366
|
configurable: false
|
|
474
367
|
});
|
|
475
|
-
Object.
|
|
476
|
-
get() {
|
|
477
|
-
return breaker ? breaker.open : false;
|
|
478
|
-
},
|
|
479
|
-
enumerable: true
|
|
480
|
-
});
|
|
368
|
+
Object.defineProperties(client, extensionDescriptors);
|
|
481
369
|
return client;
|
|
482
370
|
}
|
|
483
|
-
|
|
484
|
-
// src/index.ts
|
|
485
|
-
var index_default = createClient;
|
|
486
371
|
export {
|
|
487
372
|
AbortError,
|
|
488
373
|
CircuitOpenError,
|
|
489
374
|
NetworkError,
|
|
490
375
|
RetryLimitError,
|
|
491
376
|
TimeoutError,
|
|
492
|
-
createClient
|
|
493
|
-
index_default as default
|
|
377
|
+
createClient
|
|
494
378
|
};
|
|
495
379
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dedupeRequestHash.ts","../src/retry.ts","../src/should-retry.ts","../src/circuit.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["export type DedupeHashParams = {\n method: string\n url: string\n body:\n | string\n | FormData\n | URLSearchParams\n | Blob\n | ArrayBuffer\n | BufferSource\n | null\n | ReadableStream<unknown>\n headers?: Headers | Record<string, string>\n signal?: AbortSignal\n requestInit?: RequestInit\n request?: Request\n}\n\nexport function dedupeRequestHash(\n params: DedupeHashParams\n): string | undefined {\n const { method, url, body } = params\n let bodyString = ''\n if (body instanceof FormData) {\n // Skip deduplication for FormData\n return undefined\n }\n // Skip deduplication for ReadableStream\n if (typeof ReadableStream !== 'undefined' && body instanceof ReadableStream) {\n return undefined\n }\n if (typeof body === 'string') {\n bodyString = body\n } else if (body instanceof URLSearchParams) {\n bodyString = body.toString()\n } else if (body instanceof ArrayBuffer) {\n bodyString = Buffer.from(body).toString('base64')\n } else if (body instanceof Uint8Array) {\n bodyString = Buffer.from(body).toString('base64')\n } else if (body instanceof Blob) {\n bodyString = `[blob:${body.type}:${body.size}]`\n } else if (body == null) {\n bodyString = ''\n } else {\n try {\n bodyString = JSON.stringify(body)\n } catch {\n bodyString = '[unserializable-body]'\n }\n }\n return `${method.toUpperCase()}|${url}|${bodyString}`\n}\n","import type { RetryContext } from './types.js'\n\nexport type RetryDelay = number | ((ctx: RetryContext) => number)\n\nexport const defaultDelay: RetryDelay = (ctx) => {\n const retryAfter = ctx.response?.headers.get('Retry-After')\n if (retryAfter) {\n const seconds = parseInt(retryAfter, 10)\n if (!isNaN(seconds)) return seconds * 1000\n const date = Date.parse(retryAfter)\n if (!isNaN(date)) return Math.max(0, date - Date.now())\n }\n return 2 ** ctx.attempt * 200 + Math.random() * 100\n}\n\nexport async function retry(\n fn: () => Promise<Response>,\n retries: number,\n delay: RetryDelay,\n shouldRetry: (ctx: RetryContext) => boolean = () => true,\n request: Request\n): Promise<Response> {\n let lastErr: unknown\n let lastRes: Response | undefined\n\n for (let i = 0; i <= retries; i++) {\n const ctx: RetryContext = {\n attempt: i + 1,\n request,\n response: lastRes,\n error: lastErr,\n }\n try {\n lastRes = await fn()\n ctx.response = lastRes\n ctx.error = undefined\n if (i < retries && shouldRetry(ctx)) {\n const wait = typeof delay === 'function' ? delay(ctx) : delay\n await new Promise((r) => setTimeout(r, wait))\n continue\n }\n return lastRes\n } catch (err) {\n lastErr = err\n ctx.error = err\n if (i === retries || !shouldRetry(ctx)) throw err\n const wait = typeof delay === 'function' ? delay(ctx) : delay\n await new Promise((r) => setTimeout(r, wait))\n }\n }\n throw lastErr\n}\n","import { AbortError, CircuitOpenError, TimeoutError } from './error.js'\nimport type { RetryContext } from './types.js'\n\nexport function shouldRetry(ctx: RetryContext): boolean {\n const { error, response } = ctx\n if (\n error instanceof AbortError ||\n error instanceof CircuitOpenError ||\n error instanceof TimeoutError\n )\n return false\n if (!response) return true // network error\n return response.status >= 500 || response.status === 429\n}\n","import { CircuitOpenError, RetryLimitError } from './error.js'\n\nexport class CircuitBreaker {\n private failures = 0\n private nextAttempt = 0\n private isOpen = false\n\n // Returns true if the circuit breaker is currently open (blocking requests).\n get open(): boolean {\n return this.isOpen\n }\n private hooks?: {\n onCircuitOpen?: (req: Request) => void | Promise<void>\n onCircuitClose?: (req: Request) => void | Promise<void>\n }\n private lastSuccessRequest?: Request\n private lastOpenRequest?: Request\n\n constructor(\n private threshold: number,\n private resetTimeout: number\n ) {}\n\n // Call this after each request to record the result and update circuit state.\n // Returns true if the result was counted as a failure.\n recordResult(response?: Response, error?: unknown, req?: Request): boolean {\n // Count thrown errors (network, abort, timeout) as failures\n if (error && !(error instanceof RetryLimitError)) {\n this.setLastOpenRequest(req!)\n this.onFailure()\n return true\n }\n // Count HTTP 5xx and 429 responses as failures\n if (response && (response.status >= 500 || response.status === 429)) {\n this.setLastOpenRequest(req!)\n this.onFailure()\n return true\n }\n // Otherwise, count as success\n if (req) this.setLastSuccessRequest(req)\n this.onSuccess()\n return false\n }\n\n setHooks(hooks: {\n onCircuitOpen?: (req: Request) => void | Promise<void>\n onCircuitClose?: (req: Request) => void | Promise<void>\n }) {\n this.hooks = hooks\n }\n setLastOpenRequest(req: Request) {\n this.lastOpenRequest = req\n }\n\n setLastSuccessRequest(req: Request) {\n this.lastSuccessRequest = req\n }\n\n async invoke<T>(fn: () => Promise<T>): Promise<T> {\n if (Date.now() < this.nextAttempt)\n throw new CircuitOpenError('Circuit is open')\n try {\n const res = await fn()\n this.onSuccess()\n return res\n } catch (err) {\n this.onFailure()\n throw err\n }\n }\n\n private onSuccess() {\n const wasOpen = this.isOpen\n this.failures = 0\n if (wasOpen) {\n this.isOpen = false\n if (this.hooks?.onCircuitClose && this.lastSuccessRequest) {\n this.hooks.onCircuitClose(this.lastSuccessRequest)\n }\n }\n this.lastSuccessRequest = undefined\n }\n\n private onFailure() {\n this.failures++\n if (this.failures >= this.threshold) {\n this.nextAttempt = Date.now() + this.resetTimeout\n this.isOpen = true\n if (this.hooks?.onCircuitOpen && this.lastOpenRequest) {\n this.hooks.onCircuitOpen(this.lastOpenRequest)\n }\n }\n }\n}\n","import type {\r\n FFetchOptions,\r\n FFetch,\r\n FFetchRequestInit,\r\n PendingRequest,\r\n} from './types.js'\r\nimport { dedupeRequestHash } from './dedupeRequestHash.js'\r\nimport { retry, defaultDelay } from './retry.js'\r\nimport { shouldRetry as defaultShouldRetry } from './should-retry.js'\r\nimport { CircuitBreaker } from './circuit.js'\r\nimport {\r\n TimeoutError,\r\n CircuitOpenError,\r\n AbortError,\r\n RetryLimitError,\r\n NetworkError,\r\n} from './error.js'\r\n\r\nexport function createClient(opts: FFetchOptions = {}): FFetch {\r\n // Track in-flight deduped requests and their resolvers\r\n const dedupeMap = new Map<\r\n string,\r\n {\r\n promise: Promise<Response>\r\n resolve: (value: Response | PromiseLike<Response>) => void\r\n reject: (reason?: unknown) => void\r\n }\r\n >()\r\n const {\r\n timeout: clientDefaultTimeout = 5_000,\r\n retries: clientDefaultRetries = 0,\r\n retryDelay: clientDefaultRetryDelay = defaultDelay,\r\n shouldRetry: clientDefaultShouldRetry = defaultShouldRetry,\r\n hooks: clientDefaultHooks = {},\r\n circuit: clientDefaultCircuit,\r\n fetchHandler,\r\n dedupe = false,\r\n dedupeHashFn = dedupeRequestHash,\r\n } = opts\r\n\r\n const breaker = clientDefaultCircuit\r\n ? new CircuitBreaker(\r\n clientDefaultCircuit.threshold,\r\n clientDefaultCircuit.reset\r\n )\r\n : null\r\n\r\n if (\r\n breaker &&\r\n (clientDefaultHooks.onCircuitClose || clientDefaultHooks.onCircuitOpen)\r\n ) {\r\n breaker.setHooks({\r\n onCircuitClose: clientDefaultHooks.onCircuitClose,\r\n onCircuitOpen: clientDefaultHooks.onCircuitOpen,\r\n })\r\n }\r\n\r\n const pendingRequests: PendingRequest[] = []\r\n\r\n // Helper to abort all pending requests\r\n function abortAll() {\r\n for (const entry of pendingRequests) {\r\n entry.controller?.abort()\r\n }\r\n }\r\n\r\n const client = async (\r\n input: RequestInfo | URL,\r\n init: FFetchRequestInit = {}\r\n ) => {\r\n // Deduplication logic\r\n const effectiveDedupe =\r\n typeof init.dedupe !== 'undefined' ? init.dedupe : dedupe\r\n const effectiveDedupeHashFn = init.dedupeHashFn || dedupeHashFn\r\n let dedupeKey: string | undefined\r\n\r\n let request = new Request(input, init)\r\n if (effectiveDedupe) {\r\n dedupeKey = effectiveDedupeHashFn({\r\n method: request.method,\r\n url: request.url,\r\n body: init.body ?? null,\r\n headers: request.headers,\r\n signal:\r\n init.signal === undefined || init.signal === null\r\n ? undefined\r\n : init.signal,\r\n requestInit: init,\r\n request,\r\n })\r\n if (dedupeKey) {\r\n if (dedupeMap.has(dedupeKey)) {\r\n return dedupeMap.get(dedupeKey)!.promise\r\n }\r\n let settled = false\r\n let resolveFn: (value: Response | PromiseLike<Response>) => void\r\n let rejectFn: (reason?: unknown) => void\r\n const inFlightPromise = new Promise<Response>((resolve, reject) => {\r\n resolveFn = (value) => {\r\n if (!settled) {\r\n settled = true\r\n resolve(value)\r\n }\r\n }\r\n rejectFn = (reason) => {\r\n if (!settled) {\r\n settled = true\r\n reject(reason)\r\n }\r\n }\r\n })\r\n dedupeMap.set(dedupeKey, {\r\n promise: inFlightPromise,\r\n resolve: resolveFn!,\r\n reject: rejectFn!,\r\n })\r\n }\r\n }\r\n\r\n // Merge hooks: per-request hooks override client hooks, but fallback to client hooks\r\n const effectiveHooks = { ...clientDefaultHooks, ...(init.hooks || {}) }\r\n if (effectiveHooks.transformRequest) {\r\n request = await effectiveHooks.transformRequest(request)\r\n }\r\n await effectiveHooks.before?.(request)\r\n\r\n // Determine throwOnHttpError (per-request overrides client default)\r\n const effectiveThrowOnHttpError =\r\n typeof init.throwOnHttpError !== 'undefined'\r\n ? init.throwOnHttpError\r\n : (opts.throwOnHttpError ?? false)\r\n\r\n // Create timeout signal (manual implementation if AbortSignal.timeout not available)\r\n function createTimeoutSignal(timeout: number): AbortSignal {\r\n if (typeof AbortSignal?.timeout === 'function') {\r\n return AbortSignal.timeout(timeout)\r\n }\r\n const controller = new AbortController()\r\n const timeoutId = setTimeout(() => controller.abort(), timeout)\r\n controller.signal.addEventListener(\r\n 'abort',\r\n () => clearTimeout(timeoutId),\r\n { once: true }\r\n )\r\n return controller.signal\r\n }\r\n\r\n // AbortSignal.timeout/any logic\r\n const effectiveTimeout = init.timeout ?? clientDefaultTimeout\r\n const userSignal = init.signal\r\n const transformedSignal = request.signal\r\n let timeoutSignal: AbortSignal | undefined = undefined\r\n let combinedSignal: AbortSignal | undefined = undefined\r\n let controller: AbortController | undefined = undefined\r\n\r\n if (effectiveTimeout > 0) {\r\n timeoutSignal = createTimeoutSignal(effectiveTimeout)\r\n }\r\n\r\n const signals: AbortSignal[] = []\r\n if (userSignal) signals.push(userSignal)\r\n if (transformedSignal && transformedSignal !== userSignal) {\r\n signals.push(transformedSignal)\r\n }\r\n if (timeoutSignal) signals.push(timeoutSignal)\r\n\r\n if (signals.length === 1) {\r\n combinedSignal = signals[0]\r\n controller = new AbortController()\r\n } else {\r\n if (typeof AbortSignal.any !== 'function') {\r\n throw new Error(\r\n 'AbortSignal.any is required for combining multiple signals. Please install a polyfill for environments that do not support it.'\r\n )\r\n }\r\n combinedSignal = AbortSignal.any(signals)\r\n controller = new AbortController()\r\n }\r\n\r\n const retryWithHooks = async () => {\r\n const effectiveRetries = init.retries ?? clientDefaultRetries\r\n const effectiveRetryDelay =\r\n typeof init.retryDelay !== 'undefined'\r\n ? init.retryDelay\r\n : clientDefaultRetryDelay\r\n const effectiveShouldRetry = init.shouldRetry ?? clientDefaultShouldRetry\r\n\r\n let attempt = 0\r\n const shouldRetryWithHook = (ctx: import('./types').RetryContext) => {\r\n attempt = ctx.attempt\r\n const retrying = effectiveShouldRetry(ctx)\r\n if (retrying && attempt <= effectiveRetries) {\r\n effectiveHooks.onRetry?.(\r\n request,\r\n attempt - 1,\r\n ctx.error,\r\n ctx.response\r\n )\r\n }\r\n return retrying\r\n }\r\n\r\n let lastResponse: Response | undefined = undefined\r\n try {\r\n let res = await retry(\r\n async () => {\r\n if (userSignal?.aborted) {\r\n effectiveHooks.onAbort?.(request)\r\n throw new AbortError('Request was aborted by user')\r\n }\r\n if (timeoutSignal?.aborted) {\r\n effectiveHooks.onTimeout?.(request)\r\n throw new TimeoutError('signal timed out')\r\n }\r\n if (typeof combinedSignal?.throwIfAborted === 'function') {\r\n combinedSignal.throwIfAborted()\r\n } else if (combinedSignal?.aborted) {\r\n if (userSignal?.aborted) {\r\n effectiveHooks.onAbort?.(request)\r\n throw new AbortError('Request was aborted by user')\r\n } else if (timeoutSignal?.aborted) {\r\n effectiveHooks.onTimeout?.(request)\r\n throw new TimeoutError('signal timed out')\r\n } else {\r\n throw new AbortError(\r\n 'Request was aborted',\r\n new DOMException('Aborted', 'AbortError')\r\n )\r\n }\r\n }\r\n const reqWithSignal = new Request(request, {\r\n signal: combinedSignal,\r\n })\r\n try {\r\n const handler = init.fetchHandler ?? fetchHandler ?? fetch\r\n const response = await handler(reqWithSignal)\r\n lastResponse = response\r\n if (\r\n breaker &&\r\n (response.status >= 500 || response.status === 429)\r\n ) {\r\n breaker.recordResult(response, undefined, request)\r\n }\r\n return response\r\n } catch (err) {\r\n if (breaker) breaker.recordResult(undefined, err, request)\r\n if (err instanceof DOMException && err.name === 'AbortError') {\r\n if (\r\n timeoutSignal?.aborted &&\r\n (!userSignal || !userSignal.aborted)\r\n ) {\r\n effectiveHooks.onTimeout?.(request)\r\n throw new TimeoutError('signal timed out', err)\r\n } else if (userSignal?.aborted) {\r\n effectiveHooks.onAbort?.(request)\r\n throw new AbortError('Request was aborted by user')\r\n } else {\r\n throw new AbortError(\r\n 'Request was aborted',\r\n new DOMException('Aborted', 'AbortError')\r\n )\r\n }\r\n } else if (\r\n err instanceof TypeError &&\r\n /NetworkError|network error|failed to fetch|lost connection|NetworkError when attempting to fetch resource/i.test(\r\n err.message\r\n )\r\n ) {\r\n throw new NetworkError(err.message, err)\r\n }\r\n throw err\r\n }\r\n },\r\n effectiveRetries,\r\n effectiveRetryDelay,\r\n shouldRetryWithHook,\r\n request\r\n )\r\n if (effectiveHooks.transformResponse) {\r\n res = await effectiveHooks.transformResponse(res, request)\r\n }\r\n await effectiveHooks.after?.(request, res)\r\n await effectiveHooks.onComplete?.(request, res, undefined)\r\n if (\r\n effectiveThrowOnHttpError &&\r\n ((res.status >= 400 && res.status < 500 && res.status !== 429) ||\r\n res.status >= 500 ||\r\n res.status === 429)\r\n ) {\r\n const { HttpError } = await import('./error.js')\r\n throw new HttpError(\r\n `HTTP error: ${res.status} ${res.statusText}`,\r\n res\r\n )\r\n }\r\n return res\r\n } catch (err: unknown) {\r\n if (lastResponse) {\r\n const resp = lastResponse as Response\r\n if (\r\n effectiveThrowOnHttpError &&\r\n ((resp.status >= 400 && resp.status < 500 && resp.status !== 429) ||\r\n resp.status >= 500 ||\r\n resp.status === 429)\r\n ) {\r\n const { HttpError } = await import('./error.js')\r\n throw new HttpError(\r\n `HTTP error: ${resp.status} ${resp.statusText}`,\r\n resp\r\n )\r\n }\r\n return resp\r\n }\r\n if (err instanceof TimeoutError) {\r\n await effectiveHooks.onTimeout?.(request)\r\n await effectiveHooks.onError?.(request, err)\r\n await effectiveHooks.onComplete?.(request, undefined, err)\r\n throw err\r\n }\r\n if (err instanceof AbortError) {\r\n await effectiveHooks.onAbort?.(request)\r\n await effectiveHooks.onError?.(request, err)\r\n await effectiveHooks.onComplete?.(request, undefined, err)\r\n throw err\r\n }\r\n if (err instanceof NetworkError) {\r\n await effectiveHooks.onError?.(request, err)\r\n await effectiveHooks.onComplete?.(request, undefined, err)\r\n throw err\r\n }\r\n const retryErr = new RetryLimitError(\r\n typeof err === 'object' &&\r\n err &&\r\n 'message' in err &&\r\n typeof (err as { message?: unknown }).message === 'string'\r\n ? (err as { message: string }).message\r\n : 'Retry limit reached',\r\n err\r\n )\r\n await effectiveHooks.onError?.(request, retryErr)\r\n await effectiveHooks.onComplete?.(request, undefined, retryErr)\r\n throw retryErr\r\n }\r\n }\r\n\r\n const actualPromise = breaker\r\n ? breaker.invoke(retryWithHooks).catch(async (err: unknown) => {\r\n if (err instanceof CircuitOpenError) {\r\n await effectiveHooks.onCircuitOpen?.(request)\r\n await effectiveHooks.onError?.(request, err)\r\n await effectiveHooks.onComplete?.(request, undefined, err)\r\n } else {\r\n await effectiveHooks.onError?.(request, err)\r\n await effectiveHooks.onComplete?.(request, undefined, err)\r\n }\r\n throw err\r\n })\r\n : retryWithHooks()\r\n\r\n // If deduplication is enabled and dedupeKey is set, resolve/reject the in-flight promise\r\n if (effectiveDedupe && dedupeKey && dedupeMap.has(dedupeKey)) {\r\n const entry = dedupeMap.get(dedupeKey)\r\n if (entry) {\r\n actualPromise.then(\r\n (result) => entry.resolve(result),\r\n (error) => entry.reject(error)\r\n )\r\n // Replace the placeholder with the actual promise for future requests\r\n dedupeMap.set(dedupeKey, {\r\n promise: actualPromise,\r\n resolve: entry.resolve,\r\n reject: entry.reject,\r\n })\r\n }\r\n }\r\n\r\n const pendingEntry: PendingRequest = {\r\n promise: actualPromise,\r\n request,\r\n controller,\r\n }\r\n pendingRequests.push(pendingEntry)\r\n\r\n return actualPromise.finally(() => {\r\n const index = pendingRequests.indexOf(pendingEntry)\r\n if (index > -1) {\r\n pendingRequests.splice(index, 1)\r\n }\r\n // Only delete dedupeMap entry if the promise is the same as the one in the map\r\n if (\r\n effectiveDedupe &&\r\n dedupeKey &&\r\n dedupeMap.get(dedupeKey)?.promise === actualPromise\r\n ) {\r\n dedupeMap.delete(dedupeKey)\r\n }\r\n })\r\n }\r\n\r\n Object.defineProperty(client, 'pendingRequests', {\r\n get() {\r\n return pendingRequests\r\n },\r\n enumerable: false,\r\n configurable: false,\r\n })\r\n\r\n Object.defineProperty(client, 'abortAll', {\r\n value: abortAll,\r\n writable: false,\r\n enumerable: false,\r\n configurable: false,\r\n })\r\n\r\n Object.defineProperty(client, 'circuitOpen', {\r\n get() {\r\n return breaker ? breaker.open : false\r\n },\r\n enumerable: true,\r\n })\r\n\r\n return client as FFetch\r\n}\r\n","export type { FFetch, FFetchOptions } from './types'\nexport type { DedupeHashParams } from './dedupeRequestHash'\nexport type { Hooks } from './hooks'\n\nimport { createClient } from './client'\nexport { createClient } from './client'\n\nexport {\n TimeoutError,\n CircuitOpenError,\n AbortError,\n RetryLimitError,\n NetworkError,\n} from './error'\n\nexport default createClient\n"],"mappings":"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","names":["shouldRetry","controller"]}
|
|
1
|
+
{"version":3,"sources":["../src/retry.ts","../src/should-retry.ts","../src/client.ts"],"sourcesContent":["import type { RetryContext } from './types.js'\n\nexport type RetryDelay = number | ((ctx: RetryContext) => number)\n\nexport const defaultDelay: RetryDelay = (ctx) => {\n const retryAfter = ctx.response?.headers.get('Retry-After')\n if (retryAfter) {\n const seconds = parseInt(retryAfter, 10)\n if (!isNaN(seconds)) return seconds * 1000\n const date = Date.parse(retryAfter)\n if (!isNaN(date)) return Math.max(0, date - Date.now())\n }\n return 2 ** ctx.attempt * 200 + Math.random() * 100\n}\n\nexport async function retry(\n fn: () => Promise<Response>,\n retries: number,\n delay: RetryDelay,\n shouldRetry: (ctx: RetryContext) => boolean = () => true,\n request: Request\n): Promise<Response> {\n let lastErr: unknown\n let lastRes: Response | undefined\n\n for (let i = 0; i <= retries; i++) {\n const ctx: RetryContext = {\n attempt: i + 1,\n request,\n response: lastRes,\n error: lastErr,\n }\n try {\n lastRes = await fn()\n ctx.response = lastRes\n ctx.error = undefined\n if (i < retries && shouldRetry(ctx)) {\n const wait = typeof delay === 'function' ? delay(ctx) : delay\n await new Promise((r) => setTimeout(r, wait))\n continue\n }\n return lastRes\n } catch (err) {\n lastErr = err\n ctx.error = err\n if (i === retries || !shouldRetry(ctx)) throw err\n const wait = typeof delay === 'function' ? delay(ctx) : delay\n await new Promise((r) => setTimeout(r, wait))\n }\n }\n throw lastErr\n}\n","import { AbortError, CircuitOpenError, TimeoutError } from './error.js'\nimport type { RetryContext } from './types.js'\n\nexport function shouldRetry(ctx: RetryContext): boolean {\n const { error, response } = ctx\n if (\n error instanceof AbortError ||\n error instanceof CircuitOpenError ||\n error instanceof TimeoutError\n )\n return false\n if (!response) return true // network error\n return response.status >= 500 || response.status === 429\n}\n","import type {\r\n FFetchOptions,\r\n FFetch,\r\n FFetchRequestInit,\r\n PendingRequest,\r\n} from './types.js'\r\nimport { retry, defaultDelay } from './retry.js'\r\nimport { shouldRetry as defaultShouldRetry } from './should-retry.js'\r\nimport {\r\n type PluginDispatch,\r\n type PluginRequestContext,\r\n type PluginExtensions,\r\n type ClientPlugin,\r\n type PluginExtensionBase,\r\n} from './plugins.js'\r\nimport {\r\n TimeoutError,\r\n AbortError,\r\n RetryLimitError,\r\n NetworkError,\r\n} from './error.js'\r\n\r\nexport function createClient<\r\n TPlugins extends\r\n readonly ClientPlugin<PluginExtensionBase>[] = readonly ClientPlugin<PluginExtensionBase>[],\r\n>(\r\n opts: FFetchOptions<TPlugins> = {} as FFetchOptions<TPlugins>\r\n): FFetch<PluginExtensions<TPlugins>> {\r\n const {\r\n timeout: clientDefaultTimeout = 5_000,\r\n retries: clientDefaultRetries = 0,\r\n retryDelay: clientDefaultRetryDelay = defaultDelay,\r\n shouldRetry: clientDefaultShouldRetry = defaultShouldRetry,\r\n hooks: clientDefaultHooks = {},\r\n fetchHandler,\r\n plugins: inputPlugins = [] as unknown as TPlugins,\r\n } = opts\r\n\r\n const extensionDescriptors: PropertyDescriptorMap = Object.create(null)\r\n\r\n const plugins = inputPlugins\r\n .map((plugin, index) => ({ plugin, index }))\r\n .sort((a, b) => {\r\n const aOrder = a.plugin.order ?? 0\r\n const bOrder = b.plugin.order ?? 0\r\n if (aOrder !== bOrder) return aOrder - bOrder\r\n return a.index - b.index\r\n })\r\n .map((entry) => entry.plugin)\r\n\r\n for (const plugin of plugins) {\r\n plugin.setup?.({\r\n defineExtension: (key, descriptor) => {\r\n const propertyKey = key as PropertyKey\r\n if (propertyKey in extensionDescriptors) {\r\n throw new Error(\r\n `Plugin extension collision for property \"${String(propertyKey)}\"`\r\n )\r\n }\r\n if ('get' in descriptor) {\r\n extensionDescriptors[propertyKey] = {\r\n get: descriptor.get,\r\n enumerable: descriptor.enumerable ?? true,\r\n configurable: false,\r\n }\r\n return\r\n }\r\n extensionDescriptors[propertyKey] = {\r\n value: descriptor.value,\r\n writable: false,\r\n enumerable: descriptor.enumerable ?? true,\r\n configurable: false,\r\n }\r\n },\r\n })\r\n }\r\n\r\n const pendingRequests: PendingRequest[] = []\r\n\r\n // Helper to abort all pending requests\r\n function abortAll() {\r\n for (const entry of pendingRequests) {\r\n entry.controller?.abort()\r\n }\r\n }\r\n\r\n const client = async (\r\n input: RequestInfo | URL,\r\n init: FFetchRequestInit = {}\r\n ) => {\r\n let request = new Request(input, init)\r\n\r\n // Merge hooks: per-request hooks override client hooks, but fallback to client hooks\r\n const effectiveHooks = { ...clientDefaultHooks, ...(init.hooks || {}) }\r\n if (effectiveHooks.transformRequest) {\r\n request = await effectiveHooks.transformRequest(request)\r\n }\r\n await effectiveHooks.before?.(request)\r\n\r\n // Determine retry config (per-request overrides client default)\r\n const effectiveRetries = init.retries ?? clientDefaultRetries\r\n const effectiveRetryDelay =\r\n typeof init.retryDelay !== 'undefined'\r\n ? init.retryDelay\r\n : clientDefaultRetryDelay\r\n const effectiveShouldRetry = init.shouldRetry ?? clientDefaultShouldRetry\r\n\r\n // AbortSignal.timeout/any logic\r\n const effectiveTimeout = init.timeout ?? clientDefaultTimeout\r\n const userSignal = init.signal\r\n const transformedSignal = request.signal\r\n\r\n const pluginContext: PluginRequestContext = {\r\n request,\r\n init,\r\n state: Object.create(null),\r\n metadata: {\r\n startedAt: Date.now(),\r\n timeoutMs: effectiveTimeout,\r\n signals: {\r\n user:\r\n userSignal === undefined || userSignal === null\r\n ? undefined\r\n : userSignal,\r\n transformed: transformedSignal,\r\n },\r\n retry: {\r\n configuredRetries: effectiveRetries,\r\n configuredDelay: effectiveRetryDelay,\r\n attempt: 0,\r\n },\r\n },\r\n }\r\n\r\n for (const plugin of plugins) {\r\n await plugin.preRequest?.(pluginContext)\r\n }\r\n\r\n // Determine throwOnHttpError (per-request overrides client default)\r\n const effectiveThrowOnHttpError =\r\n typeof init.throwOnHttpError !== 'undefined'\r\n ? init.throwOnHttpError\r\n : (opts.throwOnHttpError ?? false)\r\n\r\n // Create timeout signal (manual implementation if AbortSignal.timeout not available)\r\n function createTimeoutSignal(timeout: number): AbortSignal {\r\n if (typeof AbortSignal?.timeout === 'function') {\r\n return AbortSignal.timeout(timeout)\r\n }\r\n const controller = new AbortController()\r\n const timeoutId = setTimeout(() => controller.abort(), timeout)\r\n controller.signal.addEventListener(\r\n 'abort',\r\n () => clearTimeout(timeoutId),\r\n { once: true }\r\n )\r\n return controller.signal\r\n }\r\n\r\n let timeoutSignal: AbortSignal | undefined = undefined\r\n let combinedSignal: AbortSignal | undefined = undefined\r\n let controller: AbortController | undefined = undefined\r\n\r\n if (effectiveTimeout > 0) {\r\n timeoutSignal = createTimeoutSignal(effectiveTimeout)\r\n pluginContext.metadata.signals.timeout = timeoutSignal\r\n }\r\n\r\n const signals: AbortSignal[] = []\r\n if (userSignal) signals.push(userSignal)\r\n if (transformedSignal && transformedSignal !== userSignal) {\r\n signals.push(transformedSignal)\r\n }\r\n if (timeoutSignal) signals.push(timeoutSignal)\r\n\r\n if (signals.length === 1) {\r\n combinedSignal = signals[0]\r\n controller = new AbortController()\r\n } else {\r\n if (typeof AbortSignal.any !== 'function') {\r\n throw new Error(\r\n 'AbortSignal.any is required for combining multiple signals. Please install a polyfill for environments that do not support it.'\r\n )\r\n }\r\n combinedSignal = AbortSignal.any(signals)\r\n controller = new AbortController()\r\n }\r\n pluginContext.metadata.signals.combined = combinedSignal\r\n\r\n const retryWithHooks = async () => {\r\n let attempt = 0\r\n const shouldRetryWithHook = (ctx: import('./types').RetryContext) => {\r\n attempt = ctx.attempt\r\n pluginContext.metadata.retry.attempt = attempt\r\n pluginContext.metadata.retry.lastError = ctx.error\r\n pluginContext.metadata.retry.lastResponse = ctx.response\r\n const retrying = effectiveShouldRetry(ctx)\r\n pluginContext.metadata.retry.shouldRetryResult = retrying\r\n if (retrying && attempt <= effectiveRetries) {\r\n effectiveHooks.onRetry?.(\r\n request,\r\n attempt - 1,\r\n ctx.error,\r\n ctx.response\r\n )\r\n }\r\n return retrying\r\n }\r\n\r\n let lastResponse: Response | undefined = undefined\r\n try {\r\n let res = await retry(\r\n async () => {\r\n if (userSignal?.aborted) {\r\n effectiveHooks.onAbort?.(request)\r\n throw new AbortError('Request was aborted by user')\r\n }\r\n if (timeoutSignal?.aborted) {\r\n effectiveHooks.onTimeout?.(request)\r\n throw new TimeoutError('signal timed out')\r\n }\r\n if (typeof combinedSignal?.throwIfAborted === 'function') {\r\n combinedSignal.throwIfAborted()\r\n } else if (combinedSignal?.aborted) {\r\n if (userSignal?.aborted) {\r\n effectiveHooks.onAbort?.(request)\r\n throw new AbortError('Request was aborted by user')\r\n } else if (timeoutSignal?.aborted) {\r\n effectiveHooks.onTimeout?.(request)\r\n throw new TimeoutError('signal timed out')\r\n } else {\r\n throw new AbortError(\r\n 'Request was aborted',\r\n new DOMException('Aborted', 'AbortError')\r\n )\r\n }\r\n }\r\n const reqWithSignal = new Request(request, {\r\n signal: combinedSignal,\r\n })\r\n try {\r\n const handler = init.fetchHandler ?? fetchHandler ?? fetch\r\n const response = await handler(reqWithSignal)\r\n lastResponse = response\r\n pluginContext.metadata.retry.lastResponse = response\r\n return response\r\n } catch (err) {\r\n pluginContext.metadata.retry.lastError = err\r\n if (err instanceof DOMException && err.name === 'AbortError') {\r\n if (\r\n timeoutSignal?.aborted &&\r\n (!userSignal || !userSignal.aborted)\r\n ) {\r\n effectiveHooks.onTimeout?.(request)\r\n throw new TimeoutError('signal timed out', err)\r\n } else if (userSignal?.aborted) {\r\n effectiveHooks.onAbort?.(request)\r\n throw new AbortError('Request was aborted by user')\r\n } else {\r\n throw new AbortError(\r\n 'Request was aborted',\r\n new DOMException('Aborted', 'AbortError')\r\n )\r\n }\r\n } else if (\r\n err instanceof TypeError &&\r\n /NetworkError|network error|failed to fetch|lost connection|NetworkError when attempting to fetch resource/i.test(\r\n err.message\r\n )\r\n ) {\r\n throw new NetworkError(err.message, err)\r\n }\r\n throw err\r\n }\r\n },\r\n effectiveRetries,\r\n effectiveRetryDelay,\r\n shouldRetryWithHook,\r\n request\r\n )\r\n if (effectiveHooks.transformResponse) {\r\n res = await effectiveHooks.transformResponse(res, request)\r\n }\r\n await effectiveHooks.after?.(request, res)\r\n await effectiveHooks.onComplete?.(request, res, undefined)\r\n if (\r\n effectiveThrowOnHttpError &&\r\n ((res.status >= 400 && res.status < 500 && res.status !== 429) ||\r\n res.status >= 500 ||\r\n res.status === 429)\r\n ) {\r\n const { HttpError } = await import('./error.js')\r\n throw new HttpError(\r\n `HTTP error: ${res.status} ${res.statusText}`,\r\n res\r\n )\r\n }\r\n return res\r\n } catch (err: unknown) {\r\n pluginContext.metadata.retry.lastError = err\r\n if (lastResponse) {\r\n const resp = lastResponse as Response\r\n if (\r\n effectiveThrowOnHttpError &&\r\n ((resp.status >= 400 && resp.status < 500 && resp.status !== 429) ||\r\n resp.status >= 500 ||\r\n resp.status === 429)\r\n ) {\r\n const { HttpError } = await import('./error.js')\r\n throw new HttpError(\r\n `HTTP error: ${resp.status} ${resp.statusText}`,\r\n resp\r\n )\r\n }\r\n return resp\r\n }\r\n if (err instanceof TimeoutError) {\r\n await effectiveHooks.onTimeout?.(request)\r\n await effectiveHooks.onError?.(request, err)\r\n await effectiveHooks.onComplete?.(request, undefined, err)\r\n throw err\r\n }\r\n if (err instanceof AbortError) {\r\n await effectiveHooks.onAbort?.(request)\r\n await effectiveHooks.onError?.(request, err)\r\n await effectiveHooks.onComplete?.(request, undefined, err)\r\n throw err\r\n }\r\n if (err instanceof NetworkError) {\r\n await effectiveHooks.onError?.(request, err)\r\n await effectiveHooks.onComplete?.(request, undefined, err)\r\n throw err\r\n }\r\n const retryErr = new RetryLimitError(\r\n typeof err === 'object' &&\r\n err &&\r\n 'message' in err &&\r\n typeof (err as { message?: unknown }).message === 'string'\r\n ? (err as { message: string }).message\r\n : 'Retry limit reached',\r\n err\r\n )\r\n await effectiveHooks.onError?.(request, retryErr)\r\n await effectiveHooks.onComplete?.(request, undefined, retryErr)\r\n throw retryErr\r\n }\r\n }\r\n\r\n const baseDispatch: PluginDispatch = async () => retryWithHooks()\r\n\r\n let dispatch = baseDispatch\r\n for (let i = plugins.length - 1; i >= 0; i--) {\r\n const plugin = plugins[i]\r\n if (plugin.wrapDispatch) {\r\n dispatch = plugin.wrapDispatch(dispatch)\r\n }\r\n }\r\n\r\n const actualPromise = dispatch(pluginContext)\r\n .then(async (response) => {\r\n for (const plugin of plugins) {\r\n await plugin.onSuccess?.(pluginContext, response)\r\n }\r\n return response\r\n })\r\n .catch(async (err: unknown) => {\r\n for (const plugin of plugins) {\r\n await plugin.onError?.(pluginContext, err)\r\n }\r\n throw err\r\n })\r\n\r\n const pendingEntry: PendingRequest = {\r\n promise: actualPromise,\r\n request,\r\n controller,\r\n }\r\n pendingRequests.push(pendingEntry)\r\n\r\n return actualPromise.finally(async () => {\r\n for (const plugin of plugins) {\r\n await plugin.onFinally?.(pluginContext)\r\n }\r\n\r\n const index = pendingRequests.indexOf(pendingEntry)\r\n if (index > -1) {\r\n pendingRequests.splice(index, 1)\r\n }\r\n })\r\n }\r\n\r\n Object.defineProperty(client, 'pendingRequests', {\r\n get() {\r\n return pendingRequests\r\n },\r\n enumerable: false,\r\n configurable: false,\r\n })\r\n\r\n Object.defineProperty(client, 'abortAll', {\r\n value: abortAll,\r\n writable: false,\r\n enumerable: false,\r\n configurable: false,\r\n })\r\n\r\n Object.defineProperties(client, extensionDescriptors)\r\n\r\n return client as FFetch<PluginExtensions<TPlugins>>\r\n}\r\n"],"mappings":"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","names":["shouldRetry","controller"]}
|