@noodleseed/one 0.21.0 → 0.23.0

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 (215) hide show
  1. package/dist/commands/author-loop.d.ts.map +1 -1
  2. package/dist/commands/author-loop.js +2 -2
  3. package/dist/commands/author-loop.js.map +1 -1
  4. package/dist/commands/catalog-dispatch.d.ts.map +1 -1
  5. package/dist/commands/catalog-dispatch.js +21 -2
  6. package/dist/commands/catalog-dispatch.js.map +1 -1
  7. package/dist/commands/deploy-ops.d.ts.map +1 -1
  8. package/dist/commands/deploy-ops.js +28 -11
  9. package/dist/commands/deploy-ops.js.map +1 -1
  10. package/dist/first-run.d.ts +11 -0
  11. package/dist/first-run.d.ts.map +1 -1
  12. package/dist/first-run.js +19 -4
  13. package/dist/first-run.js.map +1 -1
  14. package/dist/project-scaffold-templates.d.ts +11 -0
  15. package/dist/project-scaffold-templates.d.ts.map +1 -0
  16. package/dist/project-scaffold-templates.js +359 -0
  17. package/dist/project-scaffold-templates.js.map +1 -0
  18. package/dist/project.d.ts.map +1 -1
  19. package/dist/project.js +1 -323
  20. package/dist/project.js.map +1 -1
  21. package/dist/react.d.ts +2 -2
  22. package/dist/react.d.ts.map +1 -1
  23. package/dist/react.js +1 -1
  24. package/dist/react.js.map +1 -1
  25. package/dist/validate.d.ts +12 -0
  26. package/dist/validate.d.ts.map +1 -1
  27. package/dist/validate.js +11 -0
  28. package/dist/validate.js.map +1 -1
  29. package/node_modules/@noodle-borg/agent-kit/dist/curated/hook-notes.d.ts.map +1 -1
  30. package/node_modules/@noodle-borg/agent-kit/dist/curated/hook-notes.js +2 -1
  31. package/node_modules/@noodle-borg/agent-kit/dist/curated/hook-notes.js.map +1 -1
  32. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.d.ts.map +1 -1
  33. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js +1 -0
  34. package/node_modules/@noodle-borg/agent-kit/dist/generated/surface.js.map +1 -1
  35. package/node_modules/@noodle-borg/agent-kit/dist/skill-content.d.ts.map +1 -1
  36. package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js +6 -9
  37. package/node_modules/@noodle-borg/agent-kit/dist/skill-content.js.map +1 -1
  38. package/node_modules/@noodle-borg/agent-kit/package.json +1 -1
  39. package/node_modules/@noodle-borg/authoring/dist/index.d.ts +3 -3
  40. package/node_modules/@noodle-borg/authoring/dist/index.d.ts.map +1 -1
  41. package/node_modules/@noodle-borg/authoring/dist/index.js +1 -1
  42. package/node_modules/@noodle-borg/authoring/dist/index.js.map +1 -1
  43. package/node_modules/@noodle-borg/authoring/dist/react/bridge.d.ts +9 -1
  44. package/node_modules/@noodle-borg/authoring/dist/react/bridge.d.ts.map +1 -1
  45. package/node_modules/@noodle-borg/authoring/dist/react/bridge.js +11 -1
  46. package/node_modules/@noodle-borg/authoring/dist/react/bridge.js.map +1 -1
  47. package/node_modules/@noodle-borg/authoring/dist/react/components.d.ts +306 -9
  48. package/node_modules/@noodle-borg/authoring/dist/react/components.d.ts.map +1 -1
  49. package/node_modules/@noodle-borg/authoring/dist/react/components.js +63 -11
  50. package/node_modules/@noodle-borg/authoring/dist/react/components.js.map +1 -1
  51. package/node_modules/@noodle-borg/authoring/dist/react/hooks.d.ts +2 -0
  52. package/node_modules/@noodle-borg/authoring/dist/react/hooks.d.ts.map +1 -1
  53. package/node_modules/@noodle-borg/authoring/dist/react/hooks.js +11 -0
  54. package/node_modules/@noodle-borg/authoring/dist/react/hooks.js.map +1 -1
  55. package/node_modules/@noodle-borg/authoring/dist/react/index.d.ts +7 -3
  56. package/node_modules/@noodle-borg/authoring/dist/react/index.d.ts.map +1 -1
  57. package/node_modules/@noodle-borg/authoring/dist/react/index.js +4 -2
  58. package/node_modules/@noodle-borg/authoring/dist/react/index.js.map +1 -1
  59. package/node_modules/@noodle-borg/authoring/dist/react/native-components.d.ts +1159 -0
  60. package/node_modules/@noodle-borg/authoring/dist/react/native-components.d.ts.map +1 -0
  61. package/node_modules/@noodle-borg/authoring/dist/react/native-components.js +66 -0
  62. package/node_modules/@noodle-borg/authoring/dist/react/native-components.js.map +1 -0
  63. package/node_modules/@noodle-borg/authoring/dist/react/semantic-components.d.ts +2618 -0
  64. package/node_modules/@noodle-borg/authoring/dist/react/semantic-components.d.ts.map +1 -0
  65. package/node_modules/@noodle-borg/authoring/dist/react/semantic-components.js +110 -0
  66. package/node_modules/@noodle-borg/authoring/dist/react/semantic-components.js.map +1 -0
  67. package/node_modules/@noodle-borg/authoring/dist/react.d.ts +2 -2
  68. package/node_modules/@noodle-borg/authoring/dist/react.d.ts.map +1 -1
  69. package/node_modules/@noodle-borg/authoring/dist/react.js +1 -1
  70. package/node_modules/@noodle-borg/authoring/dist/react.js.map +1 -1
  71. package/node_modules/@noodle-borg/authoring/dist/recording.d.ts +1 -1
  72. package/node_modules/@noodle-borg/authoring/dist/recording.d.ts.map +1 -1
  73. package/node_modules/@noodle-borg/authoring/dist/recording.js +14 -1
  74. package/node_modules/@noodle-borg/authoring/dist/recording.js.map +1 -1
  75. package/node_modules/@noodle-borg/authoring/dist/server.d.ts +25 -2
  76. package/node_modules/@noodle-borg/authoring/dist/server.d.ts.map +1 -1
  77. package/node_modules/@noodle-borg/authoring/dist/server.js +7 -3
  78. package/node_modules/@noodle-borg/authoring/dist/server.js.map +1 -1
  79. package/node_modules/@noodle-borg/compiler/dist/compile.d.ts.map +1 -1
  80. package/node_modules/@noodle-borg/compiler/dist/compile.js +20 -8
  81. package/node_modules/@noodle-borg/compiler/dist/compile.js.map +1 -1
  82. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts +2 -0
  83. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.d.ts.map +1 -1
  84. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js +6 -0
  85. package/node_modules/@noodle-borg/compiler/dist/manifest/schema.js.map +1 -1
  86. package/node_modules/@noodle-borg/connector-http/package.json +1 -1
  87. package/node_modules/@noodle-borg/protocol/dist/mapping.d.ts.map +1 -1
  88. package/node_modules/@noodle-borg/protocol/dist/mapping.js +8 -0
  89. package/node_modules/@noodle-borg/protocol/dist/mapping.js.map +1 -1
  90. package/node_modules/hono/dist/adapter/aws-lambda/handler.js +15 -21
  91. package/node_modules/hono/dist/adapter/bun/websocket.js +3 -1
  92. package/node_modules/hono/dist/adapter/lambda-edge/handler.js +8 -2
  93. package/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +15 -21
  94. package/node_modules/hono/dist/cjs/adapter/bun/websocket.js +3 -1
  95. package/node_modules/hono/dist/cjs/adapter/lambda-edge/handler.js +8 -2
  96. package/node_modules/hono/dist/cjs/helper/css/common.js +3 -1
  97. package/node_modules/hono/dist/cjs/helper/css/index.js +9 -1
  98. package/node_modules/hono/dist/cjs/jsx/base.js +8 -14
  99. package/node_modules/hono/dist/cjs/jsx/components.js +41 -21
  100. package/node_modules/hono/dist/cjs/jsx/context.js +131 -5
  101. package/node_modules/hono/dist/cjs/jsx/streaming.js +9 -7
  102. package/node_modules/hono/dist/cjs/middleware/cors/index.js +2 -5
  103. package/node_modules/hono/dist/cjs/middleware/serve-static/index.js +2 -2
  104. package/node_modules/hono/dist/cjs/utils/body.js +12 -4
  105. package/node_modules/hono/dist/cjs/utils/buffer.js +2 -1
  106. package/node_modules/hono/dist/cjs/validator/validator.js +3 -3
  107. package/node_modules/hono/dist/helper/css/common.js +3 -1
  108. package/node_modules/hono/dist/helper/css/index.js +9 -1
  109. package/node_modules/hono/dist/jsx/base.js +15 -15
  110. package/node_modules/hono/dist/jsx/components.js +42 -22
  111. package/node_modules/hono/dist/jsx/context.js +129 -5
  112. package/node_modules/hono/dist/jsx/streaming.js +10 -8
  113. package/node_modules/hono/dist/middleware/cors/index.js +2 -5
  114. package/node_modules/hono/dist/middleware/serve-static/index.js +2 -2
  115. package/node_modules/hono/dist/types/adapter/aws-lambda/handler.d.ts +1 -1
  116. package/node_modules/hono/dist/types/jsx/base.d.ts +1 -3
  117. package/node_modules/hono/dist/types/jsx/context.d.ts +39 -0
  118. package/node_modules/hono/dist/types/middleware/context-storage/index.d.ts +2 -2
  119. package/node_modules/hono/dist/types/utils/body.d.ts +1 -1
  120. package/node_modules/hono/dist/utils/body.js +12 -4
  121. package/node_modules/hono/dist/utils/buffer.js +2 -1
  122. package/node_modules/hono/dist/validator/validator.js +3 -3
  123. package/node_modules/hono/package.json +9 -10
  124. package/node_modules/tailwindcss/dist/chunk-HMCCH6MG.mjs +1 -0
  125. package/node_modules/tailwindcss/dist/default-theme.mjs +1 -1
  126. package/node_modules/tailwindcss/dist/lib.js +13 -13
  127. package/node_modules/tailwindcss/dist/lib.mjs +18 -18
  128. package/node_modules/tailwindcss/package.json +2 -2
  129. package/node_modules/undici/README.md +3 -2
  130. package/node_modules/undici/docs/docs/api/Agent.md +248 -44
  131. package/node_modules/undici/docs/docs/api/BalancedPool.md +246 -48
  132. package/node_modules/undici/docs/docs/api/CacheStorage.md +171 -13
  133. package/node_modules/undici/docs/docs/api/CacheStore.md +294 -98
  134. package/node_modules/undici/docs/docs/api/Client.md +365 -178
  135. package/node_modules/undici/docs/docs/api/ClientStats.md +80 -14
  136. package/node_modules/undici/docs/docs/api/Connector.md +118 -36
  137. package/node_modules/undici/docs/docs/api/ContentType.md +65 -25
  138. package/node_modules/undici/docs/docs/api/Cookies.md +125 -47
  139. package/node_modules/undici/docs/docs/api/Debug.md +34 -18
  140. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +364 -164
  141. package/node_modules/undici/docs/docs/api/Dispatcher.md +479 -1093
  142. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +101 -87
  143. package/node_modules/undici/docs/docs/api/Errors.md +503 -40
  144. package/node_modules/undici/docs/docs/api/EventSource.md +294 -32
  145. package/node_modules/undici/docs/docs/api/Fetch.md +680 -31
  146. package/node_modules/undici/docs/docs/api/GlobalInstallation.md +78 -98
  147. package/node_modules/undici/docs/docs/api/H2CClient.md +298 -176
  148. package/node_modules/undici/docs/docs/api/Interceptors.md +355 -0
  149. package/node_modules/undici/docs/docs/api/MockAgent.md +314 -322
  150. package/node_modules/undici/docs/docs/api/MockCallHistory.md +272 -98
  151. package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +189 -26
  152. package/node_modules/undici/docs/docs/api/MockClient.md +151 -33
  153. package/node_modules/undici/docs/docs/api/MockErrors.md +56 -5
  154. package/node_modules/undici/docs/docs/api/MockPool.md +299 -263
  155. package/node_modules/undici/docs/docs/api/Pool.md +235 -43
  156. package/node_modules/undici/docs/docs/api/PoolStats.md +119 -13
  157. package/node_modules/undici/docs/docs/api/ProxyAgent.md +179 -160
  158. package/node_modules/undici/docs/docs/api/RedirectHandler.md +238 -63
  159. package/node_modules/undici/docs/docs/api/RetryAgent.md +113 -26
  160. package/node_modules/undici/docs/docs/api/RetryHandler.md +161 -77
  161. package/node_modules/undici/docs/docs/api/RoundRobinPool.md +166 -72
  162. package/node_modules/undici/docs/docs/api/SnapshotAgent.md +264 -542
  163. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +162 -186
  164. package/node_modules/undici/docs/docs/api/Util.md +68 -11
  165. package/node_modules/undici/docs/docs/api/WebSocket.md +475 -80
  166. package/node_modules/undici/docs/docs/api/api-lifecycle.md +100 -32
  167. package/node_modules/undici/docs/docs/best-practices/client-certificate.md +2 -0
  168. package/node_modules/undici/docs/docs/best-practices/crawling.md +3 -1
  169. package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +6 -4
  170. package/node_modules/undici/docs/docs/best-practices/mocking-request.md +9 -7
  171. package/node_modules/undici/docs/docs/best-practices/proxy.md +3 -1
  172. package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +10 -8
  173. package/node_modules/undici/docs/docs/best-practices/writing-tests.md +2 -0
  174. package/node_modules/undici/docs/docs/{GettingStarted.md → getting-started.md} +22 -19
  175. package/node_modules/undici/docs/docs/index.md +779 -0
  176. package/node_modules/undici/docs/docs/site.json +125 -0
  177. package/node_modules/undici/docs/docs/type-map.json +79 -0
  178. package/node_modules/undici/lib/api/api-request.js +7 -1
  179. package/node_modules/undici/lib/api/readable.js +47 -2
  180. package/node_modules/undici/lib/core/errors.js +20 -0
  181. package/node_modules/undici/lib/core/request.js +1 -1
  182. package/node_modules/undici/lib/core/util.js +24 -1
  183. package/node_modules/undici/lib/dispatcher/client-h1.js +92 -1
  184. package/node_modules/undici/lib/dispatcher/client-h2.js +322 -118
  185. package/node_modules/undici/lib/dispatcher/client.js +6 -2
  186. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +1 -0
  187. package/node_modules/undici/lib/dispatcher/proxy-agent.js +42 -7
  188. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +4 -2
  189. package/node_modules/undici/lib/handler/redirect-handler.js +1 -0
  190. package/node_modules/undici/lib/handler/retry-handler.js +57 -19
  191. package/node_modules/undici/lib/util/cache.js +8 -2
  192. package/node_modules/undici/lib/web/cookies/parse.js +20 -27
  193. package/node_modules/undici/lib/web/cookies/util.js +1 -1
  194. package/node_modules/undici/lib/web/eventsource/eventsource.js +7 -18
  195. package/node_modules/undici/lib/web/eventsource/util.js +32 -1
  196. package/node_modules/undici/lib/web/fetch/body.js +43 -0
  197. package/node_modules/undici/lib/web/fetch/constants.js +1 -1
  198. package/node_modules/undici/lib/web/fetch/index.js +11 -2
  199. package/node_modules/undici/lib/web/fetch/request.js +1 -0
  200. package/node_modules/undici/lib/web/fetch/util.js +4 -1
  201. package/node_modules/undici/lib/web/websocket/receiver.js +20 -3
  202. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +8 -1
  203. package/node_modules/undici/lib/web/websocket/websocket.js +3 -1
  204. package/node_modules/undici/package.json +1 -1
  205. package/node_modules/undici/types/client.d.ts +6 -1
  206. package/node_modules/undici/types/cookies.d.ts +1 -1
  207. package/node_modules/undici/types/errors.d.ts +10 -0
  208. package/node_modules/undici/types/fetch.d.ts +1 -0
  209. package/node_modules/undici/types/handlers.d.ts +2 -0
  210. package/node_modules/undici/types/proxy-agent.d.ts +7 -0
  211. package/package.json +8 -6
  212. package/react/styles.css +851 -0
  213. package/react/styles.source.css +850 -0
  214. package/node_modules/hono/dist/tsconfig.build.tsbuildinfo +0 -1
  215. package/node_modules/tailwindcss/dist/chunk-XVOTX5KS.mjs +0 -1
