Skip to content

Commit bd7e2e3

Browse files
deps: update undici to 8.0.2
1 parent a3108ff commit bd7e2e3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+3927
-3282
lines changed

deps/undici/src/.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,9 @@ test/request-timeout.10mb.bin
9393
CLAUDE.md
9494
.claude
9595

96-
# Ignore .pi
96+
# Local tooling
9797
.pi
98+
AGENTS.md
9899

99100
# Ignore .githuman
100101
.githuman

deps/undici/src/CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ Create a commit which includes all of the updated files in lib/llhttp.
9696

9797
### Steps:
9898

99+
`npm run test:wpt` and `node test/web-platform-tests/wpt-runner.mjs setup` will initialize the WPT submodule automatically when it is missing.
100+
101+
If you want to prepare the checkout explicitly, run:
102+
99103
```bash
100104
git submodule update --init --recursive
101105
```

deps/undici/src/README.md

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,57 @@ const { statusCode, body } = await request('https://api.example.com/data');
154154
const data = await body.json();
155155
```
156156

157+
### Keep `fetch` and `FormData` together
158+
159+
When you send a `FormData` body, keep `fetch` and `FormData` from the same
160+
implementation.
161+
162+
Use one of these patterns:
163+
164+
```js
165+
// Built-in globals
166+
const body = new FormData()
167+
body.set('name', 'some')
168+
await fetch('https://example.com', {
169+
method: 'POST',
170+
body
171+
})
172+
```
173+
174+
```js
175+
// undici module imports
176+
import { fetch, FormData } from 'undici'
177+
178+
const body = new FormData()
179+
body.set('name', 'some')
180+
await fetch('https://example.com', {
181+
method: 'POST',
182+
body
183+
})
184+
```
185+
186+
If you want the installed `undici` package to provide the globals, call
187+
`install()` first:
188+
189+
```js
190+
import { install } from 'undici'
191+
192+
install()
193+
194+
const body = new FormData()
195+
body.set('name', 'some')
196+
await fetch('https://example.com', {
197+
method: 'POST',
198+
body
199+
})
200+
```
201+
202+
`install()` replaces the global `fetch`, `Headers`, `Response`, `Request`, and
203+
`FormData` implementations with undici's versions, so they all match.
204+
205+
Avoid mixing a global `FormData` with `undici.fetch()`, or `undici.FormData`
206+
with the built-in global `fetch()`.
207+
157208
### Version Compatibility
158209

159210
You can check which version of undici is bundled with your Node.js version:
@@ -263,6 +314,11 @@ The `install()` function adds the following classes to `globalThis`:
263314
- `CloseEvent`, `ErrorEvent`, `MessageEvent` - WebSocket events
264315
- `EventSource` - Server-sent events client
265316

317+
When you call `install()`, these globals come from the same undici
318+
implementation. For example, global `fetch` and global `FormData` will both be
319+
undici's versions, which is the recommended setup if you want to use undici
320+
through globals.
321+
266322
This is useful for:
267323
- Polyfilling environments that don't have fetch
268324
- Ensuring consistent fetch behavior across different Node.js versions
@@ -563,6 +619,12 @@ See [Dispatcher.upgrade](./docs/docs/api/Dispatcher.md#dispatcherupgradeoptions-
563619
Sets the global dispatcher used by Common API Methods. Global dispatcher is shared among compatible undici modules,
564620
including undici that is bundled internally with node.js.
565621

622+
Undici stores this dispatcher under `Symbol.for('undici.globalDispatcher.2')`.
623+
624+
`setGlobalDispatcher()` also mirrors the configured dispatcher to
625+
`Symbol.for('undici.globalDispatcher.1')` using `Dispatcher1Wrapper`, so Node.js built-in `fetch`
626+
can keep using the legacy handler contract while Undici uses the new handler API.
627+
566628
### `undici.getGlobalDispatcher()`
567629

568630
Gets the global dispatcher used by Common API Methods.

deps/undici/src/docs/docs/api/Client.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Returns: `Client`
2929
* **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. **Security Warning:** Disabling this option can expose your application to HTTP Request Smuggling attacks, where mismatched content-length headers cause servers and proxies to interpret request boundaries differently. This can lead to cache poisoning, credential hijacking, and bypassing security controls. Only disable this in controlled environments where you fully trust the request source.
3030
* **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.
3131
* **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.
32-
* **allowH2**: `boolean` - Default: `false`. Enables support for H2 if the server has assigned bigger priority to it through ALPN negotiation.
32+
* **allowH2**: `boolean` - Default: `true`. Enables support for H2 if the server has assigned bigger priority to it through ALPN negotiation.
3333
* **useH2c**: `boolean` - Default: `false`. Enforces h2c for non-https connections.
3434
* **maxConcurrentStreams**: `number` - Default: `100`. Dictates the maximum number of concurrent streams for a single H2 session. It can be overridden by a SETTINGS remote frame.
3535
* **initialWindowSize**: `number` (optional) - Default: `262144` (256KB). Sets the HTTP/2 stream-level flow-control window size (SETTINGS_INITIAL_WINDOW_SIZE). Must be a positive integer greater than 0. This default is higher than Node.js core's default (65535 bytes) to improve throughput, Node's choice is very conservative for current high-bandwith networks. See [RFC 7540 Section 6.9.2](https://datatracker.ietf.org/doc/html/rfc7540#section-6.9.2) for more details.
@@ -282,4 +282,4 @@ console.log('requests completed')
282282

283283
### Event: `'error'`
284284

285-
Invoked for users errors such as throwing in the `onError` handler.
285+
Invoked for user errors such as throwing in the `onResponseError` handler.

deps/undici/src/docs/docs/api/DiagnosticsChannel.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,22 +182,24 @@ diagnosticsChannel.channel('undici:websocket:open').subscribe(({
182182
console.log(websocket) // the WebSocket instance
183183

184184
// Handshake response details
185-
console.log(handshakeResponse.status) // 101 for successful WebSocket upgrade
186-
console.log(handshakeResponse.statusText) // 'Switching Protocols'
185+
console.log(handshakeResponse.status) // 101 for HTTP/1.1, 200 for HTTP/2 extended CONNECT
186+
console.log(handshakeResponse.statusText) // 'Switching Protocols' for HTTP/1.1, commonly 'OK' for HTTP/2 in Node.js
187187
console.log(handshakeResponse.headers) // Object containing response headers
188188
})
189189
```
190190

