@openclaw/discord 2026.6.33 → 2026.6.35

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 (179) hide show
  1. package/dist/action-runtime-api.js +1 -1
  2. package/dist/{api-CjnGBhM3.js → api-1GXlSrYP.js} +42 -21
  3. package/dist/api.js +14 -14
  4. package/dist/{approval-handler.runtime-BWPQrzpP.js → approval-handler.runtime-Dv4p7REU.js} +3 -3
  5. package/dist/{audit-BwJ_2OjL.js → audit-DEVi9nIs.js} +3 -3
  6. package/dist/{channel-Ddnonoy4.js → channel-CQIRiosn.js} +15 -15
  7. package/dist/{channel-actions-CwmIqnYN.js → channel-actions-JziPEcBU.js} +2 -2
  8. package/dist/{channel-actions.runtime-DvpTfaJ4.js → channel-actions.runtime-D7L47LY3.js} +5 -5
  9. package/dist/channel-plugin-api.js +1 -1
  10. package/dist/{channel.setup-glZ5Y98a.js → channel.setup-oMeR19Cc.js} +2 -2
  11. package/dist/{components-j6lTZBsT.js → components-_s5UPJqU.js} +1 -1
  12. package/dist/{conversation-identity-36FFBwm5.js → conversation-identity-B0k94-bz.js} +2 -2
  13. package/dist/{directory-config-BYMFzL29.js → directory-config-CD1svkyN.js} +1 -1
  14. package/dist/directory-contract-api.js +1 -1
  15. package/dist/{directory-live-9JtJCiu8.js → directory-live-DBTsSRxl.js} +5 -5
  16. package/dist/{handle-action.guild-admin-xxGYrp-I.js → handle-action.guild-admin-CYIFMxh-.js} +2 -2
  17. package/dist/index.js +1 -1
  18. package/dist/{manager.runtime-BK6cf2Zu.js → manager.runtime-BZVdGX2d.js} +17 -9
  19. package/dist/{message-handler-BqpJIavO.js → message-handler-DZd9Bpq8.js} +7 -6
  20. package/dist/{message-handler.preflight-C90MxCcv.js → message-handler.preflight-Axv9J9EO.js} +12 -11
  21. package/dist/{message-handler.process-CeQ7Bd_3.js → message-handler.process-CG0zFS-Z.js} +10 -10
  22. package/dist/{message-utils-CJeAoISH.js → message-utils-Dbuw27gd.js} +1 -1
  23. package/dist/{outbound-adapter-Dxs6iKEq.js → outbound-adapter-CKC_kmUN.js} +6 -6
  24. package/dist/pluralkit-CfTReLl3.js +40 -0
  25. package/dist/{probe-esE_Oqdm.js → probe-DcgZIpyF.js} +3 -2
  26. package/dist/{probe.runtime-C3Atgpvr.js → probe.runtime-CVwM9L5E.js} +1 -1
  27. package/dist/{provider-C7376XFH.js → provider-CwwSXIIj.js} +102 -37
  28. package/dist/{provider-session.runtime-CCdqogGf.js → provider-session.runtime-reBWkqHZ.js} +3 -3
  29. package/dist/provider.runtime-BsmTLYS_.js +2 -0
  30. package/dist/{resolve-allowlist-common-3gB2Gpmm.js → resolve-allowlist-common-D7bZqAw3.js} +3 -3
  31. package/dist/{resolve-channels-B3gQf8QL.js → resolve-channels--oE-RnO6.js} +6 -6
  32. package/dist/{resolve-users-BO10y5fJ.js → resolve-users-QXo8CXBU.js} +5 -5
  33. package/dist/{runtime-CFlR3L9X.js → runtime-CF7ramAs.js} +7 -7
  34. package/dist/runtime-api.actions.js +2 -2
  35. package/dist/runtime-api.js +19 -19
  36. package/dist/runtime-api.lookup.js +5 -5
  37. package/dist/runtime-api.monitor-CzF8MUl_.js +6 -0
  38. package/dist/runtime-api.monitor.js +5 -5
  39. package/dist/runtime-api.send.js +5 -5
  40. package/dist/runtime-api.threads.js +3 -3
  41. package/dist/{send-JHxfT4Pk.js → send-Bb295iHT.js} +5 -5
  42. package/dist/{send.components-CN35E2Ck.js → send.components-COkDUO3B.js} +4 -4
  43. package/dist/{send.outbound-B-cA1Esv.js → send.outbound-B_sk0hNe.js} +3 -3
  44. package/dist/{send.receipt-CGecJDin.js → send.receipt-Cli6_9Sn.js} +19 -7
  45. package/dist/{send.shared-vcbfThdy.js → send.shared-BCG7MWnP.js} +2 -2
  46. package/dist/session-binding-contract-api.js +1 -1
  47. package/dist/setup-plugin-api.js +1 -1
  48. package/dist/{subagent-hooks-20wXhVzZ.js → subagent-hooks-CtqoWK4x.js} +2 -2
  49. package/dist/subagent-hooks-api.js +1 -1
  50. package/dist/{system-events-DR27TE7p.js → system-events-BxGNk_wE.js} +1 -1
  51. package/dist/{target-resolver-CDi1gI90.js → target-resolver-BcoK6b0g.js} +2 -2
  52. package/dist/targets-Q-ZoP7K4.js +3 -0
  53. package/dist/{thread-bindings-DU4T6nDo.js → thread-bindings-DJ_HT6GJ.js} +4 -4
  54. package/dist/{thread-bindings.discord-api-CYkr-3Gj.js → thread-bindings.discord-api-OPyjvgyz.js} +4 -4
  55. package/dist/{thread-bindings.manager-BqWs1UE2.js → thread-bindings.manager-Cd2HAVw_.js} +3 -3
  56. package/dist/{transcripts-source-D-lBI5ZD.js → transcripts-source-CPf5gURy.js} +1 -1
  57. package/dist/transcripts-source-api.js +1 -1
  58. package/dist/{typing-xr05bL-r.js → typing-DY0cwLdg.js} +1 -1
  59. package/node_modules/undici/README.md +8 -2
  60. package/node_modules/undici/docs/docs/api/Agent.md +248 -44
  61. package/node_modules/undici/docs/docs/api/BalancedPool.md +246 -48
  62. package/node_modules/undici/docs/docs/api/CacheStorage.md +171 -13
  63. package/node_modules/undici/docs/docs/api/CacheStore.md +294 -98
  64. package/node_modules/undici/docs/docs/api/Client.md +386 -179
  65. package/node_modules/undici/docs/docs/api/ClientStats.md +80 -14
  66. package/node_modules/undici/docs/docs/api/Connector.md +118 -36
  67. package/node_modules/undici/docs/docs/api/ContentType.md +65 -25
  68. package/node_modules/undici/docs/docs/api/Cookies.md +122 -71
  69. package/node_modules/undici/docs/docs/api/Debug.md +34 -18
  70. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +364 -164
  71. package/node_modules/undici/docs/docs/api/Dispatcher.md +485 -1102
  72. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +102 -87
  73. package/node_modules/undici/docs/docs/api/Errors.md +503 -40
  74. package/node_modules/undici/docs/docs/api/EventSource.md +298 -32
  75. package/node_modules/undici/docs/docs/api/Fetch.md +680 -31
  76. package/node_modules/undici/docs/docs/api/GlobalInstallation.md +78 -98
  77. package/node_modules/undici/docs/docs/api/H2CClient.md +298 -176
  78. package/node_modules/undici/docs/docs/api/Interceptors.md +418 -0
  79. package/node_modules/undici/docs/docs/api/MockAgent.md +333 -314
  80. package/node_modules/undici/docs/docs/api/MockCallHistory.md +272 -98
  81. package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +189 -26
  82. package/node_modules/undici/docs/docs/api/MockClient.md +151 -33
  83. package/node_modules/undici/docs/docs/api/MockErrors.md +56 -5
  84. package/node_modules/undici/docs/docs/api/MockPool.md +321 -258
  85. package/node_modules/undici/docs/docs/api/Pool.md +235 -43
  86. package/node_modules/undici/docs/docs/api/PoolStats.md +119 -13
  87. package/node_modules/undici/docs/docs/api/ProxyAgent.md +179 -160
  88. package/node_modules/undici/docs/docs/api/RedirectHandler.md +238 -63
  89. package/node_modules/undici/docs/docs/api/RetryAgent.md +113 -26
  90. package/node_modules/undici/docs/docs/api/RetryHandler.md +161 -77
  91. package/node_modules/undici/docs/docs/api/RoundRobinPool.md +166 -72
  92. package/node_modules/undici/docs/docs/api/SnapshotAgent.md +264 -542
  93. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +177 -196
  94. package/node_modules/undici/docs/docs/api/Util.md +68 -11
  95. package/node_modules/undici/docs/docs/api/WebSocket.md +475 -80
  96. package/node_modules/undici/docs/docs/api/api-lifecycle.md +100 -32
  97. package/node_modules/undici/docs/docs/best-practices/client-certificate.md +2 -0
  98. package/node_modules/undici/docs/docs/best-practices/crawling.md +3 -1
  99. package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +6 -4
  100. package/node_modules/undici/docs/docs/best-practices/mocking-request.md +9 -7
  101. package/node_modules/undici/docs/docs/best-practices/proxy.md +3 -1
  102. package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +10 -8
  103. package/node_modules/undici/docs/docs/best-practices/writing-tests.md +2 -0
  104. package/node_modules/undici/docs/docs/{GettingStarted.md → getting-started.md} +22 -19
  105. package/node_modules/undici/docs/docs/index.md +784 -0
  106. package/node_modules/undici/docs/docs/site.json +125 -0
  107. package/node_modules/undici/docs/docs/type-map.json +79 -0
  108. package/node_modules/undici/lib/api/api-request.js +7 -1
  109. package/node_modules/undici/lib/api/readable.js +42 -7
  110. package/node_modules/undici/lib/cache/memory-cache-store.js +56 -11
  111. package/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
  112. package/node_modules/undici/lib/core/connect.js +16 -2
  113. package/node_modules/undici/lib/core/errors.js +20 -0
  114. package/node_modules/undici/lib/core/request.js +14 -3
  115. package/node_modules/undici/lib/core/symbols.js +3 -0
  116. package/node_modules/undici/lib/core/util.js +30 -2
  117. package/node_modules/undici/lib/dispatcher/agent.js +10 -5
  118. package/node_modules/undici/lib/dispatcher/balanced-pool.js +7 -4
  119. package/node_modules/undici/lib/dispatcher/client-h1.js +74 -9
  120. package/node_modules/undici/lib/dispatcher/client-h2.js +483 -151
  121. package/node_modules/undici/lib/dispatcher/client.js +76 -30
  122. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +13 -1
  123. package/node_modules/undici/lib/dispatcher/dispatcher.js +15 -1
  124. package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +3 -0
  125. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +37 -8
  126. package/node_modules/undici/lib/dispatcher/proxy-agent.js +58 -7
  127. package/node_modules/undici/lib/dispatcher/retry-agent.js +3 -0
  128. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +1 -1
  129. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +106 -22
  130. package/node_modules/undici/lib/global.js +36 -16
  131. package/node_modules/undici/lib/handler/cache-handler.js +297 -65
  132. package/node_modules/undici/lib/handler/cache-revalidation-handler.js +13 -3
  133. package/node_modules/undici/lib/handler/decorator-handler.js +7 -1
  134. package/node_modules/undici/lib/handler/deduplication-handler.js +12 -6
  135. package/node_modules/undici/lib/handler/redirect-handler.js +26 -5
  136. package/node_modules/undici/lib/handler/retry-handler.js +238 -51
  137. package/node_modules/undici/lib/interceptor/cache.js +221 -58
  138. package/node_modules/undici/lib/interceptor/decompress.js +124 -15
  139. package/node_modules/undici/lib/interceptor/deduplicate.js +5 -4
  140. package/node_modules/undici/lib/interceptor/dns.js +7 -0
  141. package/node_modules/undici/lib/interceptor/dump.js +10 -23
  142. package/node_modules/undici/lib/mock/mock-agent.js +13 -1
  143. package/node_modules/undici/lib/mock/mock-interceptor.js +25 -7
  144. package/node_modules/undici/lib/mock/mock-utils.js +246 -27
  145. package/node_modules/undici/lib/util/cache.js +415 -71
  146. package/node_modules/undici/lib/util/date.js +23 -6
  147. package/node_modules/undici/lib/web/cookies/parse.js +150 -146
  148. package/node_modules/undici/lib/web/cookies/util.js +79 -9
  149. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +28 -1
  150. package/node_modules/undici/lib/web/eventsource/eventsource.js +13 -3
  151. package/node_modules/undici/lib/web/eventsource/util.js +1 -1
  152. package/node_modules/undici/lib/web/fetch/body.js +2 -1
  153. package/node_modules/undici/lib/web/fetch/constants.js +1 -1
  154. package/node_modules/undici/lib/web/fetch/index.js +17 -2
  155. package/node_modules/undici/lib/web/fetch/request.js +2 -3
  156. package/node_modules/undici/lib/web/fetch/response.js +1 -3
  157. package/node_modules/undici/lib/web/fetch/util.js +10 -2
  158. package/node_modules/undici/lib/web/webidl/index.js +3 -3
  159. package/node_modules/undici/lib/web/websocket/connection.js +1 -1
  160. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +5 -0
  161. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +8 -10
  162. package/node_modules/undici/lib/web/websocket/websocket.js +22 -0
  163. package/node_modules/undici/package.json +4 -4
  164. package/node_modules/undici/types/client.d.ts +53 -3
  165. package/node_modules/undici/types/cookies.d.ts +1 -1
  166. package/node_modules/undici/types/dispatcher.d.ts +3 -3
  167. package/node_modules/undici/types/errors.d.ts +10 -0
  168. package/node_modules/undici/types/handlers.d.ts +2 -0
  169. package/node_modules/undici/types/interceptors.d.ts +2 -0
  170. package/node_modules/undici/types/mock-agent.d.ts +11 -10
  171. package/node_modules/undici/types/mock-interceptor.d.ts +5 -1
  172. package/node_modules/undici/types/proxy-agent.d.ts +7 -0
  173. package/node_modules/undici/types/socks5-proxy-agent.d.ts +2 -0
  174. package/npm-shrinkwrap.json +7 -7
  175. package/package.json +6 -5
  176. package/dist/pluralkit-DI6RYaVj.js +0 -24
  177. package/dist/provider.runtime-D1m66kDS.js +0 -2
  178. package/dist/runtime-api.monitor-4oc58TSk.js +0 -6
  179. package/dist/targets-C6yd3y8R.js +0 -3
