@entelligentsia/forgecli 0.7.10 → 0.8.4
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.
- package/CHANGELOG.md +74 -0
- package/dist/CHANGELOG-forge-plugin.md +70 -0
- package/dist/CHANGELOG-pi.md +63 -0
- package/dist/bin/argv.d.ts +2 -2
- package/dist/bin/argv.js +10 -0
- package/dist/bin/argv.js.map +1 -1
- package/dist/bin/env-defaults.d.ts +1 -0
- package/dist/bin/env-defaults.js +13 -0
- package/dist/bin/env-defaults.js.map +1 -0
- package/dist/bin/forge.js +9 -0
- package/dist/bin/forge.js.map +1 -1
- package/dist/bin/update-cli.d.ts +9 -0
- package/dist/bin/update-cli.js +120 -0
- package/dist/bin/update-cli.js.map +1 -0
- package/dist/extensions/forgecli/index.js +3 -3
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/update-check.js +1 -1
- package/dist/extensions/forgecli/update-check.js.map +1 -1
- package/dist/extensions/forgecli/whats-new-widget.d.ts +5 -5
- package/dist/extensions/forgecli/whats-new-widget.js +11 -11
- package/dist/extensions/forgecli/whats-new-widget.js.map +1 -1
- package/dist/extensions/forgecli/whats-new.js +6 -5
- package/dist/extensions/forgecli/whats-new.js.map +1 -1
- package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +27 -98
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +62 -132
- package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +25 -15
- package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +1 -0
- package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +17 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +8 -2
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +17 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +8 -1
- package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
- package/node_modules/@earendil-works/pi-ai/package.json +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +63 -0
- package/node_modules/@earendil-works/pi-coding-agent/README.md +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli.js +6 -10
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +12 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +1 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +30 -15
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts +3 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +23 -13
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.d.ts +4 -0
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +58 -38
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.js +0 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +3 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.d.ts +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js +7 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +6 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js +3 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.d.ts +7 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.d.ts.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.js +60 -7
- package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/docs/packages.md +2 -2
- package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +1 -3
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package.json +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
- package/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/node_modules/@protobufjs/fetch/CHANGELOG.md +8 -0
- package/node_modules/@protobufjs/fetch/index.d.ts +7 -7
- package/node_modules/@protobufjs/fetch/index.js +4 -7
- package/node_modules/@protobufjs/fetch/package.json +7 -5
- package/node_modules/@protobufjs/fetch/tests/data/file.txt +1 -0
- package/node_modules/@protobufjs/fetch/tests/index.js +150 -8
- package/node_modules/@protobufjs/fetch/util/fs.js +11 -0
- package/node_modules/@protobufjs/inquire/CHANGELOG.md +8 -0
- package/node_modules/@protobufjs/inquire/index.d.ts +1 -0
- package/node_modules/@protobufjs/inquire/index.js +1 -0
- package/node_modules/@protobufjs/inquire/package.json +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.js +187 -153
- package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.js +14 -5
- package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.js +207 -173
- package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
- package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
- package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
- package/node_modules/protobufjs/package.json +6 -3
- package/node_modules/protobufjs/src/util/fs.js +11 -0
- package/node_modules/protobufjs/src/util/minimal.js +10 -2
- package/node_modules/protobufjs/src/util.js +1 -1
- package/node_modules/undici/README.md +14 -5
- package/node_modules/undici/docs/docs/api/Client.md +4 -2
- package/node_modules/undici/docs/docs/api/Dispatcher.md +62 -27
- package/node_modules/undici/docs/docs/api/GlobalInstallation.md +7 -5
- package/node_modules/undici/docs/docs/api/H2CClient.md +1 -1
- package/node_modules/undici/docs/docs/api/RedirectHandler.md +14 -9
- package/node_modules/undici/docs/docs/api/RetryAgent.md +0 -1
- package/node_modules/undici/docs/docs/api/RetryHandler.md +12 -14
- package/node_modules/undici/docs/docs/api/SnapshotAgent.md +23 -0
- package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +231 -0
- package/node_modules/undici/index.js +4 -2
- package/node_modules/undici/lib/api/api-connect.js +13 -11
- package/node_modules/undici/lib/api/api-pipeline.js +26 -13
- package/node_modules/undici/lib/api/api-request.js +45 -21
- package/node_modules/undici/lib/api/api-stream.js +81 -20
- package/node_modules/undici/lib/api/api-upgrade.js +21 -11
- package/node_modules/undici/lib/api/readable.js +3 -2
- package/node_modules/undici/lib/cache/memory-cache-store.js +1 -1
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +6 -4
- package/node_modules/undici/lib/core/connect.js +17 -1
- package/node_modules/undici/lib/core/constants.js +1 -24
- package/node_modules/undici/lib/core/errors.js +2 -2
- package/node_modules/undici/lib/core/request.js +115 -18
- package/node_modules/undici/lib/core/socks5-client.js +24 -9
- package/node_modules/undici/lib/core/socks5-utils.js +32 -23
- package/node_modules/undici/lib/core/symbols.js +1 -0
- package/node_modules/undici/lib/core/util.js +70 -43
- package/node_modules/undici/lib/dispatcher/agent.js +47 -33
- package/node_modules/undici/lib/dispatcher/balanced-pool.js +21 -26
- package/node_modules/undici/lib/dispatcher/client-h1.js +98 -39
- package/node_modules/undici/lib/dispatcher/client-h2.js +603 -272
- package/node_modules/undici/lib/dispatcher/client.js +12 -5
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +24 -5
- package/node_modules/undici/lib/dispatcher/dispatcher.js +0 -4
- package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +107 -0
- package/node_modules/undici/lib/dispatcher/h2c-client.js +5 -5
- package/node_modules/undici/lib/dispatcher/pool-base.js +28 -10
- package/node_modules/undici/lib/dispatcher/pool.js +31 -6
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +38 -13
- package/node_modules/undici/lib/dispatcher/round-robin-pool.js +31 -9
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +95 -80
- package/node_modules/undici/lib/global.js +13 -1
- package/node_modules/undici/lib/handler/cache-handler.js +16 -8
- package/node_modules/undici/lib/handler/decorator-handler.js +1 -2
- package/node_modules/undici/lib/handler/redirect-handler.js +5 -51
- package/node_modules/undici/lib/handler/retry-handler.js +15 -2
- package/node_modules/undici/lib/interceptor/cache.js +30 -17
- package/node_modules/undici/lib/interceptor/decompress.js +28 -2
- package/node_modules/undici/lib/interceptor/dns.js +1 -1
- package/node_modules/undici/lib/interceptor/redirect.js +3 -3
- package/node_modules/undici/lib/llhttp/llhttp-wasm.js +1 -1
- package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +1 -1
- package/node_modules/undici/lib/mock/mock-agent.js +8 -8
- package/node_modules/undici/lib/mock/mock-call-history.js +15 -15
- package/node_modules/undici/lib/mock/mock-utils.js +37 -22
- package/node_modules/undici/lib/mock/snapshot-agent.js +16 -6
- package/node_modules/undici/lib/mock/snapshot-recorder.js +38 -3
- package/node_modules/undici/lib/util/cache.js +8 -7
- package/node_modules/undici/lib/util/runtime-features.js +3 -34
- package/node_modules/undici/lib/web/cache/cache.js +6 -8
- package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +245 -150
- package/node_modules/undici/lib/web/fetch/body.js +3 -9
- package/node_modules/undici/lib/web/fetch/formdata-parser.js +17 -6
- package/node_modules/undici/lib/web/fetch/formdata.js +21 -2
- package/node_modules/undici/lib/web/fetch/index.js +214 -221
- package/node_modules/undici/lib/web/webidl/index.js +7 -9
- package/node_modules/undici/lib/web/websocket/frame.js +1 -7
- package/node_modules/undici/lib/web/websocket/permessage-deflate.js +13 -31
- package/node_modules/undici/lib/web/websocket/receiver.js +62 -22
- package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +11 -17
- package/node_modules/undici/lib/web/websocket/websocket.js +6 -1
- package/node_modules/undici/package.json +9 -9
- package/node_modules/undici/types/agent.d.ts +0 -2
- package/node_modules/undici/types/client.d.ts +25 -19
- package/node_modules/undici/types/dispatcher.d.ts +7 -27
- package/node_modules/undici/types/dispatcher1-wrapper.d.ts +7 -0
- package/node_modules/undici/types/formdata.d.ts +0 -6
- package/node_modules/undici/types/h2c-client.d.ts +6 -6
- package/node_modules/undici/types/header.d.ts +5 -0
- package/node_modules/undici/types/index.d.ts +3 -1
- package/node_modules/undici/types/interceptors.d.ts +1 -1
- package/node_modules/undici/types/pool.d.ts +0 -2
- package/node_modules/undici/types/proxy-agent.d.ts +2 -2
- package/node_modules/undici/types/round-robin-pool.d.ts +0 -2
- package/node_modules/undici/types/snapshot-agent.d.ts +4 -0
- package/node_modules/undici/types/socks5-proxy-agent.d.ts +2 -2
- package/node_modules/undici/types/webidl.d.ts +0 -1
- package/package.json +7 -8
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package-lock.json +0 -24
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package-lock.json +0 -92
- package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package-lock.json +0 -31
- package/node_modules/undici/lib/handler/unwrap-handler.js +0 -100
- package/node_modules/undici/lib/handler/wrap-handler.js +0 -105
- package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
- package/node_modules/undici/lib/util/promise.js +0 -28
- package/skills/refresh-kb-links/SKILL.md +0 -217
- package/skills/store-custodian/SKILL.md +0 -163
- package/skills/store-query-grammar/SKILL.md +0 -145
- package/skills/store-query-nlp/SKILL.md +0 -110
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Migrating from Undici 7 to 8
|
|
2
|
+
|
|
3
|
+
This guide covers the changes you are most likely to hit when upgrading an
|
|
4
|
+
application or library from Undici v7 to v8.
|
|
5
|
+
|
|
6
|
+
## Before you upgrade
|
|
7
|
+
|
|
8
|
+
- Make sure your runtime is Node.js `>= 22.19.0`.
|
|
9
|
+
- If you have custom dispatchers, interceptors, or handlers, review the
|
|
10
|
+
handler API changes before updating.
|
|
11
|
+
- If you rely on HTTP/1.1-only behavior, plan to set `allowH2: false`
|
|
12
|
+
explicitly.
|
|
13
|
+
|
|
14
|
+
## 1. Update your Node.js version
|
|
15
|
+
|
|
16
|
+
Undici v8 requires Node.js `>= 22.19.0`.
|
|
17
|
+
|
|
18
|
+
If you are still on Node.js 20 or an older Node.js 22 release, upgrade Node.js
|
|
19
|
+
first:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
node -v
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
If that command prints a version lower than `v22.19.0`, upgrade Node.js before
|
|
26
|
+
installing Undici v8.
|
|
27
|
+
|
|
28
|
+
## 2. Migrate custom dispatcher handlers to the v2 API
|
|
29
|
+
|
|
30
|
+
Undici v8 uses the newer dispatcher handler API consistently.
|
|
31
|
+
|
|
32
|
+
If you implemented custom dispatchers, interceptors, or wrappers around
|
|
33
|
+
`dispatch()`, update legacy callbacks such as `onConnect`, `onHeaders`, and
|
|
34
|
+
`onComplete` to the newer callback names.
|
|
35
|
+
|
|
36
|
+
### Old handler callbacks vs. v8 callbacks
|
|
37
|
+
|
|
38
|
+
| Undici 7 style | Undici 8 style |
|
|
39
|
+
|---|---|
|
|
40
|
+
| `onConnect(abort, context)` | `onRequestStart(controller, context)` |
|
|
41
|
+
| `onHeaders(statusCode, rawHeaders, resume, statusText)` | `onResponseStart(controller, statusCode, headers, statusText)` |
|
|
42
|
+
| `onData(chunk)` | `onResponseData(controller, chunk)` |
|
|
43
|
+
| `onComplete(trailers)` | `onResponseEnd(controller, trailers)` |
|
|
44
|
+
| `onError(err)` | `onResponseError(controller, err)` |
|
|
45
|
+
| `onUpgrade(statusCode, rawHeaders, socket)` | `onRequestUpgrade(controller, statusCode, headers, socket)` |
|
|
46
|
+
|
|
47
|
+
### Example
|
|
48
|
+
|
|
49
|
+
Before:
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
client.dispatch(options, {
|
|
53
|
+
onConnect (abort) {
|
|
54
|
+
this.abort = abort
|
|
55
|
+
},
|
|
56
|
+
onHeaders (statusCode, headers, resume) {
|
|
57
|
+
this.resume = resume
|
|
58
|
+
return true
|
|
59
|
+
},
|
|
60
|
+
onData (chunk) {
|
|
61
|
+
chunks.push(chunk)
|
|
62
|
+
return true
|
|
63
|
+
},
|
|
64
|
+
onComplete (trailers) {
|
|
65
|
+
console.log(trailers)
|
|
66
|
+
},
|
|
67
|
+
onError (err) {
|
|
68
|
+
console.error(err)
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
After:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
client.dispatch(options, {
|
|
77
|
+
onRequestStart (controller) {
|
|
78
|
+
this.controller = controller
|
|
79
|
+
},
|
|
80
|
+
onResponseStart (controller, statusCode, headers, statusText) {
|
|
81
|
+
console.log(statusCode, statusText, headers)
|
|
82
|
+
},
|
|
83
|
+
onResponseData (controller, chunk) {
|
|
84
|
+
chunks.push(chunk)
|
|
85
|
+
},
|
|
86
|
+
onResponseEnd (controller, trailers) {
|
|
87
|
+
console.log(trailers)
|
|
88
|
+
},
|
|
89
|
+
onResponseError (controller, err) {
|
|
90
|
+
console.error(err)
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Pause, resume, and abort now go through the controller
|
|
96
|
+
|
|
97
|
+
In Undici v7, legacy handlers could return `false` or keep references to
|
|
98
|
+
`abort()` and `resume()` callbacks. In Undici v8, use the controller instead:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
onRequestStart (controller) {
|
|
102
|
+
this.controller = controller
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
onResponseData (controller, chunk) {
|
|
106
|
+
controller.pause()
|
|
107
|
+
setImmediate(() => controller.resume())
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
onResponseError (controller, err) {
|
|
111
|
+
controller.abort(err)
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Raw headers and trailers moved to the controller
|
|
116
|
+
|
|
117
|
+
If you need the raw header arrays, read them from the controller:
|
|
118
|
+
|
|
119
|
+
- `controller.rawHeaders`
|
|
120
|
+
- `controller.rawTrailers`
|
|
121
|
+
|
|
122
|
+
## 3. Update `onBodySent()` handlers
|
|
123
|
+
|
|
124
|
+
If you implemented `onBodySent()`, note that its signature changed.
|
|
125
|
+
|
|
126
|
+
Before, handlers received counters:
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
onBodySent (chunkSize, totalBytesSent) {}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
In Undici v8, handlers receive the actual chunk:
|
|
133
|
+
|
|
134
|
+
```js
|
|
135
|
+
onBodySent (chunk) {}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
If you need a notification that the whole body has been sent, use
|
|
139
|
+
`onRequestSent()`:
|
|
140
|
+
|
|
141
|
+
```js
|
|
142
|
+
onRequestSent () {
|
|
143
|
+
console.log('request body fully sent')
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## 4. If you need HTTP/1.1 only, disable HTTP/2 explicitly
|
|
148
|
+
|
|
149
|
+
Undici v8 enables HTTP/2 by default when a TLS server negotiates it via ALPN.
|
|
150
|
+
|
|
151
|
+
If your application depends on HTTP/1.1-specific behavior, set `allowH2: false`
|
|
152
|
+
explicitly.
|
|
153
|
+
|
|
154
|
+
Before:
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
const client = new Client('https://example.com')
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
After, to keep HTTP/1.1 only:
|
|
161
|
+
|
|
162
|
+
```js
|
|
163
|
+
const client = new Client('https://example.com', {
|
|
164
|
+
allowH2: false
|
|
165
|
+
})
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The same applies when you configure an `Agent`:
|
|
169
|
+
|
|
170
|
+
```js
|
|
171
|
+
const agent = new Agent({
|
|
172
|
+
allowH2: false
|
|
173
|
+
})
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## 5. Use real `Blob` and `File` instances
|
|
177
|
+
|
|
178
|
+
Undici v8 no longer accepts fake Blob-like values that only imitate `Blob` or
|
|
179
|
+
`File` via properties such as `Symbol.toStringTag`.
|
|
180
|
+
|
|
181
|
+
If you were passing custom objects that looked like `Blob`s, replace them with
|
|
182
|
+
actual `Blob` or `File` instances:
|
|
183
|
+
|
|
184
|
+
```js
|
|
185
|
+
const body = new Blob(['hello'])
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## 6. Avoid depending on the internal global dispatcher symbol
|
|
189
|
+
|
|
190
|
+
`setGlobalDispatcher()` and `getGlobalDispatcher()` remain the public APIs and
|
|
191
|
+
should continue to be used.
|
|
192
|
+
|
|
193
|
+
Internally, Undici v8 stores its dispatcher under
|
|
194
|
+
`Symbol.for('undici.globalDispatcher.2')` and mirrors a v1-compatible wrapper
|
|
195
|
+
for legacy consumers such as Node.js built-in `fetch`.
|
|
196
|
+
|
|
197
|
+
If your code was reading or writing `Symbol.for('undici.globalDispatcher.1')`
|
|
198
|
+
directly, migrate to the public APIs instead:
|
|
199
|
+
|
|
200
|
+
```js
|
|
201
|
+
import { setGlobalDispatcher, getGlobalDispatcher, Agent } from 'undici'
|
|
202
|
+
|
|
203
|
+
setGlobalDispatcher(new Agent())
|
|
204
|
+
const dispatcher = getGlobalDispatcher()
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
If you must expose a dispatcher to legacy v1 handler consumers, wrap it with
|
|
208
|
+
`Dispatcher1Wrapper`:
|
|
209
|
+
|
|
210
|
+
```js
|
|
211
|
+
import { Agent, Dispatcher1Wrapper } from 'undici'
|
|
212
|
+
|
|
213
|
+
const legacyCompatibleDispatcher = new Dispatcher1Wrapper(new Agent())
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## 7. Verify the upgrade
|
|
217
|
+
|
|
218
|
+
After moving to Undici v8, it is worth checking these paths in your test suite:
|
|
219
|
+
|
|
220
|
+
- requests that use a custom `dispatcher`
|
|
221
|
+
- `setGlobalDispatcher()` behavior
|
|
222
|
+
- any custom interceptor or retry handler
|
|
223
|
+
- uploads that use `Blob`, `File`, or `FormData`
|
|
224
|
+
- integrations that depend on HTTP/1.1-only behavior
|
|
225
|
+
|
|
226
|
+
## Related documentation
|
|
227
|
+
|
|
228
|
+
- [Dispatcher](/docs/api/Dispatcher.md)
|
|
229
|
+
- [Client](/docs/api/Client.md)
|
|
230
|
+
- [Global Installation](/docs/api/GlobalInstallation.md)
|
|
231
|
+
- [Undici Module vs. Node.js Built-in Fetch](/docs/best-practices/undici-vs-builtin-fetch.md)
|
|
@@ -6,6 +6,7 @@ const Pool = require('./lib/dispatcher/pool')
|
|
|
6
6
|
const BalancedPool = require('./lib/dispatcher/balanced-pool')
|
|
7
7
|
const RoundRobinPool = require('./lib/dispatcher/round-robin-pool')
|
|
8
8
|
const Agent = require('./lib/dispatcher/agent')
|
|
9
|
+
const Dispatcher1Wrapper = require('./lib/dispatcher/dispatcher1-wrapper')
|
|
9
10
|
const ProxyAgent = require('./lib/dispatcher/proxy-agent')
|
|
10
11
|
const Socks5ProxyAgent = require('./lib/dispatcher/socks5-proxy-agent')
|
|
11
12
|
const EnvHttpProxyAgent = require('./lib/dispatcher/env-http-proxy-agent')
|
|
@@ -35,6 +36,7 @@ module.exports.Pool = Pool
|
|
|
35
36
|
module.exports.BalancedPool = BalancedPool
|
|
36
37
|
module.exports.RoundRobinPool = RoundRobinPool
|
|
37
38
|
module.exports.Agent = Agent
|
|
39
|
+
module.exports.Dispatcher1Wrapper = Dispatcher1Wrapper
|
|
38
40
|
module.exports.ProxyAgent = ProxyAgent
|
|
39
41
|
module.exports.Socks5ProxyAgent = Socks5ProxyAgent
|
|
40
42
|
module.exports.EnvHttpProxyAgent = EnvHttpProxyAgent
|
|
@@ -103,14 +105,14 @@ function makeDispatcher (fn) {
|
|
|
103
105
|
url = util.parseURL(url)
|
|
104
106
|
}
|
|
105
107
|
|
|
106
|
-
const { agent, dispatcher = getGlobalDispatcher() } = opts
|
|
108
|
+
const { agent, dispatcher = getGlobalDispatcher(), ...restOpts } = opts
|
|
107
109
|
|
|
108
110
|
if (agent) {
|
|
109
111
|
throw new InvalidArgumentError('unsupported opts.agent. Did you mean opts.client?')
|
|
110
112
|
}
|
|
111
113
|
|
|
112
114
|
return fn.call(dispatcher, {
|
|
113
|
-
...
|
|
115
|
+
...restOpts,
|
|
114
116
|
origin: url.origin,
|
|
115
117
|
path: url.search ? `${url.pathname}${url.search}` : url.pathname,
|
|
116
118
|
method: opts.method || (opts.body ? 'PUT' : 'GET')
|
|
@@ -32,45 +32,48 @@ class ConnectHandler extends AsyncResource {
|
|
|
32
32
|
addSignal(this, signal)
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
onRequestStart (controller, context) {
|
|
36
36
|
if (this.reason) {
|
|
37
|
-
abort(this.reason)
|
|
37
|
+
controller.abort(this.reason)
|
|
38
38
|
return
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
assert(this.callback)
|
|
42
42
|
|
|
43
|
-
this.abort = abort
|
|
43
|
+
this.abort = (reason) => controller.abort(reason)
|
|
44
44
|
this.context = context
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
onResponseStart () {
|
|
48
48
|
throw new SocketError('bad connect', null)
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
onRequestUpgrade (controller, statusCode, headers, socket) {
|
|
52
52
|
const { callback, opaque, context } = this
|
|
53
53
|
|
|
54
54
|
removeSignal(this)
|
|
55
55
|
|
|
56
56
|
this.callback = null
|
|
57
57
|
|
|
58
|
-
let
|
|
58
|
+
let responseHeaders = headers
|
|
59
|
+
const rawHeaders = controller?.rawHeaders
|
|
59
60
|
// Indicates is an HTTP2Session
|
|
60
|
-
if (
|
|
61
|
-
|
|
61
|
+
if (responseHeaders != null) {
|
|
62
|
+
responseHeaders = this.responseHeaders === 'raw'
|
|
63
|
+
? util.parseRawHeaders(rawHeaders)
|
|
64
|
+
: headers
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
this.runInAsyncScope(callback, null, null, {
|
|
65
68
|
statusCode,
|
|
66
|
-
headers,
|
|
69
|
+
headers: responseHeaders,
|
|
67
70
|
socket,
|
|
68
71
|
opaque,
|
|
69
72
|
context
|
|
70
73
|
})
|
|
71
74
|
}
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
onResponseError (_controller, err) {
|
|
74
77
|
const { callback, opaque } = this
|
|
75
78
|
|
|
76
79
|
removeSignal(this)
|
|
@@ -96,7 +99,6 @@ function connect (opts, callback) {
|
|
|
96
99
|
try {
|
|
97
100
|
const connectHandler = new ConnectHandler(opts, callback)
|
|
98
101
|
const connectOptions = { ...opts, method: 'CONNECT' }
|
|
99
|
-
|
|
100
102
|
this.dispatch(connectOptions, connectHandler)
|
|
101
103
|
} catch (err) {
|
|
102
104
|
if (typeof callback !== 'function') {
|
|
@@ -13,6 +13,7 @@ const {
|
|
|
13
13
|
RequestAbortedError
|
|
14
14
|
} = require('../core/errors')
|
|
15
15
|
const util = require('../core/util')
|
|
16
|
+
const { kBodyUsed } = require('../core/symbols')
|
|
16
17
|
const { addSignal, removeSignal } = require('./abort-signal')
|
|
17
18
|
|
|
18
19
|
function noop () {}
|
|
@@ -24,6 +25,9 @@ class PipelineRequest extends Readable {
|
|
|
24
25
|
super({ autoDestroy: true })
|
|
25
26
|
|
|
26
27
|
this[kResume] = null
|
|
28
|
+
// Pipeline request bodies come from a live writable side and cannot be
|
|
29
|
+
// replayed across redirects or retries, even before any bytes are read.
|
|
30
|
+
this[kBodyUsed] = true
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
_read () {
|
|
@@ -146,40 +150,46 @@ class PipelineHandler extends AsyncResource {
|
|
|
146
150
|
addSignal(this, signal)
|
|
147
151
|
}
|
|
148
152
|
|
|
149
|
-
|
|
153
|
+
onRequestStart (controller, context) {
|
|
150
154
|
const { res } = this
|
|
151
155
|
|
|
152
156
|
if (this.reason) {
|
|
153
|
-
abort(this.reason)
|
|
157
|
+
controller.abort(this.reason)
|
|
154
158
|
return
|
|
155
159
|
}
|
|
156
160
|
|
|
157
161
|
assert(!res, 'pipeline cannot be retried')
|
|
158
162
|
|
|
159
|
-
this.abort = abort
|
|
163
|
+
this.abort = (reason) => controller.abort(reason)
|
|
160
164
|
this.context = context
|
|
161
165
|
}
|
|
162
166
|
|
|
163
|
-
|
|
167
|
+
onResponseStart (controller, statusCode, headers, _statusMessage) {
|
|
164
168
|
const { opaque, handler, context } = this
|
|
165
169
|
|
|
166
170
|
if (statusCode < 200) {
|
|
167
171
|
if (this.onInfo) {
|
|
168
|
-
const
|
|
169
|
-
this.
|
|
172
|
+
const rawHeaders = controller?.rawHeaders
|
|
173
|
+
const responseHeaders = this.responseHeaders === 'raw'
|
|
174
|
+
? util.parseRawHeaders(rawHeaders)
|
|
175
|
+
: headers
|
|
176
|
+
this.onInfo({ statusCode, headers: responseHeaders })
|
|
170
177
|
}
|
|
171
178
|
return
|
|
172
179
|
}
|
|
173
180
|
|
|
174
|
-
this.res = new PipelineResponse(resume)
|
|
181
|
+
this.res = new PipelineResponse(() => controller.resume())
|
|
175
182
|
|
|
176
183
|
let body
|
|
177
184
|
try {
|
|
178
185
|
this.handler = null
|
|
179
|
-
const
|
|
186
|
+
const rawHeaders = controller?.rawHeaders
|
|
187
|
+
const responseHeaders = this.responseHeaders === 'raw'
|
|
188
|
+
? util.parseRawHeaders(rawHeaders)
|
|
189
|
+
: headers
|
|
180
190
|
body = this.runInAsyncScope(handler, null, {
|
|
181
191
|
statusCode,
|
|
182
|
-
headers,
|
|
192
|
+
headers: responseHeaders,
|
|
183
193
|
opaque,
|
|
184
194
|
body: this.res,
|
|
185
195
|
context
|
|
@@ -222,17 +232,20 @@ class PipelineHandler extends AsyncResource {
|
|
|
222
232
|
this.body = body
|
|
223
233
|
}
|
|
224
234
|
|
|
225
|
-
|
|
235
|
+
onResponseData (controller, chunk) {
|
|
226
236
|
const { res } = this
|
|
227
|
-
|
|
237
|
+
|
|
238
|
+
if (res.push(chunk) === false) {
|
|
239
|
+
controller.pause()
|
|
240
|
+
}
|
|
228
241
|
}
|
|
229
242
|
|
|
230
|
-
|
|
243
|
+
onResponseEnd (_controller, _trailers) {
|
|
231
244
|
const { res } = this
|
|
232
245
|
res.push(null)
|
|
233
246
|
}
|
|
234
247
|
|
|
235
|
-
|
|
248
|
+
onResponseError (_controller, err) {
|
|
236
249
|
const { ret } = this
|
|
237
250
|
this.handler = null
|
|
238
251
|
util.destroy(ret, err)
|
|
@@ -21,7 +21,7 @@ class RequestHandler extends AsyncResource {
|
|
|
21
21
|
throw new InvalidArgumentError('invalid callback')
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
if (highWaterMark && (
|
|
24
|
+
if (highWaterMark != null && (!Number.isFinite(highWaterMark) || highWaterMark < 0)) {
|
|
25
25
|
throw new InvalidArgumentError('invalid highWaterMark')
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -54,6 +54,7 @@ class RequestHandler extends AsyncResource {
|
|
|
54
54
|
this.body = body
|
|
55
55
|
this.trailers = {}
|
|
56
56
|
this.context = null
|
|
57
|
+
this.controller = null
|
|
57
58
|
this.onInfo = onInfo || null
|
|
58
59
|
this.highWaterMark = highWaterMark
|
|
59
60
|
this.reason = null
|
|
@@ -73,36 +74,40 @@ class RequestHandler extends AsyncResource {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
|
|
77
|
+
onRequestStart (controller, context) {
|
|
77
78
|
if (this.reason) {
|
|
78
|
-
abort(this.reason)
|
|
79
|
+
controller.abort(this.reason)
|
|
79
80
|
return
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
assert(this.callback)
|
|
83
84
|
|
|
84
|
-
this.
|
|
85
|
+
this.controller = controller
|
|
86
|
+
this.abort = (reason) => controller.abort(reason)
|
|
85
87
|
this.context = context
|
|
86
88
|
}
|
|
87
89
|
|
|
88
|
-
|
|
89
|
-
const { callback, opaque,
|
|
90
|
+
onResponseStart (controller, statusCode, headers, statusText) {
|
|
91
|
+
const { callback, opaque, context, responseHeaders, highWaterMark } = this
|
|
90
92
|
|
|
91
|
-
const
|
|
93
|
+
const rawHeaders = controller?.rawHeaders
|
|
94
|
+
const responseHeaderData = responseHeaders === 'raw'
|
|
95
|
+
? util.parseRawHeaders(rawHeaders)
|
|
96
|
+
: headers
|
|
92
97
|
|
|
93
98
|
if (statusCode < 200) {
|
|
94
99
|
if (this.onInfo) {
|
|
95
|
-
this.onInfo({ statusCode, headers })
|
|
100
|
+
this.onInfo({ statusCode, headers: responseHeaderData })
|
|
96
101
|
}
|
|
97
102
|
return
|
|
98
103
|
}
|
|
99
104
|
|
|
100
|
-
const parsedHeaders =
|
|
101
|
-
const contentType = parsedHeaders['content-type']
|
|
102
|
-
const contentLength = parsedHeaders['content-length']
|
|
105
|
+
const parsedHeaders = headers
|
|
106
|
+
const contentType = parsedHeaders?.['content-type']
|
|
107
|
+
const contentLength = parsedHeaders?.['content-length']
|
|
103
108
|
const res = new Readable({
|
|
104
|
-
resume,
|
|
105
|
-
abort,
|
|
109
|
+
resume: () => controller.resume(),
|
|
110
|
+
abort: (reason) => controller.abort(reason),
|
|
106
111
|
contentType,
|
|
107
112
|
contentLength: this.method !== 'HEAD' && contentLength
|
|
108
113
|
? Number(contentLength)
|
|
@@ -121,8 +126,8 @@ class RequestHandler extends AsyncResource {
|
|
|
121
126
|
try {
|
|
122
127
|
this.runInAsyncScope(callback, null, null, {
|
|
123
128
|
statusCode,
|
|
124
|
-
statusText
|
|
125
|
-
headers,
|
|
129
|
+
statusText,
|
|
130
|
+
headers: responseHeaderData,
|
|
126
131
|
trailers: this.trailers,
|
|
127
132
|
opaque,
|
|
128
133
|
body: res,
|
|
@@ -144,16 +149,35 @@ class RequestHandler extends AsyncResource {
|
|
|
144
149
|
}
|
|
145
150
|
}
|
|
146
151
|
|
|
147
|
-
|
|
148
|
-
|
|
152
|
+
onResponseData (controller, chunk) {
|
|
153
|
+
if (!this.res) {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (this.res.push(chunk) === false) {
|
|
158
|
+
controller.pause()
|
|
159
|
+
}
|
|
149
160
|
}
|
|
150
161
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
162
|
+
onResponseEnd (_controller, trailers) {
|
|
163
|
+
if (trailers && typeof trailers === 'object') {
|
|
164
|
+
for (const key of Object.keys(trailers)) {
|
|
165
|
+
if (key === '__proto__') {
|
|
166
|
+
Object.defineProperty(this.trailers, key, {
|
|
167
|
+
value: trailers[key],
|
|
168
|
+
enumerable: true,
|
|
169
|
+
configurable: true,
|
|
170
|
+
writable: true
|
|
171
|
+
})
|
|
172
|
+
} else {
|
|
173
|
+
this.trailers[key] = trailers[key]
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
this.res?.push(null)
|
|
154
178
|
}
|
|
155
179
|
|
|
156
|
-
|
|
180
|
+
onResponseError (_controller, err) {
|
|
157
181
|
const { res, callback, body, opaque } = this
|
|
158
182
|
|
|
159
183
|
if (callback) {
|