191191
### Handshake Response Object
192192

193-
The `handshakeResponse` object contains the HTTP response that upgraded the connection to WebSocket:
193+
The `handshakeResponse` object contains the HTTP response that established the WebSocket connection:
194194

195-
- `status` (number): The HTTP status code (101 for successful WebSocket upgrade)
196-
- `statusText` (string): The HTTP status message ('Switching Protocols' for successful upgrade)
195+
- `status` (number): The HTTP status code (`101` for HTTP/1.1 upgrade, `200` for HTTP/2 extended CONNECT)
196+
- `statusText` (string): The HTTP status message (`'Switching Protocols'` for HTTP/1.1, commonly `'OK'` for HTTP/2 in Node.js)
197197
- `headers` (object): The HTTP response headers from the server, including:
198+
- `sec-websocket-accept` and other WebSocket-related headers
198199
- `upgrade: 'websocket'`
199200
- `connection: 'upgrade'`
200-
- `sec-websocket-accept` and other WebSocket-related headers
201+
202+
The `upgrade` and `connection` headers are only present for HTTP/1.1 handshakes.
201203

202204
This information is particularly useful for debugging and monitoring WebSocket connections, as it provides access to the initial HTTP handshake response that established the WebSocket connection.
203205

deps/undici/src/docs/docs/api/Dispatcher.md

