aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/node_modules/undici/docs/api
diff options
context:
space:
mode:
authorEgor Tensin <egor@tensin.name>2026-02-28 21:59:12 +0100
committerEgor Tensin <egor@tensin.name>2026-02-28 22:19:57 +0100
commit9611c248995ad3bacda1d0a93d0b5e1e6605d162 (patch)
treeeb3ae35b426e9d72e7cb34e8e9cc0453745a8e17 /node_modules/undici/docs/api
parentDEVELOPMENT.md: expand on sources (diff)
downloadcleanup-path-9611c248995ad3bacda1d0a93d0b5e1e6605d162.tar.gz
cleanup-path-9611c248995ad3bacda1d0a93d0b5e1e6605d162.zip
upgrade actions/core to version 2
Diffstat (limited to '')
-rw-r--r--node_modules/undici/docs/api/Fetch.md27
-rw-r--r--node_modules/undici/docs/docs/api/Agent.md (renamed from node_modules/undici/docs/api/Agent.md)0
-rw-r--r--node_modules/undici/docs/docs/api/BalancedPool.md (renamed from node_modules/undici/docs/api/BalancedPool.md)2
-rw-r--r--node_modules/undici/docs/docs/api/CacheStorage.md (renamed from node_modules/undici/docs/api/CacheStorage.md)0
-rw-r--r--node_modules/undici/docs/docs/api/Client.md (renamed from node_modules/undici/docs/api/Client.md)7
-rw-r--r--node_modules/undici/docs/docs/api/Connector.md (renamed from node_modules/undici/docs/api/Connector.md)0
-rw-r--r--node_modules/undici/docs/docs/api/ContentType.md (renamed from node_modules/undici/docs/api/ContentType.md)0
-rw-r--r--node_modules/undici/docs/docs/api/Cookies.md (renamed from node_modules/undici/docs/api/Cookies.md)0
-rw-r--r--node_modules/undici/docs/docs/api/DiagnosticsChannel.md (renamed from node_modules/undici/docs/api/DiagnosticsChannel.md)10
-rw-r--r--node_modules/undici/docs/docs/api/DispatchInterceptor.md (renamed from node_modules/undici/docs/api/DispatchInterceptor.md)0
-rw-r--r--node_modules/undici/docs/docs/api/Dispatcher.md (renamed from node_modules/undici/docs/api/Dispatcher.md)476
-rw-r--r--node_modules/undici/docs/docs/api/Errors.md (renamed from node_modules/undici/docs/api/Errors.md)1
-rw-r--r--node_modules/undici/docs/docs/api/MockAgent.md (renamed from node_modules/undici/docs/api/MockAgent.md)0
-rw-r--r--node_modules/undici/docs/docs/api/MockClient.md (renamed from node_modules/undici/docs/api/MockClient.md)0
-rw-r--r--node_modules/undici/docs/docs/api/MockErrors.md (renamed from node_modules/undici/docs/api/MockErrors.md)0
-rw-r--r--node_modules/undici/docs/docs/api/MockPool.md (renamed from node_modules/undici/docs/api/MockPool.md)0
-rw-r--r--node_modules/undici/docs/docs/api/Pool.md (renamed from node_modules/undici/docs/api/Pool.md)0
-rw-r--r--node_modules/undici/docs/docs/api/PoolStats.md (renamed from node_modules/undici/docs/api/PoolStats.md)0
-rw-r--r--node_modules/undici/docs/docs/api/ProxyAgent.md (renamed from node_modules/undici/docs/api/ProxyAgent.md)11
-rw-r--r--node_modules/undici/docs/docs/api/RetryHandler.md (renamed from node_modules/undici/docs/api/RetryHandler.md)13
-rw-r--r--node_modules/undici/docs/docs/api/WebSocket.md (renamed from node_modules/undici/docs/api/WebSocket.md)0
-rw-r--r--node_modules/undici/docs/docs/api/api-lifecycle.md (renamed from node_modules/undici/docs/api/api-lifecycle.md)33
22 files changed, 529 insertions, 51 deletions
diff --git a/node_modules/undici/docs/api/Fetch.md b/node_modules/undici/docs/api/Fetch.md
deleted file mode 100644
index b5a6242..0000000
--- a/node_modules/undici/docs/api/Fetch.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# Fetch
-
-Undici exposes a fetch() method starts the process of fetching a resource from the network.
-
-Documentation and examples can be found on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/fetch).
-
-## File
-
-This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/File)
-
-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.
-
-## FormData
-
-This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData)
-
-## Response
-
-This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Response)
-
-## Request
-
-This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Request)
-
-## Header
-
-This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Headers)
diff --git a/node_modules/undici/docs/api/Agent.md b/node_modules/undici/docs/docs/api/Agent.md
index dd5d99b..dd5d99b 100644
--- a/node_modules/undici/docs/api/Agent.md
+++ b/node_modules/undici/docs/docs/api/Agent.md
diff --git a/node_modules/undici/docs/api/BalancedPool.md b/node_modules/undici/docs/docs/api/BalancedPool.md
index 290c734..183ef52 100644
--- a/node_modules/undici/docs/api/BalancedPool.md
+++ b/node_modules/undici/docs/docs/api/BalancedPool.md
@@ -50,7 +50,7 @@ Arguments:
### `BalancedPool.removeUpstream(upstream)`
-Removes an upstream that was previously addded.
+Removes an upstream that was previously added.
### `BalancedPool.close([callback])`
diff --git a/node_modules/undici/docs/api/CacheStorage.md b/node_modules/undici/docs/docs/api/CacheStorage.md
index 08ee99f..08ee99f 100644
--- a/node_modules/undici/docs/api/CacheStorage.md
+++ b/node_modules/undici/docs/docs/api/CacheStorage.md
diff --git a/node_modules/undici/docs/api/Client.md b/node_modules/undici/docs/docs/api/Client.md
index b9e26f0..03342f5 100644
--- a/node_modules/undici/docs/api/Client.md
+++ b/node_modules/undici/docs/docs/api/Client.md
@@ -19,17 +19,18 @@ Returns: `Client`
> ⚠️ Warning: The `H2` support is experimental.
-* **bodyTimeout** `number | null` (optional) - Default: `300e3` - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 300 seconds.
+* **bodyTimeout** `number | null` (optional) - Default: `300e3` - The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Defaults to 300 seconds. Please note the `timeout` will be reset if you keep writing data to the scoket everytime.
* **headersTimeout** `number | null` (optional) - Default: `300e3` - The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers while not sending the request. Defaults to 300 seconds.
* **keepAliveMaxTimeout** `number | null` (optional) - Default: `600e3` - The maximum allowed `keepAliveTimeout`, in milliseconds, when overridden by *keep-alive* hints from the server. Defaults to 10 minutes.
* **keepAliveTimeout** `number | null` (optional) - Default: `4e3` - The timeout, in milliseconds, after which a socket without active requests will time out. Monitors time between activity on a connected socket. This value may be overridden by *keep-alive* hints from the server. See [MDN: HTTP - Headers - Keep-Alive directives](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Keep-Alive#directives) for more details. Defaults to 4 seconds.
-* **keepAliveTimeoutThreshold** `number | null` (optional) - Default: `1e3` - A number of milliseconds subtracted from server *keep-alive* hints when overriding `keepAliveTimeout` to account for timing inaccuracies caused by e.g. transport latency. Defaults to 1 second.
+* **keepAliveTimeoutThreshold** `number | null` (optional) - Default: `2e3` - A number of milliseconds subtracted from server *keep-alive* hints when overriding `keepAliveTimeout` to account for timing inaccuracies caused by e.g. transport latency. Defaults to 2 seconds.
* **maxHeaderSize** `number | null` (optional) - Default: `--max-http-header-size` or `16384` - The maximum length of request headers in bytes. Defaults to Node.js' --max-http-header-size or 16KiB.
* **maxResponseSize** `number | null` (optional) - Default: `-1` - The maximum length of response body in bytes. Set to `-1` to disable.
* **pipelining** `number | null` (optional) - Default: `1` - The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Carefully consider your workload and environment before enabling concurrent requests as pipelining may reduce performance if used incorrectly. Pipelining is sensitive to network stack settings as well as head of line blocking caused by e.g. long running requests. Set to `0` to disable keep-alive connections.
* **connect** `ConnectOptions | Function | null` (optional) - Default: `null`.
* **strictContentLength** `Boolean` (optional) - Default: `true` - Whether to treat request content length mismatches as errors. If true, an error is thrown when the request content-length header doesn't match the length of the request body.
-* **interceptors** `{ Client: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - 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). Note that the behavior of interceptors is Experimental and might change at any given time.
+ <!-- TODO: Remove once we drop its support -->
+* **interceptors** `{ Client: DispatchInterceptor[] }` - Default: `[RedirectInterceptor]` - 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). Note that the behavior of interceptors is Experimental and might change at any given time. **Note: this is deprecated in favor of [Dispatcher#compose](./Dispatcher.md#dispatcher). Support will be droped in next major.**
* **autoSelectFamily**: `boolean` (optional) - Default: depends on local Node version, on Node 18.13.0 and above is `false`. Enables a family autodetection algorithm that loosely implements section 5 of [RFC 8305](https://tools.ietf.org/html/rfc8305#section-5). See [here](https://nodejs.org/api/net.html#socketconnectoptions-connectlistener) for more details. This option is ignored if not supported by the current Node version.
* **autoSelectFamilyAttemptTimeout**: `number` - Default: depends on local Node version, on Node 18.13.0 and above is `250`. The amount of time in milliseconds to wait for a connection attempt to finish before trying the next address when using the `autoSelectFamily` option. See [here](https://nodejs.org/api/net.html#socketconnectoptions-connectlistener) for more details.
* **allowH2**: `boolean` - Default: `false`. Enables support for H2 if the server has assigned bigger priority to it through ALPN negotiation.
diff --git a/node_modules/undici/docs/api/Connector.md b/node_modules/undici/docs/docs/api/Connector.md
index 56821bd..56821bd 100644
--- a/node_modules/undici/docs/api/Connector.md
+++ b/node_modules/undici/docs/docs/api/Connector.md
diff --git a/node_modules/undici/docs/api/ContentType.md b/node_modules/undici/docs/docs/api/ContentType.md
index 2bcc9f7..2bcc9f7 100644
--- a/node_modules/undici/docs/api/ContentType.md
+++ b/node_modules/undici/docs/docs/api/ContentType.md
diff --git a/node_modules/undici/docs/api/Cookies.md b/node_modules/undici/docs/docs/api/Cookies.md
index 0cad379..0cad379 100644
--- a/node_modules/undici/docs/api/Cookies.md
+++ b/node_modules/undici/docs/docs/api/Cookies.md
diff --git a/node_modules/undici/docs/api/DiagnosticsChannel.md b/node_modules/undici/docs/docs/api/DiagnosticsChannel.md
index 0aa0b9a..099c072 100644
--- a/node_modules/undici/docs/api/DiagnosticsChannel.md
+++ b/node_modules/undici/docs/docs/api/DiagnosticsChannel.md
@@ -19,9 +19,9 @@ diagnosticsChannel.channel('undici:request:create').subscribe(({ request }) => {
console.log('completed', request.completed)
console.log('method', request.method)
console.log('path', request.path)
- console.log('headers') // raw text, e.g: 'bar: bar\r\n'
+ console.log('headers') // array of strings, e.g: ['foo', 'bar']
request.addHeader('hello', 'world')
- console.log('headers', request.headers) // e.g. 'bar: bar\r\nhello: world\r\n'
+ console.log('headers', request.headers) // e.g. ['foo', 'bar', 'hello', 'world']
})
```
@@ -105,7 +105,7 @@ You can not assume that this event is related to any specific request.
import diagnosticsChannel from 'diagnostics_channel'
diagnosticsChannel.channel('undici:client:beforeConnect').subscribe(({ connectParams, connector }) => {
- // const { host, hostname, protocol, port, servername } = connectParams
+ // const { host, hostname, protocol, port, servername, version } = connectParams
// connector is a function that creates the socket
})
```
@@ -118,7 +118,7 @@ This message is published after a connection is established.
import diagnosticsChannel from 'diagnostics_channel'
diagnosticsChannel.channel('undici:client:connected').subscribe(({ socket, connectParams, connector }) => {
- // const { host, hostname, protocol, port, servername } = connectParams
+ // const { host, hostname, protocol, port, servername, version } = connectParams
// connector is a function that creates the socket
})
```
@@ -131,7 +131,7 @@ This message is published if it did not succeed to create new connection
import diagnosticsChannel from 'diagnostics_channel'
diagnosticsChannel.channel('undici:client:connectError').subscribe(({ error, socket, connectParams, connector }) => {
- // const { host, hostname, protocol, port, servername } = connectParams
+ // const { host, hostname, protocol, port, servername, version } = connectParams
// connector is a function that creates the socket
console.log(`Connect failed with ${error.message}`)
})
diff --git a/node_modules/undici/docs/api/DispatchInterceptor.md b/node_modules/undici/docs/docs/api/DispatchInterceptor.md
index 7dfc260..7dfc260 100644
--- a/node_modules/undici/docs/api/DispatchInterceptor.md
+++ b/node_modules/undici/docs/docs/api/DispatchInterceptor.md
diff --git a/node_modules/undici/docs/api/Dispatcher.md b/node_modules/undici/docs/docs/api/Dispatcher.md
index fd463bf..ce14bfe 100644
--- a/node_modules/undici/docs/api/Dispatcher.md
+++ b/node_modules/undici/docs/docs/api/Dispatcher.md
@@ -209,6 +209,7 @@ Returns: `Boolean` - `false` if dispatcher is busy and further dispatch calls wo
* **onConnect** `(abort: () => void, context: object) => void` - Invoked before request is dispatched on socket. May be invoked multiple times when a request is retried when the request at the head of the pipeline fails.
* **onError** `(error: Error) => void` - Invoked when an error has occurred. May not throw.
* **onUpgrade** `(statusCode: number, headers: Buffer[], socket: Duplex) => void` (optional) - Invoked when request is upgraded. Required if `DispatchOptions.upgrade` is defined or `DispatchOptions.method === 'CONNECT'`.
+* **onResponseStarted** `() => void` (optional) - Invoked when response is received, before headers have been read.
* **onHeaders** `(statusCode: number, headers: Buffer[], resume: () => void, statusText: string) => boolean` - Invoked when statusCode and headers have been received. May be invoked multiple times due to 1xx informational headers. Not required for `upgrade` requests.
* **onData** `(chunk: Buffer) => boolean` - Invoked when response payload data is received. Not required for `upgrade` requests.
* **onComplete** `(trailers: Buffer[]) => void` - Invoked when response payload and trailers have been received and the request has completed. Not required for `upgrade` requests.
@@ -487,11 +488,13 @@ The `RequestOptions.method` property should not be value `'CONNECT'`.
`body` contains the following additional [body mixin](https://fetch.spec.whatwg.org/#body-mixin) methods and properties:
-- `text()`
-- `json()`
-- `arrayBuffer()`
-- `body`
-- `bodyUsed`
+* [`.arrayBuffer()`](https://fetch.spec.whatwg.org/#dom-body-arraybuffer)
+* [`.blob()`](https://fetch.spec.whatwg.org/#dom-body-blob)
+* [`.bytes()`](https://fetch.spec.whatwg.org/#dom-body-bytes)
+* [`.json()`](https://fetch.spec.whatwg.org/#dom-body-json)
+* [`.text()`](https://fetch.spec.whatwg.org/#dom-body-text)
+* `body`
+* `bodyUsed`
`body` can not be consumed twice. For example, calling `text()` after `json()` throws `TypeError`.
@@ -816,6 +819,421 @@ try {
}
```
+### `Dispatcher.compose(interceptors[, interceptor])`
+
+Compose a new dispatcher from the current dispatcher and the given interceptors.
+
+> _Notes_:
+> - The order of the interceptors matters. The first interceptor will be the first to be called.
+> - It is important to note that the `interceptor` function should return a function that follows the `Dispatcher.dispatch` signature.
+> - Any fork of the chain of `interceptors` can lead to unexpected results.
+
+Arguments:
+
+* **interceptors** `Interceptor[interceptor[]]`: It is an array of `Interceptor` functions passed as only argument, or several interceptors passed as separate arguments.
+
+Returns: `Dispatcher`.
+
+#### Parameter: `Interceptor`
+
+A function that takes a `dispatch` method and returns a `dispatch`-like function.
+
+#### Example 1 - Basic Compose
+
+```js
+const { Client, RedirectHandler } = require('undici')
+
+const redirectInterceptor = dispatch => {
+ return (opts, handler) => {
+ const { maxRedirections } = opts
+
+ if (!maxRedirections) {
+ return dispatch(opts, handler)
+ }
+
+ const redirectHandler = new RedirectHandler(
+ dispatch,
+ maxRedirections,
+ opts,
+ handler
+ )
+ opts = { ...opts, maxRedirections: 0 } // Stop sub dispatcher from also redirecting.
+ return dispatch(opts, redirectHandler)
+ }
+}
+
+const client = new Client('http://localhost:3000')
+ .compose(redirectInterceptor)
+
+await client.request({ path: '/', method: 'GET' })
+```
+
+#### Example 2 - Chained Compose
+
+```js
+const { Client, RedirectHandler, RetryHandler } = require('undici')
+
+const redirectInterceptor = dispatch => {
+ return (opts, handler) => {
+ const { maxRedirections } = opts
+
+ if (!maxRedirections) {
+ return dispatch(opts, handler)
+ }
+
+ const redirectHandler = new RedirectHandler(
+ dispatch,
+ maxRedirections,
+ opts,
+ handler
+ )
+ opts = { ...opts, maxRedirections: 0 }
+ return dispatch(opts, redirectHandler)
+ }
+}
+
+const retryInterceptor = dispatch => {
+ return function retryInterceptor (opts, handler) {
+ return dispatch(
+ opts,
+ new RetryHandler(opts, {
+ handler,
+ dispatch
+ })
+ )
+ }
+}
+
+const client = new Client('http://localhost:3000')
+ .compose(redirectInterceptor)
+ .compose(retryInterceptor)
+
+await client.request({ path: '/', method: 'GET' })
+```
+
+#### Pre-built interceptors
+
+##### `redirect`
+
+The `redirect` interceptor allows you to customize the way your dispatcher handles redirects.
+
+It accepts the same arguments as the [`RedirectHandler` constructor](./RedirectHandler.md).
+
+**Example - Basic Redirect Interceptor**
+
+```js
+const { Client, interceptors } = require("undici");
+const { redirect } = interceptors;
+
+const client = new Client("http://example.com").compose(
+ redirect({ maxRedirections: 3, throwOnMaxRedirects: true })
+);
+client.request({ path: "/" })
+```
+
+##### `retry`
+
+The `retry` interceptor allows you to customize the way your dispatcher handles retries.
+
+It accepts the same arguments as the [`RetryHandler` constructor](./RetryHandler.md).
+
+**Example - Basic Redirect Interceptor**
+
+```js
+const { Client, interceptors } = require("undici");
+const { retry } = interceptors;
+
+const client = new Client("http://example.com").compose(
+ retry({
+ maxRetries: 3,
+ minTimeout: 1000,
+ maxTimeout: 10000,
+ timeoutFactor: 2,
+ retryAfter: true,
+ })
+);
+```
+
+##### `dump`
+
+The `dump` interceptor enables you to dump the response body from a request upon a given limit.
+
+**Options**
+- `maxSize` - The maximum size (in bytes) of the response body to dump. If the size of the request's body exceeds this value then the connection will be closed. Default: `1048576`.
+
+> The `Dispatcher#options` also gets extended with the options `dumpMaxSize`, `abortOnDumped`, and `waitForTrailers` which can be used to configure the interceptor at a request-per-request basis.
+
+**Example - Basic Dump Interceptor**
+
+```js
+const { Client, interceptors } = require("undici");
+const { dump } = interceptors;
+
+const client = new Client("http://example.com").compose(
+ dump({
+ maxSize: 1024,
+ })
+);
+
+// or
+client.dispatch(
+ {
+ path: "/",
+ method: "GET",
+ dumpMaxSize: 1024,
+ },
+ handler
+);
+```
+
+##### `dns`
+
+The `dns` interceptor enables you to cache DNS lookups for a given duration, per origin.
+
+>It is well suited for scenarios where you want to cache DNS lookups to avoid the overhead of resolving the same domain multiple times
+
+**Options**
+- `maxTTL` - The maximum time-to-live (in milliseconds) of the DNS cache. It should be a positive integer. Default: `10000`.
+ - Set `0` to disable TTL.
+- `maxItems` - The maximum number of items to cache. It should be a positive integer. Default: `Infinity`.
+- `dualStack` - Whether to resolve both IPv4 and IPv6 addresses. Default: `true`.
+ - It will also attempt a happy-eyeballs-like approach to connect to the available addresses in case of a connection failure.
+- `affinity` - Whether to use IPv4 or IPv6 addresses. Default: `4`.
+ - It can be either `'4` or `6`.
+ - It will only take effect if `dualStack` is `false`.
+- `lookup: (hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, addresses: DNSInterceptorRecord[]) => void) => void` - Custom lookup function. Default: `dns.lookup`.
+ - For more info see [dns.lookup](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback).
+- `pick: (origin: URL, records: DNSInterceptorRecords, affinity: 4 | 6) => DNSInterceptorRecord` - Custom pick function. Default: `RoundRobin`.
+ - The function should return a single record from the records array.
+ - By default a simplified version of Round Robin is used.
+ - The `records` property can be mutated to store the state of the balancing algorithm.
+
+> The `Dispatcher#options` also gets extended with the options `dns.affinity`, `dns.dualStack`, `dns.lookup` and `dns.pick` which can be used to configure the interceptor at a request-per-request basis.
+
+
+**DNSInterceptorRecord**
+It represents a DNS record.
+- `family` - (`number`) The IP family of the address. It can be either `4` or `6`.
+- `address` - (`string`) The IP address.
+
+**DNSInterceptorOriginRecords**
+It represents a map of DNS IP addresses records for a single origin.
+- `4.ips` - (`DNSInterceptorRecord[] | null`) The IPv4 addresses.
+- `6.ips` - (`DNSInterceptorRecord[] | null`) The IPv6 addresses.
+
+**Example - Basic DNS Interceptor**
+
+```js
+const { Client, interceptors } = require("undici");
+const { dns } = interceptors;
+
+const client = new Agent().compose([
+ dns({ ...opts })
+])
+
+const response = await client.request({
+ origin: `http://localhost:3030`,
+ ...requestOpts
+})
+```
+
+##### `Response Error Interceptor`
+
+**Introduction**
+
+The Response Error Interceptor is designed to handle HTTP response errors efficiently. It intercepts responses and throws detailed errors for responses with status codes indicating failure (4xx, 5xx). This interceptor enhances error handling by providing structured error information, including response headers, data, and status codes.
+
+**ResponseError Class**
+
+The `ResponseError` class extends the `UndiciError` class and encapsulates detailed error information. It captures the response status code, headers, and data, providing a structured way to handle errors.
+
+**Definition**
+
+```js
+class ResponseError extends UndiciError {
+ constructor (message, code, { headers, data }) {
+ super(message);
+ this.name = 'ResponseError';
+ this.message = message || 'Response error';
+ this.code = 'UND_ERR_RESPONSE';
+ this.statusCode = code;
+ this.data = data;
+ this.headers = headers;
+ }
+}
+```
+
+**Interceptor Handler**
+
+The interceptor's handler class extends `DecoratorHandler` and overrides methods to capture response details and handle errors based on the response status code.
+
+**Methods**
+
+- **onConnect**: Initializes response properties.
+- **onHeaders**: Captures headers and status code. Decodes body if content type is `application/json` or `text/plain`.
+- **onData**: Appends chunks to the body if status code indicates an error.
+- **onComplete**: Finalizes error handling, constructs a `ResponseError`, and invokes the `onError` method.
+- **onError**: Propagates errors to the handler.
+
+**Definition**
+
+```js
+class Handler extends DecoratorHandler {
+ // Private properties
+ #handler;
+ #statusCode;
+ #contentType;
+ #decoder;
+ #headers;
+ #body;
+
+ constructor (opts, { handler }) {
+ super(handler);
+ this.#handler = handler;
+ }
+
+ onConnect (abort) {
+ this.#statusCode = 0;
+ this.#contentType = null;
+ this.#decoder = null;
+ this.#headers = null;
+ this.#body = '';
+ return this.#handler.onConnect(abort);
+ }
+
+ onHeaders (statusCode, rawHeaders, resume, statusMessage, headers = parseHeaders(rawHeaders)) {
+ this.#statusCode = statusCode;
+ this.#headers = headers;
+ this.#contentType = headers['content-type'];
+
+ if (this.#statusCode < 400) {
+ return this.#handler.onHeaders(statusCode, rawHeaders, resume, statusMessage, headers);
+ }
+
+ if (this.#contentType === 'application/json' || this.#contentType === 'text/plain') {
+ this.#decoder = new TextDecoder('utf-8');
+ }
+ }
+
+ onData (chunk) {
+ if (this.#statusCode < 400) {
+ return this.#handler.onData(chunk);
+ }
+ this.#body += this.#decoder?.decode(chunk, { stream: true }) ?? '';
+ }
+
+ onComplete (rawTrailers) {
+ if (this.#statusCode >= 400) {
+ this.#body += this.#decoder?.decode(undefined, { stream: false }) ?? '';
+ if (this.#contentType === 'application/json') {
+ try {
+ this.#body = JSON.parse(this.#body);
+ } catch {
+ // Do nothing...
+ }
+ }
+
+ let err;
+ const stackTraceLimit = Error.stackTraceLimit;
+ Error.stackTraceLimit = 0;
+ try {
+ err = new ResponseError('Response Error', this.#statusCode, this.#headers, this.#body);
+ } finally {
+ Error.stackTraceLimit = stackTraceLimit;
+ }
+
+ this.#handler.onError(err);
+ } else {
+ this.#handler.onComplete(rawTrailers);
+ }
+ }
+
+ onError (err) {
+ this.#handler.onError(err);
+ }
+}
+
+module.exports = (dispatch) => (opts, handler) => opts.throwOnError
+ ? dispatch(opts, new Handler(opts, { handler }))
+ : dispatch(opts, handler);
+```
+
+**Tests**
+
+Unit tests ensure the interceptor functions correctly, handling both error and non-error responses appropriately.
+
+**Example Tests**
+
+- **No Error if `throwOnError` is False**:
+
+```js
+test('should not error if request is not meant to throw error', async (t) => {
+ const opts = { throwOnError: false };
+ const handler = { onError: () => {}, onData: () => {}, onComplete: () => {} };
+ const interceptor = createResponseErrorInterceptor((opts, handler) => handler.onComplete());
+ assert.doesNotThrow(() => interceptor(opts, handler));
+});
+```
+
+- **Error if Status Code is in Specified Error Codes**:
+
+```js
+test('should error if request status code is in the specified error codes', async (t) => {
+ const opts = { throwOnError: true, statusCodes: [500] };
+ const response = { statusCode: 500 };
+ let capturedError;
+ const handler = {
+ onError: (err) => { capturedError = err; },
+ onData: () => {},
+ onComplete: () => {}
+ };
+
+ const interceptor = createResponseErrorInterceptor((opts, handler) => {
+ if (opts.throwOnError && opts.statusCodes.includes(response.statusCode)) {
+ handler.onError(new Error('Response Error'));
+ } else {
+ handler.onComplete();
+ }
+ });
+
+ interceptor({ ...opts, response }, handler);
+
+ await new Promise(resolve => setImmediate(resolve));
+
+ assert(capturedError, 'Expected error to be captured but it was not.');
+ assert.strictEqual(capturedError.message, 'Response Error');
+ assert.strictEqual(response.statusCode, 500);
+});
+```
+
+- **No Error if Status Code is Not in Specified Error Codes**:
+
+```js
+test('should not error if request status code is not in the specified error codes', async (t) => {
+ const opts = { throwOnError: true, statusCodes: [500] };
+ const response = { statusCode: 404 };
+ const handler = {
+ onError: () => {},
+ onData: () => {},
+ onComplete: () => {}
+ };
+
+ const interceptor = createResponseErrorInterceptor((opts, handler) => {
+ if (opts.throwOnError && opts.statusCodes.includes(response.statusCode)) {
+ handler.onError(new Error('Response Error'));
+ } else {
+ handler.onComplete();
+ }
+ });
+
+ assert.doesNotThrow(() => interceptor({ ...opts, response }, handler));
+});
+```
+
+**Conclusion**
+
+The Response Error Interceptor provides a robust mechanism for handling HTTP response errors by capturing detailed error information and propagating it through a structured `ResponseError` class. This enhancement improves error handling and debugging capabilities in applications using the interceptor.
+
## Instance Events
### Event: `'connect'`
@@ -833,6 +1251,12 @@ Parameters:
* **targets** `Array<Dispatcher>`
* **error** `Error`
+Emitted when the dispatcher has been disconnected from the origin.
+
+> **Note**: For HTTP/2, this event is also emitted when the dispatcher has received the [GOAWAY Frame](https://webconcepts.info/concepts/http2-frame-type/0x7) with an Error with the message `HTTP/2: "GOAWAY" frame received` and the code `UND_ERR_INFO`.
+> Due to nature of the protocol of using binary frames, it is possible that requests gets hanging as a frame can be received between the `HEADER` and `DATA` frames.
+> It is recommended to handle this event and close the dispatcher to create a new HTTP/2 session.
+
### Event: `'connectionError'`
Parameters:
@@ -854,10 +1278,12 @@ Emitted when dispatcher is no longer busy.
## Parameter: `UndiciHeaders`
-* `Record<string, string | string[] | undefined> | string[] | null`
-
-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.
+* `Record<string, string | string[] | undefined> | string[] | Iterable<[string, string | string[] | undefined]> | null`
+Header arguments such as `options.headers` in [`Client.dispatch`](Client.md#clientdispatchoptions-handlers) can be specified in three forms:
+* As an object specified by the `Record<string, string | string[] | undefined>` (`IncomingHttpHeaders`) type.
+* As an array of strings. An array representation of a header list must have an even length, or an `InvalidArgumentError` will be thrown.
+* As an iterable that can encompass `Headers`, `Map`, or a custom iterator returning key-value pairs.
Keys are lowercase and values are not modified.
Response headers will derive a `host` from the `url` of the [Client](Client.md#class-client) instance if no `host` header was previously specified.
@@ -885,3 +1311,37 @@ Response headers will derive a `host` from the `url` of the [Client](Client.md#c
'accept', '*/*'
]
```
+
+### Example 3 - Iterable
+
+```js
+new Headers({
+ 'content-length': '123',
+ 'content-type': 'text/plain',
+ connection: 'keep-alive',
+ host: 'mysite.com',
+ accept: '*/*'
+})
+```
+or
+```js
+new Map([
+ ['content-length', '123'],
+ ['content-type', 'text/plain'],
+ ['connection', 'keep-alive'],
+ ['host', 'mysite.com'],
+ ['accept', '*/*']
+])
+```
+or
+```js
+{
+ *[Symbol.iterator] () {
+ yield ['content-length', '123']
+ yield ['content-type', 'text/plain']
+ yield ['connection', 'keep-alive']
+ yield ['host', 'mysite.com']
+ yield ['accept', '*/*']
+ }
+}
+```
diff --git a/node_modules/undici/docs/api/Errors.md b/node_modules/undici/docs/docs/api/Errors.md
index 917e45d..c328689 100644
--- a/node_modules/undici/docs/api/Errors.md
+++ b/node_modules/undici/docs/docs/api/Errors.md
@@ -26,6 +26,7 @@ import { errors } from 'undici'
| `ResponseContentLengthMismatchError` | `UND_ERR_RES_CONTENT_LENGTH_MISMATCH` | response body does not match content-length header |
| `InformationalError` | `UND_ERR_INFO` | expected error with reason |
| `ResponseExceededMaxSizeError` | `UND_ERR_RES_EXCEEDED_MAX_SIZE` | response body exceed the max size allowed |
+| `SecureProxyConnectionError` | `UND_ERR_PRX_TLS` | tls connection to a proxy failed |
### `SocketError`
diff --git a/node_modules/undici/docs/api/MockAgent.md b/node_modules/undici/docs/docs/api/MockAgent.md
index 85ae690..85ae690 100644
--- a/node_modules/undici/docs/api/MockAgent.md
+++ b/node_modules/undici/docs/docs/api/MockAgent.md
diff --git a/node_modules/undici/docs/api/MockClient.md b/node_modules/undici/docs/docs/api/MockClient.md
index ac54691..ac54691 100644
--- a/node_modules/undici/docs/api/MockClient.md
+++ b/node_modules/undici/docs/docs/api/MockClient.md
diff --git a/node_modules/undici/docs/api/MockErrors.md b/node_modules/undici/docs/docs/api/MockErrors.md
index c1aa3db..c1aa3db 100644
--- a/node_modules/undici/docs/api/MockErrors.md
+++ b/node_modules/undici/docs/docs/api/MockErrors.md
diff --git a/node_modules/undici/docs/api/MockPool.md b/node_modules/undici/docs/docs/api/MockPool.md
index 96a986f..96a986f 100644
--- a/node_modules/undici/docs/api/MockPool.md
+++ b/node_modules/undici/docs/docs/api/MockPool.md
diff --git a/node_modules/undici/docs/api/Pool.md b/node_modules/undici/docs/docs/api/Pool.md
index 8fcabac..8fcabac 100644
--- a/node_modules/undici/docs/api/Pool.md
+++ b/node_modules/undici/docs/docs/api/Pool.md
diff --git a/node_modules/undici/docs/api/PoolStats.md b/node_modules/undici/docs/docs/api/PoolStats.md
index 16b6dc2..16b6dc2 100644
--- a/node_modules/undici/docs/api/PoolStats.md
+++ b/node_modules/undici/docs/docs/api/PoolStats.md
diff --git a/node_modules/undici/docs/api/ProxyAgent.md b/node_modules/undici/docs/docs/api/ProxyAgent.md
index cebfe68..a1a0d46 100644
--- a/node_modules/undici/docs/api/ProxyAgent.md
+++ b/node_modules/undici/docs/docs/api/ProxyAgent.md
@@ -16,12 +16,15 @@ Returns: `ProxyAgent`
Extends: [`AgentOptions`](Agent.md#parameter-agentoptions)
-* **uri** `string` (required) - It can be passed either by a string or a object containing `uri` as string.
+* **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.
+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).
+For detailed information on the parsing process and potential validation errors, please refer to the ["Writing" section](https://url.spec.whatwg.org/#writing) of the WHATWG URL Specification.
* **token** `string` (optional) - It can be passed by a string of token for authentication.
* **auth** `string` (**deprecated**) - Use token.
* **clientFactory** `(origin: URL, opts: Object) => Dispatcher` (optional) - Default: `(origin, opts) => new Pool(origin, opts)`
-* **requestTls** `BuildOptions` (optional) - Options object passed when creating the underlying socket via the connector builder for the request. See [TLS](https://nodejs.org/api/tls.html#tlsconnectoptions-callback).
-* **proxyTls** `BuildOptions` (optional) - Options object passed when creating the underlying socket via the connector builder for the proxy server. See [TLS](https://nodejs.org/api/tls.html#tlsconnectoptions-callback).
+* **requestTls** `BuildOptions` (optional) - Options object passed when creating the underlying socket via the connector builder for the request. It extends from [`Client#ConnectOptions`](/docs/docs/api/Client.md#parameter-connectoptions).
+* **proxyTls** `BuildOptions` (optional) - Options object passed when creating the underlying socket via the connector builder for the proxy server. It extends from [`Client#ConnectOptions`](/docs/docs/api/Client.md#parameter-connectoptions).
+* **proxyTunnel** `boolean` (optional) - For connections involving secure protocols, Undici will always establish a tunnel via the HTTP2 CONNECT extension. If proxyTunnel is set to true, this will occur for unsecured proxy/endpoint connections as well. Currently, there is no way to facilitate HTTP1 IP tunneling as described in https://www.rfc-editor.org/rfc/rfc9484.html#name-http-11-request. If proxyTunnel is set to false (the default), ProxyAgent connections where both the Proxy and Endpoint are unsecured will issue all requests to the Proxy, and prefix the endpoint request path with the endpoint origin address.
Examples:
@@ -30,6 +33,8 @@ import { ProxyAgent } from 'undici'
const proxyAgent = new ProxyAgent('my.proxy.server')
// or
+const proxyAgent = new ProxyAgent(new URL('my.proxy.server'))
+// or
const proxyAgent = new ProxyAgent({ uri: 'my.proxy.server' })
```
diff --git a/node_modules/undici/docs/api/RetryHandler.md b/node_modules/undici/docs/docs/api/RetryHandler.md
index 2323ce4..0dd9f29 100644
--- a/node_modules/undici/docs/api/RetryHandler.md
+++ b/node_modules/undici/docs/docs/api/RetryHandler.md
@@ -19,7 +19,7 @@ Extends: [`Dispatch.DispatchOptions`](Dispatcher.md#parameter-dispatchoptions).
#### `RetryOptions`
-- **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.
+- **retry** `(err: Error, context: RetryContext, callback: (err?: Error | null) => void) => number | null` (optional) - Function to be called after every retry. It should pass error if no more retries should be performed.
- **maxRetries** `number` (optional) - Maximum number of retries. Default: `5`
- **maxTimeout** `number` (optional) - Maximum number of milliseconds to wait before retrying. Default: `30000` (30 seconds)
- **minTimeout** `number` (optional) - Minimum number of milliseconds to wait before retrying. Default: `500` (half a second)
@@ -28,18 +28,27 @@ Extends: [`Dispatch.DispatchOptions`](Dispatcher.md#parameter-dispatchoptions).
-
- **methods** `string[]` (optional) - Array of HTTP methods to retry. Default: `['GET', 'PUT', 'HEAD', 'OPTIONS', 'DELETE']`
- **statusCodes** `number[]` (optional) - Array of HTTP status codes to retry. Default: `[429, 500, 502, 503, 504]`
-- **errorCodes** `string[]` (optional) - Array of Error codes to retry. Default: `['ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ENETDOWN','ENETUNREACH', 'EHOSTDOWN',
+- **errorCodes** `string[]` (optional) - Array of Error codes to retry. Default: `['ECONNRESET', 'ECONNREFUSED', 'ENOTFOUND', 'ENETDOWN','ENETUNREACH', 'EHOSTDOWN', 'UND_ERR_SOCKET']`
**`RetryContext`**
- `state`: `RetryState` - Current retry state. It can be mutated.
- `opts`: `Dispatch.DispatchOptions & RetryOptions` - Options passed to the retry handler.
+**`RetryState`**
+
+It represents the retry state for a given request.
+
+- `counter`: `number` - Current retry attempt.
+
### Parameter `RetryHandlers`
- **dispatch** `(options: Dispatch.DispatchOptions, handlers: Dispatch.DispatchHandlers) => Promise<Dispatch.DispatchResponse>` (required) - Dispatch function to be called after every retry.
- **handler** Extends [`Dispatch.DispatchHandlers`](Dispatcher.md#dispatcherdispatchoptions-handler) (required) - Handler function to be called after the request is successful or the retries are exhausted.
+>__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
+>the body as stateful and will not retry the request rejecting with the error `UND_ERR_REQ_RETRY`.
+
Examples:
```js
diff --git a/node_modules/undici/docs/api/WebSocket.md b/node_modules/undici/docs/docs/api/WebSocket.md
index 9d374f4..9d374f4 100644
--- a/node_modules/undici/docs/api/WebSocket.md
+++ b/node_modules/undici/docs/docs/api/WebSocket.md
diff --git a/node_modules/undici/docs/api/api-lifecycle.md b/node_modules/undici/docs/docs/api/api-lifecycle.md
index d158126..2e7db25 100644
--- a/node_modules/undici/docs/api/api-lifecycle.md
+++ b/node_modules/undici/docs/docs/api/api-lifecycle.md
@@ -21,10 +21,39 @@ An Undici [Client](Client.md) can be best described as a state machine. The foll
* At any point in time, the *destroy* event will transition the `Client` from the **processing** state to the **destroyed** state, destroying any queued requests.
* The **destroyed** state is a final state and the `Client` is no longer functional.
-![A state diagram representing an Undici Client instance](../assets/lifecycle-diagram.png)
+A state diagram representing an Undici Client instance:
-> 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)
+```mermaid
+stateDiagram-v2
+ [*] --> idle
+ idle --> pending : connect
+ idle --> destroyed : destroy/close
+
+ pending --> idle : timeout
+ pending --> destroyed : destroy
+ state close_fork <<fork>>
+ pending --> close_fork : close
+ close_fork --> processing
+ close_fork --> destroyed
+
+ pending --> processing : process
+
+ processing --> pending : keepalive
+ processing --> destroyed : done
+ processing --> destroyed : destroy
+
+ destroyed --> [*]
+
+ state processing {
+ [*] --> running
+ running --> closing : close
+ running --> busy : needDrain
+ busy --> running : drainComplete
+ running --> [*] : keepalive
+ closing --> [*] : done
+ }
+```
## State details
### idle