Skip to content

deps: update undici to 7.11.0 #58859

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions deps/undici/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,125 @@ The benchmark is a simple getting data [example](https://github.com/nodejs/undic
└────────────────────────┴─────────┴────────────────────┴────────────┴─────────────────────────┘
```

## Undici vs. Fetch

### Overview

Node.js includes a built-in `fetch()` implementation powered by undici starting from Node.js v18. However, there are important differences between using the built-in fetch and installing undici as a separate module.

### Built-in Fetch (Node.js v18+)

Node.js's built-in fetch is powered by a bundled version of undici:

```js
// Available globally in Node.js v18+
const response = await fetch('https://api.example.com/data');
const data = await response.json();

// Check the bundled undici version
console.log(process.versions.undici); // e.g., "5.28.4"
```

**Pros:**
- No additional dependencies required
- Works across different JavaScript runtimes
- Automatic compression handling (gzip, deflate, br)
- Built-in caching support (in development)

**Cons:**
- Limited to the undici version bundled with your Node.js version
- Less control over connection pooling and advanced features
- Error handling follows Web API standards (errors wrapped in `TypeError`)
- Performance overhead due to Web Streams implementation

### Undici Module

Installing undici as a separate module gives you access to the latest features and APIs:

```bash
npm install undici
```

```js
import { request, fetch, Agent, setGlobalDispatcher } from 'undici';

// Use undici.request for maximum performance
const { statusCode, headers, body } = await request('https://api.example.com/data');
const data = await body.json();

// Or use undici.fetch with custom configuration
const agent = new Agent({ keepAliveTimeout: 10000 });
setGlobalDispatcher(agent);
const response = await fetch('https://api.example.com/data');
```

**Pros:**
- Latest undici features and bug fixes
- Access to advanced APIs (`request`, `stream`, `pipeline`)
- Fine-grained control over connection pooling
- Better error handling with clearer error messages
- Superior performance, especially with `undici.request`
- HTTP/1.1 pipelining support
- Custom interceptors and middleware
- Advanced features like `ProxyAgent`, `MockAgent`

**Cons:**
- Additional dependency to manage
- Larger bundle size

### When to Use Each

#### Use Built-in Fetch When:
- You want zero dependencies
- Building isomorphic code that runs in browsers and Node.js
- Simple HTTP requests without advanced configuration
- You're okay with the undici version bundled in your Node.js version

#### Use Undici Module When:
- You need the latest undici features and performance improvements
- You require advanced connection pooling configuration
- You need APIs not available in the built-in fetch (`ProxyAgent`, `MockAgent`, etc.)
- Performance is critical (use `undici.request` for maximum speed)
- You want better error handling and debugging capabilities
- You need HTTP/1.1 pipelining or advanced interceptors
- You prefer decoupled protocol and API interfaces

### Performance Comparison

Based on benchmarks, here's the typical performance hierarchy:

1. **`undici.request()`** - Fastest, most efficient
2. **`undici.fetch()`** - Good performance, standard compliance
3. **Node.js `http`/`https`** - Baseline performance

### Migration Guide

If you're currently using built-in fetch and want to migrate to undici:

```js
// Before: Built-in fetch
const response = await fetch('https://api.example.com/data');

// After: Undici fetch (drop-in replacement)
import { fetch } from 'undici';
const response = await fetch('https://api.example.com/data');

// Or: Undici request (better performance)
import { request } from 'undici';
const { statusCode, body } = await request('https://api.example.com/data');
const data = await body.json();
```

### Version Compatibility

You can check which version of undici is bundled with your Node.js version:

```js
console.log(process.versions.undici);
```

Installing undici as a module allows you to use a newer version than what's bundled with Node.js, giving you access to the latest features and performance improvements.

## Quick Start

```js
Expand All @@ -63,6 +182,44 @@ for await (const data of body) { console.log('data', data) }
console.log('trailers', trailers)
```

## Global Installation

Undici provides an `install()` function to add all WHATWG fetch classes to `globalThis`, making them available globally:

```js
import { install } from 'undici'

// Install all WHATWG fetch classes globally
install()

// Now you can use fetch classes globally without importing
const response = await fetch('https://api.example.com/data')
const data = await response.json()

// All classes are available globally:
const headers = new Headers([['content-type', 'application/json']])
const request = new Request('https://example.com')
const formData = new FormData()
const ws = new WebSocket('wss://example.com')
const eventSource = new EventSource('https://example.com/events')
```

The `install()` function adds the following classes to `globalThis`:

- `fetch` - The fetch function
- `Headers` - HTTP headers management
- `Response` - HTTP response representation
- `Request` - HTTP request representation
- `FormData` - Form data handling
- `WebSocket` - WebSocket client
- `CloseEvent`, `ErrorEvent`, `MessageEvent` - WebSocket events
- `EventSource` - Server-sent events client

This is useful for:
- Polyfilling environments that don't have fetch
- Ensuring consistent fetch behavior across different Node.js versions
- Making undici's implementations available globally for libraries that expect them

## Body Mixins

The `body` mixins are the most common way to format the request/response body. Mixins include:
Expand Down
6 changes: 3 additions & 3 deletions deps/undici/src/docs/docs/api/CacheStore.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ The `MemoryCacheStore` stores the responses in-memory.

**Options**

- `maxSize` - The maximum total size in bytes of all stored responses. Default `Infinity`.
- `maxCount` - The maximum amount of responses to store. Default `Infinity`.
- `maxEntrySize` - The maximum size in bytes that a response's body can be. If a response's body is greater than or equal to this, the response will not be cached. Default `Infinity`.
- `maxSize` - The maximum total size in bytes of all stored responses. Default `104857600` (100MB).
- `maxCount` - The maximum amount of responses to store. Default `1024`.
- `maxEntrySize` - The maximum size in bytes that a response's body can be. If a response's body is greater than or equal to this, the response will not be cached. Default `5242880` (5MB).

### Getters

Expand Down
26 changes: 13 additions & 13 deletions deps/undici/src/docs/docs/api/Debug.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ NODE_DEBUG=undici node script.js
UNDICI 16241: connecting to nodejs.org using https:h1
UNDICI 16241: connecting to nodejs.org using https:h1
UNDICI 16241: connected to nodejs.org using https:h1
UNDICI 16241: sending request to GET https://nodejs.org//
UNDICI 16241: received response to GET https://nodejs.org// - HTTP 307
UNDICI 16241: sending request to GET https://nodejs.org/
UNDICI 16241: received response to GET https://nodejs.org/ - HTTP 307
UNDICI 16241: connecting to nodejs.org using https:h1
UNDICI 16241: trailers received from GET https://nodejs.org//
UNDICI 16241: trailers received from GET https://nodejs.org/
UNDICI 16241: connected to nodejs.org using https:h1
UNDICI 16241: sending request to GET https://nodejs.org//en
UNDICI 16241: received response to GET https://nodejs.org//en - HTTP 200
UNDICI 16241: trailers received from GET https://nodejs.org//en
UNDICI 16241: sending request to GET https://nodejs.org/en
UNDICI 16241: received response to GET https://nodejs.org/en - HTTP 200
UNDICI 16241: trailers received from GET https://nodejs.org/en
```

## `fetch`
Expand All @@ -36,14 +36,14 @@ NODE_DEBUG=fetch node script.js
FETCH 16241: connecting to nodejs.org using https:h1
FETCH 16241: connecting to nodejs.org using https:h1
FETCH 16241: connected to nodejs.org using https:h1
FETCH 16241: sending request to GET https://nodejs.org//
FETCH 16241: received response to GET https://nodejs.org// - HTTP 307
FETCH 16241: sending request to GET https://nodejs.org/
FETCH 16241: received response to GET https://nodejs.org/ - HTTP 307
FETCH 16241: connecting to nodejs.org using https:h1
FETCH 16241: trailers received from GET https://nodejs.org//
FETCH 16241: trailers received from GET https://nodejs.org/
FETCH 16241: connected to nodejs.org using https:h1
FETCH 16241: sending request to GET https://nodejs.org//en
FETCH 16241: received response to GET https://nodejs.org//en - HTTP 200
FETCH 16241: trailers received from GET https://nodejs.org//en
FETCH 16241: sending request to GET https://nodejs.org/en
FETCH 16241: received response to GET https://nodejs.org/en - HTTP 200
FETCH 16241: trailers received from GET https://nodejs.org/en
```

## `websocket`
Expand All @@ -57,6 +57,6 @@ NODE_DEBUG=websocket node script.js

WEBSOCKET 18309: connecting to echo.websocket.org using https:h1
WEBSOCKET 18309: connected to echo.websocket.org using https:h1
WEBSOCKET 18309: sending request to GET https://echo.websocket.org//
WEBSOCKET 18309: sending request to GET https://echo.websocket.org/
WEBSOCKET 18309: connection opened <ip_address>
```
25 changes: 25 additions & 0 deletions deps/undici/src/docs/docs/api/DiagnosticsChannel.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,22 @@ diagnosticsChannel.channel('undici:request:create').subscribe(({ request }) => {

Note: a request is only loosely completed to a given socket.

## `undici:request:bodyChunkSent`

This message is published when a chunk of the request body is being sent.

```js
import diagnosticsChannel from 'diagnostics_channel'

diagnosticsChannel.channel('undici:request:bodyChunkSent').subscribe(({ request, chunk }) => {
// request is the same object undici:request:create
})
```

## `undici:request:bodySent`

This message is published after the request body has been fully sent.

```js
import diagnosticsChannel from 'diagnostics_channel'

Expand All @@ -54,6 +67,18 @@ diagnosticsChannel.channel('undici:request:headers').subscribe(({ request, respo
})
```

## `undici:request:bodyChunkReceived`

This message is published after a chunk of the response body has been received.

```js
import diagnosticsChannel from 'diagnostics_channel'

diagnosticsChannel.channel('undici:request:bodyChunkReceived').subscribe(({ request, chunk }) => {
// request is the same object undici:request:create
})
```

## `undici:request:trailers`

This message is published after the response body and trailers have been received, i.e. the response has been completed.
Expand Down
21 changes: 20 additions & 1 deletion deps/undici/src/docs/docs/api/Dispatcher.md
Original file line number Diff line number Diff line change
Expand Up @@ -841,9 +841,28 @@ try {
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.
> - The order of the interceptors matters. The last 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.
>
> **Interceptor Stack Visualization:**
> ```
> compose([interceptor1, interceptor2, interceptor3])
>
> Request Flow:
> ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
> │ Request │───▶│interceptor3 │───▶│interceptor2 │───▶│interceptor1 │───▶│ dispatcher │
> └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ .dispatch │
> ▲ ▲ ▲ └─────────────┘
> │ │ │ ▲
> (called first) (called second) (called last) │
> │
> ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
> │ Response │◀───│interceptor3 │◀───│interceptor2 │◀───│interceptor1 │◀─────────┘
> └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
>
> The interceptors are composed in reverse order due to function composition.
> ```
Arguments:
Expand Down
91 changes: 91 additions & 0 deletions deps/undici/src/docs/docs/api/GlobalInstallation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Global Installation

Undici provides an `install()` function to add all WHATWG fetch classes to `globalThis`, making them available globally without requiring imports.

## `install()`

Install all WHATWG fetch classes globally on `globalThis`.

**Example:**

```js
import { install } from 'undici'

// Install all WHATWG fetch classes globally
install()

// Now you can use fetch classes globally without importing
const response = await fetch('https://api.example.com/data')
const data = await response.json()

// All classes are available globally:
const headers = new Headers([['content-type', 'application/json']])
const request = new Request('https://example.com')
const formData = new FormData()
const ws = new WebSocket('wss://example.com')
const eventSource = new EventSource('https://example.com/events')
```

## Installed Classes

The `install()` function adds the following classes to `globalThis`:

| Class | Description |
|-------|-------------|
| `fetch` | The fetch function for making HTTP requests |
| `Headers` | HTTP headers management |
| `Response` | HTTP response representation |
| `Request` | HTTP request representation |
| `FormData` | Form data handling |
| `WebSocket` | WebSocket client |
| `CloseEvent` | WebSocket close event |
| `ErrorEvent` | WebSocket error event |
| `MessageEvent` | WebSocket message event |
| `EventSource` | Server-sent events client |

## Use Cases

Global installation is useful for:

- **Polyfilling environments** that don't have native fetch support
- **Ensuring consistent behavior** across different Node.js versions
- **Library compatibility** when third-party libraries expect global fetch
- **Migration scenarios** where you want to replace built-in implementations
- **Testing environments** where you need predictable fetch behavior

## Example: Polyfilling an Environment

```js
import { install } from 'undici'

// Check if fetch is available and install if needed
if (typeof globalThis.fetch === 'undefined') {
install()
console.log('Undici fetch installed globally')
}

// Now fetch is guaranteed to be available
const response = await fetch('https://api.example.com')
```

## Example: Testing Environment

```js
import { install } from 'undici'

// In test setup, ensure consistent fetch behavior
install()

// Now all tests use undici's implementations
test('fetch API test', async () => {
const response = await fetch('https://example.com')
expect(response).toBeInstanceOf(Response)
})
```

## Notes

- The `install()` function overwrites any existing global implementations
- Classes installed are undici's implementations, not Node.js built-ins
- This provides access to undici's latest features and performance improvements
- The global installation persists for the lifetime of the process
Loading
Loading