undici 6.9.0 → 6.10.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/docs/docs/api/RetryHandler.md +6 -0
- package/lib/handler/retry-handler.js +17 -10
- package/lib/web/fetch/formdata.js +20 -5
- package/lib/web/fetch/headers.js +2 -8
- package/lib/web/fetch/request.js +3 -1
- package/lib/web/fetch/response.js +3 -1
- package/package.json +1 -1
- package/types/dispatcher.d.ts +5 -0
- package/types/retry-handler.d.ts +1 -1
|
@@ -35,6 +35,12 @@ Extends: [`Dispatch.DispatchOptions`](Dispatcher.md#parameter-dispatchoptions).
|
|
|
35
35
|
- `state`: `RetryState` - Current retry state. It can be mutated.
|
|
36
36
|
- `opts`: `Dispatch.DispatchOptions & RetryOptions` - Options passed to the retry handler.
|
|
37
37
|
|
|
38
|
+
**`RetryState`**
|
|
39
|
+
|
|
40
|
+
It represents the retry state for a given request.
|
|
41
|
+
|
|
42
|
+
- `counter`: `number` - Current retry attempt.
|
|
43
|
+
|
|
38
44
|
### Parameter `RetryHandlers`
|
|
39
45
|
|
|
40
46
|
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandlers) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every retry.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use strict'
|
|
1
2
|
const assert = require('node:assert')
|
|
2
3
|
|
|
3
4
|
const { kRetryHandlerDefaultRetry } = require('../core/symbols')
|
|
@@ -37,7 +38,7 @@ class RetryHandler {
|
|
|
37
38
|
retry: retryFn ?? RetryHandler[kRetryHandlerDefaultRetry],
|
|
38
39
|
retryAfter: retryAfter ?? true,
|
|
39
40
|
maxTimeout: maxTimeout ?? 30 * 1000, // 30s,
|
|
40
|
-
|
|
41
|
+
minTimeout: minTimeout ?? 500, // .5s
|
|
41
42
|
timeoutFactor: timeoutFactor ?? 2,
|
|
42
43
|
maxRetries: maxRetries ?? 5,
|
|
43
44
|
// What errors we should retry
|
|
@@ -59,6 +60,7 @@ class RetryHandler {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
this.retryCount = 0
|
|
63
|
+
this.retryCountCheckpoint = 0
|
|
62
64
|
this.start = 0
|
|
63
65
|
this.end = null
|
|
64
66
|
this.etag = null
|
|
@@ -104,17 +106,14 @@ class RetryHandler {
|
|
|
104
106
|
const { method, retryOptions } = opts
|
|
105
107
|
const {
|
|
106
108
|
maxRetries,
|
|
107
|
-
|
|
109
|
+
minTimeout,
|
|
108
110
|
maxTimeout,
|
|
109
111
|
timeoutFactor,
|
|
110
112
|
statusCodes,
|
|
111
113
|
errorCodes,
|
|
112
114
|
methods
|
|
113
115
|
} = retryOptions
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
currentTimeout =
|
|
117
|
-
currentTimeout != null && currentTimeout > 0 ? currentTimeout : timeout
|
|
116
|
+
const { counter } = state
|
|
118
117
|
|
|
119
118
|
// Any code that is not a Undici's originated and allowed to retry
|
|
120
119
|
if (
|
|
@@ -159,9 +158,7 @@ class RetryHandler {
|
|
|
159
158
|
const retryTimeout =
|
|
160
159
|
retryAfterHeader > 0
|
|
161
160
|
? Math.min(retryAfterHeader, maxTimeout)
|
|
162
|
-
: Math.min(
|
|
163
|
-
|
|
164
|
-
state.currentTimeout = retryTimeout
|
|
161
|
+
: Math.min(minTimeout * timeoutFactor ** (counter - 1), maxTimeout)
|
|
165
162
|
|
|
166
163
|
setTimeout(() => cb(null), retryTimeout)
|
|
167
164
|
}
|
|
@@ -309,10 +306,19 @@ class RetryHandler {
|
|
|
309
306
|
return this.handler.onError(err)
|
|
310
307
|
}
|
|
311
308
|
|
|
309
|
+
// We reconcile in case of a mix between network errors
|
|
310
|
+
// and server error response
|
|
311
|
+
if (this.retryCount - this.retryCountCheckpoint > 0) {
|
|
312
|
+
// We count the difference between the last checkpoint and the current retry count
|
|
313
|
+
this.retryCount = this.retryCountCheckpoint + (this.retryCount - this.retryCountCheckpoint)
|
|
314
|
+
} else {
|
|
315
|
+
this.retryCount += 1
|
|
316
|
+
}
|
|
317
|
+
|
|
312
318
|
this.retryOpts.retry(
|
|
313
319
|
err,
|
|
314
320
|
{
|
|
315
|
-
state: { counter: this.retryCount
|
|
321
|
+
state: { counter: this.retryCount },
|
|
316
322
|
opts: { retryOptions: this.retryOpts, ...this.opts }
|
|
317
323
|
},
|
|
318
324
|
onRetry.bind(this)
|
|
@@ -334,6 +340,7 @@ class RetryHandler {
|
|
|
334
340
|
}
|
|
335
341
|
|
|
336
342
|
try {
|
|
343
|
+
this.retryCountCheckpoint = this.retryCount
|
|
337
344
|
this.dispatch(this.opts, this)
|
|
338
345
|
} catch (err) {
|
|
339
346
|
this.handler.onError(err)
|
|
@@ -157,12 +157,27 @@ class FormData {
|
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
[nodeUtil.inspect.custom] (depth, options) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
160
|
+
const state = this[kState].reduce((a, b) => {
|
|
161
|
+
if (a[b.name]) {
|
|
162
|
+
if (Array.isArray(a[b.name])) {
|
|
163
|
+
a[b.name].push(b.value)
|
|
164
|
+
} else {
|
|
165
|
+
a[b.name] = [a[b.name], b.value]
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
a[b.name] = b.value
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return a
|
|
172
|
+
}, { __proto__: null })
|
|
173
|
+
|
|
174
|
+
options.depth ??= depth
|
|
175
|
+
options.colors ??= true
|
|
176
|
+
|
|
177
|
+
const output = nodeUtil.formatWithOptions(options, state)
|
|
164
178
|
|
|
165
|
-
|
|
179
|
+
// remove [Object null prototype]
|
|
180
|
+
return `FormData ${output.slice(output.indexOf(']') + 2)}`
|
|
166
181
|
}
|
|
167
182
|
}
|
|
168
183
|
|
package/lib/web/fetch/headers.js
CHANGED
|
@@ -572,16 +572,10 @@ class Headers {
|
|
|
572
572
|
return (this[kHeadersList][kHeadersSortedMap] = headers)
|
|
573
573
|
}
|
|
574
574
|
|
|
575
|
-
[Symbol.for('nodejs.util.inspect.custom')] () {
|
|
576
|
-
webidl.brandCheck(this, Headers)
|
|
577
|
-
|
|
578
|
-
return this[kHeadersList]
|
|
579
|
-
}
|
|
580
|
-
|
|
581
575
|
[util.inspect.custom] (depth, options) {
|
|
582
|
-
|
|
576
|
+
options.depth ??= depth
|
|
583
577
|
|
|
584
|
-
return `Headers ${
|
|
578
|
+
return `Headers ${util.formatWithOptions(options, this[kHeadersList].entries)}`
|
|
585
579
|
}
|
|
586
580
|
}
|
|
587
581
|
|
package/lib/web/fetch/request.js
CHANGED
|
@@ -778,6 +778,8 @@ class Request {
|
|
|
778
778
|
options.depth = 2
|
|
779
779
|
}
|
|
780
780
|
|
|
781
|
+
options.colors ??= true
|
|
782
|
+
|
|
781
783
|
const properties = {
|
|
782
784
|
method: this.method,
|
|
783
785
|
url: this.url,
|
|
@@ -796,7 +798,7 @@ class Request {
|
|
|
796
798
|
signal: this.signal
|
|
797
799
|
}
|
|
798
800
|
|
|
799
|
-
return nodeUtil.formatWithOptions(options,
|
|
801
|
+
return `Request ${nodeUtil.formatWithOptions(options, properties)}`
|
|
800
802
|
}
|
|
801
803
|
}
|
|
802
804
|
|
|
@@ -259,6 +259,8 @@ class Response {
|
|
|
259
259
|
options.depth = 2
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
options.colors ??= true
|
|
263
|
+
|
|
262
264
|
const properties = {
|
|
263
265
|
status: this.status,
|
|
264
266
|
statusText: this.statusText,
|
|
@@ -271,7 +273,7 @@ class Response {
|
|
|
271
273
|
url: this.url
|
|
272
274
|
}
|
|
273
275
|
|
|
274
|
-
return
|
|
276
|
+
return `Response ${nodeUtil.formatWithOptions(options, properties)}`
|
|
275
277
|
}
|
|
276
278
|
}
|
|
277
279
|
|
package/package.json
CHANGED
package/types/dispatcher.d.ts
CHANGED
|
@@ -18,6 +18,9 @@ declare class Dispatcher extends EventEmitter {
|
|
|
18
18
|
/** Starts two-way communications with the requested resource. */
|
|
19
19
|
connect(options: Dispatcher.ConnectOptions): Promise<Dispatcher.ConnectData>;
|
|
20
20
|
connect(options: Dispatcher.ConnectOptions, callback: (err: Error | null, data: Dispatcher.ConnectData) => void): void;
|
|
21
|
+
/** Compose a chain of dispatchers */
|
|
22
|
+
compose(dispatchers: Dispatcher['dispatch'][]): Dispatcher.ComposedDispatcher;
|
|
23
|
+
compose(...dispatchers: Dispatcher['dispatch'][]): Dispatcher.ComposedDispatcher;
|
|
21
24
|
/** Performs an HTTP request. */
|
|
22
25
|
request(options: Dispatcher.RequestOptions): Promise<Dispatcher.ResponseData>;
|
|
23
26
|
request(options: Dispatcher.RequestOptions, callback: (err: Error | null, data: Dispatcher.ResponseData) => void): void;
|
|
@@ -93,6 +96,8 @@ declare class Dispatcher extends EventEmitter {
|
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
declare namespace Dispatcher {
|
|
99
|
+
export interface ComposedDispatcher extends Dispatcher {}
|
|
100
|
+
export type DispatcherInterceptor = (dispatch: Dispatcher['dispatch']) => Dispatcher['dispatch'];
|
|
96
101
|
export interface DispatchOptions {
|
|
97
102
|
origin?: string | URL;
|
|
98
103
|
path: string;
|
package/types/retry-handler.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ declare class RetryHandler implements Dispatcher.DispatchHandlers {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
declare namespace RetryHandler {
|
|
15
|
-
export type RetryState = { counter: number;
|
|
15
|
+
export type RetryState = { counter: number; };
|
|
16
16
|
|
|
17
17
|
export type RetryContext = {
|
|
18
18
|
state: RetryState;
|