undici 6.6.2 → 6.7.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.
Files changed (114) hide show
  1. package/{README.md → docs/README.md} +19 -15
  2. package/docs/{api → docs/api}/Dispatcher.md +39 -3
  3. package/docs/docs/api/Fetch.md +57 -0
  4. package/docs/{api → docs/api}/ProxyAgent.md +3 -1
  5. package/docs/docs/api/RetryAgent.md +45 -0
  6. package/docs/{api → docs/api}/RetryHandler.md +1 -1
  7. package/docs/{api → docs/api}/api-lifecycle.md +33 -4
  8. package/docs/{best-practices → docs/best-practices}/proxy.md +6 -6
  9. package/index-fetch.js +9 -8
  10. package/index.js +31 -25
  11. package/lib/core/request.js +72 -135
  12. package/lib/core/symbols.js +6 -5
  13. package/lib/core/tree.js +46 -26
  14. package/lib/core/util.js +41 -20
  15. package/lib/{agent.js → dispatcher/agent.js} +4 -4
  16. package/lib/{balanced-pool.js → dispatcher/balanced-pool.js} +3 -3
  17. package/lib/dispatcher/client-h1.js +1339 -0
  18. package/lib/dispatcher/client-h2.js +639 -0
  19. package/lib/dispatcher/client.js +611 -0
  20. package/lib/{dispatcher-base.js → dispatcher/dispatcher-base.js} +2 -2
  21. package/lib/{pool-base.js → dispatcher/pool-base.js} +3 -3
  22. package/lib/{pool-stats.js → dispatcher/pool-stats.js} +1 -1
  23. package/lib/{pool.js → dispatcher/pool.js} +4 -4
  24. package/lib/{proxy-agent.js → dispatcher/proxy-agent.js} +29 -35
  25. package/lib/dispatcher/retry-agent.js +35 -0
  26. package/lib/global.js +1 -1
  27. package/lib/handler/{RetryHandler.js → retry-handler.js} +2 -2
  28. package/lib/interceptor/{redirectInterceptor.js → redirect-interceptor.js} +1 -1
  29. package/lib/mock/mock-agent.js +2 -2
  30. package/lib/mock/mock-client.js +1 -1
  31. package/lib/mock/mock-interceptor.js +2 -2
  32. package/lib/mock/mock-pool.js +1 -1
  33. package/lib/mock/mock-utils.js +6 -4
  34. package/lib/{cache → web/cache}/cache.js +2 -4
  35. package/lib/{cache → web/cache}/cachestorage.js +1 -1
  36. package/lib/web/cache/symbols.js +5 -0
  37. package/lib/{cache → web/cache}/util.js +5 -9
  38. package/lib/{cookies → web/cookies}/parse.js +1 -1
  39. package/lib/{cookies → web/cookies}/util.js +76 -60
  40. package/lib/{eventsource → web/eventsource}/eventsource.js +2 -6
  41. package/lib/{fetch → web/fetch}/body.js +23 -52
  42. package/lib/{fetch/dataURL.js → web/fetch/data-url.js} +2 -0
  43. package/lib/{compat → web/fetch}/dispatcher-weakref.js +1 -1
  44. package/lib/{fetch → web/fetch}/file.js +2 -2
  45. package/lib/{fetch → web/fetch}/formdata.js +6 -67
  46. package/lib/{fetch → web/fetch}/headers.js +99 -71
  47. package/lib/{fetch → web/fetch}/index.js +33 -25
  48. package/lib/{fetch → web/fetch}/request.js +14 -6
  49. package/lib/{fetch → web/fetch}/response.js +3 -3
  50. package/lib/{fetch → web/fetch}/symbols.js +2 -1
  51. package/lib/{fetch → web/fetch}/util.js +142 -48
  52. package/lib/{fetch → web/fetch}/webidl.js +46 -16
  53. package/lib/{fileapi → web/fileapi}/filereader.js +1 -1
  54. package/lib/{fileapi → web/fileapi}/util.js +1 -1
  55. package/lib/{websocket → web/websocket}/connection.js +20 -10
  56. package/lib/{websocket → web/websocket}/constants.js +7 -0
  57. package/lib/{websocket → web/websocket}/events.js +1 -1
  58. package/lib/{websocket → web/websocket}/frame.js +1 -0
  59. package/lib/{websocket → web/websocket}/receiver.js +9 -16
  60. package/lib/{websocket → web/websocket}/util.js +37 -23
  61. package/lib/{websocket → web/websocket}/websocket.js +21 -9
  62. package/package.json +26 -51
  63. package/types/dispatcher.d.ts +1 -1
  64. package/types/fetch.d.ts +20 -21
  65. package/types/index.d.ts +2 -1
  66. package/types/retry-agent.d.ts +11 -0
  67. package/types/webidl.d.ts +6 -1
  68. package/docs/api/Fetch.md +0 -27
  69. package/docs/assets/lifecycle-diagram.png +0 -0
  70. package/lib/cache/symbols.js +0 -5
  71. package/lib/client.js +0 -2295
  72. package/lib/llhttp/llhttp-wasm.js +0 -3
  73. package/lib/llhttp/llhttp.wasm +0 -0
  74. package/lib/llhttp/llhttp_simd.wasm +0 -0
  75. /package/docs/{api → docs/api}/Agent.md +0 -0
  76. /package/docs/{api → docs/api}/BalancedPool.md +0 -0
  77. /package/docs/{api → docs/api}/CacheStorage.md +0 -0
  78. /package/docs/{api → docs/api}/Client.md +0 -0
  79. /package/docs/{api → docs/api}/Connector.md +0 -0
  80. /package/docs/{api → docs/api}/ContentType.md +0 -0
  81. /package/docs/{api → docs/api}/Cookies.md +0 -0
  82. /package/docs/{api → docs/api}/Debug.md +0 -0
  83. /package/docs/{api → docs/api}/DiagnosticsChannel.md +0 -0
  84. /package/docs/{api → docs/api}/DispatchInterceptor.md +0 -0
  85. /package/docs/{api → docs/api}/Errors.md +0 -0
  86. /package/docs/{api → docs/api}/EventSource.md +0 -0
  87. /package/docs/{api → docs/api}/MockAgent.md +0 -0
  88. /package/docs/{api → docs/api}/MockClient.md +0 -0
  89. /package/docs/{api → docs/api}/MockErrors.md +0 -0
  90. /package/docs/{api → docs/api}/MockPool.md +0 -0
  91. /package/docs/{api → docs/api}/Pool.md +0 -0
  92. /package/docs/{api → docs/api}/PoolStats.md +0 -0
  93. /package/docs/{api → docs/api}/RedirectHandler.md +0 -0
  94. /package/docs/{api → docs/api}/Util.md +0 -0
  95. /package/docs/{api → docs/api}/WebSocket.md +0 -0
  96. /package/docs/{best-practices → docs/best-practices}/client-certificate.md +0 -0
  97. /package/docs/{best-practices → docs/best-practices}/mocking-request.md +0 -0
  98. /package/docs/{best-practices → docs/best-practices}/writing-tests.md +0 -0
  99. /package/lib/{dispatcher.js → dispatcher/dispatcher.js} +0 -0
  100. /package/lib/{node → dispatcher}/fixed-queue.js +0 -0
  101. /package/lib/handler/{DecoratorHandler.js → decorator-handler.js} +0 -0
  102. /package/lib/handler/{RedirectHandler.js → redirect-handler.js} +0 -0
  103. /package/lib/{timers.js → util/timers.js} +0 -0
  104. /package/lib/{cookies → web/cookies}/constants.js +0 -0
  105. /package/lib/{cookies → web/cookies}/index.js +0 -0
  106. /package/lib/{eventsource → web/eventsource}/eventsource-stream.js +0 -0
  107. /package/lib/{eventsource → web/eventsource}/util.js +0 -0
  108. /package/lib/{fetch → web/fetch}/LICENSE +0 -0
  109. /package/lib/{fetch → web/fetch}/constants.js +0 -0
  110. /package/lib/{fetch → web/fetch}/global.js +0 -0
  111. /package/lib/{fileapi → web/fileapi}/encoding.js +0 -0
  112. /package/lib/{fileapi → web/fileapi}/progressevent.js +0 -0
  113. /package/lib/{fileapi → web/fileapi}/symbols.js +0 -0
  114. /package/lib/{websocket → web/websocket}/symbols.js +0 -0
