@openclaw/discord 2026.6.8 → 2026.6.9-beta.1
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.
- package/dist/action-runtime-api.js +1 -1
- package/dist/api.js +13 -13
- package/dist/{approval-handler.runtime-B3gyUd-L.js → approval-handler.runtime-BprBDUQG.js} +3 -3
- package/dist/{audit-BlfewK04.js → audit-DuZUxGjM.js} +3 -3
- package/dist/{channel-b0hY1EJw.js → channel--3YhTUOb.js} +27 -19
- package/dist/{channel-actions-BnPHwCZ_.js → channel-actions-CoudAyAB.js} +12 -6
- package/dist/{channel-actions.runtime-DX5iW6ut.js → channel-actions.runtime-DdOfD3fi.js} +5 -5
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-By5cfELZ.js → channel.setup-C-y6Jifd.js} +2 -2
- package/dist/{components-D-CYw0-b.js → components-CUmrNvv-.js} +1 -1
- package/dist/{conversation-identity-CKzQAqFF.js → conversation-identity-CN-HPn11.js} +2 -2
- package/dist/{directory-config-Bu7FYOsl.js → directory-config-BCt5KxcX.js} +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-LjENjK6L.js → directory-live-CE7IDmwo.js} +1 -1
- package/dist/{handle-action.guild-admin-BS2qnhXF.js → handle-action.guild-admin-B7SnVS0m.js} +14 -9
- package/dist/index.js +1 -1
- package/dist/{manager.runtime-BU1vkOeO.js → manager.runtime-zMVwNPAT.js} +12 -4
- package/dist/{message-handler-CQVkXHMN.js → message-handler-DE413Oj4.js} +6 -6
- package/dist/{message-handler.preflight-DAnLOeDA.js → message-handler.preflight-BuF-DsE2.js} +10 -10
- package/dist/{message-handler.process-Dp5NQT05.js → message-handler.process-BX8HsMfV.js} +37 -23
- package/dist/{message-utils-Bx993JLN.js → message-utils-s_8KDqAQ.js} +1 -1
- package/dist/{outbound-adapter-CmN7ao1t.js → outbound-adapter-CNievjXH.js} +6 -6
- package/dist/{pluralkit-SYmlmerw.js → pluralkit-BXkU9XmC.js} +1 -1
- package/dist/{provider-DrScDA1p.js → provider-ByZ6xxgi.js} +85 -56
- package/dist/{provider-session.runtime-DXTzSYOJ.js → provider-session.runtime-DMfaQ9Z6.js} +3 -3
- package/dist/provider.runtime-EW-G8l_U.js +2 -0
- package/dist/{resolve-channels-Rautpk8n.js → resolve-channels-t1URw0Qz.js} +1 -1
- package/dist/{resolve-users-Bw7vvtsi.js → resolve-users-Bapkb237.js} +1 -1
- package/dist/{runtime-C80YEJ7Z.js → runtime-C6jV3hf4.js} +24 -10
- package/dist/runtime-api.actions.js +2 -2
- package/dist/runtime-api.js +19 -19
- package/dist/runtime-api.lookup.js +4 -4
- package/dist/runtime-api.monitor-5BSxmucu.js +6 -0
- package/dist/runtime-api.monitor.js +4 -4
- package/dist/runtime-api.send.js +5 -5
- package/dist/runtime-api.threads.js +3 -3
- package/dist/{send-zGsXF-up.js → send-o-Y1DiAT.js} +3 -3
- package/dist/{send.components-ktzrUTkt.js → send.components-B4_oNcOh.js} +4 -4
- package/dist/{send.outbound-C8oC51um.js → send.outbound-DhiXV3UJ.js} +53 -10
- package/dist/{send.receipt-DsQWEQ2O.js → send.receipt-HXIwVvXy.js} +2 -1
- package/dist/{send.shared-Dvo2ZCVG.js → send.shared-DYdjs_Zh.js} +13 -5
- package/dist/session-binding-contract-api.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{subagent-hooks-kjrWDeDg.js → subagent-hooks-CbF_Z5F0.js} +2 -2
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/{system-events-CvU3Aduf.js → system-events-BxTHlBbM.js} +1 -1
- package/dist/{target-resolver-DMPTzuo7.js → target-resolver-DpC8iueE.js} +2 -2
- package/dist/targets-BEIgHBHc.js +3 -0
- package/dist/{thread-bindings-DO32M2kW.js → thread-bindings-CEVvN75T.js} +4 -4
- package/dist/{thread-bindings.discord-api-304M1PMr.js → thread-bindings.discord-api-B8NfbxEB.js} +4 -4
- package/dist/{thread-bindings.manager-C9YT7wF2.js → thread-bindings.manager-BKfUaXGt.js} +3 -3
- package/dist/{transcripts-source-Chy2OrO_.js → transcripts-source-W6n_8J8g.js} +1 -1
- package/dist/transcripts-source-api.js +1 -1
- package/dist/{typing-BaivbXIG.js → typing-0-pUmlY9.js} +1 -1
- package/node_modules/undici/README.md +59 -18
- package/node_modules/undici/docs/docs/GettingStarted.md +278 -0
- package/node_modules/undici/docs/docs/api/Agent.md +3 -0
- package/node_modules/undici/docs/docs/api/BalancedPool.md +1 -1
- package/node_modules/undici/docs/docs/api/Client.md +44 -5
- package/node_modules/undici/docs/docs/api/Connector.md +1 -0
- package/node_modules/undici/docs/docs/api/Cookies.md +28 -1
- package/node_modules/undici/docs/docs/api/Dispatcher.md +22 -5
- package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +6 -9
- package/node_modules/undici/docs/docs/api/Errors.md +12 -0
- package/node_modules/undici/docs/docs/api/EventSource.md +50 -3
- package/node_modules/undici/docs/docs/api/Fetch.md +5 -3
- package/node_modules/undici/docs/docs/api/H2CClient.md +3 -3
- package/node_modules/undici/docs/docs/api/MockAgent.md +1 -1
- package/node_modules/undici/docs/docs/api/MockCallHistory.md +1 -1
- package/node_modules/undici/docs/docs/api/Pool.md +4 -1
- package/node_modules/undici/docs/docs/api/RedirectHandler.md +4 -1
- package/node_modules/undici/docs/docs/api/RetryAgent.md +3 -3
- package/node_modules/undici/docs/docs/api/RetryHandler.md +6 -6
- package/node_modules/undici/docs/docs/api/RoundRobinPool.md +1 -1
- package/node_modules/undici/docs/docs/api/SnapshotAgent.md +3 -3
- package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +1 -0
- package/node_modules/undici/docs/docs/api/api-lifecycle.md +4 -4
- package/node_modules/undici/lib/core/connect.js +29 -4
- package/node_modules/undici/lib/core/util.js +8 -6
- package/node_modules/undici/lib/dispatcher/client-h1.js +69 -2
- package/node_modules/undici/lib/dispatcher/client-h2.js +160 -37
- package/node_modules/undici/lib/dispatcher/client.js +36 -7
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +1 -0
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +2 -1
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +4 -2
- package/node_modules/undici/lib/handler/redirect-handler.js +36 -11
- package/node_modules/undici/lib/interceptor/dns.js +4 -0
- package/node_modules/undici/lib/interceptor/redirect.js +3 -3
- package/node_modules/undici/lib/mock/mock-call-history.js +1 -1
- package/node_modules/undici/lib/mock/snapshot-agent.js +9 -1
- package/node_modules/undici/lib/util/cache.js +8 -2
- package/node_modules/undici/lib/web/cookies/parse.js +17 -25
- package/node_modules/undici/lib/web/eventsource/eventsource.js +7 -18
- package/node_modules/undici/lib/web/eventsource/util.js +32 -1
- package/node_modules/undici/lib/web/fetch/body.js +43 -0
- package/node_modules/undici/lib/web/fetch/index.js +17 -3
- package/node_modules/undici/lib/web/fetch/request.js +33 -3
- package/node_modules/undici/lib/web/websocket/receiver.js +20 -3
- package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +8 -1
- package/node_modules/undici/lib/web/websocket/websocket.js +3 -1
- package/node_modules/undici/package.json +1 -1
- package/node_modules/undici/types/client.d.ts +5 -0
- package/node_modules/undici/types/connector.d.ts +1 -0
- package/node_modules/undici/types/fetch.d.ts +5 -1
- package/node_modules/undici/types/interceptors.d.ts +1 -1
- package/npm-shrinkwrap.json +7 -7
- package/package.json +5 -5
- package/dist/provider.runtime-nb-6cRoy.js +0 -2
- package/dist/runtime-api.monitor-D8KNDAd5.js +0 -6
- package/dist/targets-CKaNidbk.js +0 -3
|
@@ -8,7 +8,9 @@ const {
|
|
|
8
8
|
RequestAbortedError,
|
|
9
9
|
SocketError,
|
|
10
10
|
InformationalError,
|
|
11
|
-
InvalidArgumentError
|
|
11
|
+
InvalidArgumentError,
|
|
12
|
+
HeadersTimeoutError,
|
|
13
|
+
BodyTimeoutError
|
|
12
14
|
} = require('../core/errors.js')
|
|
13
15
|
const {
|
|
14
16
|
kUrl,
|
|
@@ -33,6 +35,8 @@ const {
|
|
|
33
35
|
kSize,
|
|
34
36
|
kHTTPContext,
|
|
35
37
|
kClosed,
|
|
38
|
+
kKeepAliveDefaultTimeout,
|
|
39
|
+
kHeadersTimeout,
|
|
36
40
|
kBodyTimeout,
|
|
37
41
|
kEnableConnectProtocol,
|
|
38
42
|
kRemoteSettings,
|
|
@@ -81,6 +85,29 @@ function getGoAwayError (session, errorCode) {
|
|
|
81
85
|
: new SocketError(`HTTP/2: "GOAWAY" frame received with code ${errorCode}`, util.getSocketInfo(session[kSocket])))
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
function resetHttp2Session (session, err) {
|
|
89
|
+
const client = session[kClient]
|
|
90
|
+
const socket = session[kSocket]
|
|
91
|
+
|
|
92
|
+
if (client[kHTTP2Session] === session) {
|
|
93
|
+
client[kSocket] = null
|
|
94
|
+
client[kHTTPContext] = null
|
|
95
|
+
client[kHTTP2Session] = null
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (socket != null && socket[kError] == null) {
|
|
99
|
+
socket[kError] = err
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!session.closed && !session.destroyed) {
|
|
103
|
+
try {
|
|
104
|
+
session.destroy(err)
|
|
105
|
+
} catch {}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
util.destroy(socket, err)
|
|
109
|
+
}
|
|
110
|
+
|
|
84
111
|
function getGoAwayPendingIdx (client, lastStreamID) {
|
|
85
112
|
const maxAcceptedStreamID = Number.isInteger(lastStreamID) ? lastStreamID : Number.MAX_SAFE_INTEGER
|
|
86
113
|
|
|
@@ -122,6 +149,25 @@ function clearRequestStream (request) {
|
|
|
122
149
|
cleanup?.(stream)
|
|
123
150
|
}
|
|
124
151
|
|
|
152
|
+
function requeueUnsentRequest (client, request) {
|
|
153
|
+
client[kQueue].splice(client[kPendingIdx] + 1, 0, request)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function completeRequest (client, request, resetPendingIdx = false) {
|
|
157
|
+
const index = client[kQueue].indexOf(request, client[kRunningIdx])
|
|
158
|
+
|
|
159
|
+
if (index === -1 || index >= client[kPendingIdx]) {
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
client[kQueue].splice(index, 1)
|
|
164
|
+
client[kPendingIdx]--
|
|
165
|
+
|
|
166
|
+
if (resetPendingIdx && client[kPendingIdx] < client[kRunningIdx]) {
|
|
167
|
+
client[kPendingIdx] = client[kRunningIdx]
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
125
171
|
function canRetryRequestAfterGoAway (request) {
|
|
126
172
|
const { body } = request
|
|
127
173
|
|
|
@@ -161,6 +207,7 @@ function connectH2 (client, socket) {
|
|
|
161
207
|
session[kClient] = client
|
|
162
208
|
session[kSocket] = socket
|
|
163
209
|
session[kHTTP2SessionState] = {
|
|
210
|
+
idleTimeout: null,
|
|
164
211
|
ping: {
|
|
165
212
|
interval: client[kPingInterval] === 0 ? null : setInterval(onHttp2SendPing, client[kPingInterval], session).unref()
|
|
166
213
|
}
|
|
@@ -249,10 +296,10 @@ function connectH2 (client, socket) {
|
|
|
249
296
|
if (client[kRunning] > 0) {
|
|
250
297
|
// We are already processing requests
|
|
251
298
|
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
|
|
299
|
+
// Unlike HTTP/1.1 pipelining, HTTP/2 multiplexes requests on
|
|
300
|
+
// independent streams, so non-idempotent requests can be dispatched
|
|
301
|
+
// concurrently. Retry eligibility is handled by stream/session error
|
|
302
|
+
// handling instead of by serializing all non-idempotent requests.
|
|
256
303
|
// Don't dispatch an upgrade until all preceding requests have completed.
|
|
257
304
|
// Possibly, we do not have remote settings confirmed yet.
|
|
258
305
|
if ((request.upgrade === 'websocket' || request.method === 'CONNECT') && session[kRemoteSettings] === false) return true
|
|
@@ -278,16 +325,66 @@ function connectH2 (client, socket) {
|
|
|
278
325
|
|
|
279
326
|
function resumeH2 (client) {
|
|
280
327
|
const socket = client[kSocket]
|
|
328
|
+
const session = client[kHTTP2Session]
|
|
281
329
|
|
|
282
330
|
if (socket?.destroyed === false) {
|
|
283
331
|
if (client[kSize] === 0 || client[kMaxConcurrentStreams] === 0) {
|
|
284
332
|
socket.unref()
|
|
285
|
-
|
|
333
|
+
session.unref()
|
|
286
334
|
} else {
|
|
287
335
|
socket.ref()
|
|
288
|
-
|
|
336
|
+
session.ref()
|
|
289
337
|
}
|
|
338
|
+
|
|
339
|
+
if (client[kSize] === 0 && session[kOpenStreams] === 0) {
|
|
340
|
+
setHttp2IdleTimeout(session)
|
|
341
|
+
} else {
|
|
342
|
+
clearHttp2IdleTimeout(session)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function clearHttp2IdleTimeout (session) {
|
|
348
|
+
const state = session[kHTTP2SessionState]
|
|
349
|
+
|
|
350
|
+
if (state?.idleTimeout != null) {
|
|
351
|
+
clearTimeout(state.idleTimeout)
|
|
352
|
+
state.idleTimeout = null
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function setHttp2IdleTimeout (session) {
|
|
357
|
+
const client = session[kClient]
|
|
358
|
+
|
|
359
|
+
if (client[kHTTP2Session] !== session || session.closed || session.destroyed) {
|
|
360
|
+
return
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (session[kOpenStreams] !== 0 || client[kSize] !== 0) {
|
|
364
|
+
clearHttp2IdleTimeout(session)
|
|
365
|
+
return
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
const state = session[kHTTP2SessionState]
|
|
369
|
+
if (state.idleTimeout == null) {
|
|
370
|
+
state.idleTimeout = setTimeout(onHttp2SessionIdleTimeout, client[kKeepAliveDefaultTimeout], session).unref()
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function onHttp2SessionIdleTimeout (session) {
|
|
375
|
+
const client = session[kClient]
|
|
376
|
+
const socket = session[kSocket]
|
|
377
|
+
const state = session[kHTTP2SessionState]
|
|
378
|
+
|
|
379
|
+
state.idleTimeout = null
|
|
380
|
+
|
|
381
|
+
if (client[kHTTP2Session] !== session || session[kOpenStreams] !== 0 || client[kSize] !== 0 || session.closed || session.destroyed) {
|
|
382
|
+
return
|
|
290
383
|
}
|
|
384
|
+
|
|
385
|
+
const err = new InformationalError('socket idle timeout')
|
|
386
|
+
socket[kError] = err
|
|
387
|
+
util.destroy(socket, err)
|
|
291
388
|
}
|
|
292
389
|
|
|
293
390
|
function applyConnectionWindowSize (connectionWindowSize) {
|
|
@@ -415,6 +512,8 @@ function onHttp2SessionGoAway (errorCode, lastStreamID) {
|
|
|
415
512
|
client[kHTTP2Session] = null
|
|
416
513
|
}
|
|
417
514
|
|
|
515
|
+
clearHttp2IdleTimeout(this)
|
|
516
|
+
|
|
418
517
|
if (!this.closed && !this.destroyed) {
|
|
419
518
|
this.close()
|
|
420
519
|
}
|
|
@@ -437,6 +536,8 @@ function onHttp2SessionClose () {
|
|
|
437
536
|
client[kHTTP2Session] = null
|
|
438
537
|
}
|
|
439
538
|
|
|
539
|
+
clearHttp2IdleTimeout(this)
|
|
540
|
+
|
|
440
541
|
if (state.ping.interval != null) {
|
|
441
542
|
clearInterval(state.ping.interval)
|
|
442
543
|
state.ping.interval = null
|
|
@@ -449,7 +550,9 @@ function onHttp2SessionClose () {
|
|
|
449
550
|
const requests = client[kQueue].splice(client[kRunningIdx])
|
|
450
551
|
for (let i = 0; i < requests.length; i++) {
|
|
451
552
|
const request = requests[i]
|
|
452
|
-
|
|
553
|
+
if (request != null) {
|
|
554
|
+
util.errorRequest(client, request, err)
|
|
555
|
+
}
|
|
453
556
|
}
|
|
454
557
|
}
|
|
455
558
|
}
|
|
@@ -512,6 +615,7 @@ function closeStreamSession (stream) {
|
|
|
512
615
|
session[kOpenStreams] -= 1
|
|
513
616
|
if (session[kOpenStreams] === 0) {
|
|
514
617
|
session.unref()
|
|
618
|
+
setHttp2IdleTimeout(session)
|
|
515
619
|
}
|
|
516
620
|
}
|
|
517
621
|
|
|
@@ -526,6 +630,19 @@ function onUpgradeStreamClose () {
|
|
|
526
630
|
}
|
|
527
631
|
|
|
528
632
|
function onRequestStreamClose () {
|
|
633
|
+
const state = this[kRequestStreamState]
|
|
634
|
+
|
|
635
|
+
if (state) {
|
|
636
|
+
// Release the stream first so request references are cleared,
|
|
637
|
+
// then complete the response with trailers if available.
|
|
638
|
+
releaseRequestStream(this)
|
|
639
|
+
|
|
640
|
+
if (state.pendingEnd && !state.request.aborted && !state.request.completed) {
|
|
641
|
+
state.request.onResponseEnd(state.trailers || {})
|
|
642
|
+
state.finalizeRequest()
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
529
646
|
this.off('data', onData)
|
|
530
647
|
this.off('error', noop)
|
|
531
648
|
closeStreamSession(this)
|
|
@@ -629,7 +746,7 @@ function onUpgradeStreamEnd () {
|
|
|
629
746
|
|
|
630
747
|
function onUpgradeStreamTimeout () {
|
|
631
748
|
const state = this[kRequestStreamState]
|
|
632
|
-
failUpgradeStream(state, new InformationalError(`HTTP/2: "stream timeout after ${state.
|
|
749
|
+
failUpgradeStream(state, new InformationalError(`HTTP/2: "stream timeout after ${state.headersTimeout}"`))
|
|
633
750
|
}
|
|
634
751
|
|
|
635
752
|
function onUpgradeResponse (headers, _flags) {
|
|
@@ -654,7 +771,7 @@ function onUpgradeResponse (headers, _flags) {
|
|
|
654
771
|
}
|
|
655
772
|
|
|
656
773
|
function setupUpgradeStream (stream, state) {
|
|
657
|
-
const { request,
|
|
774
|
+
const { request, headersTimeout, session } = state
|
|
658
775
|
|
|
659
776
|
stream[kHTTP2Stream] = true
|
|
660
777
|
stream[kHTTP2Session] = session
|
|
@@ -668,12 +785,14 @@ function setupUpgradeStream (stream, state) {
|
|
|
668
785
|
stream.on('timeout', onUpgradeStreamTimeout)
|
|
669
786
|
stream.once('close', onUpgradeStreamClose)
|
|
670
787
|
|
|
788
|
+
clearHttp2IdleTimeout(session)
|
|
671
789
|
++session[kOpenStreams]
|
|
672
|
-
stream.setTimeout(
|
|
790
|
+
stream.setTimeout(headersTimeout)
|
|
673
791
|
}
|
|
674
792
|
|
|
675
793
|
function writeH2 (client, request) {
|
|
676
|
-
const
|
|
794
|
+
const headersTimeout = request.headersTimeout ?? client[kHeadersTimeout]
|
|
795
|
+
const bodyTimeout = request.bodyTimeout ?? client[kBodyTimeout]
|
|
677
796
|
const session = client[kHTTP2Session]
|
|
678
797
|
const { method, path, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request
|
|
679
798
|
let { body } = request
|
|
@@ -698,11 +817,7 @@ function writeH2 (client, request) {
|
|
|
698
817
|
}
|
|
699
818
|
|
|
700
819
|
requestFinalized = true
|
|
701
|
-
client
|
|
702
|
-
|
|
703
|
-
if (resetPendingIdx) {
|
|
704
|
-
client[kPendingIdx] = client[kRunningIdx]
|
|
705
|
-
}
|
|
820
|
+
completeRequest(client, request, resetPendingIdx)
|
|
706
821
|
|
|
707
822
|
client[kResume]()
|
|
708
823
|
}
|
|
@@ -736,8 +851,14 @@ function writeH2 (client, request) {
|
|
|
736
851
|
try {
|
|
737
852
|
return session.request(headers, options)
|
|
738
853
|
} catch (err) {
|
|
739
|
-
if (err?.code
|
|
740
|
-
|
|
854
|
+
if (err?.code === 'ERR_HTTP2_INVALID_SESSION') {
|
|
855
|
+
const wrappedErr = new SocketError(err.message, util.getSocketInfo(session[kSocket]))
|
|
856
|
+
wrappedErr.cause = err
|
|
857
|
+
session[kError] = wrappedErr
|
|
858
|
+
resetHttp2Session(session, wrappedErr)
|
|
859
|
+
requeueUnsentRequest(client, request)
|
|
860
|
+
|
|
861
|
+
return null
|
|
741
862
|
}
|
|
742
863
|
|
|
743
864
|
const wrappedErr = new InformationalError(err.message, { cause: err })
|
|
@@ -771,7 +892,8 @@ function writeH2 (client, request) {
|
|
|
771
892
|
abort,
|
|
772
893
|
finalizeRequest,
|
|
773
894
|
request,
|
|
774
|
-
|
|
895
|
+
headersTimeout,
|
|
896
|
+
bodyTimeout,
|
|
775
897
|
responseReceived: false,
|
|
776
898
|
session,
|
|
777
899
|
stream: null
|
|
@@ -912,7 +1034,8 @@ function writeH2 (client, request) {
|
|
|
912
1034
|
expectsPayload,
|
|
913
1035
|
finalizeRequest,
|
|
914
1036
|
request,
|
|
915
|
-
|
|
1037
|
+
headersTimeout,
|
|
1038
|
+
bodyTimeout,
|
|
916
1039
|
responseReceived: false,
|
|
917
1040
|
session,
|
|
918
1041
|
stream: null
|
|
@@ -929,11 +1052,11 @@ function writeH2 (client, request) {
|
|
|
929
1052
|
stream[kHTTP2Stream] = true
|
|
930
1053
|
stream[kRequestStreamState] = state
|
|
931
1054
|
state.stream = stream
|
|
932
|
-
bindRequestToStream(request, stream, null)
|
|
933
1055
|
|
|
934
1056
|
// Increment counter as we have new streams open
|
|
1057
|
+
clearHttp2IdleTimeout(session)
|
|
935
1058
|
++session[kOpenStreams]
|
|
936
|
-
stream.setTimeout(
|
|
1059
|
+
stream.setTimeout(headersTimeout)
|
|
937
1060
|
|
|
938
1061
|
stream[kHTTP2Session] = session
|
|
939
1062
|
stream.once('close', onRequestStreamClose)
|
|
@@ -1017,6 +1140,7 @@ function onResponse (headers) {
|
|
|
1017
1140
|
delete headers[HTTP2_HEADER_STATUS]
|
|
1018
1141
|
request.onResponseStarted()
|
|
1019
1142
|
state.responseReceived = true
|
|
1143
|
+
stream.setTimeout(state.bodyTimeout)
|
|
1020
1144
|
|
|
1021
1145
|
// Due to the stream nature, it is possible we face a race condition
|
|
1022
1146
|
// where the stream has been assigned, but the request has been aborted
|
|
@@ -1042,14 +1166,14 @@ function onEnd () {
|
|
|
1042
1166
|
|
|
1043
1167
|
stream.off('end', onEnd)
|
|
1044
1168
|
|
|
1045
|
-
|
|
1046
|
-
//
|
|
1169
|
+
// If we received a response, this is a normal completion.
|
|
1170
|
+
// Defer actual completion to onRequestStreamClose so that
|
|
1171
|
+
// onTrailers (which may fire after 'end' on Windows) can
|
|
1172
|
+
// store trailers first.
|
|
1047
1173
|
if (state.responseReceived) {
|
|
1048
1174
|
if (!request.aborted && !request.completed) {
|
|
1049
|
-
|
|
1175
|
+
state.pendingEnd = true
|
|
1050
1176
|
}
|
|
1051
|
-
|
|
1052
|
-
state.finalizeRequest()
|
|
1053
1177
|
} else {
|
|
1054
1178
|
// Stream ended without receiving a response - this is an error
|
|
1055
1179
|
// (e.g., server destroyed the stream before sending headers)
|
|
@@ -1062,8 +1186,6 @@ function onError (err) {
|
|
|
1062
1186
|
const state = stream[kRequestStreamState]
|
|
1063
1187
|
|
|
1064
1188
|
stream.off('error', onError)
|
|
1065
|
-
|
|
1066
|
-
releaseRequestStream(stream)
|
|
1067
1189
|
state.abort(err)
|
|
1068
1190
|
}
|
|
1069
1191
|
|
|
@@ -1072,8 +1194,6 @@ function onFrameError (type, code) {
|
|
|
1072
1194
|
const state = stream[kRequestStreamState]
|
|
1073
1195
|
|
|
1074
1196
|
stream.off('frameError', onFrameError)
|
|
1075
|
-
|
|
1076
|
-
releaseRequestStream(stream)
|
|
1077
1197
|
state.abort(new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`))
|
|
1078
1198
|
}
|
|
1079
1199
|
|
|
@@ -1085,9 +1205,12 @@ function onTimeout () {
|
|
|
1085
1205
|
const stream = this
|
|
1086
1206
|
const state = stream[kRequestStreamState]
|
|
1087
1207
|
|
|
1088
|
-
|
|
1208
|
+
// Remove self so timeout doesn't fire again after we handle it
|
|
1209
|
+
stream.off('timeout', onTimeout)
|
|
1089
1210
|
|
|
1090
|
-
const err =
|
|
1211
|
+
const err = state.responseReceived
|
|
1212
|
+
? new BodyTimeoutError(`HTTP/2: "stream timeout after ${state.bodyTimeout}"`)
|
|
1213
|
+
: new HeadersTimeoutError(`HTTP/2: "headers timeout after ${state.headersTimeout}"`)
|
|
1091
1214
|
state.abort(err)
|
|
1092
1215
|
}
|
|
1093
1216
|
|
|
@@ -1097,14 +1220,14 @@ function onTrailers (trailers) {
|
|
|
1097
1220
|
const { request } = state
|
|
1098
1221
|
|
|
1099
1222
|
stream.off('trailers', onTrailers)
|
|
1223
|
+
stream.off('data', onData)
|
|
1100
1224
|
|
|
1101
1225
|
if (request.aborted || request.completed) {
|
|
1102
1226
|
return
|
|
1103
1227
|
}
|
|
1104
1228
|
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
state.finalizeRequest()
|
|
1229
|
+
// Store trailers for onRequestStreamClose to use when completing
|
|
1230
|
+
state.trailers = trailers
|
|
1108
1231
|
}
|
|
1109
1232
|
|
|
1110
1233
|
function writeBodyH2 () {
|
|
@@ -76,6 +76,18 @@ function getPipelining (client) {
|
|
|
76
76
|
return client[kPipelining] ?? client[kHTTPContext]?.defaultPipelining ?? 1
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
// Protocol-aware dispatch ceiling. h1 RFC7230 pipelining is unrelated to h2
|
|
80
|
+
// stream multiplexing — over h2 the ceiling is the (server-confirmed)
|
|
81
|
+
// maxConcurrentStreams. Before a context is attached we use the h1
|
|
82
|
+
// pipelining factor; once h2 attaches the queued requests can drain in
|
|
83
|
+
// one batch up to maxConcurrentStreams.
|
|
84
|
+
function getMaxConcurrent (client) {
|
|
85
|
+
if (client[kHTTPContext]?.version === 'h2') {
|
|
86
|
+
return client[kMaxConcurrentStreams]
|
|
87
|
+
}
|
|
88
|
+
return getPipelining(client)
|
|
89
|
+
}
|
|
90
|
+
|
|
79
91
|
/**
|
|
80
92
|
* @type {import('../../types/client.js').default}
|
|
81
93
|
*/
|
|
@@ -326,10 +338,17 @@ class Client extends DispatcherBase {
|
|
|
326
338
|
}
|
|
327
339
|
|
|
328
340
|
get [kBusy] () {
|
|
341
|
+
// The `kPending > 0` check below is the gate Pool uses to decide whether
|
|
342
|
+
// to spin up an additional Client. For h1 that fan-out is correct —
|
|
343
|
+
// each socket only handles one pipelined request at a time. Once an h2
|
|
344
|
+
// context is attached we want concurrent dispatches to multiplex onto
|
|
345
|
+
// the shared session, so suppress that signal in the h2 case.
|
|
346
|
+
const allowsMux = this[kHTTPContext]?.version === 'h2'
|
|
347
|
+
|
|
329
348
|
return Boolean(
|
|
330
349
|
this[kHTTPContext]?.busy(null) ||
|
|
331
|
-
(this[kSize] >= (
|
|
332
|
-
this[kPending] > 0
|
|
350
|
+
(this[kSize] >= (getMaxConcurrent(this) || 1)) ||
|
|
351
|
+
(this[kPending] > 0 && !allowsMux)
|
|
333
352
|
)
|
|
334
353
|
}
|
|
335
354
|
|
|
@@ -376,7 +395,9 @@ class Client extends DispatcherBase {
|
|
|
376
395
|
const requests = this[kQueue].splice(this[kPendingIdx])
|
|
377
396
|
for (let i = 0; i < requests.length; i++) {
|
|
378
397
|
const request = requests[i]
|
|
379
|
-
|
|
398
|
+
if (request != null) {
|
|
399
|
+
util.errorRequest(this, request, err)
|
|
400
|
+
}
|
|
380
401
|
}
|
|
381
402
|
|
|
382
403
|
const callback = () => {
|
|
@@ -415,7 +436,9 @@ function onError (client, err) {
|
|
|
415
436
|
|
|
416
437
|
for (let i = 0; i < requests.length; i++) {
|
|
417
438
|
const request = requests[i]
|
|
418
|
-
|
|
439
|
+
if (request != null) {
|
|
440
|
+
util.errorRequest(client, request, err)
|
|
441
|
+
}
|
|
419
442
|
}
|
|
420
443
|
assert(client[kSize] === 0)
|
|
421
444
|
}
|
|
@@ -549,9 +572,15 @@ function handleConnectError (client, err, { host, hostname, protocol, port }) {
|
|
|
549
572
|
}
|
|
550
573
|
|
|
551
574
|
if (err.code === 'ERR_TLS_CERT_ALTNAME_INVALID') {
|
|
552
|
-
|
|
575
|
+
const running = client[kQueue].splice(client[kRunningIdx], client[kRunning])
|
|
576
|
+
client[kPendingIdx] = client[kRunningIdx]
|
|
577
|
+
|
|
578
|
+
for (let i = 0; i < running.length; i++) {
|
|
579
|
+
util.errorRequest(client, running[i], err)
|
|
580
|
+
}
|
|
581
|
+
|
|
553
582
|
while (client[kPending] > 0 && client[kQueue][client[kPendingIdx]].servername === client[kServerName]) {
|
|
554
|
-
const request = client[kQueue]
|
|
583
|
+
const request = client[kQueue].splice(client[kPendingIdx], 1)[0]
|
|
555
584
|
util.errorRequest(client, request, err)
|
|
556
585
|
}
|
|
557
586
|
} else {
|
|
@@ -616,7 +645,7 @@ function _resume (client, sync) {
|
|
|
616
645
|
return
|
|
617
646
|
}
|
|
618
647
|
|
|
619
|
-
if (client[kRunning] >= (
|
|
648
|
+
if (client[kRunning] >= (getMaxConcurrent(client) || 1)) {
|
|
620
649
|
return
|
|
621
650
|
}
|
|
622
651
|
|
|
@@ -147,7 +147,8 @@ class ProxyAgent extends DispatcherBase {
|
|
|
147
147
|
factory: agentFactory,
|
|
148
148
|
username: opts.username || username,
|
|
149
149
|
password: opts.password || password,
|
|
150
|
-
proxyTls: opts.proxyTls
|
|
150
|
+
proxyTls: opts.proxyTls,
|
|
151
|
+
requestTls: opts.requestTls
|
|
151
152
|
})
|
|
152
153
|
}
|
|
153
154
|
|
|
@@ -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()
|
|
@@ -29,9 +29,11 @@ class RedirectHandler {
|
|
|
29
29
|
|
|
30
30
|
this.dispatch = dispatch
|
|
31
31
|
this.location = null
|
|
32
|
-
const { maxRedirections: _, ...cleanOpts } = opts
|
|
32
|
+
const { maxRedirections: _, stripHeadersOnRedirect, stripHeadersOnCrossOriginRedirect, ...cleanOpts } = opts
|
|
33
33
|
this.opts = cleanOpts // opts must be a copy, exclude maxRedirections
|
|
34
34
|
this.opts.body = util.wrapRequestBody(this.opts.body)
|
|
35
|
+
this.stripHeadersOnRedirect = normalizeStripHeaders(stripHeadersOnRedirect, 'stripHeadersOnRedirect')
|
|
36
|
+
this.stripHeadersOnCrossOriginRedirect = normalizeStripHeaders(stripHeadersOnCrossOriginRedirect, 'stripHeadersOnCrossOriginRedirect')
|
|
35
37
|
this.maxRedirections = maxRedirections
|
|
36
38
|
this.handler = handler
|
|
37
39
|
this.history = []
|
|
@@ -100,7 +102,7 @@ class RedirectHandler {
|
|
|
100
102
|
// Remove headers referring to the original URL.
|
|
101
103
|
// By default it is Host only, unless it's a 303 (see below), which removes also all Content-* headers.
|
|
102
104
|
// https://tools.ietf.org/html/rfc7231#section-6.4
|
|
103
|
-
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin)
|
|
105
|
+
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin, this.stripHeadersOnRedirect, this.stripHeadersOnCrossOriginRedirect)
|
|
104
106
|
this.opts.path = path
|
|
105
107
|
this.opts.origin = origin
|
|
106
108
|
this.opts.query = null
|
|
@@ -152,26 +154,49 @@ class RedirectHandler {
|
|
|
152
154
|
}
|
|
153
155
|
|
|
154
156
|
// https://tools.ietf.org/html/rfc7231#section-6.4.4
|
|
155
|
-
function shouldRemoveHeader (header, removeContent, unknownOrigin) {
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
function shouldRemoveHeader (header, removeContent, unknownOrigin, stripHeaders, stripHeadersOnCrossOrigin) {
|
|
158
|
+
const name = util.headerNameToString(header)
|
|
159
|
+
if (name === 'host') {
|
|
160
|
+
return true
|
|
161
|
+
}
|
|
162
|
+
if (stripHeaders?.has(name) || (unknownOrigin && stripHeadersOnCrossOrigin?.has(name))) {
|
|
163
|
+
return true
|
|
158
164
|
}
|
|
159
|
-
if (removeContent &&
|
|
165
|
+
if (removeContent && name.startsWith('content-')) {
|
|
160
166
|
return true
|
|
161
167
|
}
|
|
162
|
-
if (unknownOrigin
|
|
163
|
-
const name = util.headerNameToString(header)
|
|
168
|
+
if (unknownOrigin) {
|
|
164
169
|
return name === 'authorization' || name === 'cookie' || name === 'proxy-authorization'
|
|
165
170
|
}
|
|
166
171
|
return false
|
|
167
172
|
}
|
|
168
173
|
|
|
169
174
|
// https://tools.ietf.org/html/rfc7231#section-6.4
|
|
170
|
-
function
|
|
175
|
+
function normalizeStripHeaders (headers, optionName) {
|
|
176
|
+
if (headers == null) {
|
|
177
|
+
return null
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (!Array.isArray(headers)) {
|
|
181
|
+
throw new InvalidArgumentError(`${optionName} must be an array`)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const normalized = new Set()
|
|
185
|
+
for (const header of headers) {
|
|
186
|
+
if (typeof header !== 'string') {
|
|
187
|
+
throw new InvalidArgumentError(`${optionName} must contain header names`)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
normalized.add(util.headerNameToString(header))
|
|
191
|
+
}
|
|
192
|
+
return normalized
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function cleanRequestHeaders (headers, removeContent, unknownOrigin, stripHeaders, stripHeadersOnCrossOrigin) {
|
|
171
196
|
const ret = []
|
|
172
197
|
if (Array.isArray(headers)) {
|
|
173
198
|
for (let i = 0; i < headers.length; i += 2) {
|
|
174
|
-
if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin)) {
|
|
199
|
+
if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin, stripHeaders, stripHeadersOnCrossOrigin)) {
|
|
175
200
|
ret.push(headers[i], headers[i + 1])
|
|
176
201
|
}
|
|
177
202
|
}
|
|
@@ -179,7 +204,7 @@ function cleanRequestHeaders (headers, removeContent, unknownOrigin) {
|
|
|
179
204
|
const entries = util.hasSafeIterator(headers) ? headers : Object.entries(headers)
|
|
180
205
|
|
|
181
206
|
for (const [key, value] of entries) {
|
|
182
|
-
if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) {
|
|
207
|
+
if (!shouldRemoveHeader(key, removeContent, unknownOrigin, stripHeaders, stripHeadersOnCrossOrigin)) {
|
|
183
208
|
ret.push(key, value)
|
|
184
209
|
}
|
|
185
210
|
}
|
|
@@ -535,6 +535,10 @@ module.exports = interceptorOpts => {
|
|
|
535
535
|
|
|
536
536
|
return dispatch => {
|
|
537
537
|
return function dnsInterceptor (origDispatchOpts, handler) {
|
|
538
|
+
if (origDispatchOpts.origin == null) {
|
|
539
|
+
return dispatch(origDispatchOpts, handler)
|
|
540
|
+
}
|
|
541
|
+
|
|
538
542
|
const origin =
|
|
539
543
|
origDispatchOpts.origin.constructor === URL
|
|
540
544
|
? origDispatchOpts.origin
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
const RedirectHandler = require('../handler/redirect-handler')
|
|
4
4
|
|
|
5
|
-
function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections, throwOnMaxRedirect: defaultThrowOnMaxRedirect } = {}) {
|
|
5
|
+
function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections, throwOnMaxRedirect: defaultThrowOnMaxRedirect, stripHeadersOnRedirect: defaultStripHeadersOnRedirect, stripHeadersOnCrossOriginRedirect: defaultStripHeadersOnCrossOriginRedirect } = {}) {
|
|
6
6
|
return (dispatch) => {
|
|
7
7
|
return function Intercept (opts, handler) {
|
|
8
|
-
const { maxRedirections = defaultMaxRedirections, throwOnMaxRedirect = defaultThrowOnMaxRedirect, ...rest } = opts
|
|
8
|
+
const { maxRedirections = defaultMaxRedirections, throwOnMaxRedirect = defaultThrowOnMaxRedirect, stripHeadersOnRedirect = defaultStripHeadersOnRedirect, stripHeadersOnCrossOriginRedirect = defaultStripHeadersOnCrossOriginRedirect, ...rest } = opts
|
|
9
9
|
|
|
10
10
|
if (maxRedirections == null || maxRedirections === 0) {
|
|
11
11
|
return dispatch(opts, handler)
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
const dispatchOpts = { ...rest, throwOnMaxRedirect } // Stop sub dispatcher from also redirecting.
|
|
14
|
+
const dispatchOpts = { ...rest, throwOnMaxRedirect, stripHeadersOnRedirect, stripHeadersOnCrossOriginRedirect } // Stop sub dispatcher from also redirecting.
|
|
15
15
|
const redirectHandler = new RedirectHandler(dispatch, maxRedirections, dispatchOpts, handler)
|
|
16
16
|
return dispatch(dispatchOpts, redirectHandler)
|
|
17
17
|
}
|
|
@@ -35,7 +35,7 @@ function buildAndValidateFilterCallsOptions (options = {}) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
function makeFilterCalls (parameterName) {
|
|
38
|
-
return (parameterValue, logs) => {
|
|
38
|
+
return (parameterValue, logs = this.logs) => {
|
|
39
39
|
if (typeof parameterValue === 'string' || parameterValue == null) {
|
|
40
40
|
return logs.filter((log) => {
|
|
41
41
|
return log[parameterName] === parameterValue
|
|
@@ -354,7 +354,15 @@ class SnapshotAgent extends MockAgent {
|
|
|
354
354
|
* @returns {Promise<void>}
|
|
355
355
|
*/
|
|
356
356
|
async close () {
|
|
357
|
-
|
|
357
|
+
// In playback mode the recorder must not persist to disk. findSnapshot()
|
|
358
|
+
// mutates each matched snapshot's callCount, so saving on close would
|
|
359
|
+
// rewrite the snapshot file even though nothing new was recorded. Only
|
|
360
|
+
// record/update modes should write snapshots; playback just cleans up.
|
|
361
|
+
if (this[kSnapshotMode] === 'playback') {
|
|
362
|
+
this[kSnapshotRecorder].destroy()
|
|
363
|
+
} else {
|
|
364
|
+
await this[kSnapshotRecorder].close()
|
|
365
|
+
}
|
|
358
366
|
await this[kRealAgent]?.close()
|
|
359
367
|
await super.close()
|
|
360
368
|
}
|