@xrkseek/harness 0.2.4 → 0.2.6

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 (309) hide show
  1. package/node_modules/@xrkseek/core-tools/dist/index.d.ts +1 -0
  2. package/node_modules/@xrkseek/core-tools/dist/index.d.ts.map +1 -1
  3. package/node_modules/@xrkseek/core-tools/dist/index.js +1 -0
  4. package/node_modules/@xrkseek/core-tools/dist/index.js.map +1 -1
  5. package/node_modules/@xrkseek/core-tools/dist/settings-tools.d.ts +37 -0
  6. package/node_modules/@xrkseek/core-tools/dist/settings-tools.d.ts.map +1 -0
  7. package/node_modules/@xrkseek/core-tools/dist/settings-tools.js +161 -0
  8. package/node_modules/@xrkseek/core-tools/dist/settings-tools.js.map +1 -0
  9. package/node_modules/@xrkseek/core-tools/dist/std-tools.d.ts +4 -1
  10. package/node_modules/@xrkseek/core-tools/dist/std-tools.d.ts.map +1 -1
  11. package/node_modules/@xrkseek/core-tools/dist/std-tools.js +6 -1
  12. package/node_modules/@xrkseek/core-tools/dist/std-tools.js.map +1 -1
  13. package/node_modules/@xrkseek/exec-fs/dist/read-image.d.ts.map +1 -1
  14. package/node_modules/@xrkseek/exec-fs/dist/read-image.js +20 -2
  15. package/node_modules/@xrkseek/exec-fs/dist/read-image.js.map +1 -1
  16. package/node_modules/@xrkseek/preset-harness/dist/tsconfig.tsbuildinfo +1 -1
  17. package/node_modules/@xrkseek/preset-minimal/dist/tsconfig.tsbuildinfo +1 -1
  18. package/node_modules/@xrkseek/preset-server/dist/tsconfig.tsbuildinfo +1 -1
  19. package/node_modules/@xrkseek/server-config/dist/index.d.ts +2 -2
  20. package/node_modules/@xrkseek/server-config/dist/index.d.ts.map +1 -1
  21. package/node_modules/@xrkseek/server-config/dist/index.js +3 -2
  22. package/node_modules/@xrkseek/server-config/dist/index.js.map +1 -1
  23. package/node_modules/@xrkseek/server-config/dist/mcp-servers.d.ts +12 -1
  24. package/node_modules/@xrkseek/server-config/dist/mcp-servers.d.ts.map +1 -1
  25. package/node_modules/@xrkseek/server-config/dist/mcp-servers.js +56 -1
  26. package/node_modules/@xrkseek/server-config/dist/mcp-servers.js.map +1 -1
  27. package/node_modules/@xrkseek/server-face/dist/adapt/wire-event.d.ts.map +1 -1
  28. package/node_modules/@xrkseek/server-face/dist/adapt/wire-event.js +17 -1
  29. package/node_modules/@xrkseek/server-face/dist/adapt/wire-event.js.map +1 -1
  30. package/node_modules/@xrkseek/server-face/dist/context.d.ts +16 -0
  31. package/node_modules/@xrkseek/server-face/dist/context.d.ts.map +1 -1
  32. package/node_modules/@xrkseek/server-face/dist/dispatch.d.ts.map +1 -1
  33. package/node_modules/@xrkseek/server-face/dist/dispatch.js +5 -1
  34. package/node_modules/@xrkseek/server-face/dist/dispatch.js.map +1 -1
  35. package/node_modules/@xrkseek/server-face/dist/face-schema.d.ts.map +1 -1
  36. package/node_modules/@xrkseek/server-face/dist/face-schema.js +2 -0
  37. package/node_modules/@xrkseek/server-face/dist/face-schema.js.map +1 -1
  38. package/node_modules/@xrkseek/server-face/dist/handlers/host.d.ts.map +1 -1
  39. package/node_modules/@xrkseek/server-face/dist/handlers/host.js +2 -0
  40. package/node_modules/@xrkseek/server-face/dist/handlers/host.js.map +1 -1
  41. package/node_modules/@xrkseek/server-face/dist/handlers/remotes.d.ts +8 -0
  42. package/node_modules/@xrkseek/server-face/dist/handlers/remotes.d.ts.map +1 -1
  43. package/node_modules/@xrkseek/server-face/dist/handlers/remotes.js +155 -1
  44. package/node_modules/@xrkseek/server-face/dist/handlers/remotes.js.map +1 -1
  45. package/node_modules/@xrkseek/server-face/dist/handlers/session.d.ts.map +1 -1
  46. package/node_modules/@xrkseek/server-face/dist/handlers/session.js +11 -112
  47. package/node_modules/@xrkseek/server-face/dist/handlers/session.js.map +1 -1
  48. package/node_modules/@xrkseek/server-face/dist/index.d.ts +3 -2
  49. package/node_modules/@xrkseek/server-face/dist/index.d.ts.map +1 -1
  50. package/node_modules/@xrkseek/server-face/dist/index.js +3 -2
  51. package/node_modules/@xrkseek/server-face/dist/index.js.map +1 -1
  52. package/node_modules/@xrkseek/server-face/dist/plugin-inventory.d.ts +29 -3
  53. package/node_modules/@xrkseek/server-face/dist/plugin-inventory.d.ts.map +1 -1
  54. package/node_modules/@xrkseek/server-face/dist/plugin-inventory.js +169 -6
  55. package/node_modules/@xrkseek/server-face/dist/plugin-inventory.js.map +1 -1
  56. package/node_modules/@xrkseek/server-face/dist/presets-catalog.d.ts +9 -7
  57. package/node_modules/@xrkseek/server-face/dist/presets-catalog.d.ts.map +1 -1
  58. package/node_modules/@xrkseek/server-face/dist/presets-catalog.js +7 -17
  59. package/node_modules/@xrkseek/server-face/dist/presets-catalog.js.map +1 -1
  60. package/node_modules/@xrkseek/server-face/dist/runtime.d.ts +10 -0
  61. package/node_modules/@xrkseek/server-face/dist/runtime.d.ts.map +1 -1
  62. package/node_modules/@xrkseek/server-face/dist/runtime.js +8 -0
  63. package/node_modules/@xrkseek/server-face/dist/runtime.js.map +1 -1
  64. package/node_modules/@xrkseek/server-face/dist/select-session-model.d.ts +15 -0
  65. package/node_modules/@xrkseek/server-face/dist/select-session-model.d.ts.map +1 -0
  66. package/node_modules/@xrkseek/server-face/dist/select-session-model.js +117 -0
  67. package/node_modules/@xrkseek/server-face/dist/select-session-model.js.map +1 -0
  68. package/node_modules/@xrkseek/server-face/dist/settings-agent-tools.d.ts +7 -0
  69. package/node_modules/@xrkseek/server-face/dist/settings-agent-tools.d.ts.map +1 -0
  70. package/node_modules/@xrkseek/server-face/dist/settings-agent-tools.js +91 -0
  71. package/node_modules/@xrkseek/server-face/dist/settings-agent-tools.js.map +1 -0
  72. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts +7 -1
  73. package/node_modules/@xrkseek/server-face/dist/settings-credentials.d.ts.map +1 -1
  74. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js +85 -26
  75. package/node_modules/@xrkseek/server-face/dist/settings-credentials.js.map +1 -1
  76. package/node_modules/@xrkseek/server-face/dist/slash.d.ts +4 -3
  77. package/node_modules/@xrkseek/server-face/dist/slash.d.ts.map +1 -1
  78. package/node_modules/@xrkseek/server-face/dist/slash.js +191 -20
  79. package/node_modules/@xrkseek/server-face/dist/slash.js.map +1 -1
  80. package/node_modules/@xrkseek/server-host/dist/http-proxy.d.ts +11 -0
  81. package/node_modules/@xrkseek/server-host/dist/http-proxy.d.ts.map +1 -0
  82. package/node_modules/@xrkseek/server-host/dist/http-proxy.js +42 -0
  83. package/node_modules/@xrkseek/server-host/dist/http-proxy.js.map +1 -0
  84. package/node_modules/@xrkseek/server-host/dist/index.d.ts.map +1 -1
  85. package/node_modules/@xrkseek/server-host/dist/index.js +43 -3
  86. package/node_modules/@xrkseek/server-host/dist/index.js.map +1 -1
  87. package/node_modules/@xrkseek/server-host/dist/mcp-wire.d.ts +4 -3
  88. package/node_modules/@xrkseek/server-host/dist/mcp-wire.d.ts.map +1 -1
  89. package/node_modules/@xrkseek/server-host/dist/mcp-wire.js +14 -10
  90. package/node_modules/@xrkseek/server-host/dist/mcp-wire.js.map +1 -1
  91. package/node_modules/@xrkseek/server-host/package.json +57 -56
  92. package/node_modules/@xrkseek/server-http/dist/index.d.ts +1 -0
  93. package/node_modules/@xrkseek/server-http/dist/index.d.ts.map +1 -1
  94. package/node_modules/@xrkseek/server-http/dist/index.js +1 -0
  95. package/node_modules/@xrkseek/server-http/dist/index.js.map +1 -1
  96. package/node_modules/@xrkseek/server-http/dist/xrk/plugin-mutate.d.ts.map +1 -1
  97. package/node_modules/@xrkseek/server-http/dist/xrk/plugin-mutate.js +6 -1
  98. package/node_modules/@xrkseek/server-http/dist/xrk/plugin-mutate.js.map +1 -1
  99. package/node_modules/undici/LICENSE +21 -0
  100. package/node_modules/undici/README.md +741 -0
  101. package/node_modules/undici/docs/docs/api/Agent.md +84 -0
  102. package/node_modules/undici/docs/docs/api/BalancedPool.md +99 -0
  103. package/node_modules/undici/docs/docs/api/CacheStorage.md +30 -0
  104. package/node_modules/undici/docs/docs/api/CacheStore.md +164 -0
  105. package/node_modules/undici/docs/docs/api/Client.md +288 -0
  106. package/node_modules/undici/docs/docs/api/ClientStats.md +27 -0
  107. package/node_modules/undici/docs/docs/api/Connector.md +115 -0
  108. package/node_modules/undici/docs/docs/api/ContentType.md +57 -0
  109. package/node_modules/undici/docs/docs/api/Cookies.md +128 -0
  110. package/node_modules/undici/docs/docs/api/Debug.md +62 -0
  111. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +315 -0
  112. package/node_modules/undici/docs/docs/api/Dispatcher.md +1392 -0
  113. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +159 -0
  114. package/node_modules/undici/docs/docs/api/Errors.md +49 -0
  115. package/node_modules/undici/docs/docs/api/EventSource.md +45 -0
  116. package/node_modules/undici/docs/docs/api/Fetch.md +60 -0
  117. package/node_modules/undici/docs/docs/api/GlobalInstallation.md +139 -0
  118. package/node_modules/undici/docs/docs/api/H2CClient.md +263 -0
  119. package/node_modules/undici/docs/docs/api/MockAgent.md +603 -0
  120. package/node_modules/undici/docs/docs/api/MockCallHistory.md +197 -0
  121. package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +43 -0
  122. package/node_modules/undici/docs/docs/api/MockClient.md +81 -0
  123. package/node_modules/undici/docs/docs/api/MockErrors.md +12 -0
  124. package/node_modules/undici/docs/docs/api/MockPool.md +555 -0
  125. package/node_modules/undici/docs/docs/api/Pool.md +84 -0
  126. package/node_modules/undici/docs/docs/api/PoolStats.md +35 -0
  127. package/node_modules/undici/docs/docs/api/ProxyAgent.md +229 -0
  128. package/node_modules/undici/docs/docs/api/RedirectHandler.md +93 -0
  129. package/node_modules/undici/docs/docs/api/RetryAgent.md +50 -0
  130. package/node_modules/undici/docs/docs/api/RetryHandler.md +118 -0
  131. package/node_modules/undici/docs/docs/api/RoundRobinPool.md +145 -0
  132. package/node_modules/undici/docs/docs/api/SnapshotAgent.md +616 -0
  133. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +275 -0
  134. package/node_modules/undici/docs/docs/api/Util.md +25 -0
  135. package/node_modules/undici/docs/docs/api/WebSocket.md +141 -0
  136. package/node_modules/undici/docs/docs/api/api-lifecycle.md +91 -0
  137. package/node_modules/undici/docs/docs/best-practices/client-certificate.md +64 -0
  138. package/node_modules/undici/docs/docs/best-practices/crawling.md +58 -0
  139. package/node_modules/undici/docs/docs/best-practices/mocking-request.md +190 -0
  140. package/node_modules/undici/docs/docs/best-practices/proxy.md +127 -0
  141. package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +224 -0
  142. package/node_modules/undici/docs/docs/best-practices/writing-tests.md +63 -0
  143. package/node_modules/undici/index-fetch.js +65 -0
  144. package/node_modules/undici/index.d.ts +3 -0
  145. package/node_modules/undici/index.js +234 -0
  146. package/node_modules/undici/lib/api/abort-signal.js +59 -0
  147. package/node_modules/undici/lib/api/api-connect.js +110 -0
  148. package/node_modules/undici/lib/api/api-pipeline.js +252 -0
  149. package/node_modules/undici/lib/api/api-request.js +214 -0
  150. package/node_modules/undici/lib/api/api-stream.js +209 -0
  151. package/node_modules/undici/lib/api/api-upgrade.js +111 -0
  152. package/node_modules/undici/lib/api/index.js +7 -0
  153. package/node_modules/undici/lib/api/readable.js +580 -0
  154. package/node_modules/undici/lib/cache/memory-cache-store.js +279 -0
  155. package/node_modules/undici/lib/cache/sqlite-cache-store.js +467 -0
  156. package/node_modules/undici/lib/core/connect.js +153 -0
  157. package/node_modules/undici/lib/core/constants.js +143 -0
  158. package/node_modules/undici/lib/core/diagnostics.js +227 -0
  159. package/node_modules/undici/lib/core/errors.js +477 -0
  160. package/node_modules/undici/lib/core/request.js +464 -0
  161. package/node_modules/undici/lib/core/socks5-client.js +422 -0
  162. package/node_modules/undici/lib/core/socks5-utils.js +212 -0
  163. package/node_modules/undici/lib/core/symbols.js +75 -0
  164. package/node_modules/undici/lib/core/tree.js +160 -0
  165. package/node_modules/undici/lib/core/util.js +992 -0
  166. package/node_modules/undici/lib/dispatcher/agent.js +158 -0
  167. package/node_modules/undici/lib/dispatcher/balanced-pool.js +221 -0
  168. package/node_modules/undici/lib/dispatcher/client-h1.js +1739 -0
  169. package/node_modules/undici/lib/dispatcher/client-h2.js +1051 -0
  170. package/node_modules/undici/lib/dispatcher/client.js +668 -0
  171. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +184 -0
  172. package/node_modules/undici/lib/dispatcher/dispatcher.js +48 -0
  173. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +146 -0
  174. package/node_modules/undici/lib/dispatcher/fixed-queue.js +135 -0
  175. package/node_modules/undici/lib/dispatcher/h2c-client.js +51 -0
  176. package/node_modules/undici/lib/dispatcher/pool-base.js +214 -0
  177. package/node_modules/undici/lib/dispatcher/pool.js +118 -0
  178. package/node_modules/undici/lib/dispatcher/proxy-agent.js +319 -0
  179. package/node_modules/undici/lib/dispatcher/retry-agent.js +35 -0
  180. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +137 -0
  181. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +260 -0
  182. package/node_modules/undici/lib/encoding/index.js +33 -0
  183. package/node_modules/undici/lib/global.js +59 -0
  184. package/node_modules/undici/lib/handler/cache-handler.js +776 -0
  185. package/node_modules/undici/lib/handler/cache-revalidation-handler.js +124 -0
  186. package/node_modules/undici/lib/handler/decorator-handler.js +67 -0
  187. package/node_modules/undici/lib/handler/deduplication-handler.js +460 -0
  188. package/node_modules/undici/lib/handler/redirect-handler.js +238 -0
  189. package/node_modules/undici/lib/handler/retry-handler.js +453 -0
  190. package/node_modules/undici/lib/handler/unwrap-handler.js +106 -0
  191. package/node_modules/undici/lib/handler/wrap-handler.js +105 -0
  192. package/node_modules/undici/lib/interceptor/cache.js +621 -0
  193. package/node_modules/undici/lib/interceptor/decompress.js +391 -0
  194. package/node_modules/undici/lib/interceptor/deduplicate.js +117 -0
  195. package/node_modules/undici/lib/interceptor/dns.js +571 -0
  196. package/node_modules/undici/lib/interceptor/dump.js +99 -0
  197. package/node_modules/undici/lib/interceptor/redirect.js +21 -0
  198. package/node_modules/undici/lib/interceptor/response-error.js +95 -0
  199. package/node_modules/undici/lib/interceptor/retry.js +19 -0
  200. package/node_modules/undici/lib/llhttp/.gitkeep +0 -0
  201. package/node_modules/undici/lib/llhttp/constants.d.ts +195 -0
  202. package/node_modules/undici/lib/llhttp/constants.js +531 -0
  203. package/node_modules/undici/lib/llhttp/llhttp-wasm.js +15 -0
  204. package/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +15 -0
  205. package/node_modules/undici/lib/llhttp/utils.d.ts +2 -0
  206. package/node_modules/undici/lib/llhttp/utils.js +12 -0
  207. package/node_modules/undici/lib/mock/mock-agent.js +232 -0
  208. package/node_modules/undici/lib/mock/mock-call-history.js +248 -0
  209. package/node_modules/undici/lib/mock/mock-client.js +68 -0
  210. package/node_modules/undici/lib/mock/mock-errors.js +29 -0
  211. package/node_modules/undici/lib/mock/mock-interceptor.js +209 -0
  212. package/node_modules/undici/lib/mock/mock-pool.js +68 -0
  213. package/node_modules/undici/lib/mock/mock-symbols.js +32 -0
  214. package/node_modules/undici/lib/mock/mock-utils.js +486 -0
  215. package/node_modules/undici/lib/mock/pending-interceptors-formatter.js +43 -0
  216. package/node_modules/undici/lib/mock/snapshot-agent.js +353 -0
  217. package/node_modules/undici/lib/mock/snapshot-recorder.js +588 -0
  218. package/node_modules/undici/lib/mock/snapshot-utils.js +158 -0
  219. package/node_modules/undici/lib/util/cache.js +676 -0
  220. package/node_modules/undici/lib/util/date.js +670 -0
  221. package/node_modules/undici/lib/util/promise.js +28 -0
  222. package/node_modules/undici/lib/util/runtime-features.js +124 -0
  223. package/node_modules/undici/lib/util/stats.js +32 -0
  224. package/node_modules/undici/lib/util/timers.js +425 -0
  225. package/node_modules/undici/lib/web/cache/cache.js +864 -0
  226. package/node_modules/undici/lib/web/cache/cachestorage.js +152 -0
  227. package/node_modules/undici/lib/web/cache/util.js +45 -0
  228. package/node_modules/undici/lib/web/cookies/constants.js +12 -0
  229. package/node_modules/undici/lib/web/cookies/index.js +199 -0
  230. package/node_modules/undici/lib/web/cookies/parse.js +314 -0
  231. package/node_modules/undici/lib/web/cookies/util.js +352 -0
  232. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +494 -0
  233. package/node_modules/undici/lib/web/eventsource/eventsource.js +501 -0
  234. package/node_modules/undici/lib/web/eventsource/util.js +29 -0
  235. package/node_modules/undici/lib/web/fetch/LICENSE +21 -0
  236. package/node_modules/undici/lib/web/fetch/body.js +509 -0
  237. package/node_modules/undici/lib/web/fetch/constants.js +131 -0
  238. package/node_modules/undici/lib/web/fetch/data-url.js +596 -0
  239. package/node_modules/undici/lib/web/fetch/formdata-parser.js +586 -0
  240. package/node_modules/undici/lib/web/fetch/formdata.js +259 -0
  241. package/node_modules/undici/lib/web/fetch/global.js +40 -0
  242. package/node_modules/undici/lib/web/fetch/headers.js +719 -0
  243. package/node_modules/undici/lib/web/fetch/index.js +2413 -0
  244. package/node_modules/undici/lib/web/fetch/request.js +1115 -0
  245. package/node_modules/undici/lib/web/fetch/response.js +641 -0
  246. package/node_modules/undici/lib/web/fetch/util.js +1522 -0
  247. package/node_modules/undici/lib/web/infra/index.js +229 -0
  248. package/node_modules/undici/lib/web/subresource-integrity/Readme.md +9 -0
  249. package/node_modules/undici/lib/web/subresource-integrity/subresource-integrity.js +307 -0
  250. package/node_modules/undici/lib/web/webidl/index.js +1006 -0
  251. package/node_modules/undici/lib/web/websocket/connection.js +329 -0
  252. package/node_modules/undici/lib/web/websocket/constants.js +126 -0
  253. package/node_modules/undici/lib/web/websocket/events.js +331 -0
  254. package/node_modules/undici/lib/web/websocket/frame.js +133 -0
  255. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +105 -0
  256. package/node_modules/undici/lib/web/websocket/receiver.js +507 -0
  257. package/node_modules/undici/lib/web/websocket/sender.js +109 -0
  258. package/node_modules/undici/lib/web/websocket/stream/websocketerror.js +104 -0
  259. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +496 -0
  260. package/node_modules/undici/lib/web/websocket/util.js +347 -0
  261. package/node_modules/undici/lib/web/websocket/websocket.js +758 -0
  262. package/node_modules/undici/package.json +152 -0
  263. package/node_modules/undici/scripts/strip-comments.js +10 -0
  264. package/node_modules/undici/types/README.md +6 -0
  265. package/node_modules/undici/types/agent.d.ts +32 -0
  266. package/node_modules/undici/types/api.d.ts +43 -0
  267. package/node_modules/undici/types/balanced-pool.d.ts +30 -0
  268. package/node_modules/undici/types/cache-interceptor.d.ts +179 -0
  269. package/node_modules/undici/types/cache.d.ts +36 -0
  270. package/node_modules/undici/types/client-stats.d.ts +15 -0
  271. package/node_modules/undici/types/client.d.ts +139 -0
  272. package/node_modules/undici/types/connector.d.ts +36 -0
  273. package/node_modules/undici/types/content-type.d.ts +21 -0
  274. package/node_modules/undici/types/cookies.d.ts +30 -0
  275. package/node_modules/undici/types/diagnostics-channel.d.ts +74 -0
  276. package/node_modules/undici/types/dispatcher.d.ts +275 -0
  277. package/node_modules/undici/types/env-http-proxy-agent.d.ts +22 -0
  278. package/node_modules/undici/types/errors.d.ts +177 -0
  279. package/node_modules/undici/types/eventsource.d.ts +66 -0
  280. package/node_modules/undici/types/fetch.d.ts +231 -0
  281. package/node_modules/undici/types/formdata.d.ts +114 -0
  282. package/node_modules/undici/types/global-dispatcher.d.ts +9 -0
  283. package/node_modules/undici/types/global-origin.d.ts +7 -0
  284. package/node_modules/undici/types/h2c-client.d.ts +73 -0
  285. package/node_modules/undici/types/handlers.d.ts +14 -0
  286. package/node_modules/undici/types/header.d.ts +160 -0
  287. package/node_modules/undici/types/index.d.ts +91 -0
  288. package/node_modules/undici/types/interceptors.d.ts +82 -0
  289. package/node_modules/undici/types/mock-agent.d.ts +68 -0
  290. package/node_modules/undici/types/mock-call-history.d.ts +111 -0
  291. package/node_modules/undici/types/mock-client.d.ts +27 -0
  292. package/node_modules/undici/types/mock-errors.d.ts +12 -0
  293. package/node_modules/undici/types/mock-interceptor.d.ts +94 -0
  294. package/node_modules/undici/types/mock-pool.d.ts +27 -0
  295. package/node_modules/undici/types/patch.d.ts +29 -0
  296. package/node_modules/undici/types/pool-stats.d.ts +19 -0
  297. package/node_modules/undici/types/pool.d.ts +41 -0
  298. package/node_modules/undici/types/proxy-agent.d.ts +29 -0
  299. package/node_modules/undici/types/readable.d.ts +68 -0
  300. package/node_modules/undici/types/retry-agent.d.ts +8 -0
  301. package/node_modules/undici/types/retry-handler.d.ts +125 -0
  302. package/node_modules/undici/types/round-robin-pool.d.ts +41 -0
  303. package/node_modules/undici/types/snapshot-agent.d.ts +109 -0
  304. package/node_modules/undici/types/socks5-proxy-agent.d.ts +25 -0
  305. package/node_modules/undici/types/util.d.ts +18 -0
  306. package/node_modules/undici/types/utility.d.ts +7 -0
  307. package/node_modules/undici/types/webidl.d.ts +347 -0
  308. package/node_modules/undici/types/websocket.d.ts +188 -0
  309. package/package.json +3 -1