Lines changed: 62 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,41 @@ Returns: `Boolean` - `false` if dispatcher is busy and further dispatch calls wo
212212
* **onResponseEnd** `(controller: DispatchController, trailers: Record<string, string | string[]>) => void` - Invoked when response payload and trailers have been received and the request has completed. Not required for `upgrade` requests.
213213
* **onResponseError** `(controller: DispatchController, error: Error) => void` - Invoked when an error has occurred. May not throw.
214214

215+
#### Migration from legacy handler API
216+
217+
If you were previously using `onConnect/onHeaders/onData/onComplete/onError`, switch to the new callbacks:
218+
219+
- `onConnect(abort)``onRequestStart(controller)` and call `controller.abort(reason)`
220+
- `onHeaders(status, rawHeaders, resume, statusText)``onResponseStart(controller, status, headers, statusText)`
221+
- `onData(chunk)``onResponseData(controller, chunk)`
222+
- `onComplete(trailers)``onResponseEnd(controller, trailers)`
223+
- `onError(err)``onResponseError(controller, err)`
224+
- `onUpgrade(status, rawHeaders, socket)``onRequestUpgrade(controller, status, headers, socket)`
225+
226+
To access raw header arrays (for preserving duplicates/casing), read them from the controller:
227+
228+
- `controller.rawHeaders` for response headers
229+
- `controller.rawTrailers` for trailers
230+
231+
Pause/resume now uses the controller:
232+
233+
- Call `controller.pause()` and `controller.resume()` instead of returning `false` from handlers.
234+
235+
#### Compatibility notes
236+
237+
Undici now stores the global dispatcher under `Symbol.for('undici.globalDispatcher.2')`.
238+
This avoids conflicts with runtimes (such as Node.js built-in `fetch`) that still rely on the legacy dispatcher handler interface.
239+
240+
`setGlobalDispatcher()` also mirrors the configured dispatcher to `Symbol.for('undici.globalDispatcher.1')` using a `Dispatcher1Wrapper`, so Node's built-in `fetch` can keep using the legacy handler contract.
241+
242+
If you need to expose a new dispatcher/agent to legacy v1 handler consumers (`onConnect/onHeaders/onData/onComplete/onError/onUpgrade`), use `Dispatcher1Wrapper`:
243+
244+
```js
245+
import { Agent, Dispatcher1Wrapper } from 'undici'
246+
247+
const legacyCompatibleDispatcher = new Dispatcher1Wrapper(new Agent())
248+
```
249+
215250
#### Example 1 - Dispatch GET request
216251

