@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.
Files changed (227) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/CHANGELOG-forge-plugin.md +70 -0
  3. package/dist/CHANGELOG-pi.md +63 -0
  4. package/dist/bin/argv.d.ts +2 -2
  5. package/dist/bin/argv.js +10 -0
  6. package/dist/bin/argv.js.map +1 -1
  7. package/dist/bin/env-defaults.d.ts +1 -0
  8. package/dist/bin/env-defaults.js +13 -0
  9. package/dist/bin/env-defaults.js.map +1 -0
  10. package/dist/bin/forge.js +9 -0
  11. package/dist/bin/forge.js.map +1 -1
  12. package/dist/bin/update-cli.d.ts +9 -0
  13. package/dist/bin/update-cli.js +120 -0
  14. package/dist/bin/update-cli.js.map +1 -0
  15. package/dist/extensions/forgecli/index.js +3 -3
  16. package/dist/extensions/forgecli/index.js.map +1 -1
  17. package/dist/extensions/forgecli/update-check.js +1 -1
  18. package/dist/extensions/forgecli/update-check.js.map +1 -1
  19. package/dist/extensions/forgecli/whats-new-widget.d.ts +5 -5
  20. package/dist/extensions/forgecli/whats-new-widget.js +11 -11
  21. package/dist/extensions/forgecli/whats-new-widget.js.map +1 -1
  22. package/dist/extensions/forgecli/whats-new.js +6 -5
  23. package/dist/extensions/forgecli/whats-new.js.map +1 -1
  24. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  25. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +27 -98
  26. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  27. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +62 -132
  28. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js.map +1 -1
  29. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.d.ts.map +1 -1
  30. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +25 -15
  31. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  32. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  33. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +1 -0
  34. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js.map +1 -1
  35. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  36. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +17 -1
  37. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  38. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  39. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +8 -2
  40. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js.map +1 -1
  41. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  42. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +17 -1
  43. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js.map +1 -1
  44. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  45. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js +8 -1
  46. package/node_modules/@earendil-works/pi-ai/dist/providers/simple-options.js.map +1 -1
  47. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  48. package/node_modules/@earendil-works/pi-coding-agent/CHANGELOG.md +63 -0
  49. package/node_modules/@earendil-works/pi-coding-agent/README.md +1 -1
  50. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.d.ts.map +1 -1
  51. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.js +1 -1
  52. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/config-selector.js.map +1 -1
  53. package/node_modules/@earendil-works/pi-coding-agent/dist/cli.d.ts.map +1 -1
  54. package/node_modules/@earendil-works/pi-coding-agent/dist/cli.js +6 -10
  55. package/node_modules/@earendil-works/pi-coding-agent/dist/cli.js.map +1 -1
  56. package/node_modules/@earendil-works/pi-coding-agent/dist/config.d.ts.map +1 -1
  57. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +12 -3
  58. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js.map +1 -1
  59. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +1 -0
  60. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  61. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +30 -15
  62. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  63. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts +3 -3
  64. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  65. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +23 -13
  66. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  67. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.d.ts +4 -0
  68. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  69. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +58 -38
  70. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  71. package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  72. package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.js +0 -1
  73. package/node_modules/@earendil-works/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  74. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  75. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +3 -2
  76. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  77. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.d.ts +2 -2
  78. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  79. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js +7 -4
  80. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js.map +1 -1
  81. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  82. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +6 -2
  83. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  84. package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.d.ts.map +1 -1
  85. package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js +3 -4
  86. package/node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js.map +1 -1
  87. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.d.ts.map +1 -1
  88. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js +2 -2
  89. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/changelog.js.map +1 -1
  90. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.d.ts +7 -1
  91. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.d.ts.map +1 -1
  92. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.js +60 -7
  93. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/child-process.js.map +1 -1
  94. package/node_modules/@earendil-works/pi-coding-agent/docs/packages.md +2 -2
  95. package/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +1 -3
  96. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package.json +1 -1
  97. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  98. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package.json +1 -1
  99. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package.json +1 -1
  100. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
  101. package/node_modules/@earendil-works/pi-tui/package.json +2 -2
  102. package/node_modules/@protobufjs/fetch/CHANGELOG.md +8 -0
  103. package/node_modules/@protobufjs/fetch/index.d.ts +7 -7
  104. package/node_modules/@protobufjs/fetch/index.js +4 -7
  105. package/node_modules/@protobufjs/fetch/package.json +7 -5
  106. package/node_modules/@protobufjs/fetch/tests/data/file.txt +1 -0
  107. package/node_modules/@protobufjs/fetch/tests/index.js +150 -8
  108. package/node_modules/@protobufjs/fetch/util/fs.js +11 -0
  109. package/node_modules/@protobufjs/inquire/CHANGELOG.md +8 -0
  110. package/node_modules/@protobufjs/inquire/index.d.ts +1 -0
  111. package/node_modules/@protobufjs/inquire/index.js +1 -0
  112. package/node_modules/@protobufjs/inquire/package.json +1 -1
  113. package/node_modules/protobufjs/dist/light/protobuf.js +187 -153
  114. package/node_modules/protobufjs/dist/light/protobuf.js.map +1 -1
  115. package/node_modules/protobufjs/dist/light/protobuf.min.js +3 -3
  116. package/node_modules/protobufjs/dist/light/protobuf.min.js.map +1 -1
  117. package/node_modules/protobufjs/dist/minimal/protobuf.js +14 -5
  118. package/node_modules/protobufjs/dist/minimal/protobuf.js.map +1 -1
  119. package/node_modules/protobufjs/dist/minimal/protobuf.min.js +3 -3
  120. package/node_modules/protobufjs/dist/minimal/protobuf.min.js.map +1 -1
  121. package/node_modules/protobufjs/dist/protobuf.js +207 -173
  122. package/node_modules/protobufjs/dist/protobuf.js.map +1 -1
  123. package/node_modules/protobufjs/dist/protobuf.min.js +3 -3
  124. package/node_modules/protobufjs/dist/protobuf.min.js.map +1 -1
  125. package/node_modules/protobufjs/package.json +6 -3
  126. package/node_modules/protobufjs/src/util/fs.js +11 -0
  127. package/node_modules/protobufjs/src/util/minimal.js +10 -2
  128. package/node_modules/protobufjs/src/util.js +1 -1
  129. package/node_modules/undici/README.md +14 -5
  130. package/node_modules/undici/docs/docs/api/Client.md +4 -2
  131. package/node_modules/undici/docs/docs/api/Dispatcher.md +62 -27
  132. package/node_modules/undici/docs/docs/api/GlobalInstallation.md +7 -5
  133. package/node_modules/undici/docs/docs/api/H2CClient.md +1 -1
  134. package/node_modules/undici/docs/docs/api/RedirectHandler.md +14 -9
  135. package/node_modules/undici/docs/docs/api/RetryAgent.md +0 -1
  136. package/node_modules/undici/docs/docs/api/RetryHandler.md +12 -14
  137. package/node_modules/undici/docs/docs/api/SnapshotAgent.md +23 -0
  138. package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +231 -0
  139. package/node_modules/undici/index.js +4 -2
  140. package/node_modules/undici/lib/api/api-connect.js +13 -11
  141. package/node_modules/undici/lib/api/api-pipeline.js +26 -13
  142. package/node_modules/undici/lib/api/api-request.js +45 -21
  143. package/node_modules/undici/lib/api/api-stream.js +81 -20
  144. package/node_modules/undici/lib/api/api-upgrade.js +21 -11
  145. package/node_modules/undici/lib/api/readable.js +3 -2
  146. package/node_modules/undici/lib/cache/memory-cache-store.js +1 -1
  147. package/node_modules/undici/lib/cache/sqlite-cache-store.js +6 -4
  148. package/node_modules/undici/lib/core/connect.js +17 -1
  149. package/node_modules/undici/lib/core/constants.js +1 -24
  150. package/node_modules/undici/lib/core/errors.js +2 -2
  151. package/node_modules/undici/lib/core/request.js +115 -18
  152. package/node_modules/undici/lib/core/socks5-client.js +24 -9
  153. package/node_modules/undici/lib/core/socks5-utils.js +32 -23
  154. package/node_modules/undici/lib/core/symbols.js +1 -0
  155. package/node_modules/undici/lib/core/util.js +70 -43
  156. package/node_modules/undici/lib/dispatcher/agent.js +47 -33
  157. package/node_modules/undici/lib/dispatcher/balanced-pool.js +21 -26
  158. package/node_modules/undici/lib/dispatcher/client-h1.js +98 -39
  159. package/node_modules/undici/lib/dispatcher/client-h2.js +603 -272
  160. package/node_modules/undici/lib/dispatcher/client.js +12 -5
  161. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +24 -5
  162. package/node_modules/undici/lib/dispatcher/dispatcher.js +0 -4
  163. package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +107 -0
  164. package/node_modules/undici/lib/dispatcher/h2c-client.js +5 -5
  165. package/node_modules/undici/lib/dispatcher/pool-base.js +28 -10
  166. package/node_modules/undici/lib/dispatcher/pool.js +31 -6
  167. package/node_modules/undici/lib/dispatcher/proxy-agent.js +38 -13
  168. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +31 -9
  169. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +95 -80
  170. package/node_modules/undici/lib/global.js +13 -1
  171. package/node_modules/undici/lib/handler/cache-handler.js +16 -8
  172. package/node_modules/undici/lib/handler/decorator-handler.js +1 -2
  173. package/node_modules/undici/lib/handler/redirect-handler.js +5 -51
  174. package/node_modules/undici/lib/handler/retry-handler.js +15 -2
  175. package/node_modules/undici/lib/interceptor/cache.js +30 -17
  176. package/node_modules/undici/lib/interceptor/decompress.js +28 -2
  177. package/node_modules/undici/lib/interceptor/dns.js +1 -1
  178. package/node_modules/undici/lib/interceptor/redirect.js +3 -3
  179. package/node_modules/undici/lib/llhttp/llhttp-wasm.js +1 -1
  180. package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +1 -1
  181. package/node_modules/undici/lib/mock/mock-agent.js +8 -8
  182. package/node_modules/undici/lib/mock/mock-call-history.js +15 -15
  183. package/node_modules/undici/lib/mock/mock-utils.js +37 -22
  184. package/node_modules/undici/lib/mock/snapshot-agent.js +16 -6
  185. package/node_modules/undici/lib/mock/snapshot-recorder.js +38 -3
  186. package/node_modules/undici/lib/util/cache.js +8 -7
  187. package/node_modules/undici/lib/util/runtime-features.js +3 -34
  188. package/node_modules/undici/lib/web/cache/cache.js +6 -8
  189. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +245 -150
  190. package/node_modules/undici/lib/web/fetch/body.js +3 -9
  191. package/node_modules/undici/lib/web/fetch/formdata-parser.js +17 -6
  192. package/node_modules/undici/lib/web/fetch/formdata.js +21 -2
  193. package/node_modules/undici/lib/web/fetch/index.js +214 -221
  194. package/node_modules/undici/lib/web/webidl/index.js +7 -9
  195. package/node_modules/undici/lib/web/websocket/frame.js +1 -7
  196. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +13 -31
  197. package/node_modules/undici/lib/web/websocket/receiver.js +62 -22
  198. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +11 -17
  199. package/node_modules/undici/lib/web/websocket/websocket.js +6 -1
  200. package/node_modules/undici/package.json +9 -9
  201. package/node_modules/undici/types/agent.d.ts +0 -2
  202. package/node_modules/undici/types/client.d.ts +25 -19
  203. package/node_modules/undici/types/dispatcher.d.ts +7 -27
  204. package/node_modules/undici/types/dispatcher1-wrapper.d.ts +7 -0
  205. package/node_modules/undici/types/formdata.d.ts +0 -6
  206. package/node_modules/undici/types/h2c-client.d.ts +6 -6
  207. package/node_modules/undici/types/header.d.ts +5 -0
  208. package/node_modules/undici/types/index.d.ts +3 -1
  209. package/node_modules/undici/types/interceptors.d.ts +1 -1
  210. package/node_modules/undici/types/pool.d.ts +0 -2
  211. package/node_modules/undici/types/proxy-agent.d.ts +2 -2
  212. package/node_modules/undici/types/round-robin-pool.d.ts +0 -2
  213. package/node_modules/undici/types/snapshot-agent.d.ts +4 -0
  214. package/node_modules/undici/types/socks5-proxy-agent.d.ts +2 -2
  215. package/node_modules/undici/types/webidl.d.ts +0 -1
  216. package/package.json +7 -8
  217. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/custom-provider-anthropic/package-lock.json +0 -24
  218. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/sandbox/package-lock.json +0 -92
  219. package/node_modules/@earendil-works/pi-coding-agent/examples/extensions/with-deps/package-lock.json +0 -31
  220. package/node_modules/undici/lib/handler/unwrap-handler.js +0 -100
  221. package/node_modules/undici/lib/handler/wrap-handler.js +0 -105
  222. package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
  223. package/node_modules/undici/lib/util/promise.js +0 -28
  224. package/skills/refresh-kb-links/SKILL.md +0 -217
  225. package/skills/store-custodian/SKILL.md +0 -163
  226. package/skills/store-query-grammar/SKILL.md +0 -145
  227. package/skills/store-query-nlp/SKILL.md +0 -110