@@ -395,7 +395,9 @@ class Client extends DispatcherBase {
395
395
  const requests = this[kQueue].splice(this[kPendingIdx])
396
396
  for (let i = 0; i < requests.length; i++) {
397
397
  const request = requests[i]
398
- util.errorRequest(this, request, err)
398
+ if (request != null) {
399
+ util.errorRequest(this, request, err)
400
+ }
399
401
  }
400
402
 
401
403
  const callback = () => {
@@ -434,7 +436,9 @@ function onError (client, err) {
434
436
 
435
437
  for (let i = 0; i < requests.length; i++) {
436
438
  const request = requests[i]
437
- util.errorRequest(client, request, err)
439
+ if (request != null) {
440
+ util.errorRequest(client, request, err)
441
+ }
438
442
  }
439
443
  assert(client[kSize] === 0)
440
444
  }
@@ -38,6 +38,7 @@ class DispatcherBase extends Dispatcher {
38
38
  */
39
39
  get webSocketOptions () {
40
40
  return {
41
+ maxFragments: this[kWebSocketOptions].maxFragments ?? 131072,
41
42
  maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024 // 128 MB default
42
43
  }
43
44
  }
@@ -4,7 +4,7 @@ const { kProxy, kClose, kDestroy, kDispatch } = require('../core/symbols')
4
4
  const Agent = require('./agent')
5
5
  const Pool = require('./pool')
6
6
  const DispatcherBase = require('./dispatcher-base')
7
- const { InvalidArgumentError, RequestAbortedError, SecureProxyConnectionError } = require('../core/errors')
7
+ const { InvalidArgumentError, RequestAbortedError, SecureProxyConnectionError, ProxyConnectionError } = require('../core/errors')
8
8
  const buildConnector = require('../core/connect')
9
9
  const Client = require('./client')
10
10
  const { channels } = require('../core/diagnostics')
@@ -37,10 +37,15 @@ function defaultAgentFactory (origin, opts) {
37
37
  return new Pool(origin, opts)
38
38
  }
39
39
 
40
+ function shouldProxyTunnel (requestProtocol, proxyTunnel) {
41
+ return proxyTunnel === true || requestProtocol !== 'http:'
42
+ }
43
+
40
44
  class Http1ProxyWrapper extends DispatcherBase {
41
45
  #client
46
+ #proxyServername
42
47
 
43
- constructor (proxyUrl, { headers = {}, connect, factory }) {
48
+ constructor (proxyUrl, { headers = {}, connect, factory, proxyServername }) {
44
49
  if (!proxyUrl) {
45
50
  throw new InvalidArgumentError('Proxy URL is mandatory')
46
51
  }
@@ -48,6 +53,7 @@ class Http1ProxyWrapper extends DispatcherBase {
48
53
  super()
49
54
 
50
55
  this[kProxyHeaders] = headers
56
+ this.#proxyServername = proxyServername
51
57
  if (factory) {
52
58
  this.#client = factory(proxyUrl, { connect })
53
59
  } else {
@@ -82,6 +88,13 @@ class Http1ProxyWrapper extends DispatcherBase {
82
88
  }
83
89
  opts.headers = { ...this[kProxyHeaders], ...headers }
84
90
 
91
+ // Pin the SNI/cert hostname to the proxy. Without this the underlying
92
+ // Client would derive it from the (rewritten) Host header, which points
93
+ // at the target — wrong for the TLS handshake to the proxy itself.
94
+ if (this.#proxyServername != null) {
95
+ opts.servername = this.#proxyServername
96
+ }
97
+
85
98
  return this.#client[kDispatch](opts, handler)
86
99
  }
87
100
 
@@ -105,7 +118,7 @@ class ProxyAgent extends DispatcherBase {
105
118
  throw new InvalidArgumentError('Proxy opts.clientFactory must be a function.')
106
119
  }
107
120
 
108
- const { proxyTunnel = true, connectTimeout } = opts
121
+ const { proxyTunnel, connectTimeout } = opts
109
122
 
110
123
  super()
111
124
 
@@ -132,6 +145,7 @@ class ProxyAgent extends DispatcherBase {
132
145
  }
133
146
 
134
147
  const connect = buildConnector({ timeout: connectTimeout, ...opts.proxyTls })
148
+ const connectHTTP1 = buildConnector({ timeout: connectTimeout, ...opts.proxyTls, allowH2: false })
135
149
  this[kConnectEndpoint] = buildConnector({ timeout: connectTimeout, ...opts.requestTls })
136
150
  this[kConnectEndpointHTTP1] = buildConnector({ timeout: connectTimeout, ...opts.requestTls, allowH2: false })
137
151
 
@@ -147,15 +161,28 @@ class ProxyAgent extends DispatcherBase {
147
161
  factory: agentFactory,
148
162
  username: opts.username || username,
149
163
  password: opts.password || password,
150
- proxyTls: opts.proxyTls
164
+ proxyTls: opts.proxyTls,
165
+ requestTls: opts.requestTls
151
166
  })
152
167
  }
153
168
 
154
- if (!this[kTunnelProxy] && protocol === 'http:' && this[kProxy].protocol === 'http:') {
169
+ if (!shouldProxyTunnel(protocol, this[kTunnelProxy])) {
170
+ const forwardConnect = this[kProxy].protocol === 'https:'
171
+ ? (opts, cb) => connectHTTP1(opts, (err, socket) => {
172
+ if (err && err.code === 'ERR_TLS_CERT_ALTNAME_INVALID') {
173
+ cb(new SecureProxyConnectionError(err))
174
+ } else {
175
+ cb(err, socket)
176
+ }
177
+ })
178
+ : connectHTTP1
155
179
  return new Http1ProxyWrapper(this[kProxy].uri, {
156
180
  headers: this[kProxyHeaders],
157
- connect,
158
- factory: agentFactory
181
+ connect: forwardConnect,
182
+ factory: agentFactory,
183
+ proxyServername: this[kProxy].protocol === 'https:'
184
+ ? (this[kProxyTls]?.servername || proxyHostname)
185
+ : undefined
159
186
  })
160
187
  }
161
188
  return agentFactory(origin, options)
@@ -230,6 +257,14 @@ class ProxyAgent extends DispatcherBase {
230
257
  if (err.code === 'ERR_TLS_CERT_ALTNAME_INVALID') {
231
258
  // Throw a custom error to avoid loop in client.js#connect
232
259
  callback(new SecureProxyConnectionError(err))
260
+ } else if (err.code === 'UND_ERR_SOCKET') {
261
+ // A socket failure while establishing the tunnel means the CONNECT
262
+ // never completed, so there is nothing to recover - the proxy just
263
+ // tore down the connection. client.js#onError treats UND_ERR_SOCKET
264
+ // as a recoverable error on an established connection and leaves the
265
+ // request queued, which makes connect() retry forever. Surface it as
266
+ // a non-recoverable proxy error so the request fails instead. (#3897)
267
+ callback(new ProxyConnectionError(err))
233
268
  } else {
234
269
  callback(err)
235
270
  }
@@ -19,6 +19,7 @@ const kProxyAuth = Symbol('proxy auth')
19
19
  const kProxyProtocol = Symbol('proxy protocol')
20
20
  const kPools = Symbol('pools')
21
21
  const kConnector = Symbol('connector')
22
+ const kRequestTls = Symbol('request tls settings')
22
23
 
23
24
  // Static flag to ensure warning is only emitted once per process
24
25
  let experimentalWarningEmitted = false
@@ -53,6 +54,7 @@ class Socks5ProxyAgent extends DispatcherBase {
53
54
  this[kProxyUrl] = url
54
55
  this[kProxyHeaders] = options.headers || {}
55
56
  this[kProxyProtocol] = options.proxyTls ? 'https:' : 'http:'
57
+ this[kRequestTls] = options.requestTls
56
58
 
57
59
  // Extract auth from URL or options
58
60
  this[kProxyAuth] = {
@@ -205,9 +207,9 @@ class Socks5ProxyAgent extends DispatcherBase {
205
207
  }
206
208
  debug('upgrading to TLS')
207
209
  finalSocket = tls.connect({
210
+ ...this[kRequestTls],
208
211
  socket,
209
- servername: targetHost,
210
- ...connectOpts.tls || {}
212
+ servername: this[kRequestTls]?.servername || targetHost
211
213
  })
212
214
 
213
215
  const tlsReady = Promise.withResolvers()
@@ -55,6 +55,7 @@ class RedirectHandler {
55
55
  // https://tools.ietf.org/html/rfc7231#section-6.4.2
56
56
  // https://fetch.spec.whatwg.org/#http-redirect-fetch
57
57
  // In case of HTTP 301 or 302 with POST, change the method to GET
58
+ // QUERY is safe (RFC 10008) and should not change method like GET.
58
59
  if ((statusCode === 301 || statusCode === 302) && this.opts.method === 'POST') {
59
60
  this.opts.method = 'GET'
60
61
  if (util.isStream(this.opts.body)) {
@@ -14,6 +14,28 @@ function calculateRetryAfterHeader (retryAfter) {
14
14
  return isNaN(retryTime) ? 0 : retryTime - Date.now()
15
15
  }
16
16
 
17
+ // A stable controller handed to the downstream handler for the lifetime of the
18
+ // request. Each transparent retry/resume is a *separate* dispatch with its
19
+ // *own* connection controller. Without a stable proxy the downstream body keeps
20
+ // flow-controlling the original (now-dead) controller while data flows on the
21
+ // new one: backpressure pauses the new connection's controller, but the
22
+ // consumer's resume() targets the old one, so the resumed body stalls forever.
23
+ // The proxy always forwards to the controller of the currently active connection.
24
+ class RetryController {
25
+ constructor () {
26
+ this.target = null
27
+ }
28
+
29
+ pause () { this.target?.pause() }
30
+ resume () { this.target?.resume() }
31
+ abort (reason) { this.target?.abort(reason) }
32
+ get paused () { return this.target?.paused ?? false }
33
+ get aborted () { return this.target?.aborted ?? false }
34
+ get reason () { return this.target?.reason ?? null }
35
+ get rawHeaders () { return this.target?.rawHeaders ?? null }
36
+ get rawTrailers () { return this.target?.rawTrailers ?? null }
37
+ }
38
+
17
39
  class RetryHandler {
18
40
  constructor (opts, { dispatch, handler }) {
19
41
  const { retryOptions, ...dispatchOpts } = opts
@@ -45,7 +67,7 @@ class RetryHandler {
45
67
  timeoutFactor: timeoutFactor ?? 2,
46
68
  maxRetries: maxRetries ?? 5,
47
69
  // What errors we should retry
48
- methods: methods ?? ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE'],
70
+ methods: methods ?? ['GET', 'HEAD', 'OPTIONS', 'PUT', 'DELETE', 'TRACE', 'QUERY'],
49
71
  // Indicates which errors to retry
50
72
  statusCodes: statusCodes ?? [500, 502, 503, 504, 429],
51
73
  // List of errors to retry
@@ -70,6 +92,7 @@ class RetryHandler {
70
92
  this.etag = null
71
93
  this.statusCode = null
72
94
  this.headers = null
95
+ this.controllerProxy = new RetryController()
73
96
  }
74
97
 
75
98
  onResponseStartWithRetry (controller, statusCode, headers, statusMessage, err) {
@@ -77,7 +100,7 @@ class RetryHandler {
77
100
  // Preserve old behavior for status codes that are not eligible for retry
78
101
  if (this.retryOpts.statusCodes.includes(statusCode) === false) {
79
102
  this.headersSent = true
80
- this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage)
103
+ this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage)
81
104
  } else {
82
105
  this.error = err
83
106
  }
@@ -87,14 +110,14 @@ class RetryHandler {
87
110
 
88
111
  if (isDisturbed(this.opts.body)) {
89
112
  this.headersSent = true
90
- this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage)
113
+ this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage)
91
114
  return
92
115
  }
93
116
 
94
117
  function shouldRetry (passedErr) {
95
118
  if (passedErr) {
96
119
  this.headersSent = true
97
- this.handler.onResponseStart?.(controller, statusCode, headers, statusMessage)
120
+ this.handler.onResponseStart?.(this.controllerProxy, statusCode, headers, statusMessage)
98
121
  controller.resume()
99
122
  return
100
123
  }
@@ -103,6 +126,13 @@ class RetryHandler {
103
126
  controller.resume()
104
127
  }
105
128
 
129
+ // The pause()/resume() pair (here and in shouldRetry) acts on THIS
130
+ // connection's controller -- never the downstream proxy. We hold this exact
131
+ // connection while the retry policy decides (possibly after a timeout) and
132
+ // must resume the same one. Routing this through controllerProxy would risk
133
+ // resuming a different connection if a later dispatch re-points the proxy in
134
+ // between, leaving this one paused forever -- the very stall the proxy exists
135
+ // to prevent.
106
136
  controller.pause()
107
137
  this.retryOpts.retry(
108
138
  err,
@@ -115,13 +145,19 @@ class RetryHandler {
115
145
  }
116
146
 
117
147
  onRequestStart (controller, context) {
148
+ // request.js creates a fresh RequestController per dispatch and passes that
149
+ // same instance to every later callback of the dispatch. onRequestStart is
150
+ // the first callback (it is where the controller is created), so re-pointing
151
+ // the proxy here is enough to keep it on the active connection across every
152
+ // transparent retry/resume.
153
+ this.controllerProxy.target = controller
118
154
  if (!this.headersSent) {
119
- this.handler.onRequestStart?.(controller, context)
155
+ this.handler.onRequestStart?.(this.controllerProxy, context)
120
156
  }
121
157
  }
122
158
 
123
- onRequestUpgrade (controller, statusCode, headers, socket) {
124
- this.handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
159
+ onRequestUpgrade (_controller, statusCode, headers, socket) {
160
+ this.handler.onRequestUpgrade?.(this.controllerProxy, statusCode, headers, socket)
125
161
  }
126
162
 
127
163
  static [kRetryHandlerDefaultRetry] (err, { state, opts }, cb) {
@@ -248,7 +284,7 @@ class RetryHandler {
248
284
  if (range == null) {
249
285
  this.headersSent = true
250
286
  this.handler.onResponseStart?.(
251
- controller,
287
+ this.controllerProxy,
252
288
  statusCode,
253
289
  headers,
254
290
  statusMessage
@@ -295,7 +331,7 @@ class RetryHandler {
295
331
 
296
332
  this.headersSent = true
297
333
  this.handler.onResponseStart?.(
298
- controller,
334
+ this.controllerProxy,
299
335
  statusCode,
300
336
  headers,
301
337
  statusMessage
@@ -308,17 +344,17 @@ class RetryHandler {
308
344
  }
309
345
  }
310
346
 
311
- onResponseData (controller, chunk) {
347
+ onResponseData (_controller, chunk) {
312
348
  if (this.error) {
313
349
  return
314
350
  }
315
351
 
316
352
  this.start += chunk.length
317
353
 
318
- this.handler.onResponseData?.(controller, chunk)
354
+ this.handler.onResponseData?.(this.controllerProxy, chunk)
319
355
  }
320
356
 
321
- onResponseEnd (controller, trailers) {
357
+ onResponseEnd (_controller, trailers) {
322
358
  if (this.error && this.retryOpts.throwOnError) {
323
359
  throw this.error
324
360
  }
@@ -335,13 +371,13 @@ class RetryHandler {
335
371
  }
336
372
  }
337
373
  this.retryCount = 0
338
- return this.handler.onResponseEnd?.(controller, trailers)
374
+ return this.handler.onResponseEnd?.(this.controllerProxy, trailers)
339
375
  }
340
376
 
341
- this.retry(controller)
377
+ this.retry()
342
378
  }
343
379
 
344
- retry (controller) {
380
+ retry () {
345
381
  if (this.start !== 0) {
346
382
  const headers = { range: `bytes=${this.start}-${this.end ?? ''}` }
347
383
 
@@ -363,23 +399,25 @@ class RetryHandler {
363
399
  this.retryCountCheckpoint = this.retryCount
364
400
  this.dispatch(this.opts, this)
365
401
  } catch (err) {
366
- this.handler.onResponseError?.(controller, err)
402
+ this.handler.onResponseError?.(this.controllerProxy, err)
367
403
  }
368
404
  }
369
405
 
370
406
  onResponseError (controller, err) {
407
+ // controller is THIS failed connection (not the proxy): we inspect whether
408
+ // the consumer aborted it to decide retry-vs-propagate.
371
409
  if (controller?.aborted || isDisturbed(this.opts.body)) {
372
- this.handler.onResponseError?.(controller, err)
410
+ this.handler.onResponseError?.(this.controllerProxy, err)
373
411
  return
374
412
  }
375
413
 
376
414
  function shouldRetry (returnedErr) {
377
415
  if (!returnedErr) {
378
- this.retry(controller)
416
+ this.retry()
379
417
  return
380
418
  }
381
419
 
382
- this.handler?.onResponseError?.(controller, returnedErr)
420
+ this.handler?.onResponseError?.(this.controllerProxy, returnedErr)
383
421
  }
384
422
 
385
423
  // We reconcile in case of a mix between network errors
@@ -228,6 +228,10 @@ function parseCacheControlHeader (header) {
228
228
  headers[headers.length - 1] = lastHeader
229
229
  }
230
230
 
231
+ for (let j = 0; j < headers.length; j++) {
232
+ headers[j] = headers[j].trim()
233
+ }
234
+
231
235
  if (key in output) {
232
236
  output[key] = output[key].concat(headers)
233
237
  } else {
@@ -236,10 +240,12 @@ function parseCacheControlHeader (header) {
236
240
  }
237
241
  } else {
238
242
  // Something like `no-cache="some-header"`
243
+ const fieldName = value.trim()
244
+
239
245
  if (key in output) {
240
- output[key] = output[key].concat(value)
246
+ output[key] = output[key].concat(fieldName)
241
247
  } else {
242
- output[key] = [value]
248
+ output[key] = [fieldName]
243
249
  }
244
250
  }
245
251
 
@@ -4,7 +4,6 @@ const { collectASequenceOfCodePointsFast } = require('../infra')
4
4
  const { maxNameValuePairSize, maxAttributeValueSize } = require('./constants')
5
5
  const { isCTLExcludingHtab } = require('./util')
6
6
  const assert = require('node:assert')
7
- const { unescape: qsUnescape } = require('node:querystring')
8
7
 
9
8
  /**
10
9
  * @description Parses the field-value attributes of a set-cookie header string.
@@ -82,7 +81,7 @@ function parseSetCookie (header) {
82
81
  // store arbitrary data in a cookie-value SHOULD encode that data, for
83
82
  // example, using Base64 [RFC4648].
84
83
  return {
85
- name, value: qsUnescape(value), ...parseUnparsedAttributes(unparsedAttributes)
84
+ name, value, ...parseUnparsedAttributes(unparsedAttributes)
86
85
  }
87
86
  }
88
87
 
@@ -179,8 +178,9 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {})
179
178
 
180
179
  // 2. If the attribute-value failed to parse as a cookie date, ignore
181
180
  // the cookie-av.
182
-
183
- cookieAttributeList.expires = expiryTime
181
+ if (!Number.isNaN(expiryTime.getTime())) {
182
+ cookieAttributeList.expires = expiryTime
183
+ }
184
184
  } else if (attributeNameLowercase === 'max-age') {
185
185
  // https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis#section-5.4.2
186
186
  // If the attribute-name case-insensitively matches the string "Max-
@@ -280,32 +280,25 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {})
280
280
  // If the attribute-name case-insensitively matches the string
281
281
  // "SameSite", the user agent MUST process the cookie-av as follows:
282
282
 
283
- // 1. Let enforcement be "Default".
284
- let enforcement = 'Default'
285
-
286
283
  const attributeValueLowercase = attributeValue.toLowerCase()
287
- // 2. If cookie-av's attribute-value is a case-insensitive match for
288
- // "None", set enforcement to "None".
289
- if (attributeValueLowercase.includes('none')) {
290
- enforcement = 'None'
291
- }
292
284
 
293
- // 3. If cookie-av's attribute-value is a case-insensitive match for
294
- // "Strict", set enforcement to "Strict".
295
- if (attributeValueLowercase.includes('strict')) {
296
- enforcement = 'Strict'
285
+ // 1. If cookie-av's attribute-value is a case-insensitive match for
286
+ // "None", append an attribute to the cookie-attribute-list with an
287
+ // attribute-name of "SameSite" and an attribute-value of "None".
288
+ if (attributeValueLowercase === 'none') {
289
+ cookieAttributeList.sameSite = 'None'
290
+ } else if (attributeValueLowercase === 'strict') {
291
+ // 2. If cookie-av's attribute-value is a case-insensitive match for
292
+ // "Strict", append an attribute to the cookie-attribute-list with
293
+ // an attribute-name of "SameSite" and an attribute-value of
294
+ // "Strict".
295
+ cookieAttributeList.sameSite = 'Strict'
296
+ } else if (attributeValueLowercase === 'lax') {
297
+ // 3. If cookie-av's attribute-value is a case-insensitive match for
298
+ // "Lax", append an attribute to the cookie-attribute-list with an
299
+ // attribute-name of "SameSite" and an attribute-value of "Lax".
300
+ cookieAttributeList.sameSite = 'Lax'
297
301
  }
298
-
299
- // 4. If cookie-av's attribute-value is a case-insensitive match for
300
- // "Lax", set enforcement to "Lax".
301
- if (attributeValueLowercase.includes('lax')) {
302
- enforcement = 'Lax'
303
- }
304
-
305
- // 5. Append an attribute to the cookie-attribute-list with an
306
- // attribute-name of "SameSite" and an attribute-value of
307
- // enforcement.
308
- cookieAttributeList.sameSite = enforcement
309
302
  } else {
310
303
  cookieAttributeList.unparsed ??= []
311
304
 
@@ -105,7 +105,7 @@ function validateCookiePath (path) {
105
105
 
106
106
  if (
107
107
  code < 0x20 || // exclude CTLs (0-31)
108
- code === 0x7F || // DEL
108
+ code > 0x7E || // exclude non-ascii and DEL
109
109
  code === 0x3B // ;
110
110
  ) {
111
111
  throw new Error('Invalid cookie path')
@@ -2,7 +2,6 @@
2
2
 
3
3
  const { pipeline } = require('node:stream')
4
4
  const { fetching } = require('../fetch')
5
- const { makeRequest } = require('../fetch/request')
6
5
  const { webidl } = require('../webidl')
7
6
  const { EventSourceStream } = require('./eventsource-stream')
8
7
  const { parseMIMEType } = require('../fetch/data-url')
@@ -10,6 +9,7 @@ const { createFastMessageEvent } = require('../websocket/events')
10
9
  const { isNetworkError } = require('../fetch/response')
11
10
  const { kEnumerableProperty } = require('../../core/util')
12
11
  const { environmentSettingsObject } = require('../fetch/util')
12
+ const { createPotentialCORSRequest } = require('./util')
13
13
 
14
14
  let experimentalWarned = false
15
15
 
@@ -160,33 +160,22 @@ class EventSource extends EventTarget {
160
160
 
161
161
  // 8. Let request be the result of creating a potential-CORS request given
162
162
  // urlRecord, the empty string, and corsAttributeState.
163
- const initRequest = {
164
- redirect: 'follow',
165
- keepalive: true,
166
- // @see https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
167
- mode: 'cors',
168
- credentials: corsAttributeState === 'anonymous'
169
- ? 'same-origin'
170
- : 'omit',
171
- referrer: 'no-referrer'
172
- }
163
+ const request = createPotentialCORSRequest(urlRecord, '', corsAttributeState)
173
164
 
174
165
  // 9. Set request's client to settings.
175
- initRequest.client = environmentSettingsObject.settingsObject
166
+ request.client = environmentSettingsObject.settingsObject
176
167
 
177
168
  // 10. User agents may set (`Accept`, `text/event-stream`) in request's header list.
178
- initRequest.headersList = [['accept', { name: 'accept', value: 'text/event-stream' }]]
169
+ request.headersList.set('Accept', 'text/event-stream')
179
170
 
180
171
  // 11. Set request's cache mode to "no-store".
181
- initRequest.cache = 'no-store'
172
+ request.cache = 'no-store'
182
173
 
183
174
  // 12. Set request's initiator type to "other".
184
- initRequest.initiator = 'other'
185
-
186
- initRequest.urlList = [new URL(this.#url)]
175
+ request.initiator = 'other'
187
176
 
188
177
  // 13. Set ev's request to request.
189
- this.#request = makeRequest(initRequest)
178
+ this.#request = request
190
179
 
191
180
  this.#connect()
192
181
  }
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const { makeRequest } = require('../fetch/request')
4
+
3
5
  /**
4
6
  * Checks if the given value is a valid LastEventId.
5
7
  * @param {string} value
@@ -23,7 +25,36 @@ function isASCIINumber (value) {
23
25
  return true
24
26
  }
25
27
 
28
+ function createPotentialCORSRequest (url, destination, corsAttributeState, sameOriginFallback) {
29
+ // 1. Let mode be "no-cors" if corsAttributeState is No CORS, and "cors" otherwise.
30
+ let mode = corsAttributeState === 'no cors' ? 'no-cors' : 'cors'
31
+
32
+ // 2. If same-origin fallback flag is set and mode is "no-cors", set mode to "same-origin".
33
+ if (sameOriginFallback && mode === 'no-cors') {
34
+ mode = 'same-origin'
35
+ }
36
+
37
+ // 3. Let credentialsMode be "include".
38
+ let credentialsMode = 'include'
39
+
40
+ // 4. If corsAttributeState is Anonymous, set credentialsMode to "same-origin".
41
+ if (corsAttributeState === 'anonymous') {
42
+ credentialsMode = 'same-origin'
43
+ }
44
+
45
+ // 5. Return a new request whose URL is url, destination is destination, mode is mode,
46
+ // credentials mode is credentialsMode, and whose use-URL-credentials flag is set.
47
+ return makeRequest({
48
+ urlList: [url],
49
+ destination,
50
+ mode,
51
+ credentials: credentialsMode,
52
+ useURLCredentials: true
53
+ })
54
+ }
55
+
26
56
  module.exports = {
27
57
  isValidLastEventId,
28
- isASCIINumber
58
+ isASCIINumber,
59
+ createPotentialCORSRequest
29
60
  }
@@ -392,6 +392,49 @@ function bodyMixinMethods (instance, getInternalState) {
392
392
  return consumeBody(this, (bytes) => {
393
393
  return new Uint8Array(bytes)
394
394
  }, instance, getInternalState)
395
+ },
396
+
397
+ textStream () {
398
+ const this_ = getInternalState(this)
399
+
400
+ // 1. If this is unusable, then throw a TypeError.
401
+ if (bodyUnusable(this_)) {
402
+ throw new TypeError('Body is unusable: Body has already been read')
403
+ }
404
+
405
+ // 2. If this’s body is null:
406
+ if (this_.body == null) {
407
+ // 2.1. Let emptyStream be a new ReadableStream in this’s relevant realm.
408
+ // 2.2. Set up emptyStream.
409
+ /** @type {ReadableStreamDefaultController<any>} */
410
+ let controller
411
+ const emptyStream = new ReadableStream({
412
+ start: (c) => {
413
+ controller = c
414
+ },
415
+ pull: () => Promise.resolve(),
416
+ cancel: () => Promise.resolve()
417
+ }, {
418
+ size: () => 1
419
+ })
420
+
421
+ // 2.3. Close emptyStream.
422
+ controller.close()
423
+
424
+ // 2.4. Return emptyStream.
425
+ return emptyStream
426
+ }
427
+
428
+ // 3. Let stream be this’s body’s stream.
429
+ /** @type {ReadableStream} */
430
+ const stream = this_.body.stream
431
+
432
+ // 4. Let decoder be a new TextDecoderStream object in this’s relevant realm.
433
+ // 5. Set up decoder with UTF-8.
434
+ const decoder = new TextDecoderStream('UTF-8')
435
+
436
+ // 6. Return the result of stream, piped through decoder.
437
+ return stream.pipeThrough(decoder)
395
438
  }
396
439
  }
397
440
 
@@ -46,7 +46,7 @@ const referrerPolicyTokensSet = new Set(referrerPolicyTokens)
46
46
 
47
47
  const requestRedirect = /** @type {const} */ (['follow', 'manual', 'error'])
48
48
 
49
- const safeMethods = /** @type {const} */ (['GET', 'HEAD', 'OPTIONS', 'TRACE'])
49
+ const safeMethods = /** @type {const} */ (['GET', 'HEAD', 'OPTIONS', 'TRACE', 'QUERY'])
50
50
  const safeMethodsSet = new Set(safeMethods)
51
51
 
52
52
  const requestMode = /** @type {const} */ (['navigate', 'same-origin', 'no-cors', 'cors'])