217252
```js
@@ -236,21 +271,21 @@ client.dispatch({
236271
'x-foo': 'bar'
237272
}
238273
}, {
239-
onConnect: () => {
274+
onRequestStart: () => {
240275
console.log('Connected!')
241276
},
242-
onError: (error) => {
277+
onResponseError: (_controller, error) => {
243278
console.error(error)
244279
},
245-
onHeaders: (statusCode, headers) => {
246-
console.log(`onHeaders | statusCode: ${statusCode} | headers: ${headers}`)
280+
onResponseStart: (_controller, statusCode, headers) => {
281+
console.log(`onResponseStart | statusCode: ${statusCode} | headers: ${JSON.stringify(headers)}`)
247282
},
248-
onData: (chunk) => {
249-
console.log('onData: chunk received')
283+
onResponseData: (_controller, chunk) => {
284+
console.log('onResponseData: chunk received')
250285
data.push(chunk)
251286
},
252-
onComplete: (trailers) => {
253-
console.log(`onComplete | trailers: ${trailers}`)
287+
onResponseEnd: (_controller, trailers) => {
288+
console.log(`onResponseEnd | trailers: ${JSON.stringify(trailers)}`)
254289
const res = Buffer.concat(data).toString('utf8')
255290
console.log(`Data: ${res}`)
256291
client.close()
@@ -288,15 +323,15 @@ client.dispatch({
288323
method: 'GET',
289324
upgrade: 'websocket'
290325
}, {
291-
onConnect: () => {
292-
console.log('Undici Client - onConnect')
326+
onRequestStart: () => {
327+
console.log('Undici Client - onRequestStart')
293328
},
294-
onError: (error) => {
295-
console.log('onError') // shouldn't print
329+
onResponseError: () => {
330+
console.log('onResponseError') // shouldn't print
296331
},
297-
onUpgrade: (statusCode, headers, socket) => {
298-
console.log('Undici Client - onUpgrade')
299-
console.log(`onUpgrade Headers: ${headers}`)
332+
onRequestUpgrade: (_controller, statusCode, headers, socket) => {
333+
console.log('Undici Client - onRequestUpgrade')
334+
console.log(`onRequestUpgrade Headers: ${JSON.stringify(headers)}`)
300335
socket.on('data', buffer => {
301336
console.log(buffer.toString('utf8'))
302337
})
@@ -339,21 +374,21 @@ client.dispatch({
339374
},
340375
body: JSON.stringify({ message: 'Hello' })
341376
}, {
342-
onConnect: () => {
377+
onRequestStart: () => {
343378
console.log('Connected!')
344379
},
345-
onError: (error) => {
380+
onResponseError: (_controller, error) => {
346381
console.error(error)
347382
},
348-
onHeaders: (statusCode, headers) => {
349-
console.log(`onHeaders | statusCode: ${statusCode} | headers: ${headers}`)
383+
onResponseStart: (_controller, statusCode, headers) => {
384+
console.log(`onResponseStart | statusCode: ${statusCode} | headers: ${JSON.stringify(headers)}`)
350385
},
351-
onData: (chunk) => {
352-
console.log('onData: chunk received')
386+
onResponseData: (_controller, chunk) => {
387+
console.log('onResponseData: chunk received')
353388
data.push(chunk)
354389
},
355-
onComplete: (trailers) => {
356-
console.log(`onComplete | trailers: ${trailers}`)
390+
onResponseEnd: (_controller, trailers) => {
391+
console.log(`onResponseEnd | trailers: ${JSON.stringify(trailers)}`)
357392
const res = Buffer.concat(data).toString('utf8')
358393
console.log(`Response Data: ${res}`)
359394
client.close()
@@ -364,7 +399,7 @@ client.dispatch({
364399

365400
### `Dispatcher.pipeline(options, handler)`
366401

367-
For easy use with [stream.pipeline](https://nodejs.org/api/stream.html#stream_stream_pipeline_source_transforms_destination_callback). The `handler` argument should return a `Readable` from which the result will be read. Usually it should just return the `body` argument unless some kind of transformation needs to be performed based on e.g. `headers` or `statusCode`. The `handler` should validate the response and save any required state. If there is an error, it should be thrown. The function returns a `Duplex` which writes to the request and reads from the response.
402+
For easy use with [stream.pipeline](https://nodejs.org/api/stream.html#streampipelinesource-transforms-destination-options). The `handler` argument should return a `Readable` from which the result will be read. Usually it should just return the `body` argument unless some kind of transformation needs to be performed based on e.g. `headers` or `statusCode`. The `handler` should validate the response and save any required state. If there is an error, it should be thrown. The function returns a `Duplex` which writes to the request and reads from the response.
368403

369404
Arguments:
370405

@@ -963,7 +998,7 @@ const { Client, interceptors } = require("undici");
963998
const { redirect } = interceptors;
964999

9651000
const client = new Client("http://service.example").compose(
966-
redirect({ maxRedirections: 3, throwOnMaxRedirects: true })
1001+
redirect({ maxRedirections: 3, throwOnMaxRedirect: true })
9671002
);
9681003
client.request({ path: "/" })
9691004
```
@@ -1036,10 +1071,10 @@ The `dns` interceptor enables you to cache DNS lookups for a given duration, per
10361071
- `dualStack` - Whether to resolve both IPv4 and IPv6 addresses. Default: `true`.
10371072
- It will also attempt a happy-eyeballs-like approach to connect to the available addresses in case of a connection failure.
10381073
- `affinity` - Whether to use IPv4 or IPv6 addresses. Default: `4`.
1039-
- It can be either `'4` or `6`.
1074+
- It can be either `4` or `6`.
10401075
- It will only take effect if `dualStack` is `false`.
10411076
- `lookup: (hostname: string, options: LookupOptions, callback: (err: NodeJS.ErrnoException | null, addresses: DNSInterceptorRecord[]) => void) => void` - Custom lookup function. Default: `dns.lookup`.
1042-
- For more info see [dns.lookup](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback).
1077+
- For more info see [dns.lookup](https://nodejs.org/api/dns.html#dnslookuphostname-options-callback).
10431078
- `pick: (origin: URL, records: DNSInterceptorRecords, affinity: 4 | 6) => DNSInterceptorRecord` - Custom pick function. Default: `RoundRobin`.
10441079
- The function should return a single record from the records array.
10451080
- By default a simplified version of Round Robin is used.

deps/undici/src/docs/docs/api/Fetch.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ This API is implemented as per the standard, you can find documentation on [MDN]
1010

1111
If any parameters are passed to the FormData constructor other than `undefined`, an error will be thrown. Other parameters are ignored.
1212

13+
When you use `FormData` as a request body, keep `fetch` and `FormData` from the
14+
same implementation. Use the built-in global `FormData` with the built-in
15+
global `fetch()`, and use `undici`'s `FormData` with `undici.fetch()`.
16+
17+
If you want the installed `undici` package to provide the globals, call
18+
[`install()`](/docs/api/GlobalInstallation.md) so `fetch`, `Headers`,
19+
`Response`, `Request`, and `FormData` are installed together as a matching set.
20+
1321
## Response
1422

1523
This API is implemented as per the standard, you can find documentation on [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Response)

deps/undici/src/docs/docs/api/GlobalInstallation.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,54 @@ The `install()` function adds the following classes to `globalThis`:
4343
| `MessageEvent` | WebSocket message event |
4444
| `EventSource` | Server-sent events client |
4545

46+
## Using `FormData` with `fetch`
47+
48+
If you send a `FormData` body, use matching implementations for `fetch` and
49+
`FormData`.
50+
51+
These two patterns are safe:
52+
53+
```js
54+
// Built-in globals from Node.js
55+
const body = new FormData()
56+
await fetch('https://example.com', {
57+
method: 'POST',
58+
body
59+
})
60+
```
61+
62+
```js
63+
// Globals installed from the undici package
64+
import { install } from 'undici'
65+
66+
install()
67+
68+
const body = new FormData()
69+
await fetch('https://example.com', {
70+
method: 'POST',
71+
body
72+
})
73+
```
74+
75+
After `install()`, `fetch`, `Headers`, `Response`, `Request`, and `FormData`
76+
all come from the installed `undici` package, so they work as a matching set.
77+
78+
If you do not want to install globals, import both from `undici` instead:
79+
80+
```js
81+
import { fetch, FormData } from 'undici'
82+
83+
const body = new FormData()
84+
await fetch('https://example.com', {
85+
method: 'POST',
86+
body
87+
})
88+
```
89+
90+
Avoid mixing a global `FormData` with `undici.fetch()`, or `undici.FormData`
91+
with the built-in global `fetch()`. Keeping them paired avoids surprising
92+
multipart behavior across Node.js and undici versions.
93+
4694
## Use Cases
4795

4896
Global installation is useful for:

deps/undici/src/docs/docs/api/H2CClient.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,4 +260,4 @@ console.log("requests completed");
260260

261261
### Event: `'error'`
262262

263-
Invoked for users errors such as throwing in the `onError` handler.
263+
Invoked for user errors such as throwing in the `onResponseError` handler.

0 commit comments

Comments
 (0)