@openclaw/discord 2026.9.1-beta.1 → 2026.9.2

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 (165) hide show
  1. package/dist/account-inspect-BY-ve3yH.js +45 -0
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/{accounts-CfQ-vSyf.js → accounts-CwJQoLjM.js} +89 -45
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{activities-api-q-9PaaHH.js → activities-api-CTcGq3Hf.js} +30 -17
  6. package/dist/activities-api.js +1 -1
  7. package/dist/{allow-list-BDMimASD.js → allow-list-DBTtR2dz.js} +13 -35
  8. package/dist/{api-DNVbJyEy.js → api-BfmEP6wp.js} +6 -5
  9. package/dist/api.js +18 -18
  10. package/dist/{approval-handler.runtime-B7qhK3fR.js → approval-handler.runtime-DUSe5fyH.js} +19 -12
  11. package/dist/{audit-CBEv_ERu.js → audit-DpPfwoJM.js} +8 -7
  12. package/dist/{channel-Dx1tMTfx.js → channel-BHajPgwR.js} +29 -23
  13. package/dist/{channel-actions.runtime-CLWWu9nC.js → channel-actions.runtime-DS8pXo0S.js} +38 -38
  14. package/dist/channel-config-api.js +1 -1
  15. package/dist/channel-plugin-api.js +1 -1
  16. package/dist/{channel.setup-DOzXS2Pk.js → channel.setup-BWmMe1tT.js} +18 -18
  17. package/dist/command-owners-D78sAoOz.js +10 -0
  18. package/dist/{components-B9V5o361.js → components-BimX47Mq.js} +111 -149
  19. package/dist/{config-schema-BR13IAx6.js → config-schema-B797-Spt.js} +19 -12
  20. package/dist/{conversation-binding-route-DJYrY2TQ.js → conversation-binding-route-DuR5NGIx.js} +1 -1
  21. package/dist/{directory-config-BK6eqekJ.js → directory-config-CD2v2Szs.js} +2 -2
  22. package/dist/directory-contract-api.js +1 -1
  23. package/dist/{directory-live-DSAJSrJk.js → directory-live-DaJzWJ2N.js} +4 -4
  24. package/dist/{doctor-Cm7Y1pJ2.js → doctor-D4HH1inA.js} +9 -6
  25. package/dist/{doctor-contract-DsWvKIXF.js → doctor-contract-Co5vRCZ6.js} +9 -6
  26. package/dist/doctor-contract-api.js +31 -28
  27. package/dist/{handle-action.guild-admin-BdwCRHmm.js → handle-action.guild-admin-4We6wWQU.js} +6 -3
  28. package/dist/index.js +1 -1
  29. package/dist/ingress-identity-XNmW-mZS.js +60 -0
  30. package/dist/{message-handler-BXpWZyni.js → message-handler-DhgBabyU.js} +61 -70
  31. package/dist/{message-handler.preflight-Ba5LAY_X.js → message-handler.preflight-oZ7dQCd0.js} +41 -101
  32. package/dist/{message-handler.process-3HEzmemS.js → message-handler.process-BzCYf1pa.js} +82 -108
  33. package/dist/{message-text-aiwO5R2F.js → message-text-DK4NnBg-.js} +11 -6
  34. package/dist/{outbound-adapter-BE4jSq2d.js → outbound-adapter-CtggmGh9.js} +52 -67
  35. package/dist/{outbound-components-oLpg8Qzb.js → outbound-components-Dn8SJWMS.js} +5 -4
  36. package/dist/{outbound-session-route-Cg15ZFJd.js → outbound-session-route-Q_HEusBQ.js} +57 -15
  37. package/dist/{owner-access-UlYi9t0M.js → owner-access-Cp8r6Ipf.js} +9 -7
  38. package/dist/{pluralkit-Tiyl70dx.js → pluralkit-BY75YcK0.js} +2 -2
  39. package/dist/{probe-n6ZXxK8V.js → probe-3ovFAp3b.js} +3 -3
  40. package/dist/{probe.runtime-CN4bdPfZ.js → probe.runtime-BckHn3cJ.js} +1 -1
  41. package/dist/{provider-session.runtime-B9xe-Qaf.js → provider-session.runtime-BL2lHBH7.js} +3 -3
  42. package/dist/{provider-B11xwilq.js → provider-uKmmrDM4.js} +299 -136
  43. package/dist/provider.runtime-C-IkWF2w.js +2 -0
  44. package/dist/{realtime-session.runtime-CU8IQUS-.js → realtime-session.runtime-CGYm1t_0.js} +798 -448
  45. package/dist/{resolve-allowlist-common-BLoYaxEG.js → resolve-allowlist-common-sKIKy-cF.js} +3 -3
  46. package/dist/{resolve-channels-C2sT_n67.js → resolve-channels-CoiMlWy0.js} +4 -4
  47. package/dist/{resolve-users-CzpjLwjy.js → resolve-users-DJpiokfW.js} +5 -4
  48. package/dist/{retry-Cv4jCU5Z.js → retry-DQt1zDgH.js} +356 -214
  49. package/dist/{retry-after-DdLPmPoa.js → retry-after-BrLjLUJi.js} +2 -1
  50. package/dist/{runtime-CY4PRMF-.js → runtime-BHsdEdr5.js} +2 -2
  51. package/dist/{runtime-BHrTlFkf.js → runtime-Ghtfh5ZA.js} +151 -109
  52. package/dist/runtime-api.js +20 -20
  53. package/dist/{secret-config-contract-B3i6WxV5.js → secret-config-contract-DFu9hfU8.js} +14 -6
  54. package/dist/secret-contract-api.js +1 -1
  55. package/dist/{security-audit-BfJhAXZp.js → security-audit-DKfK-iPY.js} +10 -11
  56. package/dist/security-audit-contract-api.js +1 -1
  57. package/dist/{security-audit.runtime-BVKF9VtY.js → security-audit.runtime-sKZyKgpx.js} +1 -1
  58. package/dist/{send-C49MFF9j.js → send-CZeWKUiA.js} +132 -100
  59. package/dist/{send.components-DKKAw5VX.js → send.components-BG5IDABj.js} +21 -15
  60. package/dist/{send.outbound-zam0TrZx.js → send.outbound-DHuFUL6W.js} +42 -63
  61. package/dist/{send.shared-JjljcV4O.js → send.shared-B0n_fWzu.js} +77 -149
  62. package/dist/{sender-identity-BJtfyise.js → sender-identity-B8Ncfi63.js} +1 -1
  63. package/dist/setup-plugin-api.js +1 -1
  64. package/dist/{shared-_5EcP4jW.js → shared-C3dKun_X.js} +24 -15
  65. package/dist/{subagent-hooks-DQzvOptn.js → subagent-hooks-ZoQXEI1E.js} +2 -2
  66. package/dist/subagent-hooks-api.js +1 -1
  67. package/dist/{system-events-C7yxaHWP.js → system-events-DFF_awl7.js} +2 -2
  68. package/dist/{target-resolver-vxIh6O3-.js → target-resolver-DLtHDwMK.js} +6 -5
  69. package/dist/targets-BObRyaKX.js +3 -0
  70. package/dist/{thread-bindings-DW5F9vat.js → thread-bindings-DKvsNjQR.js} +7 -6
  71. package/dist/{thread-bindings.manager-ByOtwjo_.js → thread-bindings.manager-pbbRT5gb.js} +38 -29
  72. package/dist/{thread-bindings.session-updates-CJb-BpPL.js → thread-bindings.session-updates-t6jeFB1-.js} +3 -2
  73. package/dist/{thread-bindings.state-D8OMdk4O.js → thread-bindings.state-DtgOqsbX.js} +34 -1
  74. package/dist/{threading-agH1T_6s.js → threading-BCx49X-6.js} +8 -6
  75. package/dist/{timeouts-B9cy6RvQ.js → timeouts-D86uWLt_.js} +1 -1
  76. package/dist/{transcripts-source-BR11iHA4.js → transcripts-source-Dc6Nnli5.js} +55 -7
  77. package/dist/transcripts-source-api.js +1 -1
  78. package/dist/{typing-Dc_YMY2e.js → typing-CuopV-Hi.js} +2 -2
  79. package/dist/{voice-runtime-DIeaa8fJ.js → voice-runtime-BQnILUbG.js} +492 -105
  80. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/README.md +1 -1
  81. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/conforms.d.ts +2 -0
  82. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/package.json +3 -3
  83. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubArray.d.ts +2 -0
  84. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubObject.d.ts +2 -0
  85. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubString.d.ts +2 -0
  86. package/node_modules/@discordjs/voice/node_modules/@types/node/README.md +1 -1
  87. package/node_modules/@discordjs/voice/node_modules/@types/node/buffer.buffer.d.ts +5 -5
  88. package/node_modules/@discordjs/voice/node_modules/@types/node/crypto.d.ts +2 -2
  89. package/node_modules/@discordjs/voice/node_modules/@types/node/http.d.ts +16 -0
  90. package/node_modules/@discordjs/voice/node_modules/@types/node/http2.d.ts +10 -2
  91. package/node_modules/@discordjs/voice/node_modules/@types/node/package.json +2 -2
  92. package/node_modules/@discordjs/voice/node_modules/@types/node/process.d.ts +52 -0
  93. package/node_modules/@discordjs/voice/node_modules/@types/node/quic.d.ts +210 -28
  94. package/node_modules/@discordjs/voice/node_modules/@types/node/sqlite.d.ts +6 -2
  95. package/node_modules/@discordjs/voice/node_modules/@types/node/test.d.ts +36 -0
  96. package/node_modules/typebox/build/format/email.mjs +1 -1
  97. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
  98. package/node_modules/typebox/build/format/json_pointer.d.mts +2 -2
  99. package/node_modules/typebox/build/format/json_pointer.mjs +2 -2
  100. package/node_modules/typebox/build/format/json_pointer_uri_fragment.d.mts +2 -2
  101. package/node_modules/typebox/build/format/json_pointer_uri_fragment.mjs +2 -2
  102. package/node_modules/typebox/build/format/relative_json_pointer.d.mts +2 -2
  103. package/node_modules/typebox/build/format/relative_json_pointer.mjs +2 -2
  104. package/node_modules/typebox/build/system/memory/assign.mjs +2 -1
  105. package/node_modules/typebox/build/system/memory/create.mjs +3 -4
  106. package/node_modules/typebox/build/system/memory/discard.mjs +2 -2
  107. package/node_modules/typebox/build/system/memory/freeze.d.mts +4 -0
  108. package/node_modules/typebox/build/system/memory/freeze.mjs +6 -0
  109. package/node_modules/typebox/build/system/memory/update.mjs +3 -2
  110. package/node_modules/typebox/package.json +1 -1
  111. package/node_modules/undici/docs/docs/api/Client.md +4 -0
  112. package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +3 -2
  113. package/node_modules/undici/docs/docs/api/EventSource.md +4 -0
  114. package/node_modules/undici/docs/docs/api/Interceptors.md +7 -3
  115. package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +7 -1
  116. package/node_modules/undici/lib/cache/memory-cache-store.js +2 -2
  117. package/node_modules/undici/lib/core/symbols.js +2 -0
  118. package/node_modules/undici/lib/dispatcher/agent.js +7 -2
  119. package/node_modules/undici/lib/dispatcher/balanced-pool.js +7 -4
  120. package/node_modules/undici/lib/dispatcher/client-h1.js +12 -4
  121. package/node_modules/undici/lib/dispatcher/client-h2.js +43 -3
  122. package/node_modules/undici/lib/dispatcher/client.js +3 -2
  123. package/node_modules/undici/lib/dispatcher/dispatcher-base.js +13 -1
  124. package/node_modules/undici/lib/dispatcher/dispatcher.js +15 -1
  125. package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +3 -0
  126. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +10 -3
  127. package/node_modules/undici/lib/dispatcher/proxy-agent.js +18 -1
  128. package/node_modules/undici/lib/dispatcher/retry-agent.js +3 -0
  129. package/node_modules/undici/lib/dispatcher/round-robin-pool.js +1 -1
  130. package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +91 -21
  131. package/node_modules/undici/lib/handler/cache-handler.js +29 -5
  132. package/node_modules/undici/lib/handler/decorator-handler.js +7 -1
  133. package/node_modules/undici/lib/handler/deduplication-handler.js +12 -6
  134. package/node_modules/undici/lib/handler/redirect-handler.js +21 -4
  135. package/node_modules/undici/lib/handler/retry-handler.js +148 -30
  136. package/node_modules/undici/lib/interceptor/cache.js +65 -12
  137. package/node_modules/undici/lib/interceptor/decompress.js +115 -13
  138. package/node_modules/undici/lib/interceptor/deduplicate.js +5 -4
  139. package/node_modules/undici/lib/interceptor/dns.js +7 -0
  140. package/node_modules/undici/lib/interceptor/dump.js +10 -23
  141. package/node_modules/undici/lib/mock/mock-agent.js +13 -1
  142. package/node_modules/undici/lib/mock/mock-utils.js +11 -10
  143. package/node_modules/undici/lib/util/cache.js +45 -3
  144. package/node_modules/undici/lib/web/cookies/parse.js +150 -147
  145. package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +28 -1
  146. package/node_modules/undici/lib/web/eventsource/eventsource.js +13 -3
  147. package/node_modules/undici/lib/web/fetch/index.js +6 -0
  148. package/node_modules/undici/lib/web/fetch/request.js +2 -3
  149. package/node_modules/undici/lib/web/fetch/util.js +6 -1
  150. package/node_modules/undici/lib/web/webidl/index.js +3 -3
  151. package/node_modules/undici/lib/web/websocket/connection.js +1 -1
  152. package/node_modules/undici/lib/web/websocket/permessage-deflate.js +5 -0
  153. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +8 -10
  154. package/node_modules/undici/package.json +3 -3
  155. package/node_modules/undici/types/client.d.ts +10 -0
  156. package/node_modules/undici/types/interceptors.d.ts +2 -0
  157. package/node_modules/undici/types/mock-agent.d.ts +11 -10
  158. package/node_modules/undici/types/socks5-proxy-agent.d.ts +2 -0
  159. package/openclaw.plugin.json +15 -8
  160. package/package.json +7 -6
  161. package/skills/discord/SKILL.md +1 -1
  162. package/dist/account-inspect-BDfKyuvL.js +0 -89
  163. package/dist/provider.runtime-DiYaHvOz.js +0 -2
  164. package/dist/sdk-runtime-4geQHtXc.js +0 -338
  165. package/dist/targets-CtTKvntJ.js +0 -3
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const buffer = require('node:buffer')
3
4
  const Dispatcher = require('./dispatcher')
