undici 6.21.0 → 7.0.0-alpha.10

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 (156) hide show
  1. package/README.md +27 -46
  2. package/docs/docs/api/Agent.md +14 -17
  3. package/docs/docs/api/BalancedPool.md +16 -16
  4. package/docs/docs/api/CacheStore.md +131 -0
  5. package/docs/docs/api/Client.md +12 -14
  6. package/docs/docs/api/Debug.md +1 -1
  7. package/docs/docs/api/Dispatcher.md +98 -194
  8. package/docs/docs/api/EnvHttpProxyAgent.md +12 -13
  9. package/docs/docs/api/MockAgent.md +5 -3
  10. package/docs/docs/api/MockClient.md +5 -5
  11. package/docs/docs/api/MockPool.md +4 -3
  12. package/docs/docs/api/Pool.md +15 -16
  13. package/docs/docs/api/PoolStats.md +1 -1
  14. package/docs/docs/api/ProxyAgent.md +3 -3
  15. package/docs/docs/api/RedirectHandler.md +1 -1
  16. package/docs/docs/api/RetryAgent.md +1 -1
  17. package/docs/docs/api/RetryHandler.md +4 -4
  18. package/docs/docs/api/WebSocket.md +46 -4
  19. package/docs/docs/api/api-lifecycle.md +11 -11
  20. package/docs/docs/best-practices/mocking-request.md +2 -2
  21. package/docs/docs/best-practices/proxy.md +1 -1
  22. package/index.d.ts +1 -1
  23. package/index.js +23 -7
  24. package/lib/api/abort-signal.js +2 -0
  25. package/lib/api/api-connect.js +3 -1
  26. package/lib/api/api-pipeline.js +7 -6
  27. package/lib/api/api-request.js +33 -48
  28. package/lib/api/api-stream.js +39 -50
  29. package/lib/api/api-upgrade.js +5 -3
  30. package/lib/api/readable.js +235 -62
  31. package/lib/api/util.js +2 -0
  32. package/lib/cache/memory-cache-store.js +177 -0
  33. package/lib/cache/sqlite-cache-store.js +446 -0
  34. package/lib/core/constants.js +35 -10
  35. package/lib/core/diagnostics.js +122 -128
  36. package/lib/core/errors.js +6 -6
  37. package/lib/core/request.js +13 -11
  38. package/lib/core/symbols.js +2 -1
  39. package/lib/core/tree.js +9 -1
  40. package/lib/core/util.js +237 -49
  41. package/lib/dispatcher/agent.js +3 -17
  42. package/lib/dispatcher/balanced-pool.js +5 -8
  43. package/lib/dispatcher/client-h1.js +379 -134
  44. package/lib/dispatcher/client-h2.js +173 -107
  45. package/lib/dispatcher/client.js +19 -32
  46. package/lib/dispatcher/dispatcher-base.js +6 -35
  47. package/lib/dispatcher/dispatcher.js +7 -24
  48. package/lib/dispatcher/fixed-queue.js +91 -49
  49. package/lib/dispatcher/pool-stats.js +2 -0
  50. package/lib/dispatcher/pool.js +3 -6
  51. package/lib/dispatcher/proxy-agent.js +3 -6
  52. package/lib/handler/cache-handler.js +393 -0
  53. package/lib/handler/cache-revalidation-handler.js +124 -0
  54. package/lib/handler/decorator-handler.js +27 -0
  55. package/lib/handler/redirect-handler.js +54 -59
  56. package/lib/handler/retry-handler.js +77 -109
  57. package/lib/handler/unwrap-handler.js +96 -0
  58. package/lib/handler/wrap-handler.js +98 -0
  59. package/lib/interceptor/cache.js +350 -0
  60. package/lib/interceptor/dns.js +375 -0
  61. package/lib/interceptor/dump.js +2 -2
  62. package/lib/interceptor/redirect.js +11 -14
  63. package/lib/interceptor/response-error.js +18 -7
  64. package/lib/llhttp/constants.d.ts +97 -0
  65. package/lib/llhttp/constants.js +412 -192
  66. package/lib/llhttp/constants.js.map +1 -0
  67. package/lib/llhttp/llhttp-wasm.js +11 -1
  68. package/lib/llhttp/llhttp_simd-wasm.js +11 -1
  69. package/lib/llhttp/utils.d.ts +2 -0
  70. package/lib/llhttp/utils.js +9 -9
  71. package/lib/llhttp/utils.js.map +1 -0
  72. package/lib/mock/mock-agent.js +5 -8
  73. package/lib/mock/mock-client.js +9 -4
  74. package/lib/mock/mock-errors.js +3 -1
  75. package/lib/mock/mock-interceptor.js +8 -6
  76. package/lib/mock/mock-pool.js +9 -4
  77. package/lib/mock/mock-symbols.js +3 -1
  78. package/lib/mock/mock-utils.js +29 -5
  79. package/lib/util/cache.js +360 -0
  80. package/lib/web/cache/cache.js +24 -21
  81. package/lib/web/cache/cachestorage.js +1 -1
  82. package/lib/web/cookies/index.js +29 -14
  83. package/lib/web/cookies/parse.js +8 -3
  84. package/lib/web/eventsource/eventsource-stream.js +9 -8
  85. package/lib/web/eventsource/eventsource.js +10 -6
  86. package/lib/web/fetch/body.js +43 -41
  87. package/lib/web/fetch/constants.js +12 -5
  88. package/lib/web/fetch/data-url.js +3 -3
  89. package/lib/web/fetch/formdata-parser.js +72 -45
  90. package/lib/web/fetch/formdata.js +65 -54
  91. package/lib/web/fetch/headers.js +118 -86
  92. package/lib/web/fetch/index.js +58 -67
  93. package/lib/web/fetch/request.js +136 -77
  94. package/lib/web/fetch/response.js +87 -56
  95. package/lib/web/fetch/util.js +259 -109
  96. package/lib/web/fetch/webidl.js +113 -68
  97. package/lib/web/websocket/connection.js +76 -147
  98. package/lib/web/websocket/constants.js +70 -10
  99. package/lib/web/websocket/events.js +4 -2
  100. package/lib/web/websocket/frame.js +45 -3
  101. package/lib/web/websocket/receiver.js +29 -33
  102. package/lib/web/websocket/sender.js +18 -13
  103. package/lib/web/websocket/stream/websocketerror.js +83 -0
  104. package/lib/web/websocket/stream/websocketstream.js +485 -0
  105. package/lib/web/websocket/util.js +128 -77
  106. package/lib/web/websocket/websocket.js +234 -135
  107. package/package.json +24 -36
  108. package/scripts/strip-comments.js +3 -1
  109. package/types/agent.d.ts +7 -7
  110. package/types/api.d.ts +24 -24
  111. package/types/balanced-pool.d.ts +11 -11
  112. package/types/cache-interceptor.d.ts +172 -0
  113. package/types/client.d.ts +11 -12
  114. package/types/cookies.d.ts +2 -0
  115. package/types/diagnostics-channel.d.ts +10 -10
  116. package/types/dispatcher.d.ts +113 -90
  117. package/types/env-http-proxy-agent.d.ts +2 -2
  118. package/types/errors.d.ts +53 -47
  119. package/types/fetch.d.ts +17 -16
  120. package/types/formdata.d.ts +7 -7
  121. package/types/global-dispatcher.d.ts +4 -4
  122. package/types/global-origin.d.ts +5 -5
  123. package/types/handlers.d.ts +7 -7
  124. package/types/header.d.ts +157 -1
  125. package/types/index.d.ts +44 -46
  126. package/types/interceptors.d.ts +25 -8
  127. package/types/mock-agent.d.ts +21 -18
  128. package/types/mock-client.d.ts +4 -4
  129. package/types/mock-errors.d.ts +3 -3
  130. package/types/mock-interceptor.d.ts +19 -19
  131. package/types/mock-pool.d.ts +4 -4
  132. package/types/patch.d.ts +0 -4
  133. package/types/pool-stats.d.ts +8 -8
  134. package/types/pool.d.ts +12 -12
  135. package/types/proxy-agent.d.ts +4 -4
  136. package/types/readable.d.ts +18 -15
  137. package/types/retry-agent.d.ts +1 -1
  138. package/types/retry-handler.d.ts +10 -10
  139. package/types/util.d.ts +3 -3
  140. package/types/utility.d.ts +7 -0
  141. package/types/webidl.d.ts +44 -6
  142. package/types/websocket.d.ts +34 -1
  143. package/docs/docs/api/DispatchInterceptor.md +0 -60
  144. package/lib/interceptor/redirect-interceptor.js +0 -21
  145. package/lib/mock/pluralizer.js +0 -29
  146. package/lib/web/cache/symbols.js +0 -5
  147. package/lib/web/fetch/file.js +0 -126
  148. package/lib/web/fetch/symbols.js +0 -9
  149. package/lib/web/fileapi/encoding.js +0 -290
  150. package/lib/web/fileapi/filereader.js +0 -344
  151. package/lib/web/fileapi/progressevent.js +0 -78
  152. package/lib/web/fileapi/symbols.js +0 -10
  153. package/lib/web/fileapi/util.js +0 -391
  154. package/lib/web/websocket/symbols.js +0 -12
  155. package/types/file.d.ts +0 -39
  156. package/types/filereader.d.ts +0 -54