@@ -0,0 +1,1051 @@
1
+ 'use strict'
2
+
3
+ const assert = require('node:assert')
4
+ const { pipeline } = require('node:stream')
5
+ const util = require('../core/util.js')
6
+ const {
7
+ RequestContentLengthMismatchError,
8
+ RequestAbortedError,
9
+ SocketError,
10
+ InformationalError,
11
+ InvalidArgumentError,
12
+ HeadersTimeoutError,
13
+ BodyTimeoutError
14
+ } = require('../core/errors.js')
15
+ const {
16
+ kUrl,
17
+ kReset,
18
+ kClient,
19
+ kRunning,
20
+ kPending,
21
+ kQueue,
22
+ kPendingIdx,
23
+ kRunningIdx,
24
+ kError,
25
+ kSocket,
26
+ kStrictContentLength,
27
+ kOnError,
28
+ kMaxConcurrentStreams,
29
+ kPingInterval,
30
+ kHTTP2Session,
31
+ kHTTP2InitialWindowSize,
32
+ kHTTP2ConnectionWindowSize,
33
+ kResume,
34
+ kSize,
35
+ kHTTPContext,
36
+ kClosed,
37
+ kBodyTimeout,
38
+ kHeadersTimeout,
39
+ kEnableConnectProtocol,
40
+ kRemoteSettings,
41
+ kHTTP2Stream,
42
+ kHTTP2SessionState
43
+ } = require('../core/symbols.js')
44
+ const { channels } = require('../core/diagnostics.js')
45
+
46
+ const kOpenStreams = Symbol('open streams')
47
+
48
+ let extractBody
49
+
50
+ /** @type {import('http2')} */
51
+ let http2
52
+ try {
53
+ http2 = require('node:http2')
54
+ } catch {
55
+ // @ts-ignore
56
+ http2 = { constants: {} }
57
+ }
58
+
59
+ const {
60
+ constants: {
61
+ HTTP2_HEADER_AUTHORITY,
62
+ HTTP2_HEADER_METHOD,
63
+ HTTP2_HEADER_PATH,
64
+ HTTP2_HEADER_SCHEME,
65
+ HTTP2_HEADER_CONTENT_LENGTH,
66
+ HTTP2_HEADER_EXPECT,
67
+ HTTP2_HEADER_STATUS,
68
+ HTTP2_HEADER_PROTOCOL,
69
+ NGHTTP2_REFUSED_STREAM,
70
+ NGHTTP2_CANCEL
71
+ }
72
+ } = http2
73
+
74
+ function parseH2Headers (headers) {
75
+ const result = []
76
+
77
+ for (const [name, value] of Object.entries(headers)) {
78
+ // h2 may concat the header value by array
79
+ // e.g. Set-Cookie
80
+ if (Array.isArray(value)) {
81
+ for (const subvalue of value) {
82
+ // we need to provide each header value of header name
83
+ // because the headers handler expect name-value pair
84
+ result.push(Buffer.from(name), Buffer.from(subvalue))
85
+ }
86
+ } else {
87
+ result.push(Buffer.from(name), Buffer.from(value))
88
+ }
89
+ }
90
+
91
+ return result
92
+ }
93
+
94
+ function connectH2 (client, socket) {
95
+ client[kSocket] = socket
96
+
97
+ const http2InitialWindowSize = client[kHTTP2InitialWindowSize]
98
+ const http2ConnectionWindowSize = client[kHTTP2ConnectionWindowSize]
99
+
100
+ const session = http2.connect(client[kUrl], {
101
+ createConnection: () => socket,
102
+ peerMaxConcurrentStreams: client[kMaxConcurrentStreams],
103
+ settings: {
104
+ // TODO(metcoder95): add support for PUSH
105
+ enablePush: false,
106
+ ...(http2InitialWindowSize != null ? { initialWindowSize: http2InitialWindowSize } : null)
107
+ }
108
+ })
109
+
110
+ client[kSocket] = socket
111
+ session[kOpenStreams] = 0
112
+ session[kClient] = client
113
+ session[kSocket] = socket
114
+ session[kHTTP2SessionState] = {
115
+ ping: {
116
+ interval: client[kPingInterval] === 0 ? null : setInterval(onHttp2SendPing, client[kPingInterval], session).unref()
117
+ }
118
+ }
119
+ // We set it to true by default in a best-effort; however once connected to an H2 server
120
+ // we will check if extended CONNECT protocol is supported or not
121
+ // and set this value accordingly.
122
+ session[kEnableConnectProtocol] = false
123
+ // States whether or not we have received the remote settings from the server
124
+ session[kRemoteSettings] = false
125
+
126
+ // Apply connection-level flow control once connected (if supported).
127
+ if (http2ConnectionWindowSize) {
128
+ util.addListener(session, 'connect', applyConnectionWindowSize.bind(session, http2ConnectionWindowSize))
129
+ }
130
+
131
+ util.addListener(session, 'error', onHttp2SessionError)
132
+ util.addListener(session, 'frameError', onHttp2FrameError)
133
+ util.addListener(session, 'end', onHttp2SessionEnd)
134
+ util.addListener(session, 'goaway', onHttp2SessionGoAway)
135
+ util.addListener(session, 'close', onHttp2SessionClose)
136
+ util.addListener(session, 'remoteSettings', onHttp2RemoteSettings)
137
+ // TODO (@metcoder95): implement SETTINGS support
138
+ // util.addListener(session, 'localSettings', onHttp2RemoteSettings)
139
+
140
+ session.unref()
141
+
142
+ client[kHTTP2Session] = session
143
+ socket[kHTTP2Session] = session
144
+
145
+ util.addListener(socket, 'error', onHttp2SocketError)
146
+ util.addListener(socket, 'end', onHttp2SocketEnd)
147
+ util.addListener(socket, 'close', onHttp2SocketClose)
148
+
149
+ socket[kClosed] = false
150
+ socket.on('close', onSocketClose)
151
+
152
+ return {
153
+ version: 'h2',
154
+ defaultPipelining: Infinity,
155
+ /**
156
+ * @param {import('../core/request.js')} request
157
+ * @returns {boolean}
158
+ */
159
+ write (request) {
160
+ return writeH2(client, request)
161
+ },
162
+ /**
163
+ * @returns {void}
164
+ */
165
+ resume () {
166
+ resumeH2(client)
167
+ },
168
+ /**
169
+ * @param {Error | null} err
170
+ * @param {() => void} callback
171
+ */
172
+ destroy (err, callback) {
173
+ if (socket[kClosed]) {
174
+ queueMicrotask(callback)
175
+ } else {
176
+ socket.destroy(err).on('close', callback)
177
+ }
178
+ },
179
+ /**
180
+ * @type {boolean}
181
+ */
182
+ get destroyed () {
183
+ return socket.destroyed
184
+ },
185
+ /**
186
+ * @param {import('../core/request.js')} request
187
+ * @returns {boolean}
188
+ */
189
+ busy (request) {
190
+ if (request != null) {
191
+ if (client[kRunning] > 0) {
192
+ // We are already processing requests
193
+
194
+ // Non-idempotent request cannot be retried.
195
+ // Ensure that no other requests are inflight and
196
+ // could cause failure.
197
+ if (request.idempotent === false) return true
198
+ // Don't dispatch an upgrade until all preceding requests have completed.
199
+ // Possibly, we do not have remote settings confirmed yet.
200
+ if ((request.upgrade === 'websocket' || request.method === 'CONNECT') && session[kRemoteSettings] === false) return true
201
+ // Request with stream or iterator body can error while other requests
202
+ // are inflight and indirectly error those as well.
203
+ // Ensure this doesn't happen by waiting for inflight
204
+ // to complete before dispatching.
205
+
206
+ // Request with stream or iterator body cannot be retried.
207
+ // Ensure that no other requests are inflight and
208
+ // could cause failure.
209
+ if (util.bodyLength(request.body) !== 0 &&
210
+ (util.isStream(request.body) || util.isAsyncIterable(request.body) || util.isFormDataLike(request.body))) return true
211
+ } else {
212
+ return (request.upgrade === 'websocket' || request.method === 'CONNECT') && session[kRemoteSettings] === false
213
+ }
214
+ }
215
+
216
+ return false
217
+ }
218
+ }
219
+ }
220
+
221
+ function resumeH2 (client) {
222
+ const socket = client[kSocket]
223
+
224
+ if (socket?.destroyed === false) {
225
+ // Only let the process exit when there is genuinely nothing outstanding.
226
+ // Unreffing because the peer advertised MAX_CONCURRENT_STREAMS = 0 left
227
+ // queued requests with nothing holding the event loop open, so the process
228
+ // could exit with status 0 while an awaited request never settled.
229
+ if (client[kSize] === 0) {
230
+ socket.unref()
231
+ client[kHTTP2Session].unref()
232
+ } else {
233
+ socket.ref()
234
+ client[kHTTP2Session].ref()
235
+ }
236
+ }
237
+ }
238
+
239
+ function applyConnectionWindowSize (connectionWindowSize) {
240
+ try {
241
+ if (typeof this.setLocalWindowSize === 'function') {
242
+ this.setLocalWindowSize(connectionWindowSize)
243
+ }
244
+ } catch {
245
+ // Best-effort only.
246
+ }
247
+ }
248
+
249
+ function onHttp2RemoteSettings (settings) {
250
+ // Fallbacks are a safe bet, remote setting will always override
251
+ this[kClient][kMaxConcurrentStreams] = settings.maxConcurrentStreams ?? this[kClient][kMaxConcurrentStreams]
252
+ /**
253
+ * From RFC-8441
254
+ * A sender MUST NOT send a SETTINGS_ENABLE_CONNECT_PROTOCOL parameter
255
+ * with the value of 0 after previously sending a value of 1.
256
+ */
257
+ // Note: Cannot be tested in Node, it does not supports disabling the extended CONNECT protocol once enabled
258
+ if (this[kRemoteSettings] === true && this[kEnableConnectProtocol] === true && settings.enableConnectProtocol === false) {
259
+ const err = new InformationalError('HTTP/2: Server disabled extended CONNECT protocol against RFC-8441')
260
+ this[kSocket][kError] = err
261
+ this[kClient][kOnError](err)
262
+ return
263
+ }
264
+
265
+ this[kEnableConnectProtocol] = settings.enableConnectProtocol ?? this[kEnableConnectProtocol]
266
+ this[kRemoteSettings] = true
267
+ this[kClient][kResume]()
268
+ }
269
+
270
+ function onHttp2SendPing (session) {
271
+ const state = session[kHTTP2SessionState]
272
+ if ((session.closed || session.destroyed) && state.ping.interval != null) {
273
+ clearInterval(state.ping.interval)
274
+ state.ping.interval = null
275
+ return
276
+ }
277
+
278
+ // If no ping sent, do nothing
279
+ session.ping(onPing.bind(session))
280
+
281
+ function onPing (err, duration) {
282
+ const client = this[kClient]
283
+ const socket = this[kClient]
284
+
285
+ if (err != null) {
286
+ const error = new InformationalError(`HTTP/2: "PING" errored - type ${err.message}`)
287
+ socket[kError] = error
288
+ client[kOnError](error)
289
+ } else {
290
+ client.emit('ping', duration)
291
+ }
292
+ }
293
+ }
294
+
295
+ function onHttp2SessionError (err) {
296
+ assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')
297
+
298
+ this[kSocket][kError] = err
299
+ this[kClient][kOnError](err)
300
+ }
301
+
302
+ function onHttp2FrameError (type, code, id) {
303
+ if (id === 0) {
304
+ const err = new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`)
305
+ this[kSocket][kError] = err
306
+ this[kClient][kOnError](err)
307
+ }
308
+ }
309
+
310
+ function onHttp2SessionEnd () {
311
+ const err = new SocketError('other side closed', util.getSocketInfo(this[kSocket]))
312
+ this.destroy(err)
313
+ util.destroy(this[kSocket], err)
314
+ }
315
+
316
+ /**
317
+ * This is the root cause of #3011
318
+ * We need to handle GOAWAY frames properly, and trigger the session close
319
+ * along with the socket right away
320
+ *
321
+ * @this {import('http2').ClientHttp2Session}
322
+ * @param {number} errorCode
323
+ */
324
+ // Backport of #5410 and #5569. HTTP/2 multiplexes, so requests complete out of
325
+ // order; advancing kRunningIdx blindly retired whichever request happened to
326
+ // sit at the head instead of the one that actually finished, which both lost
327
+ // requests and left phantom running slots behind.
328
+ function completeRequest (client, request, resetPendingIdx = false) {
329
+ const queue = client[kQueue]
330
+ const runningIdx = client[kRunningIdx]
331
+
332
+ // In-order completion: clear the request and advance without splicing.
333
+ // The client's resume loop compacts cleared slots once the index grows.
334
+ if (runningIdx < client[kPendingIdx] && queue[runningIdx] === request) {
335
+ queue[runningIdx] = null
336
+ client[kRunningIdx] = runningIdx + 1
337
+ return
338
+ }
339
+
340
+ const index = queue.indexOf(request, runningIdx)
341
+
342
+ if (index === -1 || index >= client[kPendingIdx]) {
343
+ return
344
+ }
345
+
346
+ queue.splice(index, 1)
347
+ client[kPendingIdx]--
348
+
349
+ if (resetPendingIdx && client[kPendingIdx] < client[kRunningIdx]) {
350
+ client[kPendingIdx] = client[kRunningIdx]
351
+ }
352
+ }
353
+
354
+ function onHttp2SessionGoAway (errorCode) {
355
+ // TODO(mcollina): Verify if GOAWAY implements the spec correctly:
356
+ // https://datatracker.ietf.org/doc/html/rfc7540#section-6.8
357
+ // Specifically, we do not verify the "valid" stream id.
358
+
359
+ const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${errorCode}`, util.getSocketInfo(this[kSocket]))
360
+ const client = this[kClient]
361
+
362
+ client[kSocket] = null
363
+ client[kHTTPContext] = null
364
+
365
+ // this is an HTTP2 session
366
+ this.close()
367
+ this[kHTTP2Session] = null
368
+
369
+ util.destroy(this[kSocket], err)
370
+
371
+ // Fail head of pipeline.
372
+ if (client[kRunningIdx] < client[kQueue].length) {
373
+ const request = client[kQueue][client[kRunningIdx]]
374
+ client[kQueue][client[kRunningIdx]++] = null
375
+ if (request != null) {
376
+ util.errorRequest(client, request, err)
377
+ }
378
+ client[kPendingIdx] = client[kRunningIdx]
379
+ }
380
+
381
+ assert(client[kRunning] === 0)
382
+
383
+ client.emit('disconnect', client[kUrl], [client], err)
384
+ client.emit('connectionError', client[kUrl], [client], err)
385
+
386
+ client[kResume]()
387
+ }
388
+
389
+ function onHttp2SessionClose () {
390
+ const { [kClient]: client, [kHTTP2SessionState]: state } = this
391
+ const { [kSocket]: socket } = client
392
+
393
+ const err = this[kSocket][kError] || this[kError] || new SocketError('closed', util.getSocketInfo(socket))
394
+
395
+ client[kSocket] = null
396
+ client[kHTTPContext] = null
397
+
398
+ if (state.ping.interval != null) {
399
+ clearInterval(state.ping.interval)
400
+ state.ping.interval = null
401
+ }
402
+
403
+ if (client.destroyed) {
404
+ assert(client[kPending] === 0)
405
+
406
+ // Fail entire queue.
407
+ const requests = client[kQueue].splice(client[kRunningIdx])
408
+ for (let i = 0; i < requests.length; i++) {
409
+ const request = requests[i]
410
+ if (request != null) {
411
+ util.errorRequest(client, request, err)
412
+ }
413
+ }
414
+ }
415
+ }
416
+
417
+ function onHttp2SocketClose () {
418
+ const err = this[kError] || new SocketError('closed', util.getSocketInfo(this))
419
+
420
+ const client = this[kHTTP2Session][kClient]
421
+
422
+ client[kSocket] = null
423
+ client[kHTTPContext] = null
424
+
425
+ if (this[kHTTP2Session] !== null) {
426
+ this[kHTTP2Session].destroy(err)
427
+ }
428
+
429
+ client[kPendingIdx] = client[kRunningIdx]
430
+
431
+ assert(client[kRunning] === 0)
432
+
433
+ client.emit('disconnect', client[kUrl], [client], err)
434
+
435
+ client[kResume]()
436
+ }
437
+
438
+ function onHttp2SocketError (err) {
439
+ assert(err.code !== 'ERR_TLS_CERT_ALTNAME_INVALID')
440
+
441
+ this[kError] = err
442
+
443
+ this[kClient][kOnError](err)
444
+ }
445
+
446
+ function onHttp2SocketEnd () {
447
+ util.destroy(this, new SocketError('other side closed', util.getSocketInfo(this)))
448
+ }
449
+
450
+ function onSocketClose () {
451
+ this[kClosed] = true
452
+ }
453
+
454
+ // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2
455
+ function shouldSendContentLength (method) {
456
+ return method !== 'GET' && method !== 'HEAD' && method !== 'OPTIONS' && method !== 'TRACE' && method !== 'CONNECT'
457
+ }
458
+
459
+ function writeH2 (client, request) {
460
+ // Time to the response headers, then time between body chunks. Using
461
+ // bodyTimeout for both made headersTimeout a no-op over HTTP/2.
462
+ const headersTimeout = request.headersTimeout ?? client[kHeadersTimeout]
463
+ const bodyTimeout = request.bodyTimeout ?? client[kBodyTimeout]
464
+ const session = client[kHTTP2Session]
465
+ const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request
466
+ let { body } = request
467
+
468
+ if (upgrade != null && upgrade !== 'websocket') {
469
+ util.errorRequest(client, request, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`))
470
+ return false
471
+ }
472
+
473
+ const headers = {}
474
+ for (let n = 0; n < reqHeaders.length; n += 2) {
475
+ const key = reqHeaders[n + 0]
476
+ const val = reqHeaders[n + 1]
477
+
478
+ if (key === 'cookie') {
479
+ if (headers[key] != null) {
480
+ headers[key] = Array.isArray(headers[key]) ? (headers[key].push(val), headers[key]) : [headers[key], val]
481
+ } else {
482
+ headers[key] = val
483
+ }
484
+
485
+ continue
486
+ }
487
+
488
+ if (Array.isArray(val)) {
489
+ for (let i = 0; i < val.length; i++) {
490
+ if (headers[key]) {
491
+ headers[key] += `, ${val[i]}`
492
+ } else {
493
+ headers[key] = val[i]
494
+ }
495
+ }
496
+ } else if (headers[key]) {
497
+ headers[key] += `, ${val}`
498
+ } else {
499
+ headers[key] = val
500
+ }
501
+ }
502
+
503
+ /** @type {import('node:http2').ClientHttp2Stream} */
504
+ let stream = null
505
+
506
+ const { hostname, port } = client[kUrl]
507
+
508
+ headers[HTTP2_HEADER_AUTHORITY] = host || `${hostname}${port ? `:${port}` : ''}`
509
+ headers[HTTP2_HEADER_METHOD] = method
510
+
511
+ const abort = (err) => {
512
+ if (request.aborted || request.completed) {
513
+ return
514
+ }
515
+
516
+ err = err || new RequestAbortedError()
517
+
518
+ util.errorRequest(client, request, err)
519
+
520
+ if (stream != null) {
521
+ // Some chunks might still come after abort,
522
+ // let's ignore them
523
+ stream.removeAllListeners('data')
524
+
525
+ // On Abort, we close the stream to send RST_STREAM frame
526
+ stream.close()
527
+
528
+ // We move the running index to the next request
529
+ client[kOnError](err)
530
+ completeRequest(client, request)
531
+ client[kResume]()
532
+ }
533
+
534
+ // We do not destroy the socket as we can continue using the session
535
+ // the stream gets destroyed and the session remains to create new streams
536
+ util.destroy(body, err)
537
+ }
538
+
539
+ try {
540
+ // We are already connected, streams are pending.
541
+ // We can call on connect, and wait for abort
542
+ request.onConnect(abort)
543
+ } catch (err) {
544
+ util.errorRequest(client, request, err)
545
+ }
546
+
547
+ if (request.aborted) {
548
+ return false
549
+ }
550
+
551
+ if (upgrade || method === 'CONNECT') {
552
+ session.ref()
553
+
554
+ if (upgrade === 'websocket') {
555
+ // We cannot upgrade to websocket if extended CONNECT protocol is not supported
556
+ if (session[kEnableConnectProtocol] === false) {
557
+ util.errorRequest(client, request, new InformationalError('HTTP/2: Extended CONNECT protocol not supported by server'))
558
+ session.unref()
559
+ return false
560
+ }
561
+
562
+ // We force the method to CONNECT
563
+ // as per RFC-8441
564
+ // https://datatracker.ietf.org/doc/html/rfc8441#section-4
565
+ headers[HTTP2_HEADER_METHOD] = 'CONNECT'
566
+ headers[HTTP2_HEADER_PROTOCOL] = 'websocket'
567
+ // :path and :scheme headers must be omitted when sending CONNECT but set if extended-CONNECT
568
+ headers[HTTP2_HEADER_PATH] = path
569
+
570
+ if (protocol === 'ws:' || protocol === 'wss:') {
571
+ headers[HTTP2_HEADER_SCHEME] = protocol === 'ws:' ? 'http' : 'https'
572
+ } else {
573
+ headers[HTTP2_HEADER_SCHEME] = protocol === 'http:' ? 'http' : 'https'
574
+ }
575
+
576
+ stream = session.request(headers, { endStream: false, signal })
577
+ stream[kHTTP2Stream] = true
578
+
579
+ stream.once('response', (headers, _flags) => {
580
+ const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers
581
+
582
+ request.onUpgrade(statusCode, parseH2Headers(realHeaders), stream)
583
+
584
+ ++session[kOpenStreams]
585
+ completeRequest(client, request)
586
+ })
587
+
588
+ stream.on('error', () => {
589
+ if (stream.rstCode === NGHTTP2_REFUSED_STREAM || stream.rstCode === NGHTTP2_CANCEL) {
590
+ // NGHTTP2_REFUSED_STREAM (7) or NGHTTP2_CANCEL (8)
591
+ // We do not treat those as errors as the server might
592
+ // not support websockets and refuse the stream
593
+ abort(new InformationalError(`HTTP/2: "stream error" received - code ${stream.rstCode}`))
594
+ }
595
+ })
596
+
597
+ stream.once('close', () => {
598
+ session[kOpenStreams] -= 1
599
+ if (session[kOpenStreams] === 0) session.unref()
600
+ })
601
+
602
+ stream.setTimeout(headersTimeout)
603
+ return true
604
+ }
605
+
606
+ // TODO: consolidate once we support CONNECT properly
607
+ // NOTE: We are already connected, streams are pending, first request
608
+ // will create a new stream. We trigger a request to create the stream and wait until
609
+ // `ready` event is triggered
610
+ // We disabled endStream to allow the user to write to the stream
611
+ stream = session.request(headers, { endStream: false, signal })
612
+ stream[kHTTP2Stream] = true
613
+ stream.on('response', headers => {
614
+ const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers
615
+
616
+ request.onUpgrade(statusCode, parseH2Headers(realHeaders), stream)
617
+ ++session[kOpenStreams]
618
+ completeRequest(client, request)
619
+ })
620
+ stream.on('error', abort)
621
+ stream.once('close', () => {
622
+ session[kOpenStreams] -= 1
623
+ if (session[kOpenStreams] === 0) session.unref()
624
+ })
625
+ stream.setTimeout(headersTimeout)
626
+
627
+ return true
628
+ }
629
+
630
+ // https://tools.ietf.org/html/rfc7540#section-8.3
631
+ // :path and :scheme headers must be omitted when sending CONNECT
632
+ headers[HTTP2_HEADER_PATH] = path
633
+ headers[HTTP2_HEADER_SCHEME] = protocol === 'http:' ? 'http' : 'https'
634
+
635
+ // https://tools.ietf.org/html/rfc7231#section-4.3.1
636
+ // https://tools.ietf.org/html/rfc7231#section-4.3.2
637
+ // https://tools.ietf.org/html/rfc7231#section-4.3.5
638
+
639
+ // Sending a payload body on a request that does not
640
+ // expect it can cause undefined behavior on some
641
+ // servers and corrupt connection state. Do not
642
+ // re-use the connection for further requests.
643
+
644
+ const expectsPayload = (
645
+ method === 'PUT' ||
646
+ method === 'POST' ||
647
+ method === 'PATCH'
648
+ )
649
+
650
+ if (body && typeof body.read === 'function') {
651
+ // Try to read EOF in order to get length.
652
+ body.read(0)
653
+ }
654
+
655
+ let contentLength = util.bodyLength(body)
656
+
657
+ if (util.isFormDataLike(body)) {
658
+ extractBody ??= require('../web/fetch/body.js').extractBody
659
+
660
+ const [bodyStream, contentType] = extractBody(body)
661
+ headers['content-type'] = contentType
662
+
663
+ body = bodyStream.stream
664
+ contentLength = bodyStream.length
665
+ }
666
+
667
+ if (contentLength == null) {
668
+ contentLength = request.contentLength
669
+ }
670
+
671
+ if (!expectsPayload) {
672
+ // https://tools.ietf.org/html/rfc7230#section-3.3.2
673
+ // A user agent SHOULD NOT send a Content-Length header field when
674
+ // the request message does not contain a payload body and the method
675
+ // semantics do not anticipate such a body.
676
+ // And for methods that don't expect a payload, omit Content-Length.
677
+ contentLength = null
678
+ }
679
+
680
+ // https://github.com/nodejs/undici/issues/2046
681
+ // A user agent may send a Content-Length header with 0 value, this should be allowed.
682
+ if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength != null && request.contentLength !== contentLength) {
683
+ if (client[kStrictContentLength]) {
684
+ util.errorRequest(client, request, new RequestContentLengthMismatchError())
685
+ return false
686
+ }
687
+
688
+ process.emitWarning(new RequestContentLengthMismatchError())
689
+ }
690
+
691
+ if (contentLength != null) {
692
+ assert(body || contentLength === 0, 'no body must not have content length')
693
+ headers[HTTP2_HEADER_CONTENT_LENGTH] = `${contentLength}`
694
+ }
695
+
696
+ session.ref()
697
+
698
+ if (channels.sendHeaders.hasSubscribers) {
699
+ let header = ''
700
+ for (const key in headers) {
701
+ header += `${key}: ${headers[key]}\r\n`
702
+ }
703
+ channels.sendHeaders.publish({ request, headers: header, socket: session[kSocket] })
704
+ }
705
+
706
+ // TODO(metcoder95): add support for sending trailers
707
+ const shouldEndStream = method === 'GET' || method === 'HEAD' || body === null
708
+ if (expectContinue) {
709
+ headers[HTTP2_HEADER_EXPECT] = '100-continue'
710
+ stream = session.request(headers, { endStream: shouldEndStream, signal })
711
+ stream[kHTTP2Stream] = true
712
+
713
+ stream.once('continue', writeBodyH2)
714
+ } else {
715
+ stream = session.request(headers, {
716
+ endStream: shouldEndStream,
717
+ signal
718
+ })
719
+ stream[kHTTP2Stream] = true
720
+
721
+ writeBodyH2()
722
+ }
723
+
724
+ // Increment counter as we have new streams open
725
+ ++session[kOpenStreams]
726
+ stream.setTimeout(headersTimeout)
727
+
728
+ // Track whether we received a response (headers)
729
+ let responseReceived = false
730
+
731
+ stream.once('response', headers => {
732
+ const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers
733
+ request.onResponseStarted()
734
+ responseReceived = true
735
+ stream.setTimeout(bodyTimeout)
736
+
737
+ // Due to the stream nature, it is possible we face a race condition
738
+ // where the stream has been assigned, but the request has been aborted
739
+ // the request remains in-flight and headers hasn't been received yet
740
+ // for those scenarios, best effort is to destroy the stream immediately
741
+ // as there's no value to keep it open.
742
+ if (request.aborted) {
743
+ stream.removeAllListeners('data')
744
+ return
745
+ }
746
+
747
+ if (request.onHeaders(Number(statusCode), parseH2Headers(realHeaders), stream.resume.bind(stream), '') === false) {
748
+ stream.pause()
749
+ }
750
+
751
+ stream.on('data', (chunk) => {
752
+ if (request.aborted || request.completed) {
753
+ return
754
+ }
755
+
756
+ if (request.onData(chunk) === false) {
757
+ stream.pause()
758
+ }
759
+ })
760
+ })
761
+
762
+ stream.once('end', () => {
763
+ stream.removeAllListeners('data')
764
+ // If we received a response, this is a normal completion
765
+ if (responseReceived) {
766
+ if (!request.aborted && !request.completed) {
767
+ request.onComplete({})
768
+ }
769
+
770
+ completeRequest(client, request)
771
+ client[kResume]()
772
+ } else {
773
+ // Stream ended without receiving a response - this is an error
774
+ // (e.g., server destroyed the stream before sending headers)
775
+ abort(new InformationalError('HTTP/2: stream half-closed (remote)'))
776
+ completeRequest(client, request, true)
777
+ client[kResume]()
778
+ }
779
+ })
780
+
781
+ stream.once('close', () => {
782
+ stream.removeAllListeners('data')
783
+ session[kOpenStreams] -= 1
784
+ if (session[kOpenStreams] === 0) {
785
+ session.unref()
786
+ }
787
+
788
+ // A stream can close without ever emitting 'end' or 'error': a peer's
789
+ // RST_STREAM(CANCEL) received before the response is reported by Node as a
790
+ // bare 'close', and destroying the stream unenrolls its timeout, so no
791
+ // 'timeout' follows either. Nothing else would ever settle this request.
792
+ if (!request.aborted && !request.completed) {
793
+ abort(new InformationalError('HTTP/2: stream closed before the response was complete'))
794
+ }
795
+ })
796
+
797
+ stream.once('error', function (err) {
798
+ stream.removeAllListeners('data')
799
+ abort(err)
800
+ })
801
+
802
+ stream.once('frameError', (type, code) => {
803
+ stream.removeAllListeners('data')
804
+ abort(new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`))
805
+ })
806
+
807
+ stream.on('aborted', () => {
808
+ stream.removeAllListeners('data')
809
+ })
810
+
811
+ stream.on('timeout', () => {
812
+ const err = responseReceived
813
+ ? new BodyTimeoutError(`HTTP/2: "body timeout after ${bodyTimeout}"`)
814
+ : new HeadersTimeoutError(`HTTP/2: "headers timeout after ${headersTimeout}"`)
815
+ stream.removeAllListeners('data')
816
+ session[kOpenStreams] -= 1
817
+
818
+ if (session[kOpenStreams] === 0) {
819
+ session.unref()
820
+ }
821
+
822
+ abort(err)
823
+ })
824
+
825
+ stream.once('trailers', trailers => {
826
+ if (request.aborted || request.completed) {
827
+ return
828
+ }
829
+
830
+ stream.removeAllListeners('data')
831
+ request.onComplete(trailers)
832
+ })
833
+
834
+ return true
835
+
836
+ function writeBodyH2 () {
837
+ if (!body || contentLength === 0) {
838
+ writeBuffer(
839
+ abort,
840
+ stream,
841
+ null,
842
+ client,
843
+ request,
844
+ client[kSocket],
845
+ contentLength,
846
+ expectsPayload
847
+ )
848
+ } else if (util.isBuffer(body)) {
849
+ writeBuffer(
850
+ abort,
851
+ stream,
852
+ body,
853
+ client,
854
+ request,
855
+ client[kSocket],
856
+ contentLength,
857
+ expectsPayload
858
+ )
859
+ } else if (util.isBlobLike(body)) {
860
+ if (typeof body.stream === 'function') {
861
+ writeIterable(
862
+ abort,
863
+ stream,
864
+ body.stream(),
865
+ client,
866
+ request,
867
+ client[kSocket],
868
+ contentLength,
869
+ expectsPayload
870
+ )
871
+ } else {
872
+ writeBlob(
873
+ abort,
874
+ stream,
875
+ body,
876
+ client,
877
+ request,
878
+ client[kSocket],
879
+ contentLength,
880
+ expectsPayload
881
+ )
882
+ }
883
+ } else if (util.isStream(body)) {
884
+ writeStream(
885
+ abort,
886
+ client[kSocket],
887
+ expectsPayload,
888
+ stream,
889
+ body,
890
+ client,
891
+ request,
892
+ contentLength
893
+ )
894
+ } else if (util.isIterable(body)) {
895
+ writeIterable(
896
+ abort,
897
+ stream,
898
+ body,
899
+ client,
900
+ request,
901
+ client[kSocket],
902
+ contentLength,
903
+ expectsPayload
904
+ )
905
+ } else {
906
+ assert(false)
907
+ }
908
+ }
909
+ }
910
+
911
+ function writeBuffer (abort, h2stream, body, client, request, socket, contentLength, expectsPayload) {
912
+ try {
913
+ if (body != null && util.isBuffer(body)) {
914
+ assert(contentLength === body.byteLength, 'buffer body must have content length')
915
+ h2stream.cork()
916
+ h2stream.write(body)
917
+ h2stream.uncork()
918
+ h2stream.end()
919
+
920
+ request.onBodySent(body)
921
+ }
922
+
923
+ if (!expectsPayload) {
924
+ socket[kReset] = true
925
+ }
926
+
927
+ request.onRequestSent()
928
+ client[kResume]()
929
+ } catch (error) {
930
+ abort(error)
931
+ }
932
+ }
933
+
934
+ function writeStream (abort, socket, expectsPayload, h2stream, body, client, request, contentLength) {
935
+ assert(contentLength !== 0 || client[kRunning] === 0, 'stream body cannot be pipelined')
936
+
937
+ // For HTTP/2, is enough to pipe the stream
938
+ const pipe = pipeline(
939
+ body,
940
+ h2stream,
941
+ (err) => {
942
+ if (err) {
943
+ util.destroy(pipe, err)
944
+ abort(err)
945
+ } else {
946
+ util.removeAllListeners(pipe)
947
+ request.onRequestSent()
948
+
949
+ if (!expectsPayload) {
950
+ socket[kReset] = true
951
+ }
952
+
953
+ client[kResume]()
954
+ }
955
+ }
956
+ )
957
+
958
+ util.addListener(pipe, 'data', onPipeData)
959
+
960
+ function onPipeData (chunk) {
961
+ request.onBodySent(chunk)
962
+ }
963
+ }
964
+
965
+ async function writeBlob (abort, h2stream, body, client, request, socket, contentLength, expectsPayload) {
966
+ assert(contentLength === body.size, 'blob body must have content length')
967
+
968
+ try {
969
+ if (contentLength != null && contentLength !== body.size) {
970
+ throw new RequestContentLengthMismatchError()
971
+ }
972
+
973
+ const buffer = Buffer.from(await body.arrayBuffer())
974
+
975
+ h2stream.cork()
976
+ h2stream.write(buffer)
977
+ h2stream.uncork()
978
+ h2stream.end()
979
+
980
+ request.onBodySent(buffer)
981
+ request.onRequestSent()
982
+
983
+ if (!expectsPayload) {
984
+ socket[kReset] = true
985
+ }
986
+
987
+ client[kResume]()
988
+ } catch (err) {
989
+ abort(err)
990
+ }
991
+ }
992
+
993
+ async function writeIterable (abort, h2stream, body, client, request, socket, contentLength, expectsPayload) {
994
+ assert(contentLength !== 0 || client[kRunning] === 0, 'iterator body cannot be pipelined')
995
+
996
+ let callback = null
997
+ function onDrain () {
998
+ if (callback) {
999
+ const cb = callback
1000
+ callback = null
1001
+ cb()
1002
+ }
1003
+ }
1004
+
1005
+ const waitForDrain = () => new Promise((resolve, reject) => {
1006
+ assert(callback === null)
1007
+
1008
+ if (socket[kError]) {
1009
+ reject(socket[kError])
1010
+ } else {
1011
+ callback = resolve
1012
+ }
1013
+ })
1014
+
1015
+ h2stream
1016
+ .on('close', onDrain)
1017
+ .on('drain', onDrain)
1018
+
1019
+ try {
1020
+ // It's up to the user to somehow abort the async iterable.
1021
+ for await (const chunk of body) {
1022
+ if (socket[kError]) {
1023
+ throw socket[kError]
1024
+ }
1025
+
1026
+ const res = h2stream.write(chunk)
1027
+ request.onBodySent(chunk)
1028
+ if (!res) {
1029
+ await waitForDrain()
1030
+ }
1031
+ }
1032
+
1033
+ h2stream.end()
1034
+
1035
+ request.onRequestSent()
1036
+
1037
+ if (!expectsPayload) {
1038
+ socket[kReset] = true
1039
+ }
1040
+
1041
+ client[kResume]()
1042
+ } catch (err) {
1043
+ abort(err)
1044
+ } finally {
1045
+ h2stream
1046
+ .off('close', onDrain)
1047
+ .off('drain', onDrain)
1048
+ }
1049
+ }
1050
+
1051
+ module.exports = connectH2