4
5
  const {
5
6
  ClientDestroyedError,
@@ -11,6 +12,7 @@ const { kDestroy, kClose, kClosed, kDestroyed, kDispatch } = require('../core/sy
11
12
  const kOnDestroyed = Symbol('onDestroyed')
12
13
  const kOnClosed = Symbol('onClosed')
13
14
  const kWebSocketOptions = Symbol('webSocketOptions')
15
+ const kEventSourceOptions = Symbol('eventSourceOptions')
14
16
 
15
17
  class DispatcherBase extends Dispatcher {
16
18
  /** @type {boolean} */
@@ -31,10 +33,11 @@ class DispatcherBase extends Dispatcher {
31
33
  constructor (opts) {
32
34
  super()
33
35
  this[kWebSocketOptions] = opts?.webSocket ?? {}
36
+ this[kEventSourceOptions] = opts?.eventSource ?? {}
34
37
  }
35
38
 
36
39
  /**
37
- * @returns {import('../../types/dispatcher').WebSocketOptions}
40
+ * @returns {import('../../types/client').Client.WebSocketOptions}
38
41
  */
39
42
  get webSocketOptions () {
40
43
  return {
@@ -43,6 +46,15 @@ class DispatcherBase extends Dispatcher {
43
46
  }
44
47
  }
45
48
 
49
+ /**
50
+ * @returns {import('../../types/client').Client.EventSourceOptions}
51
+ */
52
+ get eventSourceOptions () {
53
+ return {
54
+ maxEventSize: this[kEventSourceOptions].maxEventSize ?? buffer.kStringMaxLength
55
+ }
56
+ }
57
+
46
58
  /** @returns {boolean} */
47
59
  get destroyed () {
48
60
  return this[kDestroyed]
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
  const EventEmitter = require('node:events')
3
+ const { kOriginless, kUrl } = require('../core/symbols')
3
4
 
4
5
  class Dispatcher extends EventEmitter {
5
6
  dispatch () {
@@ -17,6 +18,10 @@ class Dispatcher extends EventEmitter {
17
18
  compose (...args) {
18
19
  // So we handle [interceptor1, interceptor2] or interceptor1, interceptor2, ...
19
20
  const interceptors = Array.isArray(args[0]) ? args[0] : args
21
+ // null disables origin-dependent interceptors; undefined uses opts.origin.
22
+ const interceptorOrigin = this[kOriginless] === true
23
+ ? null
24
+ : this[kUrl]?.origin
20
25
  let dispatch = this.dispatch.bind(this)
21
26
 
22
27
  for (const interceptor of interceptors) {
@@ -28,13 +33,22 @@ class Dispatcher extends EventEmitter {
28
33
  throw new TypeError(`invalid interceptor, expected function received ${typeof interceptor}`)
29
34
  }
30
35
 
31
- dispatch = interceptor(dispatch)
36
+ dispatch = interceptor(dispatch, interceptorOrigin)
32
37
 
33
38
  if (dispatch == null || typeof dispatch !== 'function' || dispatch.length !== 2) {
34
39
  throw new TypeError('invalid interceptor')
35
40
  }
36
41
  }
37
42
 
43
+ const originalDispatch = dispatch
44
+ const self = this
45
+ dispatch = function (opts, handler) {
46
+ if (opts && typeof opts === 'object' && !opts.origin && self[kUrl]) {
47
+ opts = Object.assign({}, opts, { origin: self[kUrl].origin })
48
+ }
49
+ return originalDispatch(opts, handler)
50
+ }
51
+
38
52
  return new Proxy(this, {
39
53
  get: (target, key) => key === 'dispatch' ? dispatch : target[key]
40
54
  })
@@ -3,6 +3,7 @@
3
3
  const Dispatcher = require('./dispatcher')
4
4
  const { InvalidArgumentError } = require('../core/errors')
5
5
  const { toRawHeaders } = require('../core/util')
6
+ const { kOriginless, kUrl } = require('../core/symbols')
6
7
 
7
8
  class LegacyHandlerWrapper {
8
9
  #handler
@@ -71,6 +72,8 @@ class Dispatcher1Wrapper extends Dispatcher {
71
72
  }
72
73
 
73
74
  this.#dispatcher = dispatcher
75
+ this[kUrl] = dispatcher[kUrl]
76
+ this[kOriginless] = dispatcher[kOriginless]
74
77
  }
75
78
 
76
79
  static wrapHandler (handler) {
@@ -16,7 +16,7 @@ class EnvHttpProxyAgent extends DispatcherBase {
16
16
  #opts = null
17
17
 
18
18
  constructor (opts = {}) {
19
- super()
19
+ super(opts)
20
20
  this.#opts = opts
21
21
 
22
22
  const { httpProxy, httpsProxy, noProxy, ...agentOpts } = opts
@@ -69,6 +69,13 @@ class EnvHttpProxyAgent extends DispatcherBase {
69
69
  // brackets from IPv6 literals (e.g. "[::1]" -> "::1") so that the
70
70
  // result matches the unbracketed form stored by #parseNoProxy.
71
71
  hostname = hostname.replace(/:\d*$/, '').replace(/^\[(.+)\]$/, '$1').toLowerCase()
72
+ // Drop a trailing dot: it only marks the fully qualified form of a domain
73
+ // name ("example.com." and "example.com" are the same name, RFC 1034 root
74
+ // label). This runs on every dispatch, so it is a charCode check rather
75
+ // than a third regex. `length > 1` leaves the degenerate host "." alone.
76
+ if (hostname.length > 1 && hostname.charCodeAt(hostname.length - 1) === 46) {
77
+ hostname = hostname.slice(0, -1)
78
+ }
72
79
  port = Number.parseInt(port, 10) || DEFAULT_PORTS[protocol] || 0
73
80
  if (!this.#shouldProxy(hostname, port)) {
74
81
  return this[kNoProxyAgent]
@@ -143,8 +150,8 @@ class EnvHttpProxyAgent extends DispatcherBase {
143
150
  }
144
151
 
145
152
  noProxyEntries.push({
146
- // strip leading dot or asterisk with dot
147
- hostname: hostname.replace(/^\*?\./, '').toLowerCase(),
153
+ // strip leading dot or asterisk with dot, and any trailing dot
154
+ hostname: hostname.replace(/^\*?\./, '').replace(/^(.+)\.$/, '$1').toLowerCase(),
148
155
  port
149
156
  })
150
157
  }
@@ -9,6 +9,7 @@ const buildConnector = require('../core/connect')
9
9
  const Client = require('./client')
10
10
  const { channels } = require('../core/diagnostics')
11
11
  const Socks5ProxyAgent = require('./socks5-proxy-agent')
12
+ const { hasSafeIterator } = require('../core/util')
12
13
 
13
14
  const kAgent = Symbol('proxy agent')
14
15
  const kClient = Symbol('proxy client')
@@ -120,7 +121,7 @@ class ProxyAgent extends DispatcherBase {
120
121
 
121
122
  const { proxyTunnel, connectTimeout } = opts
122
123
 
123
- super()
124
+ super(opts)
124
125
 
125
126
  const url = this.#getUrl(opts)
126
127
  const { href, origin, port, protocol, username, password, hostname: proxyHostname } = url
@@ -161,6 +162,7 @@ class ProxyAgent extends DispatcherBase {
161
162
  factory: agentFactory,
162
163
  username: opts.username || username,
163
164
  password: opts.password || password,
165
+ connectTimeout,
164
166
  proxyTls: opts.proxyTls,
165
167
  requestTls: opts.requestTls
166
168
  })
@@ -344,6 +346,21 @@ function buildHeaders (headers) {
344
346
  return headersPair
345
347
  }
346
348
 
349
+ // Materialize iterable header containers (e.g. Map, Headers) into a record so
350
+ // that throwIfProxyAuthIsSent() can inspect their entries. Object.keys and
351
+ // for...in see nothing on a Map/Headers instance, so without this the
352
+ // Proxy-Authorization guard is bypassed and proxy credentials can reach the
353
+ // origin server (GHSA-6cv7-626c-qhqw).
354
+ if (headers && typeof headers === 'object' && hasSafeIterator(headers)) {
355
+ const headersPair = {}
356
+
357
+ for (const [key, value] of headers) {
358
+ headersPair[key] = value
359
+ }
360
+
361
+ return headersPair
362
+ }
363
+
347
364
  return headers
348
365
  }
349
366
 
@@ -2,6 +2,7 @@
2
2
 
3
3
  const Dispatcher = require('./dispatcher')
4
4
  const RetryHandler = require('../handler/retry-handler')
5
+ const { kOriginless, kUrl } = require('../core/symbols')
5
6
 
6
7
  class RetryAgent extends Dispatcher {
7
8
  #agent = null
@@ -10,6 +11,8 @@ class RetryAgent extends Dispatcher {
10
11
  super(options)
11
12
  this.#agent = agent
12
13
  this.#options = options
14
+ this[kUrl] = agent[kUrl]
15
+ this[kOriginless] = agent[kOriginless]
13
16
  }
14
17
 
15
18
  dispatch (opts, handler) {
@@ -65,7 +65,7 @@ class RoundRobinPool extends PoolBase {
65
65
  })
66
66
  }
67
67
 
68
- super()
68
+ super(options)
69
69
 
70
70
  this[kConnections] = connections || null
71
71
  this[kUrl] = util.parseOrigin(origin)
@@ -4,22 +4,33 @@ const { URL } = require('node:url')
4
4
 
5
5
  let tls // include tls conditionally since it is not always available
6
6
  const DispatcherBase = require('./dispatcher-base')
7
- const { InvalidArgumentError } = require('../core/errors')
7
+ const { ConnectTimeoutError, InvalidArgumentError } = require('../core/errors')
8
8
  const { Socks5Client, STATES } = require('../core/socks5-client')
9
9
  const { kBusy, kConnected, kDispatch, kClose, kDestroy } = require('../core/symbols')
10
10
  const Pool = require('./pool')
11
11
  const buildConnector = require('../core/connect')
12
+ const { setupConnectTimeout } = require('../core/util')
12
13
  const { debuglog } = require('node:util')
13
14
 
14
15
  const debug = debuglog('undici:socks5-proxy')
15
16
 
17
+ const DEFAULT_SOCKS5_CONNECT_TIMEOUT = 5000
18
+
16
19
  const kProxyUrl = Symbol('proxy url')
17
20
  const kProxyHeaders = Symbol('proxy headers')
18
21
  const kProxyAuth = Symbol('proxy auth')
19
22
  const kProxyProtocol = Symbol('proxy protocol')
20
23
  const kPools = Symbol('pools')
21
24
  const kConnector = Symbol('connector')
25
+ const kConnectTimeout = Symbol('connect timeout')
22
26
  const kRequestTls = Symbol('request tls settings')
27
+ const kRequestTlsTimeout = Symbol('request tls timeout')
28
+
29
+ function createConnectTimeoutError (hostname, port, timeout) {
30
+ return new ConnectTimeoutError(
31
+ `Connect Timeout Error (attempted address: ${hostname}:${port}, timeout: ${timeout}ms)`
32
+ )
33
+ }
23
34
 
24
35
  // Static flag to ensure warning is only emitted once per process
25
36
  let experimentalWarningEmitted = false
@@ -29,7 +40,7 @@ let experimentalWarningEmitted = false
29
40
  */
30
41
  class Socks5ProxyAgent extends DispatcherBase {
31
42
  constructor (proxyUrl, options = {}) {
32
- super()
43
+ super(options)
33
44
 
34
45
  // Emit experimental warning only once
35
46
  if (!experimentalWarningEmitted) {
@@ -54,7 +65,20 @@ class Socks5ProxyAgent extends DispatcherBase {
54
65
  this[kProxyUrl] = url
55
66
  this[kProxyHeaders] = options.headers || {}
56
67
  this[kProxyProtocol] = options.proxyTls ? 'https:' : 'http:'
57
- this[kRequestTls] = options.requestTls
68
+
69
+ const connectTimeout = options.connectTimeout ?? DEFAULT_SOCKS5_CONNECT_TIMEOUT
70
+ if (!Number.isFinite(connectTimeout) || connectTimeout < 0) {
71
+ throw new InvalidArgumentError('invalid connectTimeout')
72
+ }
73
+ this[kConnectTimeout] = connectTimeout
74
+
75
+ const { timeout, ...requestTls } = options.requestTls || {}
76
+ const requestTlsTimeout = timeout ?? connectTimeout
77
+ if (!Number.isFinite(requestTlsTimeout) || requestTlsTimeout < 0) {
78
+ throw new InvalidArgumentError('invalid requestTls.timeout')
79
+ }
80
+ this[kRequestTls] = requestTls
81
+ this[kRequestTlsTimeout] = requestTlsTimeout
58
82
 
59
83
  // Extract auth from URL or options
60
84
  this[kProxyAuth] = {
@@ -63,8 +87,13 @@ class Socks5ProxyAgent extends DispatcherBase {
63
87
  }
64
88
 
65
89
  // Create connector for proxy connection
90
+ const proxyTlsTimeout = options.proxyTls?.timeout ?? connectTimeout
91
+ if (!Number.isFinite(proxyTlsTimeout) || proxyTlsTimeout < 0) {
92
+ throw new InvalidArgumentError('invalid proxyTls.timeout')
93
+ }
66
94
  this[kConnector] = options.connect || buildConnector({
67
95
  ...options.proxyTls,
96
+ timeout: proxyTlsTimeout,
68
97
  servername: options.proxyTls?.servername || url.hostname
69
98
  })
70
99
 
@@ -113,20 +142,29 @@ class Socks5ProxyAgent extends DispatcherBase {
113
142
 
114
143
  // Wait for authentication (if required)
115
144
  const authenticationReady = Promise.withResolvers()
116
-
117
- const authenticationTimeout = setTimeout(() => {
118
- authenticationReady.reject(new Error('SOCKS5 authentication timeout'))
119
- }, 5000)
120
-
121
- const onAuthenticated = () => {
145
+ const authenticationTimeout = this[kConnectTimeout] === 0
146
+ ? null
147
+ : setTimeout(() => {
148
+ cleanupAuthenticationListeners()
149
+ socks5Client.destroy()
150
+ authenticationReady.reject(
151
+ createConnectTimeoutError(proxyHost, proxyPort, this[kConnectTimeout])
152
+ )
153
+ }, this[kConnectTimeout])
154
+
155
+ const cleanupAuthenticationListeners = () => {
122
156
  clearTimeout(authenticationTimeout)
157
+ socks5Client.removeListener('authenticated', onAuthenticated)
123
158
  socks5Client.removeListener('error', onAuthenticationError)
159
+ }
160
+
161
+ const onAuthenticated = () => {
162
+ cleanupAuthenticationListeners()
124
163
  authenticationReady.resolve()
125
164
  }
126
165
 
127
166
  const onAuthenticationError = (err) => {
128
- clearTimeout(authenticationTimeout)
129
- socks5Client.removeListener('authenticated', onAuthenticated)
167
+ cleanupAuthenticationListeners()
130
168
  authenticationReady.reject(err)
131
169
  }
132
170
 
@@ -146,21 +184,30 @@ class Socks5ProxyAgent extends DispatcherBase {
146
184
 
147
185
  // Wait for connection
148
186
  const connectionReady = Promise.withResolvers()
149
-
150
- const connectionTimeout = setTimeout(() => {
151
- connectionReady.reject(new Error('SOCKS5 connection timeout'))
152
- }, 5000)
187
+ const connectionTimeout = this[kConnectTimeout] === 0
188
+ ? null
189
+ : setTimeout(() => {
190
+ cleanupConnectionListeners()
191
+ socks5Client.destroy()
192
+ connectionReady.reject(
193
+ createConnectTimeoutError(targetHost, targetPort, this[kConnectTimeout])
194
+ )
195
+ }, this[kConnectTimeout])
196
+
197
+ const cleanupConnectionListeners = () => {
198
+ clearTimeout(connectionTimeout)
199
+ socks5Client.removeListener('connected', onConnected)
200
+ socks5Client.removeListener('error', onConnectionError)
201
+ }
153
202
 
154
203
  const onConnected = (info) => {
155
204
  debug('SOCKS5 tunnel established to', targetHost, targetPort, 'via', info)
156
- clearTimeout(connectionTimeout)
157
- socks5Client.removeListener('error', onConnectionError)
205
+ cleanupConnectionListeners()
158
206
  connectionReady.resolve()
159
207
  }
160
208
 
161
209
  const onConnectionError = (err) => {
162
- clearTimeout(connectionTimeout)
163
- socks5Client.removeListener('connected', onConnected)
210
+ cleanupConnectionListeners()
164
211
  connectionReady.reject(err)
165
212
  }
166
213
 
@@ -213,8 +260,31 @@ class Socks5ProxyAgent extends DispatcherBase {
213
260
  })
214
261
 
215
262
  const tlsReady = Promise.withResolvers()
216
- finalSocket.once('secureConnect', tlsReady.resolve)
217
- finalSocket.once('error', tlsReady.reject)
263
+
264
+ const cleanupTlsListeners = () => {
265
+ queueMicrotask(clearTlsTimeout)
266
+ finalSocket.removeListener('secureConnect', onSecureConnect)
267
+ finalSocket.removeListener('error', onTlsError)
268
+ }
269
+
270
+ const onSecureConnect = () => {
271
+ cleanupTlsListeners()
272
+ tlsReady.resolve()
273
+ }
274
+
275
+ const onTlsError = (err) => {
276
+ cleanupTlsListeners()
277
+ tlsReady.reject(err)
278
+ }
279
+
280
+ const clearTlsTimeout = setupConnectTimeout(new WeakRef(finalSocket), {
281
+ timeout: this[kRequestTlsTimeout],
282
+ hostname: targetHost,
283
+ port: targetPort
284
+ })
285
+
286
+ finalSocket.once('secureConnect', onSecureConnect)
287
+ finalSocket.once('error', onTlsError)
218
288
  await tlsReady.promise
219
289
  }
220
290
 
@@ -173,6 +173,14 @@ class CacheHandler {
173
173
  this.#handler.onRequestStart?.(controller, context)
174
174
  }
175
175
 
176
+ onBodySent (chunk) {
177
+ this.#handler.onBodySent?.(chunk)
178
+ }
179
+
180
+ onRequestSent () {
181
+ this.#handler.onRequestSent?.()
182
+ }
183
+
176
184
  onRequestUpgrade (controller, statusCode, headers, socket) {
177
185
  this.#handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
178
186
  }
@@ -210,6 +218,13 @@ class CacheHandler {
210
218
  }
211
219
 
212
220
  const cacheControlHeader = resHeaders['cache-control']
221
+ const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}
222
+
223
+ if (revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives)) {
224
+ deleteCachedValue(this.#store, this.#cacheKey)
225
+ return downstreamOnHeaders()
226
+ }
227
+
213
228
  const heuristicallyCacheable = resHeaders['last-modified'] && arrayIncludes(HEURISTICALLY_CACHEABLE_STATUS_CODES, statusCode)
214
229
  if (
215
230
  !cacheControlHeader &&
@@ -226,8 +241,7 @@ class CacheHandler {
226
241
  return downstreamOnHeaders()
227
242
  }
228
243
 
229
- const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}
230
- if (!canCacheResponse(this.#cacheType, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) {
244
+ if (!canCacheResponse(this.#cacheType, this.#cacheKey.method, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) {
231
245
  if (statusCode === 304 && (cacheControlHeader || revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives))) {
232
246
  deleteCachedValue(this.#store, this.#cacheKey)
233
247
  }
@@ -476,7 +490,10 @@ function deleteCachedValueIfNotModified (statusCode, store, cacheKey) {
476
490
  */
477
491
  function revalidationResponseDisallowsCachedReuse (cacheType, resHeaders, cacheControlDirectives) {
478
492
  return cacheControlDirectives['no-store'] === true ||
479
- (cacheType === 'shared' && cacheControlDirectives.private === true) ||
493
+ (cacheType === 'shared' && (
494
+ cacheControlDirectives.private === true ||
495
+ Object.hasOwn(resHeaders, 'set-cookie')
496
+ )) ||
480
497
  (resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false)
481
498
  }
482
499
 
@@ -484,12 +501,16 @@ function revalidationResponseDisallowsCachedReuse (cacheType, resHeaders, cacheC
484
501
  * @see https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-to-authen
485
502
  *
486
503
  * @param {import('../../types/cache-interceptor.d.ts').default.CacheOptions['type']} cacheType
504
+ * @param {string} method
487
505
  * @param {number} statusCode
488
506
  * @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders
489
507
  * @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
490
508
  * @param {import('../../types/header.d.ts').IncomingHttpHeaders} [reqHeaders]
491
509
  */
492
- function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) {
510
+ function canCacheResponse (cacheType, method, statusCode, resHeaders, cacheControlDirectives, reqHeaders) {
511
+ if (!arrayIncludes(util.safeHTTPMethods, method)) {
512
+ return false
513
+ }
493
514
  // Status code must be final and understood.
494
515
  if (statusCode < 200 || arrayIncludes(NOT_UNDERSTOOD_STATUS_CODES, statusCode)) {
495
516
  return false
@@ -510,7 +531,10 @@ function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirect
510
531
  return false
511
532
  }
512
533
 
513
- if (cacheType === 'shared' && cacheControlDirectives.private === true) {
534
+ if (cacheType === 'shared' && (
535
+ cacheControlDirectives.private === true ||
536
+ Object.hasOwn(resHeaders, 'set-cookie')
537
+ )) {
514
538
  return false
515
539
  }
516
540
 
@@ -62,5 +62,11 @@ module.exports = class DecoratorHandler {
62
62
  /**
63
63
  * @deprecated
64
64
  */
65
- onBodySent () {}
65
+ onBodySent (...args) {
66
+ return this.#handler.onBodySent?.(...args)
67
+ }
68
+
69
+ onRequestSent (...args) {
70
+ return this.#handler.onRequestSent?.(...args)
71
+ }
66
72
  }
@@ -365,12 +365,22 @@ class DeduplicationHandler {
365
365
  get aborted () { return state.aborted },
366
366
  get reason () { return state.reason },
367
367
  abort: (reason) => {
368
+ if (state.aborted) {
369
+ return
370
+ }
371
+
368
372
  state.aborted = true
369
373
  state.reason = reason ?? null
370
374
  waitingHandler.done = true
371
375
  waitingHandler.pendingTrailers = null
372
376
  waitingHandler.bufferedChunks = []
373
377
  waitingHandler.bufferedBytes = 0
378
+
379
+ try {
380
+ handler.onResponseError?.(waitingHandler.controller, state.reason ?? new RequestAbortedError())
381
+ } catch {
382
+ // Ignore errors from waiting handlers
383
+ }
374
384
  }
375
385
  }
376
386
 
@@ -444,12 +454,8 @@ class DeduplicationHandler {
444
454
  waitingHandler.bufferedChunks = []
445
455
  waitingHandler.bufferedBytes = 0
446
456
 
447
- try {
448
- waitingHandler.controller.abort(err)
449
- waitingHandler.handler.onResponseError?.(waitingHandler.controller, err)
450
- } catch {
451
- // Ignore errors from waiting handlers
452
- }
457
+ // controller.abort(err) notifies the handler via onResponseError
458
+ waitingHandler.controller.abort(err)
453
459
  }
454
460
 
455
461
  #pruneDoneWaitingHandlers () {
@@ -3,6 +3,7 @@
3
3
  const util = require('../core/util')
4
4
  const assert = require('node:assert')
5
5
  const { InvalidArgumentError } = require('../core/errors')
6
+ const { kRequestOrigin } = require('../core/symbols')
6
7
 
7
8
  const redirectableStatusCodes = [300, 301, 302, 303, 307, 308]
8
9
 
@@ -43,6 +44,14 @@ class RedirectHandler {
43
44
  this.handler.onRequestStart?.(controller, { ...context, history: this.history })
44
45
  }
45
46
 
47
+ onBodySent (chunk) {
48
+ this.handler.onBodySent?.(chunk)
49
+ }
50
+
51
+ onRequestSent () {
52
+ this.handler.onRequestSent?.()
53
+ }
54
+
46
55
  onRequestUpgrade (controller, statusCode, headers, socket) {
47
56
  this.handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
48
57
  }
@@ -81,8 +90,12 @@ class RedirectHandler {
81
90
  ? null
82
91
  : headers.location
83
92
 
84
- if (this.opts.origin) {
85
- this.history.push(new URL(this.opts.path, this.opts.origin))
93
+ const requestOrigin = this.opts[kRequestOrigin] === undefined
94
+ ? this.opts.origin
95
+ : this.opts[kRequestOrigin]
96
+
97
+ if (requestOrigin) {
98
+ this.history.push(new URL(this.opts.path, requestOrigin))
86
99
  }
87
100
 
88
101
  if (!this.location) {
@@ -90,7 +103,10 @@ class RedirectHandler {
90
103
  return
91
104
  }
92
105
 
93
- const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)))
106
+ const baseUrl = requestOrigin
107
+ ? new URL(this.opts.path, requestOrigin)
108
+ : undefined
109
+ const { origin, pathname, search } = util.parseURL(new URL(this.location, baseUrl))
94
110
  const path = search ? `${pathname}${search}` : pathname
95
111
 
96
112
  // Check for redirect loops by seeing if we've already visited this URL in our history
@@ -106,9 +122,10 @@ class RedirectHandler {
106
122
  // Remove headers referring to the original URL.
107
123
  // By default it is Host only. A 303 or a 301/302 POST-to-GET redirect also removes all Content-* headers.
108
124
  // https://tools.ietf.org/html/rfc7231#section-6.4
109
- this.opts.headers = cleanRequestHeaders(this.opts.headers, removeContentHeaders, this.opts.origin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect)
125
+ this.opts.headers = cleanRequestHeaders(this.opts.headers, removeContentHeaders, requestOrigin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect)
110
126
  this.opts.path = path
111
127
  this.opts.origin = origin
128
+ this.opts[kRequestOrigin] = origin
112
129
  this.opts.query = null
113
130
  }
114
131