@@ -60,10 +60,14 @@ console.log('trailers', trailers)
60
60
 
61
61
  The `body` mixins are the most common way to format the request/response body. Mixins include:
62
62
 
63
- - [`.formData()`](https://fetch.spec.whatwg.org/#dom-body-formdata)
63
+ - [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
64
+ - [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
64
65
  - [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
65
66
  - [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
66
67
 
68
+ > [!NOTE]
69
+ > The body returned from `undici.request` does not implement `.formData()`.
70
+
67
71
  Example usage:
68
72
 
69
73
  ```js
@@ -90,14 +94,14 @@ For more information about their behavior, please reference the body mixin from
90
94
 
91
95
  ## Common API Methods
92
96
 
93
- This section documents our most commonly used API methods. Additional APIs are documented in their own files within the [docs](./docs/) folder and are accessible via the navigation list on the left side of the docs site.
97
+ This section documents our most commonly used API methods. Additional APIs are documented in their own files within the [documentation](./documentation/) folder and are accessible via the navigation list on the left side of the docs site.
94
98
 
95
99
  ### `undici.request([url, options]): Promise`
96
100
 
97
101
  Arguments:
98
102
 
99
103
  * **url** `string | URL | UrlObject`
100
- * **options** [`RequestOptions`](./docs/api/Dispatcher.md#parameter-requestoptions)
104
+ * **options** [`RequestOptions`](./documentation/docs/api/Dispatcher.md#parameter-requestoptions)
101
105
  * **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
102
106
  * **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
103
107
  * **maxRedirections** `Integer` - Default: `0`
@@ -106,14 +110,14 @@ Returns a promise with the result of the `Dispatcher.request` method.
106
110
 
107
111
  Calls `options.dispatcher.request(options)`.
108
112
 
109
- See [Dispatcher.request](./docs/api/Dispatcher.md#dispatcherrequestoptions-callback) for more details, and [request examples](./examples/README.md) for examples.
113
+ See [Dispatcher.request](./documentation/docs/api/Dispatcher.md#dispatcherrequestoptions-callback) for more details, and [request examples](./documentation/examples/README.md) for examples.
110
114
 
111
115
  ### `undici.stream([url, options, ]factory): Promise`
112
116
 
113
117
  Arguments:
114
118
 
115
119
  * **url** `string | URL | UrlObject`
116
- * **options** [`StreamOptions`](./docs/api/Dispatcher.md#parameter-streamoptions)
120
+ * **options** [`StreamOptions`](./documentation/docs/api/Dispatcher.md#parameter-streamoptions)
117
121
  * **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
118
122
  * **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
119
123
  * **maxRedirections** `Integer` - Default: `0`
@@ -123,14 +127,14 @@ Returns a promise with the result of the `Dispatcher.stream` method.
123
127
 
124
128
  Calls `options.dispatcher.stream(options, factory)`.
125
129
 
126
- See [Dispatcher.stream](docs/api/Dispatcher.md#dispatcherstreamoptions-factory-callback) for more details.
130
+ See [Dispatcher.stream](documentation/docs/api/Dispatcher.md#dispatcherstreamoptions-factory-callback) for more details.
127
131
 
128
132
  ### `undici.pipeline([url, options, ]handler): Duplex`
129
133
 
130
134
  Arguments:
131
135
 
132
136
  * **url** `string | URL | UrlObject`
133
- * **options** [`PipelineOptions`](docs/api/Dispatcher.md#parameter-pipelineoptions)
137
+ * **options** [`PipelineOptions`](documentation/docs/api/Dispatcher.md#parameter-pipelineoptions)
134
138
  * **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
135
139
  * **method** `String` - Default: `PUT` if `options.body`, otherwise `GET`
136
140
  * **maxRedirections** `Integer` - Default: `0`
@@ -140,7 +144,7 @@ Returns: `stream.Duplex`
140
144
 
141
145
  Calls `options.dispatch.pipeline(options, handler)`.
142
146
 
143
- See [Dispatcher.pipeline](docs/api/Dispatcher.md#dispatcherpipelineoptions-handler) for more details.
147
+ See [Dispatcher.pipeline](documentation/docs/api/Dispatcher.md#dispatcherpipelineoptions-handler) for more details.
144
148
 
145
149
  ### `undici.connect([url, options]): Promise`
146
150
 
@@ -149,7 +153,7 @@ Starts two-way communications with the requested resource using [HTTP CONNECT](h
149
153
  Arguments:
150
154
 
151
155
  * **url** `string | URL | UrlObject`
152
- * **options** [`ConnectOptions`](docs/api/Dispatcher.md#parameter-connectoptions)
156
+ * **options** [`ConnectOptions`](documentation/docs/api/Dispatcher.md#parameter-connectoptions)
153
157
  * **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
154
158
  * **maxRedirections** `Integer` - Default: `0`
155
159
  * **callback** `(err: Error | null, data: ConnectData | null) => void` (optional)
@@ -158,7 +162,7 @@ Returns a promise with the result of the `Dispatcher.connect` method.
158
162
 
159
163
  Calls `options.dispatch.connect(options)`.
160
164
 
161
- See [Dispatcher.connect](docs/api/Dispatcher.md#dispatcherconnectoptions-callback) for more details.
165
+ See [Dispatcher.connect](documentation/docs/api/Dispatcher.md#dispatcherconnectoptions-callback) for more details.
162
166
 
163
167
  ### `undici.fetch(input[, init]): Promise`
164
168
 
@@ -226,7 +230,7 @@ await fetch('https://example.com', { body: data, method: 'POST', duplex: 'half'
226
230
 
227
231
  - half
228
232
 
229
- In this implementation of fetch, `request.duplex` must be set if `request.body` is `ReadableStream` or `Async Iterables`. And fetch requests are currently always be full duplex. More detail refer to [Fetch Standard.](https://fetch.spec.whatwg.org/#dom-requestinit-duplex)
233
+ In this implementation of fetch, `request.duplex` must be set if `request.body` is `ReadableStream` or `Async Iterables`, however, fetch requests are currently always full duplex. For more detail refer to the [Fetch Standard.](https://fetch.spec.whatwg.org/#dom-requestinit-duplex).
230
234
 
231
235
  #### `response.body`
232
236
 
@@ -297,7 +301,7 @@ Upgrade to a different protocol. See [MDN - HTTP - Protocol upgrade mechanism](h
297
301
  Arguments:
298
302
 
299
303
  * **url** `string | URL | UrlObject`
300
- * **options** [`UpgradeOptions`](docs/api/Dispatcher.md#parameter-upgradeoptions)
304
+ * **options** [`UpgradeOptions`](documentation/docs/api/Dispatcher.md#parameter-upgradeoptions)
301
305
  * **dispatcher** `Dispatcher` - Default: [getGlobalDispatcher](#undicigetglobaldispatcher)
302
306
  * **maxRedirections** `Integer` - Default: `0`
303
307
  * **callback** `(error: Error | null, data: UpgradeData) => void` (optional)
@@ -306,7 +310,7 @@ Returns a promise with the result of the `Dispatcher.upgrade` method.
306
310
 
307
311
  Calls `options.dispatcher.upgrade(options)`.
308
312
 
309
- See [Dispatcher.upgrade](docs/api/Dispatcher.md#dispatcherupgradeoptions-callback) for more details.
313
+ See [Dispatcher.upgrade](documentation/docs/api/Dispatcher.md#dispatcherupgradeoptions-callback) for more details.
310
314
 
311
315
  ### `undici.setGlobalDispatcher(dispatcher)`
312
316
 
@@ -400,9 +404,9 @@ Refs: https://fetch.spec.whatwg.org/#atomic-http-redirect-handling
400
404
 
401
405
  If you experience problem when connecting to a remote server that is resolved by your DNS servers to a IPv6 (AAAA record)
402
406
  first, there are chances that your local router or ISP might have problem connecting to IPv6 networks. In that case
403
- undici will throw an error with code `UND_ERR_CONNECT_TIMEOUT`.
407
+ undici will throw an error with code `UND_ERR_CONNECT_TIMEOUT`.
404
408
 
405
- If the target server resolves to both a IPv6 and IPv4 (A records) address and you are using a compatible Node version
409
+ If the target server resolves to both a IPv6 and IPv4 (A records) address and you are using a compatible Node version
406
410
  (18.3.0 and above), you can fix the problem by providing the `autoSelectFamily` option (support by both `undici.request`
407
411
  and `undici.Agent`) which will enable the family autoselection algorithm when establishing the connection.
408
412
 
@@ -855,10 +855,12 @@ Emitted when dispatcher is no longer busy.
855
855
 
856
856
  ## Parameter: `UndiciHeaders`
857
857
 
858
- * `Record<string, string | string[] | undefined> | string[] | null`
859
-
860
- Header arguments such as `options.headers` in [`Client.dispatch`](Client.md#clientdispatchoptions-handlers) can be specified in two forms; either as an object specified by the `Record<string, string | string[] | undefined>` (`IncomingHttpHeaders`) type, or an array of strings. An array representation of a header list must have an even length or an `InvalidArgumentError` will be thrown.
858
+ * `Record<string, string | string[] | undefined> | string[] | Iterable<[string, string | string[] | undefined]> | null`
861
859
 
860
+ Header arguments such as `options.headers` in [`Client.dispatch`](Client.md#clientdispatchoptions-handlers) can be specified in three forms:
861
+ * As an object specified by the `Record<string, string | string[] | undefined>` (`IncomingHttpHeaders`) type.
862
+ * As an array of strings. An array representation of a header list must have an even length, or an `InvalidArgumentError` will be thrown.
863
+ * As an iterable that can encompass `Headers`, `Map`, or a custom iterator returning key-value pairs.
862
864
  Keys are lowercase and values are not modified.
863
865
 
864
866
  Response headers will derive a `host` from the `url` of the [Client](Client.md#class-client) instance if no `host` header was previously specified.
@@ -886,3 +888,37 @@ Response headers will derive a `host` from the `url` of the [Client](Client.md#c
886
888
  'accept', '*/*'
887
889
  ]
888
890
  ```
891
+
892
+ ### Example 3 - Iterable
893
+
894
+ ```js
895
+ new Headers({
896
+ 'content-length': '123',
897
+ 'content-type': 'text/plain',
898
+ connection: 'keep-alive',
899
+ host: 'mysite.com',
900
+ accept: '*/*'
901
+ })
902
+ ```
903
+ or
904
+ ```js
905
+ new Map([
906
+ ['content-length', '123'],
907
+ ['content-type', 'text/plain'],
908
+ ['connection', 'keep-alive'],
909
+ ['host', 'mysite.com'],
910
+ ['accept', '*/*']
911
+ ])
912
+ ```
913
+ or
914
+ ```js
915
+ {
916
+ *[Symbol.iterator] () {
917
+ yield ['content-length', '123']
918
+ yield ['content-type', 'text/plain']
919
+ yield ['connection', 'keep-alive']
920
+ yield ['host', 'mysite.com']
921
+ yield ['accept', '*/*']
922
+ }
923
+ }
924
+ ```
@@ -0,0 +1,57 @@
1
+ # Fetch
2
+
3
+ Undici exposes a fetch() method starts the process of fetching a resource from the network.
4
+
5
+ Documentation and examples can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/fetch).
6
+
7
+ ## File
8
+
9
+ This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/File)
10
+
11
+ In Node versions v18.13.0 and above and v19.2.0 and above, undici will default to using Node's [File](https://nodejs.org/api/buffer.html#class-file) class. In versions where it's not available, it will default to the undici one.
12
+
13
+ ## FormData
14
+
15
+ This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData).
16
+
17
+ If any parameters are passed to the FormData constructor other than `undefined`, an error will be thrown. Other parameters are ignored.
18
+
19
+ ## Response
20
+
21
+ This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Response)
22
+
23
+ ## Request
24
+
25
+ This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Request)
26
+
27
+ ## Header
28
+
29
+ This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
30
+
31
+ # Body Mixins
32
+
33
+ `Response` and `Request` body inherit body mixin methods. These methods include:
34
+
35
+ - [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
36
+ - [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
37
+ - [`.formData()`](https://fetch.spec.whatwg.org/#dom-body-formdata)
38
+ - [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
39
+ - [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
40
+
41
+ There is an ongoing discussion regarding `.formData()` and its usefulness and performance in server environments. It is recommended to use a dedicated library for parsing `multipart/form-data` bodies, such as [Busboy](https://www.npmjs.com/package/busboy) or [@fastify/busboy](https://www.npmjs.com/package/@fastify/busboy).
42
+
43
+ These libraries can be interfaced with fetch with the following example code:
44
+
45
+ ```mjs
46
+ import { Busboy } from '@fastify/busboy'
47
+ import { Readable } from 'node:stream'
48
+
49
+ const response = await fetch('...')
50
+ const busboy = new Busboy({
51
+ headers: {
52
+ 'content-type': response.headers.get('content-type')
53
+ }
54
+ })
55
+
56
+ Readable.fromWeb(response.body).pipe(busboy)
57
+ ```
@@ -16,7 +16,7 @@ Returns: `ProxyAgent`
16
16
 
17
17
  Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
18
18
 
19
- * **uri** `string` (required) - It can be passed either by a string or a object containing `uri` as string.
19
+ * **uri** `string | URL` (required) - The URI of the proxy server. This can be provided as a string, as an instance of the URL class, or as an object with a `uri` property of type string.
20
20
  * **token** `string` (optional) - It can be passed by a string of token for authentication.
21
21
  * **auth** `string` (**deprecated**) - Use token.
22
22
  * **clientFactory** `(origin: URL, opts: Object) => Dispatcher` (optional) - Default: `(origin, opts) => new Pool(origin, opts)`
@@ -30,6 +30,8 @@ import { ProxyAgent } from 'undici'
30
30
 
31
31
  const proxyAgent = new ProxyAgent('my.proxy.server')
32
32
  // or
33
+ const proxyAgent = new ProxyAgent(new URL('my.proxy.server'))
34
+ // or
33
35
  const proxyAgent = new ProxyAgent({ uri: 'my.proxy.server' })
34
36
  ```
35
37
 
@@ -0,0 +1,45 @@
1
+ # Class: RetryAgent
2
+
3
+ Extends: `undici.Dispatcher`
4
+
5
+ A `undici.Dispatcher` that allows to automatically retry a request.
6
+ Wraps a `undici.RetryHandler`.
7
+
8
+ ## `new RetryAgent(dispatcher, [options])`
9
+
10
+ Arguments:
11
+
12
+ * **dispatcher** `undici.Dispatcher` (required) - the dispatcher to wrap
13
+ * **options** `RetryHandlerOptions` (optional) - the options
14
+
15
+ Returns: `ProxyAgent`
16
+
17
+ ### Parameter: `RetryHandlerOptions`
18
+
19
+ - **retry** `(err: Error, context: RetryContext, callback: (err?: Error | null) => void) => void` (optional) - Function to be called after every retry. It should pass error if no more retries should be performed.
20
+ - **maxRetries** `number` (optional) - Maximum number of retries. Default: `5`
21
+ - **maxTimeout** `number` (optional) - Maximum number of milliseconds to wait before retrying. Default: `30000` (30 seconds)
22
+ - **minTimeout** `number` (optional) - Minimum number of milliseconds to wait before retrying. Default: `500` (half a second)
23
+ - **timeoutFactor** `number` (optional) - Factor to multiply the timeout by for each retry attempt. Default: `2`
24
+ - **retryAfter** `boolean` (optional) - It enables automatic retry after the `Retry-After` header is received. Default: `true`
25
+ -
26
+ - **methods** `string[]` (optional) - Array of HTTP methods to retry. Default: `['GET', 'PUT', 'HEAD', 'OPTIONS', 'DELETE']`
27
+ - **statusCodes** `number[]` (optional) - Array of HTTP status codes to retry. Default: `[429, 500, 502, 503, 504]`
28
+ - **errorCodes** `string[]` (optional) - Array of Error codes to retry. Default: `['ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ENETDOWN','ENETUNREACH', 'EHOSTDOWN', 'UND_ERR_SOCKET']`
29
+
30
+ **`RetryContext`**
31
+
32
+ - `state`: `RetryState` - Current retry state. It can be mutated.
33
+ - `opts`: `Dispatch.DispatchOptions & RetryOptions` - Options passed to the retry handler.
34
+
35
+ Example:
36
+
37
+ ```js
38
+ import { Agent, RetryAgent } from 'undici'
39
+
40
+ const agent = new RetryAgent(new Agent())
41
+
42
+ const res = await agent.request('http://example.com')
43
+ console.log(res.statuCode)
44
+ console.log(await res.body.text())
45
+ ```
@@ -28,7 +28,7 @@ Extends: [`Dispatch.DispatchOptions`](Dispatcher.md#parameter-dispatchoptions).
28
28
  -
29
29
  - **methods** `string[]` (optional) - Array of HTTP methods to retry. Default: `['GET', 'PUT', 'HEAD', 'OPTIONS', 'DELETE']`
30
30
  - **statusCodes** `number[]` (optional) - Array of HTTP status codes to retry. Default: `[429, 500, 502, 503, 504]`
31
- - **errorCodes** `string[]` (optional) - Array of Error codes to retry. Default: `['ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ENETDOWN','ENETUNREACH', 'EHOSTDOWN',
31
+ - **errorCodes** `string[]` (optional) - Array of Error codes to retry. Default: `['ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ENETDOWN','ENETUNREACH', 'EHOSTDOWN', 'UND_ERR_SOCKET']`
32
32
 
33
33
  **`RetryContext`**
34
34
 
@@ -21,10 +21,39 @@ An Undici [Client](Client.md) can be best described as a state machine. The foll
21
21
  * At any point in time, the *destroy* event will transition the `Client` from the **processing** state to the **destroyed** state, destroying any queued requests.
22
22
  * The **destroyed** state is a final state and the `Client` is no longer functional.
23
23
 
24
- ![A state diagram representing an Undici Client instance](../assets/lifecycle-diagram.png)
25
-
26
- > The diagram was generated using Mermaid.js Live Editor. Modify the state diagram [here](https://mermaid-js.github.io/mermaid-live-editor/#/edit/eyJjb2RlIjoic3RhdGVEaWFncmFtLXYyXG4gICAgWypdIC0tPiBpZGxlXG4gICAgaWRsZSAtLT4gcGVuZGluZyA6IGNvbm5lY3RcbiAgICBpZGxlIC0tPiBkZXN0cm95ZWQgOiBkZXN0cm95L2Nsb3NlXG4gICAgXG4gICAgcGVuZGluZyAtLT4gaWRsZSA6IHRpbWVvdXRcbiAgICBwZW5kaW5nIC0tPiBkZXN0cm95ZWQgOiBkZXN0cm95XG5cbiAgICBzdGF0ZSBjbG9zZV9mb3JrIDw8Zm9yaz4-XG4gICAgcGVuZGluZyAtLT4gY2xvc2VfZm9yayA6IGNsb3NlXG4gICAgY2xvc2VfZm9yayAtLT4gcHJvY2Vzc2luZ1xuICAgIGNsb3NlX2ZvcmsgLS0-IGRlc3Ryb3llZFxuXG4gICAgcGVuZGluZyAtLT4gcHJvY2Vzc2luZyA6IHByb2Nlc3NcblxuICAgIHByb2Nlc3NpbmcgLS0-IHBlbmRpbmcgOiBrZWVwYWxpdmVcbiAgICBwcm9jZXNzaW5nIC0tPiBkZXN0cm95ZWQgOiBkb25lXG4gICAgcHJvY2Vzc2luZyAtLT4gZGVzdHJveWVkIDogZGVzdHJveVxuXG4gICAgc3RhdGUgcHJvY2Vzc2luZyB7XG4gICAgICAgIHJ1bm5pbmcgLS0-IGJ1c3kgOiBuZWVkRHJhaW5cbiAgICAgICAgYnVzeSAtLT4gcnVubmluZyA6IGRyYWluQ29tcGxldGVcbiAgICAgICAgcnVubmluZyAtLT4gWypdIDoga2VlcGFsaXZlXG4gICAgICAgIHJ1bm5pbmcgLS0-IGNsb3NpbmcgOiBjbG9zZVxuICAgICAgICBjbG9zaW5nIC0tPiBbKl0gOiBkb25lXG4gICAgICAgIFsqXSAtLT4gcnVubmluZ1xuICAgIH1cbiAgICAiLCJtZXJtYWlkIjp7InRoZW1lIjoiYmFzZSJ9LCJ1cGRhdGVFZGl0b3IiOmZhbHNlfQ)
27
-
24
+ A state diagram representing an Undici Client instance:
25
+
26
+ ```mermaid
27
+ stateDiagram-v2
28
+ [*] --> idle
29
+ idle --> pending : connect
30
+ idle --> destroyed : destroy/close
31
+
32
+ pending --> idle : timeout
33
+ pending --> destroyed : destroy
34
+
35
+ state close_fork <<fork>>
36
+ pending --> close_fork : close
37
+ close_fork --> processing
38
+ close_fork --> destroyed
39
+
40
+ pending --> processing : process
41
+
42
+ processing --> pending : keepalive
43
+ processing --> destroyed : done
44
+ processing --> destroyed : destroy
45
+
46
+ destroyed --> [*]
47
+
48
+ state processing {
49
+ [*] --> running
50
+ running --> closing : close
51
+ running --> busy : needDrain
52
+ busy --> running : drainComplete
53
+ running --> [*] : keepalive
54
+ closing --> [*] : done
55
+ }
56
+ ```
28
57
  ## State details
29
58
 
30
59
  ### idle
@@ -17,7 +17,7 @@ If you proxy requires basic authentication, you can send it via the `proxy-autho
17
17
  ```js
18
18
  import { Client } from 'undici'
19
19
  import { createServer } from 'http'
20
- import proxy from 'proxy'
20
+ import { createProxy } from 'proxy'
21
21
 
22
22
  const server = await buildServer()
23
23
  const proxyServer = await buildProxy()
@@ -59,7 +59,7 @@ function buildServer () {
59
59
 
60
60
  function buildProxy () {
61
61
  return new Promise((resolve, reject) => {
62
- const server = proxy(createServer())
62
+ const server = createProxy(createServer())
63
63
  server.listen(0, () => resolve(server))
64
64
  })
65
65
  }
@@ -70,7 +70,7 @@ function buildProxy () {
70
70
  ```js
71
71
  import { Client } from 'undici'
72
72
  import { createServer } from 'http'
73
- import proxy from 'proxy'
73
+ import { createProxy } from 'proxy'
74
74
 
75
75
  const server = await buildServer()
76
76
  const proxyServer = await buildProxy()
@@ -78,8 +78,8 @@ const proxyServer = await buildProxy()
78
78
  const serverUrl = `http://localhost:${server.address().port}`
79
79
  const proxyUrl = `http://localhost:${proxyServer.address().port}`
80
80
 
81
- proxyServer.authenticate = function (req, fn) {
82
- fn(null, req.headers['proxy-authorization'] === `Basic ${Buffer.from('user:pass').toString('base64')}`)
81
+ proxyServer.authenticate = function (req) {
82
+ return req.headers['proxy-authorization'] === `Basic ${Buffer.from('user:pass').toString('base64')}`
83
83
  }
84
84
 
85
85
  server.on('request', (req, res) => {
@@ -119,7 +119,7 @@ function buildServer () {
119
119
 
120
120
  function buildProxy () {
121
121
  return new Promise((resolve, reject) => {
122
- const server = proxy(createServer())
122
+ const server = createProxy(createServer())
123
123
  server.listen(0, () => resolve(server))
124
124
  })
125
125
  }
package/index-fetch.js CHANGED
@@ -1,20 +1,21 @@
1
1
  'use strict'
2
2
 
3
- const fetchImpl = require('./lib/fetch').fetch
3
+ const fetchImpl = require('./lib/web/fetch').fetch
4
4
 
5
5
  module.exports.fetch = function fetch (resource, init = undefined) {
6
6
  return fetchImpl(resource, init).catch((err) => {
7
- if (typeof err === 'object') {
7
+ if (err && typeof err === 'object') {
8
8
  Error.captureStackTrace(err, this)
9
9
  }
10
10
  throw err
11
11
  })
12
12
  }
13
- module.exports.FormData = require('./lib/fetch/formdata').FormData
14
- module.exports.Headers = require('./lib/fetch/headers').Headers
15
- module.exports.Response = require('./lib/fetch/response').Response
16
- module.exports.Request = require('./lib/fetch/request').Request
13
+ module.exports.FormData = require('./lib/web/fetch/formdata').FormData
14
+ module.exports.Headers = require('./lib/web/fetch/headers').Headers
15
+ module.exports.Response = require('./lib/web/fetch/response').Response
16
+ module.exports.Request = require('./lib/web/fetch/request').Request
17
17
 
18
- module.exports.WebSocket = require('./lib/websocket/websocket').WebSocket
18
+ module.exports.WebSocket = require('./lib/web/websocket/websocket').WebSocket
19
+ module.exports.MessageEvent = require('./lib/web/websocket/events').MessageEvent
19
20
 
20
- module.exports.EventSource = require('./lib/eventsource/eventsource').EventSource
21
+ module.exports.EventSource = require('./lib/web/eventsource/eventsource').EventSource
package/index.js CHANGED
@@ -1,11 +1,13 @@
1
1
  'use strict'
2
2
 
3
- const Client = require('./lib/client')
4
- const Dispatcher = require('./lib/dispatcher')
3
+ const Client = require('./lib/dispatcher/client')
4
+ const Dispatcher = require('./lib/dispatcher/dispatcher')
5
+ const Pool = require('./lib/dispatcher/pool')
6
+ const BalancedPool = require('./lib/dispatcher/balanced-pool')
7
+ const Agent = require('./lib/dispatcher/agent')
8
+ const ProxyAgent = require('./lib/dispatcher/proxy-agent')
9
+ const RetryAgent = require('./lib/dispatcher/retry-agent')
5
10
  const errors = require('./lib/core/errors')
6
- const Pool = require('./lib/pool')
7
- const BalancedPool = require('./lib/balanced-pool')
8
- const Agent = require('./lib/agent')
9
11
  const util = require('./lib/core/util')
10
12
  const { InvalidArgumentError } = errors
11
13
  const api = require('./lib/api')
@@ -14,12 +16,11 @@ const MockClient = require('./lib/mock/mock-client')
14
16
  const MockAgent = require('./lib/mock/mock-agent')
15
17
  const MockPool = require('./lib/mock/mock-pool')
16
18
  const mockErrors = require('./lib/mock/mock-errors')
17
- const ProxyAgent = require('./lib/proxy-agent')
18
- const RetryHandler = require('./lib/handler/RetryHandler')
19
+ const RetryHandler = require('./lib/handler/retry-handler')
19
20
  const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global')
20
- const DecoratorHandler = require('./lib/handler/DecoratorHandler')
21
- const RedirectHandler = require('./lib/handler/RedirectHandler')
22
- const createRedirectInterceptor = require('./lib/interceptor/redirectInterceptor')
21
+ const DecoratorHandler = require('./lib/handler/decorator-handler')
22
+ const RedirectHandler = require('./lib/handler/redirect-handler')
23
+ const createRedirectInterceptor = require('./lib/interceptor/redirect-interceptor')
23
24
 
24
25
  Object.assign(Dispatcher.prototype, api)
25
26
 
@@ -29,6 +30,7 @@ module.exports.Pool = Pool
29
30
  module.exports.BalancedPool = BalancedPool
30
31
  module.exports.Agent = Agent
31
32
  module.exports.ProxyAgent = ProxyAgent
33
+ module.exports.RetryAgent = RetryAgent
32
34
  module.exports.RetryHandler = RetryHandler
33
35
 
34
36
  module.exports.DecoratorHandler = DecoratorHandler
@@ -94,50 +96,54 @@ function makeDispatcher (fn) {
94
96
  module.exports.setGlobalDispatcher = setGlobalDispatcher
95
97
  module.exports.getGlobalDispatcher = getGlobalDispatcher
96
98
 
97
- const fetchImpl = require('./lib/fetch').fetch
99
+ const fetchImpl = require('./lib/web/fetch').fetch
98
100
  module.exports.fetch = async function fetch (init, options = undefined) {
99
101
  try {
100
102
  return await fetchImpl(init, options)
101
103
  } catch (err) {
102
- if (typeof err === 'object') {
104
+ if (err && typeof err === 'object') {
103
105
  Error.captureStackTrace(err, this)
104
106
  }
105
107
 
106
108
  throw err
107
109
  }
108
110
  }
109
- module.exports.Headers = require('./lib/fetch/headers').Headers
110
- module.exports.Response = require('./lib/fetch/response').Response
111
- module.exports.Request = require('./lib/fetch/request').Request
112
- module.exports.FormData = require('./lib/fetch/formdata').FormData
113
- module.exports.File = require('./lib/fetch/file').File
114
- module.exports.FileReader = require('./lib/fileapi/filereader').FileReader
111
+ module.exports.Headers = require('./lib/web/fetch/headers').Headers
112
+ module.exports.Response = require('./lib/web/fetch/response').Response
113
+ module.exports.Request = require('./lib/web/fetch/request').Request
114
+ module.exports.FormData = require('./lib/web/fetch/formdata').FormData
115
+ module.exports.File = require('./lib/web/fetch/file').File
116
+ module.exports.FileReader = require('./lib/web/fileapi/filereader').FileReader
115
117
 
116
- const { setGlobalOrigin, getGlobalOrigin } = require('./lib/fetch/global')
118
+ const { setGlobalOrigin, getGlobalOrigin } = require('./lib/web/fetch/global')
117
119
 
118
120
  module.exports.setGlobalOrigin = setGlobalOrigin
119
121
  module.exports.getGlobalOrigin = getGlobalOrigin
120
122
 
121
- const { CacheStorage } = require('./lib/cache/cachestorage')
122
- const { kConstruct } = require('./lib/cache/symbols')
123
+ const { CacheStorage } = require('./lib/web/cache/cachestorage')
124
+ const { kConstruct } = require('./lib/web/cache/symbols')
123
125
 
124
126
  // Cache & CacheStorage are tightly coupled with fetch. Even if it may run
125
127
  // in an older version of Node, it doesn't have any use without fetch.
126
128
  module.exports.caches = new CacheStorage(kConstruct)
127
129
 
128
- const { deleteCookie, getCookies, getSetCookies, setCookie } = require('./lib/cookies')
130
+ const { deleteCookie, getCookies, getSetCookies, setCookie } = require('./lib/web/cookies')
129
131
 
130
132
  module.exports.deleteCookie = deleteCookie
131
133
  module.exports.getCookies = getCookies
132
134
  module.exports.getSetCookies = getSetCookies
133
135
  module.exports.setCookie = setCookie
134
136
 
135
- const { parseMIMEType, serializeAMimeType } = require('./lib/fetch/dataURL')
137
+ const { parseMIMEType, serializeAMimeType } = require('./lib/web/fetch/data-url')
136
138
 
137
139
  module.exports.parseMIMEType = parseMIMEType
138
140
  module.exports.serializeAMimeType = serializeAMimeType
139
141
 
140
- module.exports.WebSocket = require('./lib/websocket/websocket').WebSocket
142
+ const { CloseEvent, ErrorEvent, MessageEvent } = require('./lib/web/websocket/events')
143
+ module.exports.WebSocket = require('./lib/web/websocket/websocket').WebSocket
144
+ module.exports.CloseEvent = CloseEvent
145
+ module.exports.ErrorEvent = ErrorEvent
146
+ module.exports.MessageEvent = MessageEvent
141
147
 
142
148
  module.exports.request = makeDispatcher(api.request)
143
149
  module.exports.stream = makeDispatcher(api.stream)
@@ -150,6 +156,6 @@ module.exports.MockPool = MockPool
150
156
  module.exports.MockAgent = MockAgent
151
157
  module.exports.mockErrors = mockErrors
152
158
 
153
- const { EventSource } = require('./lib/eventsource/eventsource')
159
+ const { EventSource } = require('./lib/web/eventsource/eventsource')
154
160
 
155
161
  module.exports.EventSource = EventSource