@@ -7,9 +7,13 @@ const { EventSourceStream } = require('./eventsource-stream')
7
7
  const { parseMIMEType } = require('../fetch/data-url')
8
8
  const { createFastMessageEvent } = require('../websocket/events')
9
9
  const { isNetworkError } = require('../fetch/response')
10
- const { kEnumerableProperty } = require('../../core/util')
10
+ const { isValidHeaderValue, kEnumerableProperty } = require('../../core/util')
11
11
  const { environmentSettingsObject } = require('../fetch/util')
12
12
  const { createPotentialCORSRequest } = require('./util')
13
+ const { getGlobalDispatcher } = require('../../global')
14
+ const { isomorphicDecode } = require('../infra')
15
+
16
+ const textEncoder = new TextEncoder()
13
17
 
14
18
  let experimentalWarned = false
15
19
 
@@ -281,6 +285,7 @@ class EventSource extends EventTarget {
281
285
 
282
286
  const eventSourceStream = new EventSourceStream({
283
287
  eventSourceSettings: this.#state,
288
+ maxEventSize: this.#dispatcher.eventSourceOptions?.maxEventSize,
284
289
  push: (event) => {
285
290
  this.dispatchEvent(createFastMessageEvent(
286
291
  event.type,
@@ -340,8 +345,12 @@ class EventSource extends EventTarget {
340
345
  // string, encoded as UTF-8.
341
346
  // 2. Set (`Last-Event-ID`, lastEventIDValue) in request's header
342
347
  // list.
348
+ this.#request.headersList.delete('last-event-id', true)
343
349
  if (this.#state.lastEventId.length) {
344
- this.#request.headersList.set('last-event-id', this.#state.lastEventId, true)
350
+ const lastEventId = isomorphicDecode(textEncoder.encode(this.#state.lastEventId))
351
+ if (isValidHeaderValue(lastEventId)) {
352
+ this.#request.headersList.set('last-event-id', lastEventId, true)
353
+ }
345
354
  }
346
355
 
347
356
  // 4. Fetch request and process the response obtained in this fashion, if any, as described earlier in this section.
@@ -465,7 +474,8 @@ webidl.converters.EventSourceInitDict = webidl.dictionaryConverter([
465
474
  },
466
475
  {
467
476
  key: 'dispatcher', // undici only
468
- converter: webidl.converters.any
477
+ converter: webidl.converters.any,
478
+ defaultValue: () => getGlobalDispatcher()
469
479
  },
470
480
  {
471
481
  key: 'node', // undici only
@@ -49,7 +49,7 @@ function createPotentialCORSRequest (url, destination, corsAttributeState, sameO
49
49
  destination,
50
50
  mode,
51
51
  credentials: credentialsMode,
52
- useCredentials: true
52
+ useURLCredentials: true
53
53
  })
54
54
  }
55
55
 
@@ -16,6 +16,7 @@ const { serializeAMimeType } = require('./data-url')
16
16
  const { multipartFormDataParser } = require('./formdata-parser')
17
17
  const { parseJSONFromBytes } = require('../infra')
18
18
  const { utf8DecodeBytes } = require('../../encoding')
19
+ const { ReadableStreamTee } = require('node:stream/web')
19
20
 
20
21
  const textEncoder = new TextEncoder()
21
22
  function noop () {}
@@ -279,7 +280,7 @@ function cloneBody (body) {
279
280
  // https://fetch.spec.whatwg.org/#concept-body-clone
280
281
 
281
282
  // 1. Let « out1, out2 » be the result of teeing body’s stream.
282
- const { 0: out1, 1: out2 } = body.stream.tee()
283
+ const { 0: out1, 1: out2 } = ReadableStreamTee?.(body.stream, true) ?? body.stream.tee()
283
284
 
284
285
  // 2. Set body’s stream to out1.
285
286
  body.stream = out1
@@ -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'])
@@ -59,6 +59,7 @@ const {
59
59
  const EE = require('node:events')
60
60
  const { Readable, pipeline, finished, isErrored, isReadable } = require('node:stream')
61
61
  const { addAbortListener, bufferToLowerCasedHeaderName } = require('../../core/util')
62
+ const { SocketError } = require('../../core/errors')
62
63
  const { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require('./data-url')
63
64
  const { getGlobalDispatcher } = require('../../global')
64
65
  const { webidl } = require('../webidl')
@@ -1431,7 +1432,16 @@ async function httpNetworkOrCacheFetch (
1431
1432
  // Otherwise:
1432
1433
 
1433
1434
  // 1. Set httpRequest to a clone of request.
1434
- httpRequest = cloneRequest(request)
1435
+ // Implementations are encouraged to avoid teeing request’s body’s stream
1436
+ // when request’s body’s source is null as only a single body is needed in
1437
+ // that case. E.g., when request’s body’s source is null, redirects and
1438
+ // authentication will end up failing the fetch.
1439
+ if (request.body?.source != null) {
1440
+ httpRequest = cloneRequest(request)
1441
+ } else {
1442
+ httpRequest = cloneRequest({ ...request, body: null })
1443
+ httpRequest.body = request.body
1444
+ }
1435
1445
 
1436
1446
  // 2. Set httpFetchParams to a copy of fetchParams.
1437
1447
  httpFetchParams = { ...fetchParams }
@@ -1560,7 +1570,7 @@ async function httpNetworkOrCacheFetch (
1560
1570
  // TODO: https://github.com/whatwg/fetch/issues/1285#issuecomment-896560129
1561
1571
  if (!httpRequest.headersList.contains('accept-encoding', true)) {
1562
1572
  if (urlHasHttpsScheme(requestCurrentURL(httpRequest))) {
1563
- httpRequest.headersList.append('accept-encoding', 'br, gzip, deflate', true)
1573
+ httpRequest.headersList.append('accept-encoding', 'br, gzip, deflate, zstd', true)
1564
1574
  } else {
1565
1575
  httpRequest.headersList.append('accept-encoding', 'gzip, deflate', true)
1566
1576
  }
@@ -2387,6 +2397,11 @@ async function httpNetworkFetch (
2387
2397
  // We need to support 200 for websocket over h2 as per RFC-8441
2388
2398
  // Absence of session means H1
2389
2399
  if ((socket.session != null && status !== 200) || (socket.session == null && status !== 101)) {
2400
+ if (socket.session != null) {
2401
+ // The server refused the extended CONNECT, and nothing further
2402
+ // will settle this request. Fail the opening handshake here.
2403
+ controller.abort(new SocketError('bad upgrade', null))
2404
+ }
2390
2405
  return false
2391
2406
  }
2392
2407
 
@@ -923,7 +923,7 @@ function makeRequest (init) {
923
923
  serviceWorkers: init.serviceWorkers ?? 'all',
924
924
  initiator: init.initiator ?? '',
925
925
  destination: init.destination ?? '',
926
- priority: init.priority ?? null,
926
+ priority: init.priority ?? 'auto',
927
927
  origin: init.origin ?? 'client',
928
928
  policyContainer: init.policyContainer ?? 'client',
929
929
  referrer: init.referrer ?? 'client',
@@ -1129,8 +1129,7 @@ webidl.converters.RequestInit = webidl.dictionaryConverter([
1129
1129
  {
1130
1130
  key: 'priority',
1131
1131
  converter: webidl.converters.DOMString,
1132
- allowedValues: ['high', 'low', 'auto'],
1133
- defaultValue: () => 'auto'
1132
+ allowedValues: ['high', 'low', 'auto']
1134
1133
  }
1135
1134
  ])
1136
1135
 
@@ -45,9 +45,7 @@ class Response {
45
45
  static json (data, init = undefined) {
46
46
  webidl.argumentLengthCheck(arguments, 1, 'Response.json')
47
47
 
48
- if (init !== null) {
49
- init = webidl.converters.ResponseInit(init)
50
- }
48
+ init = webidl.converters.ResponseInit(init)
51
49
 
52
50
  // 1. Let bytes the result of running serialize a JavaScript value to JSON bytes on data.
53
51
  const bytes = textEncoder.encode(
@@ -227,14 +227,19 @@ function TAOCheck () {
227
227
  return 'success'
228
228
  }
229
229
 
230
+ // https://w3c.github.io/webappsec-fetch-metadata/#abstract-opdef-append-the-fetch-metadata-headers-for-a-request
230
231
  function appendFetchMetadata (httpRequest) {
232
+ // 1. If r’s url is not a potentially trustworthy URL, return.
233
+ if (!isURLPotentiallyTrustworthy(requestCurrentURL(httpRequest))) {
234
+ return
235
+ }
236
+
231
237
  // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-dest-header
232
238
  // TODO
233
239
 
234
240
  // https://w3c.github.io/webappsec-fetch-metadata/#sec-fetch-mode-header
235
241
 
236
242
  // 1. Assert: r’s url is a potentially trustworthy URL.
237
- // TODO
238
243
 
239
244
  // 2. Let header be a Structured Header whose value is a token.
240
245
  let header = null
@@ -1195,7 +1200,10 @@ function simpleRangeHeaderValue (value, allowWhitespace) {
1195
1200
  // 18. If rangeStartValue and rangeEndValue are numbers, and rangeStartValue is
1196
1201
  // greater than rangeEndValue, then return failure.
1197
1202
  // Note: ... when can they not be numbers?
1198
- if (rangeStartValue > rangeEndValue) {
1203
+ // Note: rangeStartValue or rangeEndValue may be null for open-ended ranges
1204
+ // such as `bytes=5-` or `bytes=-5`. A null value must not be coerced to 0
1205
+ // in the comparison, so this check only applies when both are numbers.
1206
+ if (rangeStartValue !== null && rangeEndValue !== null && rangeStartValue > rangeEndValue) {
1199
1207
  return 'failure'
1200
1208
  }
1201
1209
 
@@ -26,9 +26,9 @@ const webidl = {
26
26
  /**
27
27
  * @description Instantiate an error.
28
28
  *
29
- * @param {Object} opts
30
- * @param {string} opts.header
31
- * @param {string} opts.message
29
+ * @param {Object} message
30
+ * @param {string} message.header
31
+ * @param {string} message.message
32
32
  * @returns {TypeError}
33
33
  */
34
34
  webidl.errors.exception = function (message) {
@@ -200,7 +200,7 @@ function establishWebSocketConnection (url, protocols, client, handler, options)
200
200
  // is specified, the server needs to include the same field and one of
201
201
  // the selected subprotocol values in its response for the connection to
202
202
  // be established.
203
- if (!requestProtocols.includes(secProtocol)) {
203
+ if (requestProtocols === null || !requestProtocols.includes(secProtocol)) {
204
204
  failWebsocketConnection(handler, 1002, 'Protocol was not set in the opening handshake.')
205
205
  return
206
206
  }
@@ -63,7 +63,12 @@ class PerMessageDeflate {
63
63
 
64
64
  if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) {
65
65
  callback(new MessageSizeExceededError())
66
+ // The inflater may still hold buffered input that can emit a late
67
+ // zlib error. Remove the data listener, then deterministically stop
68
+ // the stream so a subsequent 'error' cannot fire without a listener
69
+ // (which would terminate the process as an unhandled error event).
66
70
  this.#inflate.removeAllListeners()
71
+ this.#inflate.destroy()
67
72
  this.#inflate = null
68
73
  return
69
74
  }
@@ -34,9 +34,9 @@ class WebSocketStream {
34
34
  /** @type {ReadableStreamDefaultController} */
35
35
  #readableStreamController
36
36
 
37
- // Each WebSocketStream object has an associated writable stream , which is a WritableStream .
38
- /** @type {WritableStream} */
39
- #writableStream
37
+ // Retain the controller so the writable stream can be errored while locked.
38
+ /** @type {WritableStreamDefaultController} */
39
+ #writableStreamController
40
40
 
41
41
  // Each WebSocketStream object has an associated boolean handshake aborted , which is initially false.
42
42
  #handshakeAborted = false
@@ -300,6 +300,9 @@ class WebSocketStream {
300
300
  // 12. Let writable be a new WritableStream .
301
301
  // 13. Set up writable with writeAlgorithm , closeAlgorithm , and abortAlgorithm .
302
302
  const writable = new WritableStream({
303
+ start: (controller) => {
304
+ this.#writableStreamController = controller
305
+ },
303
306
  write: (chunk) => this.#write(chunk),
304
307
  close: () => closeWebSocketConnection(this.#handler, null, null),
305
308
  abort: (reason) => this.#closeUsingReason(reason)
@@ -308,9 +311,6 @@ class WebSocketStream {
308
311
  // Set stream ’s readable stream to readable .
309
312
  this.#readableStream = readable
310
313
 
311
- // Set stream ’s writable stream to writable .
312
- this.#writableStream = writable
313
-
314
314
  // Resolve stream ’s opened promise with WebSocketOpenInfo «[ " extensions " → extensions , " protocol " → protocol , " readable " → readable , " writable " → writable ]».
315
315
  this.#openedPromise.resolve({
316
316
  extensions,
@@ -396,9 +396,7 @@ class WebSocketStream {
396
396
  readableStreamClose(this.#readableStreamController)
397
397
 
398
398
  // 6.2. Error stream ’s writable stream with an " InvalidStateError " DOMException indicating that a closed WebSocketStream cannot be written to.
399
- if (!this.#writableStream.locked) {
400
- this.#writableStream.abort(new DOMException('A closed WebSocketStream cannot be written to', 'InvalidStateError'))
401
- }
399
+ this.#writableStreamController.error(new DOMException('A closed WebSocketStream cannot be written to', 'InvalidStateError'))
402
400
 
403
401
  // 6.3. Resolve stream ’s closed promise with WebSocketCloseInfo «[ " closeCode " → code , " reason " → reason ]».
404
402
  this.#closedPromise.resolve({
@@ -415,7 +413,7 @@ class WebSocketStream {
415
413
  this.#readableStreamController?.error(error)
416
414
 
417
415
  // 7.3. Error stream ’s writable stream with error .
418
- this.#writableStream?.abort(error)
416
+ this.#writableStreamController?.error(error)
419
417
 
420
418
  // 7.4. Reject stream ’s closed promise with error .
421
419
  this.#closedPromise.reject(error)
@@ -25,6 +25,9 @@ const { SendQueue } = require('./sender')
25
25
  const { WebsocketFrameSend } = require('./frame')
26
26
  const { channels } = require('../../core/diagnostics')
27
27
 
28
+ const kRef = Symbol.for('nodejs.ref')
29
+ const kUnref = Symbol.for('nodejs.unref')
30
+
28
31
  function getSocketAddress (socket) {
29
32
  if (typeof socket?.address === 'function') {
30
33
  return socket.address()
@@ -68,6 +71,7 @@ class WebSocket extends EventTarget {
68
71
  #bufferedAmount = 0
69
72
  #protocol = ''
70
73
  #extensions = ''
74
+ #refed = true
71
75
 
72
76
  /** @type {SendQueue} */
73
77
  #sendQueue
@@ -194,6 +198,20 @@ class WebSocket extends EventTarget {
194
198
  this.#binaryType = 'blob'
195
199
  }
196
200
 
201
+ [kRef] () {
202
+ webidl.brandCheck(this, WebSocket)
203
+
204
+ this.#refed = true
205
+ this.#handler.socket?.ref?.()
206
+ }
207
+
208
+ [kUnref] () {
209
+ webidl.brandCheck(this, WebSocket)
210
+
211
+ this.#refed = false
212
+ this.#handler.socket?.unref?.()
213
+ }
214
+
197
215
  /**
198
216
  * @see https://websockets.spec.whatwg.org/#dom-websocket-close
199
217
  * @param {number|undefined} code
@@ -468,6 +486,10 @@ class WebSocket extends EventTarget {
468
486
  // once this happens, the connection is open
469
487
  this.#handler.socket = response.socket
470
488
 
489
+ if (!this.#refed) {
490
+ this.#handler.socket.unref?.()
491
+ }
492
+
471
493
  // Get options from dispatcher options
472
494
  const maxFragments = this.#handler.controller.dispatcher?.webSocketOptions?.maxFragments
473
495
  const maxPayloadSize = this.#handler.controller.dispatcher?.webSocketOptions?.maxPayloadSize
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "8.5.0",
3
+ "version": "8.10.2",
4
4
  "description": "An HTTP/1.1 client, written from scratch for Node.js",
5
5
  "homepage": "https://undici.nodejs.org",
6
6
  "bugs": {
@@ -97,7 +97,7 @@
97
97
  "test:websocket:autobahn": "node test/autobahn/client.js",
98
98
  "test:websocket:autobahn:report": "node test/autobahn/report.js",
99
99
  "test:wpt:setup": "node test/web-platform-tests/wpt-runner.mjs setup",
100
- "test:wpt": "npm run test:wpt:setup && node test/web-platform-tests/wpt-runner.mjs run /fetch /mimesniff /websockets /serviceWorkers /eventsource",
100
+ "test:wpt": "npm run test:wpt:setup && node test/web-platform-tests/wpt-runner.mjs run /fetch /mimesniff /xhr /websockets /eventsource",
101
101
  "test:cache-tests": "node test/cache-interceptor/cache-tests.mjs --ci",
102
102
  "coverage": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report",
103
103
  "coverage:ci": "npm run coverage:clean && cross-env NODE_V8_COVERAGE=./coverage/tmp npm run test:javascript && npm run coverage:report:ci",
@@ -109,14 +109,14 @@
109
109
  "prepare": "husky && node ./scripts/platform-shell.js"
110
110
  },
111
111
  "devDependencies": {
112
- "@fastify/busboy": "3.2.0",
112
+ "@fastify/busboy": "3.2.2",
113
113
  "@matteo.collina/tspl": "^0.2.0",
114
114
  "@metcoder95/https-pem": "^1.0.0",
115
115
  "@sinonjs/fake-timers": "^12.0.0",
116
116
  "@types/node": "^22.0.0",
117
117
  "abort-controller": "^3.0.0",
118
118
  "borp": "^1.0.0",
119
- "c8": "^11.0.0",
119
+ "c8": "^12.0.0",
120
120
  "cross-env": "^10.0.0",
121
121
  "dns-packet": "^5.4.0",
122
122
  "esbuild": "^0.28.0",
@@ -1,10 +1,15 @@
1
1
  import { URL } from 'node:url'
2
+ import { SessionOptions } from 'node:http2'
2
3
  import Dispatcher from './dispatcher'
3
4
  import buildConnector from './connector'
4
5
  import TClientStats from './client-stats'
5
6
 
6
7
  type ClientConnectOptions<TOpaque = null> = Omit<Dispatcher.ConnectOptions<TOpaque>, 'origin'>
7
8
 
9
+ // TODO: Pendings
10
+ // 1. Reflect this on Client instantiation
11
+ // 2. Client H2 should use this namespaced options instead.
12
+
8
13
  /**
9
14
  * A basic HTTP/1.1 client, mapped on top a single TCP/TLS connection. Pipelining is disabled by default.
10
15
  */
@@ -33,7 +38,7 @@ export declare namespace Client {
33
38
  export interface Options {
34
39
  /** The maximum length of request headers in bytes. Default: Node.js' `--max-http-header-size` or `16384` (16KiB). */
35
40
  maxHeaderSize?: number;
36
- /** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers (Node 14 and above only). Default: `300e3` milliseconds (300s). */
41
+ /** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers (Node 14 and above only). Default: `300e3` milliseconds (300s). HTTP/1.1 parser timeouts are not guaranteed to fire with exact millisecond precision: delays up to 1000ms use native timers, while larger delays use lower-overhead fast timers with a target resolution around 500ms. */
37
42
  headersTimeout?: number;
38
43
  /** @deprecated unsupported socketTimeout, use headersTimeout & bodyTimeout instead */
39
44
  socketTimeout?: never;
@@ -41,7 +46,7 @@ export declare namespace Client {
41
46
  requestTimeout?: never;
42
47
  /** The timeout for establishing a socket connection, in milliseconds. Use `0` to disable it entirely. Default: `10e3` milliseconds (10s). */
43
48
  connectTimeout?: number;
44
- /** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Default: `300e3` milliseconds (300s). */
49
+ /** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use `0` to disable it entirely. Default: `300e3` milliseconds (300s). HTTP/1.1 parser timeouts are not guaranteed to fire with exact millisecond precision: delays up to 1000ms use native timers, while larger delays use lower-overhead fast timers with a target resolution around 500ms. */
45
50
  bodyTimeout?: number;
46
51
  /** @deprecated unsupported idleTimeout, use keepAliveTimeout instead */
47
52
  idleTimeout?: never;
@@ -57,7 +62,7 @@ export declare namespace Client {
57
62
  keepAliveTimeoutThreshold?: number;
58
63
  /** An IPC endpoint, either a Unix domain socket or Windows named pipe. Default: `null`. */
59
64
  socketPath?: string;
60
- /** The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Default: `1`. */
65
+ /** The amount of concurrent requests to be sent over the single TCP/TLS connection according to [RFC7230](https://tools.ietf.org/html/rfc7230#section-6.3.2). Only enable values greater than `1` when the remote server is trusted. Default: `1`. */
61
66
  pipelining?: number;
62
67
  /** @deprecated use the connect option instead */
63
68
  tls?: never;
@@ -75,6 +80,8 @@ export declare namespace Client {
75
80
  maxResponseSize?: number;
76
81
  /** WebSocket-specific options */
77
82
  webSocket?: Client.WebSocketOptions;
83
+ /** EventSource-specific options */
84
+ eventSource?: Client.EventSourceOptions;
78
85
  /** Enables a family autodetection algorithm that loosely implements section 5 of RFC 8305. */
79
86
  autoSelectFamily?: boolean;
80
87
  /** The amount of time in milliseconds to wait for a connection attempt to finish before trying the next address when using the `autoSelectFamily` option. */
@@ -87,23 +94,31 @@ export declare namespace Client {
87
94
  /**
88
95
  * @description Dictates the maximum number of concurrent streams for a single H2 session. It can be overridden by a SETTINGS remote frame.
89
96
  * @default 100
97
+ * @deprecated Use h2Options.maxConcurrentStreams instead
90
98
  */
91
99
  maxConcurrentStreams?: number;
92
100
  /**
93
101
  * @description Sets the HTTP/2 stream-level flow-control window size (SETTINGS_INITIAL_WINDOW_SIZE).
94
102
  * @default 262144
103
+ * @deprecated Use h2Options.settings.initialWindowSize instead
95
104
  */
96
105
  initialWindowSize?: number;
97
106
  /**
98
107
  * @description Sets the HTTP/2 connection-level flow-control window size (ClientHttp2Session.setLocalWindowSize).
99
108
  * @default 524288
109
+ * @deprecated Use h2Options.connectionWindowSize instead
100
110
  */
101
111
  connectionWindowSize?: number;
102
112
  /**
103
113
  * @description Time interval between PING frames dispatch
104
114
  * @default 60000
115
+ * @deprecated Use h2Options.connectionWindowSize instead
105
116
  */
106
117
  pingInterval?: number;
118
+ /**
119
+ * @description HTTP/2 configuration options
120
+ */
121
+ h2Options?: Client.H2Options;
107
122
  }
108
123
  export interface SocketInfo {
109
124
  localAddress?: string
@@ -129,6 +144,41 @@ export declare namespace Client {
129
144
  */
130
145
  maxPayloadSize?: number;
131
146
  }
147
+
148
+ export interface H2Options extends Omit<SessionOptions, keyof buildConnector.BuildOptions> {
149
+ /**
150
+ * @description Sets the HTTP/2 connection-level flow-control window size (ClientHttp2Session.setLocalWindowSize).
151
+ * @default 524288
152
+ */
153
+ connectionWindowSize?: number;
154
+ /**
155
+ * @description Time interval between PING frames dispatch
156
+ * @default 60000
157
+ */
158
+ pingInterval?: number;
159
+ /**
160
+ * @description Dictates the maximum number of concurrent streams for a single H2 session. It can be overridden by a SETTINGS remote frame.
161
+ * @default 100
162
+ */
163
+ maxConcurrentStreams?: number;
164
+ /**
165
+ * @description Enable support for H2C (plain text)
166
+ * @default false
167
+ */
168
+ useH2c?: boolean;
169
+ /**
170
+ * @description SETTINGS frame object. Default to 'node:http2' defaults
171
+ */
172
+ settings?: Omit<SessionOptions['settings'], 'enablePush' | 'maxConcurrentStreams' | 'enableConnectProtocol'>
173
+ }
174
+ export interface EventSourceOptions {
175
+ /**
176
+ * Maximum allowed event size in bytes for EventSource messages.
177
+ * Set to 0 to disable the limit.
178
+ * @default buffer.kStringMaxLength
179
+ */
180
+ maxEventSize?: number;
181
+ }
132
182
  }
133
183
 
134
184
  export default Client
@@ -18,7 +18,7 @@ export interface Cookie {
18
18
  export function deleteCookie (
19
19
  headers: Headers,
20
20
  name: string,
21
- attributes?: { name?: string, domain?: string }
21
+ attributes?: { path?: string, domain?: string }
22
22
  ): void
23
23
 
24
24
  export function getCookies (headers: Headers): Record<string, string>
@@ -111,13 +111,13 @@ declare namespace Dispatcher {
111
111
  idempotent?: boolean;
112
112
  /** Whether the response is expected to take a long time and would end up blocking the pipeline. When this is set to `true` further pipelining will be avoided on the same connection until headers have been received. Defaults to `method !== 'HEAD'`. */
113
113
  blocking?: boolean;
114
- /** The IP Type of Service (ToS) value for the request socket. Must be an integer between 0 and 255. Default: `0` */
114
+ /** The IP Type of Service (ToS) value for the request socket. Must be an integer between 0 and 255. */
115
115
  typeOfService?: number | null;
116
116
  /** Upgrade the request. Should be used to specify the kind of upgrade i.e. `'Websocket'`. Default: `method === 'CONNECT' || null`. */
117
117
  upgrade?: boolean | string | null;
118
- /** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers. Defaults to 300 seconds. */
118
+ /** The amount of time, in milliseconds, the parser will wait to receive the complete HTTP headers. Defaults to 300 seconds. HTTP/1.1 parser timeouts are not guaranteed to fire with exact millisecond precision: delays up to 1000ms use native timers, while larger delays use lower-overhead fast timers with a target resolution around 500ms. */
119
119
  headersTimeout?: number | null;
120
- /** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use 0 to disable it entirely. Defaults to 300 seconds. */
120
+ /** The timeout after which a request will time out, in milliseconds. Monitors time between receiving body data. Use 0 to disable it entirely. Defaults to 300 seconds. HTTP/1.1 parser timeouts are not guaranteed to fire with exact millisecond precision: delays up to 1000ms use native timers, while larger delays use lower-overhead fast timers with a target resolution around 500ms. */
121
121
  bodyTimeout?: number | null;
122
122
  /** Whether the request should stablish a keep-alive or not. Default `false` */
123
123
  reset?: boolean;
@@ -154,6 +154,16 @@ declare namespace Errors {
154
154
  code: 'UND_ERR_PRX_TLS'
155
155
  }
156
156
 
157
+ export class ProxyConnectionError extends UndiciError {
158
+ constructor (
159
+ cause?: Error,
160
+ message?: string,
161
+ options?: Record<any, any>
162
+ )
163
+ name: 'ProxyConnectionError'
164
+ code: 'UND_ERR_PRX_CONN'
165
+ }
166
+
157
167
  export class MaxOriginsReachedError extends UndiciError {
158
168
  name: 'MaxOriginsReachedError'
159
169
  code: 'UND_ERR_MAX_ORIGINS_REACHED'
@@ -1,6 +1,8 @@
1
1
  import Dispatcher from './dispatcher'
2
2
 
3
3
  export declare class RedirectHandler implements Dispatcher.DispatchHandler {
4
+ static buildDispatch (dispatcher: Dispatcher, maxRedirections: number): Dispatcher.Dispatch
5
+
4
6
  constructor (
5
7
  dispatch: Dispatcher.Dispatch,
6
8
  maxRedirections: number,
@@ -12,6 +12,8 @@ declare namespace Interceptors {
12
12
  export type DecompressInterceptorOpts = {
13
13
  skipErrorResponses?: boolean
14
14
  skipStatusCodes?: number[]
15
+ /** Maximum decompressed response size in bytes. @default 67108864 */
16
+ maxSize?: number
15
17
  }
16
18
 
17
19
  export type ResponseErrorInterceptorOpts = { throwOnError: boolean }
@@ -6,10 +6,6 @@ import { MockCallHistory } from './mock-call-history'
6
6
 
7
7
  export default MockAgent
8
8
 
9
- interface PendingInterceptor extends MockDispatch {
10
- origin: string;
11
- }
12
-
13
9
  /** A mocked Agent class that implements the Agent API. It allows one to intercept HTTP requests made through undici and return mocked responses instead. */
14
10
  declare class MockAgent<TMockAgentOptions extends MockAgent.Options = MockAgent.Options> extends Dispatcher {
15
11
  constructor (options?: TMockAgentOptions)
@@ -40,17 +36,22 @@ declare class MockAgent<TMockAgentOptions extends MockAgent.Options = MockAgent.
40
36
  enableCallHistory (): this
41
37
  /** Disable call history. Any subsequence calls will then not be registered. */
42
38
  disableCallHistory (): this
43
- pendingInterceptors (): PendingInterceptor[]
39
+ pendingInterceptors (): MockAgent.PendingInterceptor[]
44
40
  assertNoPendingInterceptors (options?: {
45
- pendingInterceptorsFormatter?: PendingInterceptorsFormatter;
41
+ pendingInterceptorsFormatter?: MockAgent.PendingInterceptorsFormatter;
46
42
  }): void
47
43
  }
48
44
 
49
- interface PendingInterceptorsFormatter {
50
- format(pendingInterceptors: readonly PendingInterceptor[]): string;
51
- }
52
-
53
45
  declare namespace MockAgent {
46
+ /** An interceptor that was registered on a mock dispatcher and has not been consumed yet. */
47
+ export interface PendingInterceptor extends MockDispatch {
48
+ origin: string;
49
+ }
50
+
51
+ export interface PendingInterceptorsFormatter {
52
+ format(pendingInterceptors: readonly PendingInterceptor[]): string;
53
+ }
54
+
54
55
  /** MockAgent options. */
55
56
  export interface Options extends Agent.Options {
56
57
  /** A custom agent to be encapsulated by the MockAgent. */
@@ -75,9 +75,13 @@ declare namespace MockInterceptor {
75
75
  opts: MockResponseCallbackOptions
76
76
  ) => TData | Buffer | string
77
77
 
78
+ export type MockReplyOptions<TData extends object = object> = {
79
+ statusCode: number, data?: TData | Buffer | string, responseOptions?: MockResponseOptions
80
+ }
81
+
78
82
  export type MockReplyOptionsCallback<TData extends object = object> = (
79
83
  opts: MockResponseCallbackOptions
80
- ) => { statusCode: number, data?: TData | Buffer | string, responseOptions?: MockResponseOptions }
84
+ ) => MockReplyOptions<TData> | Promise<MockReplyOptions<TData>>
81
85
  }
82
86
 
83
87
  interface Interceptable extends Dispatcher {
@@ -24,6 +24,13 @@ declare namespace ProxyAgent {
24
24
  requestTls?: buildConnector.BuildOptions;
25
25
  proxyTls?: buildConnector.BuildOptions;
26
26
  clientFactory?(origin: URL, opts: object): Dispatcher;
27
+ /**
28
+ * Undici tunnels via CONNECT when the target endpoint uses HTTPS, and
29
+ * forwards (HTTP/1.1 absolute-form request-target, per RFC 9112 §3.2.2)
30
+ * otherwise, regardless of whether the proxy URL is HTTP or HTTPS. The
31
+ * non-tunneled forwarding path does not negotiate HTTP/2 with the proxy.
32
+ * Set to true to force tunneling for plain HTTP requests as well.
33
+ */
27
34
  proxyTunnel?: boolean;
28
35
  }
29
36
  }
@@ -21,5 +21,7 @@ declare namespace Socks5ProxyAgent {
21
21
  connect?: buildConnector.connector;
22
22
  /** TLS options for the proxy connection (for SOCKS5 over TLS) */
23
23
  proxyTls?: buildConnector.BuildOptions;
24
+ /** TLS options for the end-to-end connection to the target */
25
+ requestTls?: buildConnector.BuildOptions;
24
26
  }
25
27
  }