@@ -2,7 +2,7 @@
2
2
 
3
3
  Extends: `undici.Dispatcher`
4
4
 
5
- A pool of [Client](Client.md) instances connected to the same upstream target.
5
+ A pool of [Client](/docs/docs/api/Client.md) instances connected to the same upstream target.
6
6
 
7
7
  Requests are not guaranteed to be dispatched in order of invocation.
8
8
 
@@ -15,21 +15,20 @@ Arguments:
15
15
 
16
16
  ### Parameter: `PoolOptions`
17
17
 
18
- Extends: [`ClientOptions`](Client.md#parameter-clientoptions)
18
+ Extends: [`ClientOptions`](/docs/docs/api/Client.md#parameter-clientoptions)
19
19
 
20
20
  * **factory** `(origin: URL, opts: Object) => Dispatcher` - Default: `(origin, opts) => new Client(origin, opts)`
21
21
  * **connections** `number | null` (optional) - Default: `null` - The number of `Client` instances to create. When set to `null`, the `Pool` instance will create an unlimited amount of `Client` instances.
22
- * **interceptors** `{ Pool: DispatchInterceptor[] } }` - Default: `{ Pool: [] }` - A list of interceptors that are applied to the dispatch method. Additional logic can be applied (such as, but not limited to: 302 status code handling, authentication, cookies, compression and caching).
23
22
 
24
23
  ## Instance Properties
25
24
 
26
25
  ### `Pool.closed`
27
26
 
28
- Implements [Client.closed](Client.md#clientclosed)
27
+ Implements [Client.closed](/docs/docs/api/Client.md#clientclosed)
29
28
 
30
29
  ### `Pool.destroyed`
31
30
 
32
- Implements [Client.destroyed](Client.md#clientdestroyed)
31
+ Implements [Client.destroyed](/docs/docs/api/Client.md#clientdestroyed)
33
32
 
34
33
  ### `Pool.stats`
35
34
 
@@ -39,46 +38,46 @@ Returns [`PoolStats`](PoolStats.md) instance for this pool.
39
38
 
40
39
  ### `Pool.close([callback])`
41
40
 
42
- Implements [`Dispatcher.close([callback])`](Dispatcher.md#dispatcherclosecallback-promise).
41
+ Implements [`Dispatcher.close([callback])`](/docs/docs/api/Dispatcher.md#dispatcherclosecallback-promise).
43
42
 
44
43
  ### `Pool.destroy([error, callback])`
45
44
 
46
- Implements [`Dispatcher.destroy([error, callback])`](Dispatcher.md#dispatcherdestroyerror-callback-promise).
45
+ Implements [`Dispatcher.destroy([error, callback])`](/docs/docs/api/Dispatcher.md#dispatcherdestroyerror-callback-promise).
47
46
 
48
47
  ### `Pool.connect(options[, callback])`
49
48
 
50
- See [`Dispatcher.connect(options[, callback])`](Dispatcher.md#dispatcherconnectoptions-callback).
49
+ See [`Dispatcher.connect(options[, callback])`](/docs/docs/api/Dispatcher.md#dispatcherconnectoptions-callback).
51
50
 
52
51
  ### `Pool.dispatch(options, handler)`
53
52
 
54
- Implements [`Dispatcher.dispatch(options, handler)`](Dispatcher.md#dispatcherdispatchoptions-handler).
53
+ Implements [`Dispatcher.dispatch(options, handler)`](/docs/docs/api/Dispatcher.md#dispatcherdispatchoptions-handler).
55
54
 
56
55
  ### `Pool.pipeline(options, handler)`
57
56
 
58
- See [`Dispatcher.pipeline(options, handler)`](Dispatcher.md#dispatcherpipelineoptions-handler).
57
+ See [`Dispatcher.pipeline(options, handler)`](/docs/docs/api/Dispatcher.md#dispatcherpipelineoptions-handler).
59
58
 
60
59
  ### `Pool.request(options[, callback])`
61
60
 
62
- See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
61
+ See [`Dispatcher.request(options [, callback])`](/docs/docs/api/Dispatcher.md#dispatcherrequestoptions-callback).
63
62
 
64
63
  ### `Pool.stream(options, factory[, callback])`
65
64
 
66
- See [`Dispatcher.stream(options, factory[, callback])`](Dispatcher.md#dispatcherstreamoptions-factory-callback).
65
+ See [`Dispatcher.stream(options, factory[, callback])`](/docs/docs/api/Dispatcher.md#dispatcherstreamoptions-factory-callback).
67
66
 
68
67
  ### `Pool.upgrade(options[, callback])`
69
68
 
70
- See [`Dispatcher.upgrade(options[, callback])`](Dispatcher.md#dispatcherupgradeoptions-callback).
69
+ See [`Dispatcher.upgrade(options[, callback])`](/docs/docs/api/Dispatcher.md#dispatcherupgradeoptions-callback).
71
70
 
72
71
  ## Instance Events
73
72
 
74
73
  ### Event: `'connect'`
75
74
 
76
- See [Dispatcher Event: `'connect'`](Dispatcher.md#event-connect).
75
+ See [Dispatcher Event: `'connect'`](/docs/docs/api/Dispatcher.md#event-connect).
77
76
 
78
77
  ### Event: `'disconnect'`
79
78
 
80
- See [Dispatcher Event: `'disconnect'`](Dispatcher.md#event-disconnect).
79
+ See [Dispatcher Event: `'disconnect'`](/docs/docs/api/Dispatcher.md#event-disconnect).
81
80
 
82
81
  ### Event: `'drain'`
83
82
 
84
- See [Dispatcher Event: `'drain'`](Dispatcher.md#event-drain).
83
+ See [Dispatcher Event: `'drain'`](/docs/docs/api/Dispatcher.md#event-drain).
@@ -1,6 +1,6 @@
1
1
  # Class: PoolStats
2
2
 
3
- Aggregate stats for a [Pool](Pool.md) or [BalancedPool](BalancedPool.md).
3
+ Aggregate stats for a [Pool](/docs/docs/api/Pool.md) or [BalancedPool](/docs/docs/api/BalancedPool.md).
4
4
 
5
5
  ## `new PoolStats(pool)`
6
6
 
@@ -14,7 +14,7 @@ Returns: `ProxyAgent`
14
14
 
15
15
  ### Parameter: `ProxyAgentOptions`
16
16
 
17
- Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
17
+ Extends: [`AgentOptions`](/docs/docs/api/Agent.md#parameter-agentoptions)
18
18
 
19
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
  If the `uri` is provided as a string or `uri` is an object with an `uri` property of type string, then it will be parsed into a `URL` object according to the [WHATWG URL Specification](https://url.spec.whatwg.org).
@@ -123,8 +123,8 @@ await proxyAgent.close()
123
123
 
124
124
  ### `ProxyAgent.dispatch(options, handlers)`
125
125
 
126
- Implements [`Agent.dispatch(options, handlers)`](Agent.md#parameter-agentdispatchoptions).
126
+ Implements [`Agent.dispatch(options, handlers)`](/docs/docs/api/Agent.md#parameter-agentdispatchoptions).
127
127
 
128
128
  ### `ProxyAgent.request(options[, callback])`
129
129
 
130
- See [`Dispatcher.request(options [, callback])`](Dispatcher.md#dispatcherrequestoptions-callback).
130
+ See [`Dispatcher.request(options [, callback])`](/docs/docs/api/Dispatcher.md#dispatcherrequestoptions-callback).
@@ -16,7 +16,7 @@ Returns: `RedirectHandler`
16
16
 
17
17
  ### Parameters
18
18
 
19
- - **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandlers) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every redirection.
19
+ - **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandler) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every redirection.
20
20
  - **maxRedirections** `number` (required) - Maximum number of redirections allowed.
21
21
  - **opts** `object` (required) - Options for handling redirection.
22
22
  - **handler** `object` (required) - Handlers for different stages of the request lifecycle.
@@ -40,6 +40,6 @@ import { Agent, RetryAgent } from 'undici'
40
40
  const agent = new RetryAgent(new Agent())
41
41
 
42
42
  const res = await agent.request('http://example.com')
43
- console.log(res.statuCode)
43
+ console.log(res.statusCode)
44
44
  console.log(await res.body.text())
45
45
  ```
@@ -15,7 +15,7 @@ Returns: `retryHandler`
15
15
 
16
16
  ### Parameter: `Dispatch.DispatchOptions & RetryOptions`
17
17
 
18
- Extends: [`Dispatch.DispatchOptions`](Dispatcher.md#parameter-dispatchoptions).
18
+ Extends: [`Dispatch.DispatchOptions`](/docs/docs/api/Dispatcher.md#parameter-dispatchoptions).
19
19
 
20
20
  #### `RetryOptions`
21
21
 
@@ -43,10 +43,10 @@ It represents the retry state for a given request.
43
43
 
44
44
  ### Parameter `RetryHandlers`
45
45
 
46
- - **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandlers) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every retry.
47
- - **handler** Extends [`Dispatch.DispatchHandlers`](Dispatcher.md#dispatcherdispatchoptions-handler) (required) - Handler function to be called after the request is successful or the retries are exhausted.
46
+ - **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandler) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every retry.
47
+ - **handler** Extends [`Dispatch.DispatchHandler`](/docs/docs/api/Dispatcher.md#dispatcherdispatchoptions-handler) (required) - Handler function to be called after the request is successful or the retries are exhausted.
48
48
 
49
- >__Note__: The `RetryHandler` does not retry over stateful bodies (e.g. streams, AsyncIterable) as those, once consumed, are left in an state that cannot be reutilized. For these situations the `RetryHandler` will identify
49
+ >__Note__: The `RetryHandler` does not retry over stateful bodies (e.g. streams, AsyncIterable) as those, once consumed, are left in a state that cannot be reutilized. For these situations the `RetryHandler` will identify
50
50
  >the body as stateful and will not retry the request rejecting with the error `UND_ERR_REQ_RETRY`.
51
51
 
52
52
  Examples:
@@ -1,7 +1,5 @@
1
1
  # Class: WebSocket
2
2
 
3
- > ⚠️ Warning: the WebSocket API is experimental.
4
-
5
3
  Extends: [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget)
6
4
 
7
5
  The WebSocket object provides a way to manage a WebSocket connection to a server, allowing bidirectional communication. The API follows the [WebSocket spec](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) and [RFC 6455](https://datatracker.ietf.org/doc/html/rfc6455).
@@ -10,8 +8,8 @@ The WebSocket object provides a way to manage a WebSocket connection to a server
10
8
 
11
9
  Arguments:
12
10
 
13
- * **url** `URL | string` - The url's protocol *must* be `ws` or `wss`.
14
- * **protocol** `string | string[] | WebSocketInit` (optional) - Subprotocol(s) to request the server use, or a [`Dispatcher`](./Dispatcher.md).
11
+ * **url** `URL | string`
12
+ * **protocol** `string | string[] | WebSocketInit` (optional) - Subprotocol(s) to request the server use, or a [`Dispatcher`](/docs/docs/api/Dispatcher.md).
15
13
 
16
14
  ### Example:
17
15
 
@@ -36,6 +34,50 @@ import { WebSocket } from 'undici'
36
34
  const ws = new WebSocket('wss://echo.websocket.events', ['echo', 'chat'])
37
35
  ```
38
36
 
37
+ # Class: WebSocketStream
38
+
39
+ > ⚠️ Warning: the WebSocketStream API has not been finalized and is likely to change.
40
+
41
+ See [MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSocketStream) for more information.
42
+
43
+ ## `new WebSocketStream(url[, protocol])`
44
+
45
+ Arguments:
46
+
47
+ * **url** `URL | string`
48
+ * **options** `WebSocketStreamOptions` (optional)
49
+
50
+ ### WebSocketStream Example
51
+
52
+ ```js
53
+ const stream = new WebSocketStream('https://echo.websocket.org/')
54
+ const { readable, writable } = await stream.opened
55
+
56
+ async function read () {
57
+ /** @type {ReadableStreamReader} */
58
+ const reader = readable.getReader()
59
+
60
+ while (true) {
61
+ const { done, value } = await reader.read()
62
+ if (done) break
63
+
64
+ // do something with value
65
+ }
66
+ }
67
+
68
+ async function write () {
69
+ /** @type {WritableStreamDefaultWriter} */
70
+ const writer = writable.getWriter()
71
+ writer.write('Hello, world!')
72
+ writer.releaseLock()
73
+ }
74
+
75
+ read()
76
+
77
+ setInterval(() => write(), 5000)
78
+
79
+ ```
80
+
39
81
  ## Read More
40
82
 
41
83
  - [MDN - WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
@@ -1,6 +1,6 @@
1
1
  # Client Lifecycle
2
2
 
3
- An Undici [Client](Client.md) can be best described as a state machine. The following list is a summary of the various state transitions the `Client` will go through in its lifecycle. This document also contains detailed breakdowns of each state.
3
+ An Undici [Client](/docs/docs/api/Client.md) can be best described as a state machine. The following list is a summary of the various state transitions the `Client` will go through in its lifecycle. This document also contains detailed breakdowns of each state.
4
4
 
5
5
  > This diagram is not a perfect representation of the undici Client. Since the Client class is not actually implemented as a state-machine, actual execution may deviate slightly from what is described below. Consider this as a general resource for understanding the inner workings of the Undici client rather than some kind of formal specification.
6
6
 
@@ -28,7 +28,7 @@ stateDiagram-v2
28
28
  [*] --> idle
29
29
  idle --> pending : connect
30
30
  idle --> destroyed : destroy/close
31
-
31
+
32
32
  pending --> idle : timeout
33
33
  pending --> destroyed : destroy
34
34
 
@@ -58,33 +58,33 @@ stateDiagram-v2
58
58
 
59
59
  ### idle
60
60
 
61
- The **idle** state is the initial state of a `Client` instance. While an `origin` is required for instantiating a `Client` instance, the underlying socket connection will not be established until a request is queued using [`Client.dispatch()`](Client.md#clientdispatchoptions-handlers). By calling `Client.dispatch()` directly or using one of the multiple implementations ([`Client.connect()`](Client.md#clientconnectoptions-callback), [`Client.pipeline()`](Client.md#clientpipelineoptions-handler), [`Client.request()`](Client.md#clientrequestoptions-callback), [`Client.stream()`](Client.md#clientstreamoptions-factory-callback), and [`Client.upgrade()`](Client.md#clientupgradeoptions-callback)), the `Client` instance will transition from **idle** to [**pending**](#pending) and then most likely directly to [**processing**](#processing).
61
+ The **idle** state is the initial state of a `Client` instance. While an `origin` is required for instantiating a `Client` instance, the underlying socket connection will not be established until a request is queued using [`Client.dispatch()`](/docs/docs/api/Client.md#clientdispatchoptions-handlers). By calling `Client.dispatch()` directly or using one of the multiple implementations ([`Client.connect()`](Client.md#clientconnectoptions-callback), [`Client.pipeline()`](Client.md#clientpipelineoptions-handler), [`Client.request()`](Client.md#clientrequestoptions-callback), [`Client.stream()`](Client.md#clientstreamoptions-factory-callback), and [`Client.upgrade()`](/docs/docs/api/Client.md#clientupgradeoptions-callback)), the `Client` instance will transition from **idle** to [**pending**](/docs/docs/api/Client.md#pending) and then most likely directly to [**processing**](/docs/docs/api/Client.md#processing).
62
62
 
63
- Calling [`Client.close()`](Client.md#clientclosecallback) or [`Client.destroy()`](Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](#destroyed) state since the `Client` instance will have no queued requests in this state.
63
+ Calling [`Client.close()`](/docs/docs/api/Client.md#clientclosecallback) or [`Client.destroy()`](Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](/docs/docs/api/Client.md#destroyed) state since the `Client` instance will have no queued requests in this state.
64
64
 
65
65
  ### pending
66
66
 
67
- The **pending** state signifies a non-processing `Client`. Upon entering this state, the `Client` establishes a socket connection and emits the [`'connect'`](Client.md#event-connect) event signalling a connection was successfully established with the `origin` provided during `Client` instantiation. The internal queue is initially empty, and requests can start queueing.
67
+ The **pending** state signifies a non-processing `Client`. Upon entering this state, the `Client` establishes a socket connection and emits the [`'connect'`](/docs/docs/api/Client.md#event-connect) event signalling a connection was successfully established with the `origin` provided during `Client` instantiation. The internal queue is initially empty, and requests can start queueing.
68
68
 
69
- Calling [`Client.close()`](Client.md#clientclosecallback) with queued requests, transitions the `Client` to the [**processing**](#processing) state. Without queued requests, it transitions to the [**destroyed**](#destroyed) state.
69
+ Calling [`Client.close()`](/docs/docs/api/Client.md#clientclosecallback) with queued requests, transitions the `Client` to the [**processing**](/docs/docs/api/Client.md#processing) state. Without queued requests, it transitions to the [**destroyed**](/docs/docs/api/Client.md#destroyed) state.
70
70
 
71
- Calling [`Client.destroy()`](Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](#destroyed) state regardless of existing requests.
71
+ Calling [`Client.destroy()`](/docs/docs/api/Client.md#clientdestroyerror-callback) transitions directly to the [**destroyed**](/docs/docs/api/Client.md#destroyed) state regardless of existing requests.
72
72
 
73
73
  ### processing
74
74
 
75
- The **processing** state is a state machine within itself. It initializes to the [**processing.running**](#running) state. The [`Client.dispatch()`](Client.md#clientdispatchoptions-handlers), [`Client.close()`](Client.md#clientclosecallback), and [`Client.destroy()`](Client.md#clientdestroyerror-callback) can be called at any time while the `Client` is in this state. `Client.dispatch()` will add more requests to the queue while existing requests continue to be processed. `Client.close()` will transition to the [**processing.closing**](#closing) state. And `Client.destroy()` will transition to [**destroyed**](#destroyed).
75
+ The **processing** state is a state machine within itself. It initializes to the [**processing.running**](/docs/docs/api/Client.md#running) state. The [`Client.dispatch()`](/docs/docs/api/Client.md#clientdispatchoptions-handlers), [`Client.close()`](Client.md#clientclosecallback), and [`Client.destroy()`](Client.md#clientdestroyerror-callback) can be called at any time while the `Client` is in this state. `Client.dispatch()` will add more requests to the queue while existing requests continue to be processed. `Client.close()` will transition to the [**processing.closing**](/docs/docs/api/Client.md#closing) state. And `Client.destroy()` will transition to [**destroyed**](/docs/docs/api/Client.md#destroyed).
76
76
 
77
77
  #### running
78
78
 
79
- In the **processing.running** sub-state, queued requests are being processed in a FIFO order. If a request body requires draining, the *needDrain* event transitions to the [**processing.busy**](#busy) sub-state. The *close* event transitions the Client to the [**process.closing**](#closing) sub-state. If all queued requests are processed and neither [`Client.close()`](Client.md#clientclosecallback) nor [`Client.destroy()`](Client.md#clientdestroyerror-callback) are called, then the [**processing**](#processing) machine will trigger a *keepalive* event transitioning the `Client` back to the [**pending**](#pending) state. During this time, the `Client` is waiting for the socket connection to timeout, and once it does, it triggers the *timeout* event and transitions to the [**idle**](#idle) state.
79
+ In the **processing.running** sub-state, queued requests are being processed in a FIFO order. If a request body requires draining, the *needDrain* event transitions to the [**processing.busy**](/docs/docs/api/Client.md#busy) sub-state. The *close* event transitions the Client to the [**process.closing**](/docs/docs/api/Client.md#closing) sub-state. If all queued requests are processed and neither [`Client.close()`](/docs/docs/api/Client.md#clientclosecallback) nor [`Client.destroy()`](Client.md#clientdestroyerror-callback) are called, then the [**processing**](/docs/docs/api/Client.md#processing) machine will trigger a *keepalive* event transitioning the `Client` back to the [**pending**](/docs/docs/api/Client.md#pending) state. During this time, the `Client` is waiting for the socket connection to timeout, and once it does, it triggers the *timeout* event and transitions to the [**idle**](/docs/docs/api/Client.md#idle) state.
80
80
 
81
81
  #### busy
82
82
 
83
- This sub-state is only entered when a request body is an instance of [Stream](https://nodejs.org/api/stream.html) and requires draining. The `Client` cannot process additional requests while in this state and must wait until the currently processing request body is completely drained before transitioning back to [**processing.running**](#running).
83
+ This sub-state is only entered when a request body is an instance of [Stream](https://nodejs.org/api/stream.html) and requires draining. The `Client` cannot process additional requests while in this state and must wait until the currently processing request body is completely drained before transitioning back to [**processing.running**](/docs/docs/api/Client.md#running).
84
84
 
85
85
  #### closing
86
86
 
87
- This sub-state is only entered when a `Client` instance has queued requests and the [`Client.close()`](Client.md#clientclosecallback) method is called. In this state, the `Client` instance continues to process requests as usual, with the one exception that no additional requests can be queued. Once all of the queued requests are processed, the `Client` will trigger the *done* event gracefully entering the [**destroyed**](#destroyed) state without an error.
87
+ This sub-state is only entered when a `Client` instance has queued requests and the [`Client.close()`](/docs/docs/api/Client.md#clientclosecallback) method is called. In this state, the `Client` instance continues to process requests as usual, with the one exception that no additional requests can be queued. Once all of the queued requests are processed, the `Client` will trigger the *done* event gracefully entering the [**destroyed**](/docs/docs/api/Client.md#destroyed) state without an error.
88
88
 
89
89
  ### destroyed
90
90
 
@@ -1,6 +1,6 @@
1
1
  # Mocking Request
2
2
 
3
- Undici has its own mocking [utility](../api/MockAgent.md). It allow us to intercept undici HTTP requests and return mocked values instead. It can be useful for testing purposes.
3
+ Undici has its own mocking [utility](/docs/docs/api/MockAgent.md). It allow us to intercept undici HTTP requests and return mocked values instead. It can be useful for testing purposes.
4
4
 
5
5
  Example:
6
6
 
@@ -73,7 +73,7 @@ const badRequest = await bankTransfer('1234567890', '100')
73
73
  assert.deepEqual(badRequest, { message: 'bank account not found' })
74
74
  ```
75
75
 
76
- Explore other MockAgent functionality [here](../api/MockAgent.md)
76
+ Explore other MockAgent functionality [here](/docs/docs/api/MockAgent.md)
77
77
 
78
78
  ## Debug Mock Value
79
79
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Connecting through a proxy is possible by:
4
4
 
5
- - Using [ProxyAgent](../api/ProxyAgent.md).
5
+ - Using [ProxyAgent](/docs/docs/api/ProxyAgent.md).
6
6
  - Configuring `Client` or `Pool` constructor.
7
7
 
8
8
  The proxy url should be passed to the `Client` or `Pool` constructor, while the upstream server url
package/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './types/index'
2
1
  import Undici from './types/index'
3
2
  export default Undici
3
+ export * from './types/index'
package/index.js CHANGED
@@ -21,7 +21,6 @@ const RetryHandler = require('./lib/handler/retry-handler')
21
21
  const { getGlobalDispatcher, setGlobalDispatcher } = require('./lib/global')
22
22
  const DecoratorHandler = require('./lib/handler/decorator-handler')
23
23
  const RedirectHandler = require('./lib/handler/redirect-handler')
24
- const createRedirectInterceptor = require('./lib/interceptor/redirect-interceptor')
25
24
 
26
25
  Object.assign(Dispatcher.prototype, api)
27
26
 
@@ -37,11 +36,26 @@ module.exports.RetryHandler = RetryHandler
37
36
 
38
37
  module.exports.DecoratorHandler = DecoratorHandler
39
38
  module.exports.RedirectHandler = RedirectHandler
40
- module.exports.createRedirectInterceptor = createRedirectInterceptor
41
39
  module.exports.interceptors = {
42
40
  redirect: require('./lib/interceptor/redirect'),
41
+ responseError: require('./lib/interceptor/response-error'),
43
42
  retry: require('./lib/interceptor/retry'),
44
- dump: require('./lib/interceptor/dump')
43
+ dump: require('./lib/interceptor/dump'),
44
+ dns: require('./lib/interceptor/dns'),
45
+ cache: require('./lib/interceptor/cache')
46
+ }
47
+
48
+ module.exports.cacheStores = {
49
+ MemoryCacheStore: require('./lib/cache/memory-cache-store')
50
+ }
51
+
52
+ try {
53
+ const SqliteCacheStore = require('./lib/cache/sqlite-cache-store')
54
+ module.exports.cacheStores.SqliteCacheStore = SqliteCacheStore
55
+ } catch (err) {
56
+ if (err.code !== 'ERR_UNKNOWN_BUILTIN_MODULE') {
57
+ throw err
58
+ }
45
59
  }
46
60
 
47
61
  module.exports.buildConnector = buildConnector
@@ -119,8 +133,6 @@ module.exports.Headers = require('./lib/web/fetch/headers').Headers
119
133
  module.exports.Response = require('./lib/web/fetch/response').Response
120
134
  module.exports.Request = require('./lib/web/fetch/request').Request
121
135
  module.exports.FormData = require('./lib/web/fetch/formdata').FormData
122
- module.exports.File = globalThis.File ?? require('node:buffer').File
123
- module.exports.FileReader = require('./lib/web/fileapi/filereader').FileReader
124
136
 
125
137
  const { setGlobalOrigin, getGlobalOrigin } = require('./lib/web/fetch/global')
126
138
 
@@ -128,18 +140,19 @@ module.exports.setGlobalOrigin = setGlobalOrigin
128
140
  module.exports.getGlobalOrigin = getGlobalOrigin
129
141
 
130
142
  const { CacheStorage } = require('./lib/web/cache/cachestorage')
131
- const { kConstruct } = require('./lib/web/cache/symbols')
143
+ const { kConstruct } = require('./lib/core/symbols')
132
144
 
133
145
  // Cache & CacheStorage are tightly coupled with fetch. Even if it may run
134
146
  // in an older version of Node, it doesn't have any use without fetch.
135
147
  module.exports.caches = new CacheStorage(kConstruct)
136
148
 
137
- const { deleteCookie, getCookies, getSetCookies, setCookie } = require('./lib/web/cookies')
149
+ const { deleteCookie, getCookies, getSetCookies, setCookie, parseCookie } = require('./lib/web/cookies')
138
150
 
139
151
  module.exports.deleteCookie = deleteCookie
140
152
  module.exports.getCookies = getCookies
141
153
  module.exports.getSetCookies = getSetCookies
142
154
  module.exports.setCookie = setCookie
155
+ module.exports.parseCookie = parseCookie
143
156
 
144
157
  const { parseMIMEType, serializeAMimeType } = require('./lib/web/fetch/data-url')
145
158
 
@@ -152,6 +165,9 @@ module.exports.CloseEvent = CloseEvent
152
165
  module.exports.ErrorEvent = ErrorEvent
153
166
  module.exports.MessageEvent = MessageEvent
154
167
 
168
+ module.exports.WebSocketStream = require('./lib/web/websocket/stream/websocketstream').WebSocketStream
169
+ module.exports.WebSocketError = require('./lib/web/websocket/stream/websocketerror').WebSocketError
170
+
155
171
  module.exports.request = makeDispatcher(api.request)
156
172
  module.exports.stream = makeDispatcher(api.stream)
157
173
  module.exports.pipeline = makeDispatcher(api.pipeline)
@@ -1,3 +1,5 @@
1
+ 'use strict'
2
+
1
3
  const { addAbortListener } = require('../core/util')
2
4
  const { RequestAbortedError } = require('../core/errors')
3
5
 
@@ -95,7 +95,9 @@ function connect (opts, callback) {
95
95
 
96
96
  try {
97
97
  const connectHandler = new ConnectHandler(opts, callback)
98
- this.dispatch({ ...opts, method: 'CONNECT' }, connectHandler)
98
+ const connectOptions = { ...opts, method: 'CONNECT' }
99
+
100
+ this.dispatch(connectOptions, connectHandler)
99
101
  } catch (err) {
100
102
  if (typeof callback !== 'function') {
101
103
  throw err
@@ -5,15 +5,17 @@ const {
5
5
  Duplex,
6
6
  PassThrough
7
7
  } = require('node:stream')
8
+ const assert = require('node:assert')
9
+ const { AsyncResource } = require('node:async_hooks')
8
10
  const {
9
11
  InvalidArgumentError,
10
12
  InvalidReturnValueError,
11
13
  RequestAbortedError
12
14
  } = require('../core/errors')
13
15
  const util = require('../core/util')
14
- const { AsyncResource } = require('node:async_hooks')
15
16
  const { addSignal, removeSignal } = require('./abort-signal')
16
- const assert = require('node:assert')
17
+
18
+ function noop () {}
17
19
 
18
20
  const kResume = Symbol('resume')
19
21
 
@@ -92,7 +94,7 @@ class PipelineHandler extends AsyncResource {
92
94
  this.context = null
93
95
  this.onInfo = onInfo || null
94
96
 
95
- this.req = new PipelineRequest().on('error', util.nop)
97
+ this.req = new PipelineRequest().on('error', noop)
96
98
 
97
99
  this.ret = new Duplex({
98
100
  readableObjectMode: opts.objectMode,
@@ -145,7 +147,7 @@ class PipelineHandler extends AsyncResource {
145
147
  }
146
148
 
147
149
  onConnect (abort, context) {
148
- const { ret, res } = this
150
+ const { res } = this
149
151
 
150
152
  if (this.reason) {
151
153
  abort(this.reason)
@@ -153,7 +155,6 @@ class PipelineHandler extends AsyncResource {
153
155
  }
154
156
 
155
157
  assert(!res, 'pipeline cannot be retried')
156
- assert(!ret.destroyed)
157
158
 
158
159
  this.abort = abort
159
160
  this.context = context
@@ -184,7 +185,7 @@ class PipelineHandler extends AsyncResource {
184
185
  context
185
186
  })
186
187
  } catch (err) {
187
- this.res.on('error', util.nop)
188
+ this.res.on('error', noop)
188
189
  throw err
189
190
  }
190
191
 
@@ -1,11 +1,12 @@
1
1
  'use strict'
2
2
 
3
3
  const assert = require('node:assert')
4
+ const { AsyncResource } = require('node:async_hooks')
4
5
  const { Readable } = require('./readable')
5
6
  const { InvalidArgumentError, RequestAbortedError } = require('../core/errors')
6
7
  const util = require('../core/util')
7
- const { getResolveErrorBodyCallback } = require('./util')
8
- const { AsyncResource } = require('node:async_hooks')
8
+
9
+ function noop () {}
9
10
 
10
11
  class RequestHandler extends AsyncResource {
11
12
  constructor (opts, callback) {
@@ -13,7 +14,7 @@ class RequestHandler extends AsyncResource {
13
14
  throw new InvalidArgumentError('invalid opts')
14
15
  }
15
16
 
16
- const { signal, method, opaque, body, onInfo, responseHeaders, throwOnError, highWaterMark } = opts
17
+ const { signal, method, opaque, body, onInfo, responseHeaders, highWaterMark } = opts
17
18
 
18
19
  try {
19
20
  if (typeof callback !== 'function') {
@@ -39,7 +40,7 @@ class RequestHandler extends AsyncResource {
39
40
  super('UNDICI_REQUEST')
40
41
  } catch (err) {
41
42
  if (util.isStream(body)) {
42
- util.destroy(body.on('error', util.nop), err)
43
+ util.destroy(body.on('error', noop), err)
43
44
  }
44
45
  throw err
45
46
  }
@@ -54,38 +55,22 @@ class RequestHandler extends AsyncResource {
54
55
  this.trailers = {}
55
56
  this.context = null
56
57
  this.onInfo = onInfo || null
57
- this.throwOnError = throwOnError
58
58
  this.highWaterMark = highWaterMark
59
- this.signal = signal
60
59
  this.reason = null
61
60
  this.removeAbortListener = null
62
61
 
63
- if (util.isStream(body)) {
64
- body.on('error', (err) => {
65
- this.onError(err)
62
+ if (signal?.aborted) {
63
+ this.reason = signal.reason ?? new RequestAbortedError()
64
+ } else if (signal) {
65
+ this.removeAbortListener = util.addAbortListener(signal, () => {
66
+ this.reason = signal.reason ?? new RequestAbortedError()
67
+ if (this.res) {
68
+ util.destroy(this.res.on('error', noop), this.reason)
69
+ } else if (this.abort) {
70
+ this.abort(this.reason)
71
+ }
66
72
  })
67
73
  }
68
-
69
- if (this.signal) {
70
- if (this.signal.aborted) {
71
- this.reason = this.signal.reason ?? new RequestAbortedError()
72
- } else {
73
- this.removeAbortListener = util.addAbortListener(this.signal, () => {
74
- this.reason = this.signal.reason ?? new RequestAbortedError()
75
- if (this.res) {
76
- util.destroy(this.res, this.reason)
77
- } else if (this.abort) {
78
- this.abort(this.reason)
79
- }
80
-
81
- if (this.removeAbortListener) {
82
- this.res?.off('close', this.removeAbortListener)
83
- this.removeAbortListener()
84
- this.removeAbortListener = null
85
- }
86
- })
87
- }
88
- }
89
74
  }
90
75
 
91
76
  onConnect (abort, context) {
@@ -127,25 +112,20 @@ class RequestHandler extends AsyncResource {
127
112
 
128
113
  if (this.removeAbortListener) {
129
114
  res.on('close', this.removeAbortListener)
115
+ this.removeAbortListener = null
130
116
  }
131
117
 
132
118
  this.callback = null
133
119
  this.res = res
134
120
  if (callback !== null) {
135
- if (this.throwOnError && statusCode >= 400) {
136
- this.runInAsyncScope(getResolveErrorBodyCallback, null,
137
- { callback, body: res, contentType, statusCode, statusMessage, headers }
138
- )
139
- } else {
140
- this.runInAsyncScope(callback, null, null, {
141
- statusCode,
142
- headers,
143
- trailers: this.trailers,
144
- opaque,
145
- body: res,
146
- context
147
- })
148
- }
121
+ this.runInAsyncScope(callback, null, null, {
122
+ statusCode,
123
+ headers,
124
+ trailers: this.trailers,
125
+ opaque,
126
+ body: res,
127
+ context
128
+ })
149
129
  }
150
130
  }
151
131
 
@@ -173,17 +153,20 @@ class RequestHandler extends AsyncResource {
173
153
  this.res = null
174
154
  // Ensure all queued handlers are invoked before destroying res.
175
155
  queueMicrotask(() => {
176
- util.destroy(res, err)
156
+ util.destroy(res.on('error', noop), err)
177
157
  })
178
158
  }
179
159
 
180
160
  if (body) {
181
161
  this.body = null
182
- util.destroy(body, err)
162
+
163
+ if (util.isStream(body)) {
164
+ body.on('error', noop)
165
+ util.destroy(body, err)
166
+ }
183
167
  }
184
168
 
185
169
  if (this.removeAbortListener) {
186
- res?.off('close', this.removeAbortListener)
187
170
  this.removeAbortListener()
188
171
  this.removeAbortListener = null
189
172
  }
@@ -200,7 +183,9 @@ function request (opts, callback) {
200
183
  }
201
184
 
202
185
  try {
203
- this.dispatch(opts, new RequestHandler(opts, callback))
186
+ const handler = new RequestHandler(opts, callback)
187
+
188
+ this.dispatch(opts, handler)
204
189
  } catch (err) {
205
190
  if (typeof callback !== 'function') {
206
191
  throw err