@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
@@ -64,12 +64,7 @@ const { getGlobalDispatcher } = require('../../global')
64
64
  const { webidl } = require('../webidl')
65
65
  const { STATUS_CODES } = require('node:http')
66
66
  const { bytesMatch } = require('../subresource-integrity/subresource-integrity')
67
- const { createDeferredPromise } = require('../../util/promise')
68
67
  const { isomorphicEncode } = require('../infra')
69
- const { runtimeFeatures } = require('../../util/runtime-features')
70
-
71
- // Node.js v23.8.0+ and v22.15.0+ supports Zstandard
72
- const hasZstd = runtimeFeatures.has('zstd')
73
68
 
74
69
  const GET_OR_HEAD = ['GET', 'HEAD']
75
70
 
@@ -80,6 +75,35 @@ const defaultUserAgent = typeof __UNDICI_IS_NODE__ !== 'undefined' || typeof esb
80
75
  /** @type {import('buffer').resolveObjectURL} */
81
76
  let resolveObjectURL
82
77
 
78
+ function appendHeadersListFromResponseHeaders (headersList, headers, rawHeaders) {
79
+ if (Array.isArray(rawHeaders)) {
80
+ for (let i = 0; i < rawHeaders.length; i += 2) {
81
+ const nameStr = bufferToLowerCasedHeaderName(rawHeaders[i])
82
+ const value = rawHeaders[i + 1]
83
+
84
+ if (Array.isArray(value) && !Buffer.isBuffer(value)) {
85
+ for (const val of value) {
86
+ headersList.append(nameStr, val.toString('latin1'), true)
87
+ }
88
+ } else {
89
+ headersList.append(nameStr, value.toString('latin1'), true)
90
+ }
91
+ }
92
+
93
+ return
94
+ }
95
+
96
+ for (const [name, value] of Object.entries(headers ?? {})) {
97
+ if (Array.isArray(value)) {
98
+ for (const entry of value) {
99
+ headersList.append(name, `${entry}`, true)
100
+ }
101
+ } else {
102
+ headersList.append(name, `${value}`, true)
103
+ }
104
+ }
105
+ }
106
+
83
107
  class Fetch extends EE {
84
108
  constructor (dispatcher) {
85
109
  super()
@@ -136,7 +160,7 @@ function fetch (input, init = undefined) {
136
160
  webidl.argumentLengthCheck(arguments, 1, 'globalThis.fetch')
137
161
 
138
162
  // 1. Let p be a new promise.
139
- let p = createDeferredPromise()
163
+ let p = Promise.withResolvers()
140
164
 
141
165
  // 2. Let requestObject be the result of invoking the initial value of
142
166
  // Request as constructor with input and init as arguments. If this throws
@@ -1030,7 +1054,7 @@ function fetchFinale (fetchParams, response) {
1030
1054
  let responseStatus = 0
1031
1055
 
1032
1056
  // 7. If fetchParams’s request’s mode is not "navigate" or response’s has-cross-origin-redirects is false:
1033
- if (fetchParams.request.mode !== 'navigator' || !response.hasCrossOriginRedirects) {
1057
+ if (fetchParams.request.mode !== 'navigate' || !response.hasCrossOriginRedirects) {
1034
1058
  // 1. Set responseStatus to response’s status.
1035
1059
  responseStatus = response.status
1036
1060
 
@@ -1433,7 +1457,10 @@ async function httpNetworkOrCacheFetch (
1433
1457
  // 8. If contentLengthHeaderValue is non-null, then append
1434
1458
  // `Content-Length`/contentLengthHeaderValue to httpRequest’s header
1435
1459
  // list.
1436
- if (contentLengthHeaderValue != null) {
1460
+ if (
1461
+ contentLengthHeaderValue != null &&
1462
+ !httpRequest.headersList.contains('content-length', true)
1463
+ ) {
1437
1464
  httpRequest.headersList.append('content-length', contentLengthHeaderValue, true)
1438
1465
  }
1439
1466
 
@@ -2148,257 +2175,223 @@ async function httpNetworkFetch (
2148
2175
  const path = url.pathname + url.search
2149
2176
  const hasTrailingQuestionMark = url.search.length === 0 && url.href[url.href.length - url.hash.length - 1] === '?'
2150
2177
 
2151
- return new Promise((resolve, reject) => agent.dispatch(
2152
- {
2153
- path: hasTrailingQuestionMark ? `${path}?` : path,
2154
- origin: url.origin,
2155
- method: request.method,
2156
- body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body,
2157
- headers: request.headersList.entries,
2158
- maxRedirections: 0,
2159
- upgrade: request.mode === 'websocket' ? 'websocket' : undefined
2160
- },
2161
- {
2162
- body: null,
2163
- abort: null,
2164
-
2165
- onConnect (abort) {
2166
- // TODO (fix): Do we need connection here?
2167
- const { connection } = fetchParams.controller
2168
-
2169
- // Set timingInfo’s final connection timing info to the result of calling clamp and coarsen
2170
- // connection timing info with connection’s timing info, timingInfo’s post-redirect start
2171
- // time, and fetchParams’s cross-origin isolated capability.
2172
- // TODO: implement connection timing
2173
- timingInfo.finalConnectionTimingInfo = clampAndCoarsenConnectionTimingInfo(undefined, timingInfo.postRedirectStartTime, fetchParams.crossOriginIsolatedCapability)
2174
-
2175
- if (connection.destroyed) {
2176
- abort(new DOMException('The operation was aborted.', 'AbortError'))
2177
- } else {
2178
- fetchParams.controller.on('terminated', abort)
2179
- this.abort = connection.abort = abort
2180
- }
2181
-
2182
- // Set timingInfo’s final network-request start time to the coarsened shared current time given
2183
- // fetchParams’s cross-origin isolated capability.
2184
- timingInfo.finalNetworkRequestStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability)
2178
+ return dispatchWithProtocolPreference(body)
2179
+
2180
+ function dispatchWithProtocolPreference (body, allowH2) {
2181
+ return new Promise((resolve, reject) => agent.dispatch(
2182
+ {
2183
+ path: hasTrailingQuestionMark ? `${path}?` : path,
2184
+ origin: url.origin,
2185
+ method: request.method,
2186
+ body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body,
2187
+ // Preserve the serialized fetch body for MockAgent net-connect fallthroughs.
2188
+ __mockAgentBodyForDispatch: body,
2189
+ headers: request.headersList.entries,
2190
+ maxRedirections: 0,
2191
+ upgrade: request.mode === 'websocket' ? 'websocket' : undefined,
2192
+ ...(allowH2 === false ? { allowH2 } : null)
2185
2193
  },
2194
+ {
2195
+ body: null,
2196
+ abort: null,
2186
2197
 
2187
- onResponseStarted () {
2188
- // Set timingInfo’s final network-response start time to the coarsened shared current
2189
- // time given fetchParams’s cross-origin isolated capability, immediately after the
2190
- // user agent’s HTTP parser receives the first byte of the response (e.g., frame header
2191
- // bytes for HTTP/2 or response status line for HTTP/1.x).
2192
- timingInfo.finalNetworkResponseStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability)
2193
- },
2198
+ onRequestStart (controller) {
2199
+ // TODO (fix): Do we need connection here?
2200
+ const { connection } = fetchParams.controller
2194
2201
 
2195
- onHeaders (status, rawHeaders, resume, statusText) {
2196
- if (status < 200) {
2197
- return false
2198
- }
2202
+ // Set timingInfo’s final connection timing info to the result of calling clamp and coarsen
2203
+ // connection timing info with connection’s timing info, timingInfo’s post-redirect start
2204
+ // time, and fetchParams’s cross-origin isolated capability.
2205
+ // TODO: implement connection timing
2206
+ timingInfo.finalConnectionTimingInfo = clampAndCoarsenConnectionTimingInfo(undefined, timingInfo.postRedirectStartTime, fetchParams.crossOriginIsolatedCapability)
2199
2207
 
2200
- const headersList = new HeadersList()
2208
+ const abort = (reason) => controller.abort(reason)
2201
2209
 
2202
- for (let i = 0; i < rawHeaders.length; i += 2) {
2203
- const nameStr = bufferToLowerCasedHeaderName(rawHeaders[i])
2204
- const value = rawHeaders[i + 1]
2205
- if (Array.isArray(value) && !Buffer.isBuffer(rawHeaders[i + 1])) {
2206
- for (const val of value) {
2207
- headersList.append(nameStr, val.toString('latin1'), true)
2208
- }
2210
+ if (connection.destroyed) {
2211
+ abort(new DOMException('The operation was aborted.', 'AbortError'))
2209
2212
  } else {
2210
- headersList.append(nameStr, value.toString('latin1'), true)
2211
- }
2212
- }
2213
- const location = headersList.get('location', true)
2214
-
2215
- this.body = new Readable({ read: resume })
2216
-
2217
- const willFollow = location && request.redirect === 'follow' &&
2218
- redirectStatusSet.has(status)
2219
-
2220
- const decoders = []
2221
-
2222
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
2223
- if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
2224
- // https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1
2225
- const contentEncoding = headersList.get('content-encoding', true)
2226
- // "All content-coding values are case-insensitive..."
2227
- /** @type {string[]} */
2228
- const codings = contentEncoding ? contentEncoding.toLowerCase().split(',') : []
2229
-
2230
- // Limit the number of content-encodings to prevent resource exhaustion.
2231
- // CVE fix similar to urllib3 (GHSA-gm62-xv2j-4w53) and curl (CVE-2022-32206).
2232
- const maxContentEncodings = 5
2233
- if (codings.length > maxContentEncodings) {
2234
- reject(new Error(`too many content-encodings in response: ${codings.length}, maximum allowed is ${maxContentEncodings}`))
2235
- return true
2213
+ fetchParams.controller.on('terminated', abort)
2214
+ this.abort = connection.abort = abort
2236
2215
  }
2237
2216
 
2238
- for (let i = codings.length - 1; i >= 0; --i) {
2239
- const coding = codings[i].trim()
2240
- // https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2
2241
- if (coding === 'x-gzip' || coding === 'gzip') {
2242
- decoders.push(zlib.createGunzip({
2243
- // Be less strict when decoding compressed responses, since sometimes
2244
- // servers send slightly invalid responses that are still accepted
2245
- // by common browsers.
2246
- // Always using Z_SYNC_FLUSH is what cURL does.
2247
- flush: zlib.constants.Z_SYNC_FLUSH,
2248
- finishFlush: zlib.constants.Z_SYNC_FLUSH
2249
- }))
2250
- } else if (coding === 'deflate') {
2251
- decoders.push(createInflate({
2252
- flush: zlib.constants.Z_SYNC_FLUSH,
2253
- finishFlush: zlib.constants.Z_SYNC_FLUSH
2254
- }))
2255
- } else if (coding === 'br') {
2256
- decoders.push(zlib.createBrotliDecompress({
2257
- flush: zlib.constants.BROTLI_OPERATION_FLUSH,
2258
- finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
2259
- }))
2260
- } else if (coding === 'zstd' && hasZstd) {
2261
- decoders.push(zlib.createZstdDecompress({
2262
- flush: zlib.constants.ZSTD_e_continue,
2263
- finishFlush: zlib.constants.ZSTD_e_end
2264
- }))
2265
- } else {
2266
- decoders.length = 0
2267
- break
2268
- }
2217
+ // Set timingInfo’s final network-request start time to the coarsened shared current time given
2218
+ // fetchParams’s cross-origin isolated capability.
2219
+ timingInfo.finalNetworkRequestStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability)
2220
+ },
2221
+
2222
+ onResponseStarted () {
2223
+ // Set timingInfo’s final network-response start time to the coarsened shared current
2224
+ // time given fetchParams’s cross-origin isolated capability, immediately after the
2225
+ // user agent’s HTTP parser receives the first byte of the response (e.g., frame header
2226
+ // bytes for HTTP/2 or response status line for HTTP/1.x).
2227
+ timingInfo.finalNetworkResponseStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability)
2228
+ },
2229
+
2230
+ onResponseStart (controller, status, headers, statusText) {
2231
+ if (status < 200) {
2232
+ return
2269
2233
  }
2270
- }
2271
2234
 
2272
- const onError = this.onError.bind(this)
2235
+ const rawHeaders = controller?.rawHeaders ?? []
2236
+ const headersList = new HeadersList()
2237
+ appendHeadersListFromResponseHeaders(headersList, headers, rawHeaders)
2238
+ const location = headersList.get('location', true)
2273
2239
 
2274
- resolve({
2275
- status,
2276
- statusText,
2277
- headersList,
2278
- body: decoders.length
2279
- ? pipeline(this.body, ...decoders, (err) => {
2280
- if (err) {
2281
- this.onError(err)
2282
- }
2283
- }).on('error', onError)
2284
- : this.body.on('error', onError)
2285
- })
2240
+ this.body = new Readable({ read: () => controller.resume() })
2286
2241
 
2287
- return true
2288
- },
2242
+ const willFollow = location && request.redirect === 'follow' &&
2243
+ redirectStatusSet.has(status)
2289
2244
 
2290
- onData (chunk) {
2291
- if (fetchParams.controller.dump) {
2292
- return
2293
- }
2245
+ const decoders = []
2294
2246
 
2295
- // 1. If one or more bytes have been transmitted from response’s
2296
- // message body, then:
2247
+ // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
2248
+ if (request.method !== 'HEAD' && request.method !== 'CONNECT' && !nullBodyStatus.includes(status) && !willFollow) {
2249
+ // https://www.rfc-editor.org/rfc/rfc7231#section-3.1.2.1
2250
+ const contentEncoding = headersList.get('content-encoding', true)
2251
+ // "All content-coding values are case-insensitive..."
2252
+ /** @type {string[]} */
2253
+ const codings = contentEncoding ? contentEncoding.toLowerCase().split(',') : []
2297
2254
 
2298
- // 1. Let bytes be the transmitted bytes.
2299
- const bytes = chunk
2255
+ // Limit the number of content-encodings to prevent resource exhaustion.
2256
+ // CVE fix similar to urllib3 (GHSA-gm62-xv2j-4w53) and curl (CVE-2022-32206).
2257
+ const maxContentEncodings = 5
2258
+ if (codings.length > maxContentEncodings) {
2259
+ reject(new Error(`too many content-encodings in response: ${codings.length}, maximum allowed is ${maxContentEncodings}`))
2260
+ return
2261
+ }
2300
2262
 
2301
- // 2. Let codings be the result of extracting header list values
2302
- // given `Content-Encoding` and response’s header list.
2303
- // See pullAlgorithm.
2263
+ for (let i = codings.length - 1; i >= 0; --i) {
2264
+ const coding = codings[i].trim()
2265
+ // https://www.rfc-editor.org/rfc/rfc9112.html#section-7.2
2266
+ if (coding === 'x-gzip' || coding === 'gzip') {
2267
+ decoders.push(zlib.createGunzip({
2268
+ // Be less strict when decoding compressed responses, since sometimes
2269
+ // servers send slightly invalid responses that are still accepted
2270
+ // by common browsers.
2271
+ // Always using Z_SYNC_FLUSH is what cURL does.
2272
+ flush: zlib.constants.Z_SYNC_FLUSH,
2273
+ finishFlush: zlib.constants.Z_SYNC_FLUSH
2274
+ }))
2275
+ } else if (coding === 'deflate') {
2276
+ decoders.push(createInflate({
2277
+ flush: zlib.constants.Z_SYNC_FLUSH,
2278
+ finishFlush: zlib.constants.Z_SYNC_FLUSH
2279
+ }))
2280
+ } else if (coding === 'br') {
2281
+ decoders.push(zlib.createBrotliDecompress({
2282
+ flush: zlib.constants.BROTLI_OPERATION_FLUSH,
2283
+ finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH
2284
+ }))
2285
+ } else if (coding === 'zstd') {
2286
+ decoders.push(zlib.createZstdDecompress({
2287
+ flush: zlib.constants.ZSTD_e_continue,
2288
+ finishFlush: zlib.constants.ZSTD_e_end
2289
+ }))
2290
+ } else {
2291
+ decoders.length = 0
2292
+ break
2293
+ }
2294
+ }
2295
+ }
2304
2296
 
2305
- // 3. Increase timingInfo’s encoded body size by bytes’s length.
2306
- timingInfo.encodedBodySize += bytes.byteLength
2297
+ const onError = (err) => this.onResponseError(controller, err)
2298
+
2299
+ resolve({
2300
+ status,
2301
+ statusText,
2302
+ headersList,
2303
+ body: decoders.length
2304
+ ? pipeline(this.body, ...decoders, (err) => {
2305
+ if (err) {
2306
+ this.onResponseError(controller, err)
2307
+ }
2308
+ }).on('error', onError)
2309
+ : this.body.on('error', onError)
2310
+ })
2311
+ },
2312
+
2313
+ onResponseData (controller, chunk) {
2314
+ if (fetchParams.controller.dump) {
2315
+ return
2316
+ }
2307
2317
 
2308
- // 4. See pullAlgorithm...
2318
+ // 1. If one or more bytes have been transmitted from response’s
2319
+ // message body, then:
2309
2320
 
2310
- return this.body.push(bytes)
2311
- },
2321
+ // 1. Let bytes be the transmitted bytes.
2322
+ const bytes = chunk
2312
2323
 
2313
- onComplete () {
2314
- if (this.abort) {
2315
- fetchParams.controller.off('terminated', this.abort)
2316
- }
2317
-
2318
- fetchParams.controller.ended = true
2324
+ // 2. Let codings be the result of extracting header list values
2325
+ // given `Content-Encoding` and response’s header list.
2326
+ // See pullAlgorithm.
2319
2327
 
2320
- this.body.push(null)
2321
- },
2328
+ // 3. Increase timingInfo’s encoded body size by bytes’s length.
2329
+ timingInfo.encodedBodySize += bytes.byteLength
2322
2330
 
2323
- onError (error) {
2324
- if (this.abort) {
2325
- fetchParams.controller.off('terminated', this.abort)
2326
- }
2331
+ // 4. See pullAlgorithm...
2327
2332
 
2328
- this.body?.destroy(error)
2333
+ if (this.body.push(bytes) === false) {
2334
+ controller.pause()
2335
+ }
2336
+ },
2329
2337
 
2330
- fetchParams.controller.terminate(error)
2338
+ onResponseEnd () {
2339
+ if (this.abort) {
2340
+ fetchParams.controller.off('terminated', this.abort)
2341
+ }
2331
2342
 
2332
- reject(error)
2333
- },
2343
+ fetchParams.controller.ended = true
2334
2344
 
2335
- onRequestUpgrade (_controller, status, headers, socket) {
2336
- // We need to support 200 for websocket over h2 as per RFC-8441
2337
- // Absence of session means H1
2338
- if ((socket.session != null && status !== 200) || (socket.session == null && status !== 101)) {
2339
- return false
2340
- }
2345
+ this.body?.push(null)
2346
+ },
2341
2347
 
2342
- const headersList = new HeadersList()
2343
-
2344
- for (const [name, value] of Object.entries(headers)) {
2345
- if (value == null) {
2346
- continue
2348
+ onResponseError (_controller, error) {
2349
+ if (this.abort) {
2350
+ fetchParams.controller.off('terminated', this.abort)
2347
2351
  }
2348
2352
 
2349
- const headerName = name.toLowerCase()
2350
-
2351
- if (Array.isArray(value)) {
2352
- for (const entry of value) {
2353
- headersList.append(headerName, String(entry), true)
2354
- }
2355
- } else {
2356
- headersList.append(headerName, String(value), true)
2353
+ if (
2354
+ request.mode === 'websocket' &&
2355
+ allowH2 !== false &&
2356
+ error?.code === 'UND_ERR_INFO' &&
2357
+ error?.message === 'HTTP/2: Extended CONNECT protocol not supported by server'
2358
+ ) {
2359
+ // The origin negotiated H2, but RFC 8441 websocket support is unavailable.
2360
+ // Retry the opening handshake on a fresh HTTP/1.1-only connection instead.
2361
+ resolve(dispatchWithProtocolPreference(body, false))
2362
+ return
2357
2363
  }
2358
- }
2359
-
2360
- resolve({
2361
- status,
2362
- statusText: STATUS_CODES[status],
2363
- headersList,
2364
- socket
2365
- })
2366
2364
 
2367
- return true
2368
- },
2365
+ this.body?.destroy(error)
2369
2366
 
2370
- onUpgrade (status, rawHeaders, socket) {
2371
- // We need to support 200 for websocket over h2 as per RFC-8441
2372
- // Absence of session means H1
2373
- if ((socket.session != null && status !== 200) || (socket.session == null && status !== 101)) {
2374
- return false
2375
- }
2367
+ fetchParams.controller.terminate(error)
2376
2368
 
2377
- const headersList = new HeadersList()
2369
+ reject(error)
2370
+ },
2378
2371
 
2379
- for (let i = 0; i < rawHeaders.length; i += 2) {
2380
- const nameStr = bufferToLowerCasedHeaderName(rawHeaders[i])
2381
- const value = rawHeaders[i + 1]
2382
- if (Array.isArray(value) && !Buffer.isBuffer(rawHeaders[i + 1])) {
2383
- for (const val of value) {
2384
- headersList.append(nameStr, val.toString('latin1'), true)
2385
- }
2386
- } else {
2387
- headersList.append(nameStr, value.toString('latin1'), true)
2372
+ onRequestUpgrade (controller, status, headers, socket) {
2373
+ // We need to support 200 for websocket over h2 as per RFC-8441
2374
+ // Absence of session means H1
2375
+ if ((socket.session != null && status !== 200) || (socket.session == null && status !== 101)) {
2376
+ return false
2388
2377
  }
2389
- }
2390
2378
 
2391
- resolve({
2392
- status,
2393
- statusText: STATUS_CODES[status],
2394
- headersList,
2395
- socket
2396
- })
2379
+ const rawHeaders = controller?.rawHeaders ?? []
2380
+ const headersList = new HeadersList()
2381
+ appendHeadersListFromResponseHeaders(headersList, headers, rawHeaders)
2382
+
2383
+ resolve({
2384
+ status,
2385
+ statusText: STATUS_CODES[status],
2386
+ headersList,
2387
+ socket
2388
+ })
2397
2389
 
2398
- return true
2390
+ return true
2391
+ }
2399
2392
  }
2400
- }
2401
- ))
2393
+ ))
2394
+ }
2402
2395
  }
2403
2396
  }
2404
2397
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  const assert = require('node:assert')
4
4
  const { types, inspect } = require('node:util')
5
- const { runtimeFeatures } = require('../../util/runtime-features')
5
+ const { markAsUncloneable } = require('node:worker_threads')
6
6
 
7
7
  const UNDEFINED = 1
8
8
  const BOOLEAN = 2
@@ -158,9 +158,7 @@ webidl.util.TypeValueToString = function (o) {
158
158
  }
159
159
  }
160
160
 
161
- webidl.util.markAsUncloneable = runtimeFeatures.has('markAsUncloneable')
162
- ? require('node:worker_threads').markAsUncloneable
163
- : () => {}
161
+ webidl.util.markAsUncloneable = markAsUncloneable
164
162
 
165
163
  // https://webidl.spec.whatwg.org/#abstract-opdef-converttoint
166
164
  webidl.util.ConvertToInt = function (V, bitLength, signedness, flags) {
@@ -190,10 +188,10 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, flags) {
190
188
  } else {
191
189
  // 3. Otherwise:
192
190
 
193
- // 1. Let lowerBound be -2^bitLength − 1.
194
- lowerBound = Math.pow(-2, bitLength) - 1
191
+ // 1. Let lowerBound be -2^(bitLength − 1).
192
+ lowerBound = -Math.pow(2, bitLength - 1)
195
193
 
196
- // 2. Let upperBound be 2^bitLength − 1 − 1.
194
+ // 2. Let upperBound be 2^(bitLength − 1) − 1.
197
195
  upperBound = Math.pow(2, bitLength - 1) - 1
198
196
  }
199
197
 
@@ -272,9 +270,9 @@ webidl.util.ConvertToInt = function (V, bitLength, signedness, flags) {
272
270
  // 10. Set x to x modulo 2^bitLength.
273
271
  x = x % Math.pow(2, bitLength)
274
272
 
275
- // 11. If signedness is "signed" and x ≥ 2^bitLength − 1,
273
+ // 11. If signedness is "signed" and x ≥ 2^(bitLength − 1),
276
274
  // then return x − 2^bitLength.
277
- if (signedness === 'signed' && x >= Math.pow(2, bitLength) - 1) {
275
+ if (signedness === 'signed' && x >= Math.pow(2, bitLength - 1)) {
278
276
  return x - Math.pow(2, bitLength)
279
277
  }
280
278
 
@@ -10,13 +10,7 @@ let bufIdx = BUFFER_SIZE
10
10
 
11
11
  const randomFillSync = runtimeFeatures.has('crypto')
12
12
  ? require('node:crypto').randomFillSync
13
- // not full compatibility, but minimum.
14
- : function randomFillSync (buffer, _offset, _size) {
15
- for (let i = 0; i < buffer.length; ++i) {
16
- buffer[i] = Math.random() * 255 | 0
17
- }
18
- return buffer
19
- }
13
+ : null
20
14
 
21
15
  function generateMask () {
22
16
  if (bufIdx === BUFFER_SIZE) {