@@ -52,6 +52,7 @@ const {
52
52
  kOnError,
53
53
  kHTTPContext,
54
54
  kMaxConcurrentStreams,
55
+ kHostAuthority,
55
56
  kHTTP2InitialWindowSize,
56
57
  kHTTP2ConnectionWindowSize,
57
58
  kResume,
@@ -114,7 +115,8 @@ class Client extends DispatcherBase {
114
115
  useH2c,
115
116
  initialWindowSize,
116
117
  connectionWindowSize,
117
- pingInterval
118
+ pingInterval,
119
+ webSocket
118
120
  } = {}) {
119
121
  if (keepAlive !== undefined) {
120
122
  throw new InvalidArgumentError('unsupported keepAlive, use pipelining=0 instead')
@@ -222,7 +224,7 @@ class Client extends DispatcherBase {
222
224
  throw new InvalidArgumentError('pingInterval must be a positive integer, greater or equal to 0')
223
225
  }
224
226
 
225
- super()
227
+ super({ webSocket })
226
228
 
227
229
  if (typeof connect !== 'function') {
228
230
  connect = buildConnector({
@@ -235,12 +237,17 @@ class Client extends DispatcherBase {
235
237
  ...(typeof autoSelectFamily === 'boolean' ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
236
238
  ...connect
237
239
  })
238
- } else if (socketPath != null) {
240
+ } else {
239
241
  const customConnect = connect
240
- connect = (opts, callback) => customConnect({ ...opts, socketPath }, callback)
242
+ connect = (opts, callback) => customConnect({
243
+ ...opts,
244
+ ...(socketPath != null ? { socketPath } : null),
245
+ ...(allowH2 != null ? { allowH2 } : null)
246
+ }, callback)
241
247
  }
242
248
 
243
249
  this[kUrl] = util.parseOrigin(url)
250
+ this[kHostAuthority] = `${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ''}`
244
251
  this[kConnector] = connect
245
252
  this[kPipelining] = pipelining != null ? pipelining : 1
246
253
  this[kMaxHeadersSize] = maxHeaderSize
@@ -252,7 +259,7 @@ class Client extends DispatcherBase {
252
259
  this[kLocalAddress] = localAddress != null ? localAddress : null
253
260
  this[kResuming] = 0 // 0, idle, 1, scheduled, 2 resuming
254
261
  this[kNeedDrain] = 0 // 0, idle, 1, scheduled, 2 resuming
255
- this[kHostHeader] = `host: ${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ''}\r\n`
262
+ this[kHostHeader] = `host: ${this[kHostAuthority]}\r\n`
256
263
  this[kBodyTimeout] = bodyTimeout != null ? bodyTimeout : 300e3
257
264
  this[kHeadersTimeout] = headersTimeout != null ? headersTimeout : 300e3
258
265
  this[kStrictContentLength] = strictContentLength == null ? true : strictContentLength
@@ -1,7 +1,6 @@
1
1
  'use strict'
2
2
 
3
3
  const Dispatcher = require('./dispatcher')
4
- const UnwrapHandler = require('../handler/unwrap-handler')
5
4
  const {
6
5
  ClientDestroyedError,
7
6
  ClientClosedError,
@@ -11,6 +10,7 @@ const { kDestroy, kClose, kClosed, kDestroyed, kDispatch } = require('../core/sy
11
10
 
12
11
  const kOnDestroyed = Symbol('onDestroyed')
13
12
  const kOnClosed = Symbol('onClosed')
13
+ const kWebSocketOptions = Symbol('webSocketOptions')
14
14
 
15
15
  class DispatcherBase extends Dispatcher {
16
16
  /** @type {boolean} */
@@ -25,6 +25,23 @@ class DispatcherBase extends Dispatcher {
25
25
  /** @type {Array<Function>|null} */
26
26
  [kOnClosed] = null
27
27
 
28
+ /**
29
+ * @param {import('../../types/dispatcher').DispatcherOptions} [opts]
30
+ */
31
+ constructor (opts) {
32
+ super()
33
+ this[kWebSocketOptions] = opts?.webSocket ?? {}
34
+ }
35
+
36
+ /**
37
+ * @returns {import('../../types/dispatcher').WebSocketOptions}
38
+ */
39
+ get webSocketOptions () {
40
+ return {
41
+ maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024 // 128 MB default
42
+ }
43
+ }
44
+
28
45
  /** @returns {boolean} */
29
46
  get destroyed () {
30
47
  return this[kDestroyed]
@@ -134,13 +151,15 @@ class DispatcherBase extends Dispatcher {
134
151
  throw new InvalidArgumentError('handler must be an object')
135
152
  }
136
153
 
137
- handler = UnwrapHandler.unwrap(handler)
138
-
139
154
  try {
140
155
  if (!opts || typeof opts !== 'object') {
141
156
  throw new InvalidArgumentError('opts must be an object.')
142
157
  }
143
158
 
159
+ if (opts.dispatcher) {
160
+ throw new InvalidArgumentError('opts.dispatcher is not supported by instance methods. Pass opts.dispatcher to the top-level undici functions or call the dispatcher instance method directly.')
161
+ }
162
+
144
163
  if (this[kDestroyed] || this[kOnDestroyed]) {
145
164
  throw new ClientDestroyedError()
146
165
  }
@@ -151,11 +170,11 @@ class DispatcherBase extends Dispatcher {
151
170
 
152
171
  return this[kDispatch](opts, handler)
153
172
  } catch (err) {
154
- if (typeof handler.onError !== 'function') {
173
+ if (typeof handler.onResponseError !== 'function') {
155
174
  throw err
156
175
  }
157
176
 
158
- handler.onError(err)
177
+ handler.onResponseError(null, err)
159
178
 
160
179
  return false
161
180
  }
@@ -1,8 +1,5 @@
1
1
  'use strict'
2
2
  const EventEmitter = require('node:events')
3
- const WrapHandler = require('../handler/wrap-handler')
4
-
5
- const wrapInterceptor = (dispatch) => (opts, handler) => dispatch(opts, WrapHandler.wrap(handler))
6
3
 
7
4
  class Dispatcher extends EventEmitter {
8
5
  dispatch () {
@@ -32,7 +29,6 @@ class Dispatcher extends EventEmitter {
32
29
  }
33
30
 
34
31
  dispatch = interceptor(dispatch)
35
- dispatch = wrapInterceptor(dispatch)
36
32
 
37
33
  if (dispatch == null || typeof dispatch !== 'function' || dispatch.length !== 2) {
38
34
  throw new TypeError('invalid interceptor')
@@ -0,0 +1,107 @@
1
+ 'use strict'
2
+
3
+ const Dispatcher = require('./dispatcher')
4
+ const { InvalidArgumentError } = require('../core/errors')
5
+ const { toRawHeaders } = require('../core/util')
6
+
7
+ class LegacyHandlerWrapper {
8
+ #handler
9
+
10
+ constructor (handler) {
11
+ this.#handler = handler
12
+ }
13
+
14
+ onRequestStart (controller, context) {
15
+ this.#handler.onConnect?.((reason) => controller.abort(reason), context)
16
+ }
17
+
18
+ onRequestUpgrade (controller, statusCode, headers, socket) {
19
+ const rawHeaders = controller?.rawHeaders ?? toRawHeaders(headers ?? {})
20
+ this.#handler.onUpgrade?.(statusCode, rawHeaders, socket)
21
+ }
22
+
23
+ onResponseStart (controller, statusCode, headers, statusMessage) {
24
+ const rawHeaders = controller?.rawHeaders ?? toRawHeaders(headers ?? {})
25
+
26
+ if (this.#handler.onHeaders?.(statusCode, rawHeaders, () => controller.resume(), statusMessage) === false) {
27
+ controller.pause()
28
+ }
29
+ }
30
+
31
+ onResponseData (controller, chunk) {
32
+ if (this.#handler.onData?.(chunk) === false) {
33
+ controller.pause()
34
+ }
35
+ }
36
+
37
+ onResponseEnd (controller, trailers) {
38
+ const rawTrailers = controller?.rawTrailers ?? toRawHeaders(trailers ?? {})
39
+ this.#handler.onComplete?.(rawTrailers)
40
+ }
41
+
42
+ onResponseError (_controller, err) {
43
+ if (!this.#handler.onError) {
44
+ throw err
45
+ }
46
+
47
+ this.#handler.onError(err)
48
+ }
49
+
50
+ onBodySent (chunk) {
51
+ this.#handler.onBodySent?.(chunk)
52
+ }
53
+
54
+ onRequestSent () {
55
+ this.#handler.onRequestSent?.()
56
+ }
57
+
58
+ onResponseStarted () {
59
+ this.#handler.onResponseStarted?.()
60
+ }
61
+ }
62
+
63
+ class Dispatcher1Wrapper extends Dispatcher {
64
+ #dispatcher
65
+
66
+ constructor (dispatcher) {
67
+ super()
68
+
69
+ if (!dispatcher || typeof dispatcher.dispatch !== 'function') {
70
+ throw new InvalidArgumentError('Argument dispatcher must implement dispatch')
71
+ }
72
+
73
+ this.#dispatcher = dispatcher
74
+ }
75
+
76
+ static wrapHandler (handler) {
77
+ if (!handler || typeof handler !== 'object') {
78
+ throw new InvalidArgumentError('handler must be an object')
79
+ }
80
+
81
+ if (typeof handler.onRequestStart === 'function') {
82
+ return handler
83
+ }
84
+
85
+ return new LegacyHandlerWrapper(handler)
86
+ }
87
+
88
+ dispatch (opts, handler) {
89
+ // Legacy (v1) consumers do not support HTTP/2, so force HTTP/1.1.
90
+ // See https://github.com/nodejs/undici/issues/4989
91
+ if (opts.allowH2 !== false) {
92
+ opts = { ...opts, allowH2: false }
93
+ }
94
+
95
+ return this.#dispatcher.dispatch(opts, Dispatcher1Wrapper.wrapHandler(handler))
96
+ }
97
+
98
+ close (...args) {
99
+ return this.#dispatcher.close(...args)
100
+ }
101
+
102
+ destroy (...args) {
103
+ return this.#dispatcher.destroy(...args)
104
+ }
105
+ }
106
+
107
+ module.exports = Dispatcher1Wrapper
@@ -15,17 +15,17 @@ class H2CClient extends Client {
15
15
  )
16
16
  }
17
17
 
18
- const { connect, maxConcurrentStreams, pipelining, ...opts } =
18
+ const { maxConcurrentStreams, pipelining, ...opts } =
19
19
  clientOpts ?? {}
20
- let defaultMaxConcurrentStreams = 100
20
+ const defaultMaxConcurrentStreams = maxConcurrentStreams ?? 100
21
21
  let defaultPipelining = 100
22
22
 
23
23
  if (
24
24
  maxConcurrentStreams != null &&
25
- Number.isInteger(maxConcurrentStreams) &&
26
- maxConcurrentStreams > 0
25
+ (!Number.isInteger(maxConcurrentStreams) ||
26
+ maxConcurrentStreams < 1)
27
27
  ) {
28
- defaultMaxConcurrentStreams = maxConcurrentStreams
28
+ throw new InvalidArgumentError('maxConcurrentStreams must be a positive integer, greater than 0')
29
29
  }
30
30
 
31
31
  if (pipelining != null && Number.isInteger(pipelining) && pipelining > 0) {
@@ -14,6 +14,7 @@ const kOnConnect = Symbol('onConnect')
14
14
  const kOnDisconnect = Symbol('onDisconnect')
15
15
  const kOnConnectionError = Symbol('onConnectionError')
16
16
  const kGetDispatcher = Symbol('get dispatcher')
17
+ const kHasDispatcher = Symbol('has dispatcher')
17
18
  const kAddClient = Symbol('add client')
18
19
  const kRemoveClient = Symbol('remove client')
19
20
 
@@ -143,7 +144,7 @@ class PoolBase extends DispatcherBase {
143
144
  if (!item) {
144
145
  break
145
146
  }
146
- item.handler.onError(err)
147
+ item.handler.onResponseError(null, err)
147
148
  }
148
149
 
149
150
  const destroyAll = new Array(this[kClients].length)
@@ -162,12 +163,28 @@ class PoolBase extends DispatcherBase {
162
163
  this[kQueued]++
163
164
  } else if (!dispatcher.dispatch(opts, handler)) {
164
165
  dispatcher[kNeedDrain] = true
165
- this[kNeedDrain] = !this[kGetDispatcher]()
166
+ this[kNeedDrain] = !this[kHasDispatcher]()
166
167
  }
167
168
 
168
169
  return !this[kNeedDrain]
169
170
  }
170
171
 
172
+ [kHasDispatcher] () {
173
+ for (let i = 0; i < this[kClients].length; i++) {
174
+ const dispatcher = this[kClients][i]
175
+
176
+ if (
177
+ !dispatcher[kNeedDrain] &&
178
+ dispatcher.closed !== true &&
179
+ dispatcher.destroyed !== true
180
+ ) {
181
+ return true
182
+ }
183
+ }
184
+
185
+ return false
186
+ }
187
+
171
188
  [kAddClient] (client) {
172
189
  client
173
190
  .on('drain', this[kOnDrain].bind(this, client))
@@ -189,14 +206,14 @@ class PoolBase extends DispatcherBase {
189
206
  }
190
207
 
191
208
  [kRemoveClient] (client) {
192
- client.close(() => {
193
- const idx = this[kClients].indexOf(client)
194
- if (idx !== -1) {
195
- this[kClients].splice(idx, 1)
196
- }
197
- })
209
+ const idx = this[kClients].indexOf(client)
210
+ if (idx !== -1) {
211
+ this[kClients].splice(idx, 1)
212
+ }
213
+
214
+ client.close(() => {})
198
215
 
199
- this[kNeedDrain] = this[kClients].some(dispatcher => (
216
+ this[kNeedDrain] = !this[kClients].some(dispatcher => (
200
217
  !dispatcher[kNeedDrain] &&
201
218
  dispatcher.closed !== true &&
202
219
  dispatcher.destroyed !== true
@@ -210,5 +227,6 @@ module.exports = {
210
227
  kNeedDrain,
211
228
  kAddClient,
212
229
  kRemoveClient,
213
- kGetDispatcher
230
+ kGetDispatcher,
231
+ kHasDispatcher
214
232
  }
@@ -6,6 +6,7 @@ const {
6
6
  kNeedDrain,
7
7
  kAddClient,
8
8
  kGetDispatcher,
9
+ kHasDispatcher,
9
10
  kRemoveClient
10
11
  } = require('./pool-base')
11
12
  const Client = require('./client')
@@ -36,6 +37,7 @@ class Pool extends PoolBase {
36
37
  autoSelectFamily,
37
38
  autoSelectFamilyAttemptTimeout,
38
39
  allowH2,
40
+ useH2c,
39
41
  clientTtl,
40
42
  ...options
41
43
  } = {}) {
@@ -56,6 +58,7 @@ class Pool extends PoolBase {
56
58
  ...tls,
57
59
  maxCachedSessions,
58
60
  allowH2,
61
+ useH2c,
59
62
  socketPath,
60
63
  timeout: connectTimeout,
61
64
  ...(typeof autoSelectFamily === 'boolean' ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : undefined),
@@ -63,14 +66,11 @@ class Pool extends PoolBase {
63
66
  })
64
67
  }
65
68
 
66
- super()
69
+ super(options)
67
70
 
68
71
  this[kConnections] = connections || null
69
72
  this[kUrl] = util.parseOrigin(origin)
70
- this[kOptions] = { ...util.deepClone(options), connect, allowH2, clientTtl, socketPath }
71
- this[kOptions].interceptors = options.interceptors
72
- ? { ...options.interceptors }
73
- : undefined
73
+ this[kOptions] = { ...util.deepClone(options), connect, allowH2, useH2c, clientTtl, socketPath }
74
74
  this[kFactory] = factory
75
75
 
76
76
  this.on('connect', (origin, targets) => {
@@ -98,10 +98,13 @@ class Pool extends PoolBase {
98
98
 
99
99
  [kGetDispatcher] () {
100
100
  const clientTtlOption = this[kOptions].clientTtl
101
- for (const client of this[kClients]) {
101
+ for (let i = 0; i < this[kClients].length; i++) {
102
+ const client = this[kClients][i]
103
+
102
104
  // check ttl of client and if it's stale, remove it from the pool
103
105
  if (clientTtlOption != null && clientTtlOption > 0 && client.ttl && ((Date.now() - client.ttl) > clientTtlOption)) {
104
106
  this[kRemoveClient](client)
107
+ i--
105
108
  } else if (!client[kNeedDrain]) {
106
109
  return client
107
110
  }
@@ -113,6 +116,28 @@ class Pool extends PoolBase {
113
116
  return dispatcher
114
117
  }
115
118
  }
119
+
120
+ [kHasDispatcher] () {
121
+ const clientTtlOption = this[kOptions].clientTtl
122
+ for (let i = 0; i < this[kClients].length; i++) {
123
+ const client = this[kClients][i]
124
+
125
+ if (clientTtlOption != null && clientTtlOption > 0 && client.ttl && ((Date.now() - client.ttl) > clientTtlOption)) {
126
+ this[kRemoveClient](client)
127
+ i--
128
+ } else if (!client[kNeedDrain]) {
129
+ return true
130
+ }
131
+ }
132
+
133
+ if (!this[kConnections] || this[kClients].length < this[kConnections]) {
134
+ const dispatcher = this[kFactory](this[kUrl], this[kOptions])
135
+ this[kAddClient](dispatcher)
136
+ return true
137
+ }
138
+
139
+ return false
140
+ }
116
141
  }
117
142
 
118
143
  module.exports = Pool
@@ -16,7 +16,9 @@ const kProxyHeaders = Symbol('proxy headers')
16
16
  const kRequestTls = Symbol('request tls settings')
17
17
  const kProxyTls = Symbol('proxy tls settings')
18
18
  const kConnectEndpoint = Symbol('connect endpoint function')
19
+ const kConnectEndpointHTTP1 = Symbol('connect endpoint function (http/1.1 only)')
19
20
  const kTunnelProxy = Symbol('tunnel proxy')
21
+ const proxyAuthorization = 'proxy-authorization'
20
22
 
21
23
  function defaultProtocolPort (protocol) {
22
24
  return protocol === 'https:' ? 443 : 80
@@ -54,15 +56,15 @@ class Http1ProxyWrapper extends DispatcherBase {
54
56
  }
55
57
 
56
58
  [kDispatch] (opts, handler) {
57
- const onHeaders = handler.onHeaders
58
- handler.onHeaders = function (statusCode, data, resume) {
59
+ const onResponseStart = handler.onResponseStart
60
+ handler.onResponseStart = function (controller, statusCode, data, statusMessage) {
59
61
  if (statusCode === 407) {
60
- if (typeof handler.onError === 'function') {
61
- handler.onError(new InvalidArgumentError('Proxy Authentication Required (407)'))
62
+ if (typeof handler.onResponseError === 'function') {
63
+ handler.onResponseError(controller, new InvalidArgumentError('Proxy Authentication Required (407)'))
62
64
  }
63
65
  return
64
66
  }
65
- if (onHeaders) onHeaders.call(this, statusCode, data, resume)
67
+ if (onResponseStart) onResponseStart.call(this, controller, statusCode, data, statusMessage)
66
68
  }
67
69
 
68
70
  // Rewrite request as an HTTP1 Proxy request, without tunneling.
@@ -103,7 +105,7 @@ class ProxyAgent extends DispatcherBase {
103
105
  throw new InvalidArgumentError('Proxy opts.clientFactory must be a function.')
104
106
  }
105
107
 
106
- const { proxyTunnel = true } = opts
108
+ const { proxyTunnel = true, connectTimeout } = opts
107
109
 
108
110
  super()
109
111
 
@@ -125,10 +127,13 @@ class ProxyAgent extends DispatcherBase {
125
127
  this[kProxyHeaders]['proxy-authorization'] = opts.token
126
128
  } else if (username && password) {
127
129
  this[kProxyHeaders]['proxy-authorization'] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password)}`).toString('base64')}`
130
+ } else if (username) {
131
+ this[kProxyHeaders]['proxy-authorization'] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:`).toString('base64')}`
128
132
  }
129
133
 
130
- const connect = buildConnector({ ...opts.proxyTls })
131
- this[kConnectEndpoint] = buildConnector({ ...opts.requestTls })
134
+ const connect = buildConnector({ timeout: connectTimeout, ...opts.proxyTls })
135
+ this[kConnectEndpoint] = buildConnector({ timeout: connectTimeout, ...opts.requestTls })
136
+ this[kConnectEndpointHTTP1] = buildConnector({ timeout: connectTimeout, ...opts.requestTls, allowH2: false })
132
137
 
133
138
  const agentFactory = opts.factory || defaultAgentFactory
134
139
  const factory = (origin, options) => {
@@ -216,7 +221,11 @@ class ProxyAgent extends DispatcherBase {
216
221
  } else {
217
222
  servername = opts.servername
218
223
  }
219
- this[kConnectEndpoint]({ ...opts, servername, httpSocket: socket }, callback)
224
+ const connectEndpoint = opts.allowH2 === false
225
+ ? this[kConnectEndpointHTTP1]
226
+ : this[kConnectEndpoint]
227
+
228
+ connectEndpoint({ ...opts, servername, httpSocket: socket }, callback)
220
229
  } catch (err) {
221
230
  if (err.code === 'ERR_TLS_CERT_ALTNAME_INVALID') {
222
231
  // Throw a custom error to avoid loop in client.js#connect
@@ -290,6 +299,10 @@ function buildHeaders (headers) {
290
299
  const headersPair = {}
291
300
 
292
301
  for (let i = 0; i < headers.length; i += 2) {
302
+ if (isProxyAuthorizationHeader(headers[i])) {
303
+ throwProxyAuthError()
304
+ }
305
+
293
306
  headersPair[headers[i]] = headers[i + 1]
294
307
  }
295
308
 
@@ -308,11 +321,23 @@ function buildHeaders (headers) {
308
321
  * It should be removed in the next major version for performance reasons
309
322
  */
310
323
  function throwIfProxyAuthIsSent (headers) {
311
- const existProxyAuth = headers && Object.keys(headers)
312
- .find((key) => key.toLowerCase() === 'proxy-authorization')
313
- if (existProxyAuth) {
314
- throw new InvalidArgumentError('Proxy-Authorization should be sent in ProxyAgent constructor')
324
+ for (const key in headers) {
325
+ if (isProxyAuthorizationHeader(key)) {
326
+ throwProxyAuthError()
327
+ }
315
328
  }
316
329
  }
317
330
 
331
+ /**
332
+ * @param {string} key
333
+ * @returns {boolean}
334
+ */
335
+ function isProxyAuthorizationHeader (key) {
336
+ return key.length === proxyAuthorization.length && key.toLowerCase() === proxyAuthorization
337
+ }
338
+
339
+ function throwProxyAuthError () {
340
+ throw new InvalidArgumentError('Proxy-Authorization should be sent in ProxyAgent constructor')
341
+ }
342
+
318
343
  module.exports = ProxyAgent
@@ -6,6 +6,7 @@ const {
6
6
  kNeedDrain,
7
7
  kAddClient,
8
8
  kGetDispatcher,
9
+ kHasDispatcher,
9
10
  kRemoveClient
10
11
  } = require('./pool-base')
11
12
  const Client = require('./client')
@@ -69,9 +70,6 @@ class RoundRobinPool extends PoolBase {
69
70
  this[kConnections] = connections || null
70
71
  this[kUrl] = util.parseOrigin(origin)
71
72
  this[kOptions] = { ...util.deepClone(options), connect, allowH2, clientTtl, socketPath }
72
- this[kOptions].interceptors = options.interceptors
73
- ? { ...options.interceptors }
74
- : undefined
75
73
  this[kFactory] = factory
76
74
  this[kIndex] = -1
77
75
 
@@ -95,10 +93,9 @@ class RoundRobinPool extends PoolBase {
95
93
 
96
94
  [kGetDispatcher] () {
97
95
  const clientTtlOption = this[kOptions].clientTtl
98
- const clientsLength = this[kClients].length
99
96
 
100
97
  // If we have no clients yet, create one
101
- if (clientsLength === 0) {
98
+ if (this[kClients].length === 0) {
102
99
  const dispatcher = this[kFactory](this[kUrl], this[kOptions])
103
100
  this[kAddClient](dispatcher)
104
101
  return dispatcher
@@ -106,14 +103,14 @@ class RoundRobinPool extends PoolBase {
106
103
 
107
104
  // Round-robin through existing clients
108
105
  let checked = 0
109
- while (checked < clientsLength) {
110
- this[kIndex] = (this[kIndex] + 1) % clientsLength
106
+ while (checked < this[kClients].length) {
107
+ this[kIndex] = (this[kIndex] + 1) % this[kClients].length
111
108
  const client = this[kClients][this[kIndex]]
112
109
 
113
110
  // Check if client is stale (TTL expired)
114
111
  if (clientTtlOption != null && clientTtlOption > 0 && client.ttl && ((Date.now() - client.ttl) > clientTtlOption)) {
115
112
  this[kRemoveClient](client)
116
- checked++
113
+ this[kIndex]--
117
114
  continue
118
115
  }
119
116
 
@@ -126,12 +123,37 @@ class RoundRobinPool extends PoolBase {
126
123
  }
127
124
 
128
125
  // All clients are busy, create a new one if we haven't reached the limit
129
- if (!this[kConnections] || clientsLength < this[kConnections]) {
126
+ if (!this[kConnections] || this[kClients].length < this[kConnections]) {
130
127
  const dispatcher = this[kFactory](this[kUrl], this[kOptions])
131
128
  this[kAddClient](dispatcher)
132
129
  return dispatcher
133
130
  }
134
131
  }
132
+
133
+ [kHasDispatcher] () {
134
+ const clientTtlOption = this[kOptions].clientTtl
135
+ for (let i = 0; i < this[kClients].length; i++) {
136
+ const client = this[kClients][i]
137
+
138
+ if (clientTtlOption != null && clientTtlOption > 0 && client.ttl && ((Date.now() - client.ttl) > clientTtlOption)) {
139
+ this[kRemoveClient](client)
140
+ if (i <= this[kIndex]) {
141
+ this[kIndex]--
142
+ }
143
+ i--
144
+ } else if (!client[kNeedDrain]) {
145
+ return true
146
+ }
147
+ }
148
+
149
+ if (!this[kConnections] || this[kClients].length < this[kConnections]) {
150
+ const dispatcher = this[kFactory](this[kUrl], this[kOptions])
151
+ this[kAddClient](dispatcher)
152
+ return true
153
+ }
154
+
155
+ return false
156
+ }
135
157
  }
136
158
 
137
159
  module.exports = RoundRobinPool