@openclaw/discord 2026.6.8 → 2026.6.9
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-BmXlcjYW.js → api-4GFMoWu0.js} +4 -1
- package/dist/api.js +15 -15
- package/dist/{approval-handler.runtime-B3gyUd-L.js → approval-handler.runtime-20qhf0uH.js} +3 -3
- package/dist/{audit-BlfewK04.js → audit-CCffO6o7.js} +3 -3
- package/dist/{channel-actions-BnPHwCZ_.js → channel-actions-DDT9kJXw.js} +12 -6
- package/dist/{channel-actions.runtime-DX5iW6ut.js → channel-actions.runtime-CfMUtfAv.js} +5 -5
- package/dist/{channel-b0hY1EJw.js → channel-fEBKaO2Q.js} +28 -20
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-By5cfELZ.js → channel.setup-DRJiHe7I.js} +2 -3
- package/dist/{components-D-CYw0-b.js → components-CXEorOhu.js} +1 -1
- package/dist/{conversation-identity-CKzQAqFF.js → conversation-identity-BvlP-djn.js} +2 -2
- package/dist/{directory-config-Bu7FYOsl.js → directory-config-Bg8bulWB.js} +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-LjENjK6L.js → directory-live-BAJw6kS2.js} +2 -2
- package/dist/{handle-action.guild-admin-BS2qnhXF.js → handle-action.guild-admin-RxnJFLgU.js} +14 -9
- package/dist/index.js +1 -1
- package/dist/{manager.runtime-BU1vkOeO.js → manager.runtime-Bh5X0o8P.js} +12 -4
- package/dist/{message-handler-CQVkXHMN.js → message-handler-Dg3DRD0e.js} +6 -6
- package/dist/{message-handler.preflight-DAnLOeDA.js → message-handler.preflight-CcexCYuy.js} +10 -10
- package/dist/{message-handler.process-Dp5NQT05.js → message-handler.process-CN8bVDxj.js} +37 -45
- package/dist/{message-utils-Bx993JLN.js → message-utils-ConlUKCU.js} +1 -1
- package/dist/{outbound-adapter-CmN7ao1t.js → outbound-adapter-XuMiR77A.js} +6 -6
- package/dist/{pluralkit-SYmlmerw.js → pluralkit-o6s-EP9g.js} +4 -2
- package/dist/{probe-2MdGjUAf.js → probe-CxnDikWm.js} +5 -2
- package/dist/{probe.runtime-J927koKG.js → probe.runtime-DLFkSDVB.js} +1 -1
- package/dist/{provider-DrScDA1p.js → provider-4VG5CvC-.js} +98 -69
- package/dist/{provider-session.runtime-DXTzSYOJ.js → provider-session.runtime-ChdHgGCo.js} +3 -3
- package/dist/provider.runtime-B4QuZl_o.js +2 -0
- package/dist/{resolve-allowlist-common-B3p7cT8F.js → resolve-allowlist-common-BDpBb8dF.js} +1 -1
- package/dist/{resolve-channels-Rautpk8n.js → resolve-channels-DpM2v0Am.js} +3 -3
- package/dist/{resolve-users-Bw7vvtsi.js → resolve-users-Dl6np4pH.js} +3 -3
- package/dist/{runtime-C80YEJ7Z.js → runtime-CkdyyjTb.js} +24 -10
- package/dist/runtime-api.actions.js +2 -2
- package/dist/runtime-api.js +19 -19
- package/dist/runtime-api.lookup.js +5 -5
- package/dist/runtime-api.monitor-9pShEBWs.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-CIhsDMqs.js} +8 -5
- package/dist/{send.components-ktzrUTkt.js → send.components-DxoGyTkn.js} +4 -4
- package/dist/{send.outbound-C8oC51um.js → send.outbound-DaUyYuZa.js} +53 -10
- package/dist/{send.receipt-DsQWEQ2O.js → send.receipt-De_2iEWU.js} +2 -24
- package/dist/{send.shared-Dvo2ZCVG.js → send.shared-gtgBGDuV.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-DPCipg2M.js} +2 -2
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/{system-events-CvU3Aduf.js → system-events-4vmuyaBF.js} +1 -1
- package/dist/{target-resolver-DMPTzuo7.js → target-resolver-CVrOhQyC.js} +2 -2
- package/dist/targets-CRGgRKs7.js +3 -0
- package/dist/{thread-bindings-DO32M2kW.js → thread-bindings-D2SBj6F8.js} +4 -4
- package/dist/{thread-bindings.discord-api-304M1PMr.js → thread-bindings.discord-api-C7STOVXm.js} +4 -4
- package/dist/{thread-bindings.manager-C9YT7wF2.js → thread-bindings.manager-CN4MIGoJ.js} +3 -3
- package/dist/{transcripts-source-Chy2OrO_.js → transcripts-source-39NBdNeE.js} +1 -1
- package/dist/transcripts-source-api.js +1 -1
- package/dist/{typing-BaivbXIG.js → typing-CxIYS3vQ.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
|
@@ -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
|
}
|
|
@@ -228,6 +228,10 @@ function parseCacheControlHeader (header) {
|
|
|
228
228
|
headers[headers.length - 1] = lastHeader
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
for (let j = 0; j < headers.length; j++) {
|
|
232
|
+
headers[j] = headers[j].trim()
|
|
233
|
+
}
|
|
234
|
+
|
|
231
235
|
if (key in output) {
|
|
232
236
|
output[key] = output[key].concat(headers)
|
|
233
237
|
} else {
|
|
@@ -236,10 +240,12 @@ function parseCacheControlHeader (header) {
|
|
|
236
240
|
}
|
|
237
241
|
} else {
|
|
238
242
|
// Something like `no-cache="some-header"`
|
|
243
|
+
const fieldName = value.trim()
|
|
244
|
+
|
|
239
245
|
if (key in output) {
|
|
240
|
-
output[key] = output[key].concat(
|
|
246
|
+
output[key] = output[key].concat(fieldName)
|
|
241
247
|
} else {
|
|
242
|
-
output[key] = [
|
|
248
|
+
output[key] = [fieldName]
|
|
243
249
|
}
|
|
244
250
|
}
|
|
245
251
|
|
|
@@ -4,7 +4,6 @@ const { collectASequenceOfCodePointsFast } = require('../infra')
|
|
|
4
4
|
const { maxNameValuePairSize, maxAttributeValueSize } = require('./constants')
|
|
5
5
|
const { isCTLExcludingHtab } = require('./util')
|
|
6
6
|
const assert = require('node:assert')
|
|
7
|
-
const { unescape: qsUnescape } = require('node:querystring')
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* @description Parses the field-value attributes of a set-cookie header string.
|
|
@@ -82,7 +81,7 @@ function parseSetCookie (header) {
|
|
|
82
81
|
// store arbitrary data in a cookie-value SHOULD encode that data, for
|
|
83
82
|
// example, using Base64 [RFC4648].
|
|
84
83
|
return {
|
|
85
|
-
name, value
|
|
84
|
+
name, value, ...parseUnparsedAttributes(unparsedAttributes)
|
|
86
85
|
}
|
|
87
86
|
}
|
|
88
87
|
|
|
@@ -280,32 +279,25 @@ function parseUnparsedAttributes (unparsedAttributes, cookieAttributeList = {})
|
|
|
280
279
|
// If the attribute-name case-insensitively matches the string
|
|
281
280
|
// "SameSite", the user agent MUST process the cookie-av as follows:
|
|
282
281
|
|
|
283
|
-
// 1. Let enforcement be "Default".
|
|
284
|
-
let enforcement = 'Default'
|
|
285
|
-
|
|
286
282
|
const attributeValueLowercase = attributeValue.toLowerCase()
|
|
287
|
-
// 2. If cookie-av's attribute-value is a case-insensitive match for
|
|
288
|
-
// "None", set enforcement to "None".
|
|
289
|
-
if (attributeValueLowercase.includes('none')) {
|
|
290
|
-
enforcement = 'None'
|
|
291
|
-
}
|
|
292
283
|
|
|
293
|
-
//
|
|
294
|
-
// "
|
|
295
|
-
|
|
296
|
-
|
|
284
|
+
// 1. If cookie-av's attribute-value is a case-insensitive match for
|
|
285
|
+
// "None", append an attribute to the cookie-attribute-list with an
|
|
286
|
+
// attribute-name of "SameSite" and an attribute-value of "None".
|
|
287
|
+
if (attributeValueLowercase === 'none') {
|
|
288
|
+
cookieAttributeList.sameSite = 'None'
|
|
289
|
+
} else if (attributeValueLowercase === 'strict') {
|
|
290
|
+
// 2. If cookie-av's attribute-value is a case-insensitive match for
|
|
291
|
+
// "Strict", append an attribute to the cookie-attribute-list with
|
|
292
|
+
// an attribute-name of "SameSite" and an attribute-value of
|
|
293
|
+
// "Strict".
|
|
294
|
+
cookieAttributeList.sameSite = 'Strict'
|
|
295
|
+
} else if (attributeValueLowercase === 'lax') {
|
|
296
|
+
// 3. If cookie-av's attribute-value is a case-insensitive match for
|
|
297
|
+
// "Lax", append an attribute to the cookie-attribute-list with an
|
|
298
|
+
// attribute-name of "SameSite" and an attribute-value of "Lax".
|
|
299
|
+
cookieAttributeList.sameSite = 'Lax'
|
|
297
300
|
}
|
|
298
|
-
|
|
299
|
-
// 4. If cookie-av's attribute-value is a case-insensitive match for
|
|
300
|
-
// "Lax", set enforcement to "Lax".
|
|
301
|
-
if (attributeValueLowercase.includes('lax')) {
|
|
302
|
-
enforcement = 'Lax'
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
// 5. Append an attribute to the cookie-attribute-list with an
|
|
306
|
-
// attribute-name of "SameSite" and an attribute-value of
|
|
307
|
-
// enforcement.
|
|
308
|
-
cookieAttributeList.sameSite = enforcement
|
|
309
301
|
} else {
|
|
310
302
|
cookieAttributeList.unparsed ??= []
|
|
311
303
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const { pipeline } = require('node:stream')
|
|
4
4
|
const { fetching } = require('../fetch')
|
|
5
|
-
const { makeRequest } = require('../fetch/request')
|
|
6
5
|
const { webidl } = require('../webidl')
|
|
7
6
|
const { EventSourceStream } = require('./eventsource-stream')
|
|
8
7
|
const { parseMIMEType } = require('../fetch/data-url')
|
|
@@ -10,6 +9,7 @@ const { createFastMessageEvent } = require('../websocket/events')
|
|
|
10
9
|
const { isNetworkError } = require('../fetch/response')
|
|
11
10
|
const { kEnumerableProperty } = require('../../core/util')
|
|
12
11
|
const { environmentSettingsObject } = require('../fetch/util')
|
|
12
|
+
const { createPotentialCORSRequest } = require('./util')
|
|
13
13
|
|
|
14
14
|
let experimentalWarned = false
|
|
15
15
|
|
|
@@ -160,33 +160,22 @@ class EventSource extends EventTarget {
|
|
|
160
160
|
|
|
161
161
|
// 8. Let request be the result of creating a potential-CORS request given
|
|
162
162
|
// urlRecord, the empty string, and corsAttributeState.
|
|
163
|
-
const
|
|
164
|
-
redirect: 'follow',
|
|
165
|
-
keepalive: true,
|
|
166
|
-
// @see https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes
|
|
167
|
-
mode: 'cors',
|
|
168
|
-
credentials: corsAttributeState === 'anonymous'
|
|
169
|
-
? 'same-origin'
|
|
170
|
-
: 'omit',
|
|
171
|
-
referrer: 'no-referrer'
|
|
172
|
-
}
|
|
163
|
+
const request = createPotentialCORSRequest(urlRecord, '', corsAttributeState)
|
|
173
164
|
|
|
174
165
|
// 9. Set request's client to settings.
|
|
175
|
-
|
|
166
|
+
request.client = environmentSettingsObject.settingsObject
|
|
176
167
|
|
|
177
168
|
// 10. User agents may set (`Accept`, `text/event-stream`) in request's header list.
|
|
178
|
-
|
|
169
|
+
request.headersList.set('Accept', 'text/event-stream')
|
|
179
170
|
|
|
180
171
|
// 11. Set request's cache mode to "no-store".
|
|
181
|
-
|
|
172
|
+
request.cache = 'no-store'
|
|
182
173
|
|
|
183
174
|
// 12. Set request's initiator type to "other".
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
initRequest.urlList = [new URL(this.#url)]
|
|
175
|
+
request.initiator = 'other'
|
|
187
176
|
|
|
188
177
|
// 13. Set ev's request to request.
|
|
189
|
-
this.#request =
|
|
178
|
+
this.#request = request
|
|
190
179
|
|
|
191
180
|
this.#connect()
|
|
192
181
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { makeRequest } = require('../fetch/request')
|
|
4
|
+
|
|
3
5
|
/**
|
|
4
6
|
* Checks if the given value is a valid LastEventId.
|
|
5
7
|
* @param {string} value
|
|
@@ -23,7 +25,36 @@ function isASCIINumber (value) {
|
|
|
23
25
|
return true
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
function createPotentialCORSRequest (url, destination, corsAttributeState, sameOriginFallback) {
|
|
29
|
+
// 1. Let mode be "no-cors" if corsAttributeState is No CORS, and "cors" otherwise.
|
|
30
|
+
let mode = corsAttributeState === 'no cors' ? 'no-cors' : 'cors'
|
|
31
|
+
|
|
32
|
+
// 2. If same-origin fallback flag is set and mode is "no-cors", set mode to "same-origin".
|
|
33
|
+
if (sameOriginFallback && mode === 'no-cors') {
|
|
34
|
+
mode = 'same-origin'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 3. Let credentialsMode be "include".
|
|
38
|
+
let credentialsMode = 'include'
|
|
39
|
+
|
|
40
|
+
// 4. If corsAttributeState is Anonymous, set credentialsMode to "same-origin".
|
|
41
|
+
if (corsAttributeState === 'anonymous') {
|
|
42
|
+
credentialsMode = 'same-origin'
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 5. Return a new request whose URL is url, destination is destination, mode is mode,
|
|
46
|
+
// credentials mode is credentialsMode, and whose use-URL-credentials flag is set.
|
|
47
|
+
return makeRequest({
|
|
48
|
+
urlList: [url],
|
|
49
|
+
destination,
|
|
50
|
+
mode,
|
|
51
|
+
credentials: credentialsMode,
|
|
52
|
+
useCredentials: true
|
|
53
|
+
})
|
|
54
|
+
}
|
|
55
|
+
|
|
26
56
|
module.exports = {
|
|
27
57
|
isValidLastEventId,
|
|
28
|
-
isASCIINumber
|
|
58
|
+
isASCIINumber,
|
|
59
|
+
createPotentialCORSRequest
|
|
29
60
|
}
|
|
@@ -392,6 +392,49 @@ function bodyMixinMethods (instance, getInternalState) {
|
|
|
392
392
|
return consumeBody(this, (bytes) => {
|
|
393
393
|
return new Uint8Array(bytes)
|
|
394
394
|
}, instance, getInternalState)
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
textStream () {
|
|
398
|
+
const this_ = getInternalState(this)
|
|
399
|
+
|
|
400
|
+
// 1. If this is unusable, then throw a TypeError.
|
|
401
|
+
if (bodyUnusable(this_)) {
|
|
402
|
+
throw new TypeError('Body is unusable: Body has already been read')
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// 2. If this’s body is null:
|
|
406
|
+
if (this_.body == null) {
|
|
407
|
+
// 2.1. Let emptyStream be a new ReadableStream in this’s relevant realm.
|
|
408
|
+
// 2.2. Set up emptyStream.
|
|
409
|
+
/** @type {ReadableStreamDefaultController<any>} */
|
|
410
|
+
let controller
|
|
411
|
+
const emptyStream = new ReadableStream({
|
|
412
|
+
start: (c) => {
|
|
413
|
+
controller = c
|
|
414
|
+
},
|
|
415
|
+
pull: () => Promise.resolve(),
|
|
416
|
+
cancel: () => Promise.resolve()
|
|
417
|
+
}, {
|
|
418
|
+
size: () => 1
|
|
419
|
+
})
|
|
420
|
+
|
|
421
|
+
// 2.3. Close emptyStream.
|
|
422
|
+
controller.close()
|
|
423
|
+
|
|
424
|
+
// 2.4. Return emptyStream.
|
|
425
|
+
return emptyStream
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// 3. Let stream be this’s body’s stream.
|
|
429
|
+
/** @type {ReadableStream} */
|
|
430
|
+
const stream = this_.body.stream
|
|
431
|
+
|
|
432
|
+
// 4. Let decoder be a new TextDecoderStream object in this’s relevant realm.
|
|
433
|
+
// 5. Set up decoder with UTF-8.
|
|
434
|
+
const decoder = new TextDecoderStream('UTF-8')
|
|
435
|
+
|
|
436
|
+
// 6. Return the result of stream, piped through decoder.
|
|
437
|
+
return stream.pipeThrough(decoder)
|
|
395
438
|
}
|
|
396
439
|
}
|
|
397
440
|
|
|
@@ -11,7 +11,7 @@ const {
|
|
|
11
11
|
getResponseState
|
|
12
12
|
} = require('./response')
|
|
13
13
|
const { HeadersList } = require('./headers')
|
|
14
|
-
const { Request, cloneRequest, getRequestDispatcher, getRequestState } = require('./request')
|
|
14
|
+
const { Request, cloneRequest, getRequestDispatcher, getRequestState, removeRequestAbortListener } = require('./request')
|
|
15
15
|
const zlib = require('node:zlib')
|
|
16
16
|
const {
|
|
17
17
|
makePolicyContainer,
|
|
@@ -208,7 +208,7 @@ function fetch (input, init = undefined) {
|
|
|
208
208
|
let controller = null
|
|
209
209
|
|
|
210
210
|
// 11. Add the following abort steps to requestObject’s signal:
|
|
211
|
-
addAbortListener(
|
|
211
|
+
const removeAbortListener = addAbortListener(
|
|
212
212
|
requestObject.signal,
|
|
213
213
|
() => {
|
|
214
214
|
// 1. Set locallyAborted to true.
|
|
@@ -228,6 +228,15 @@ function fetch (input, init = undefined) {
|
|
|
228
228
|
}
|
|
229
229
|
)
|
|
230
230
|
|
|
231
|
+
// Remove the `abort` listeners registered above and in the Request
|
|
232
|
+
// constructor once the fetch has settled. Without this, reusing a single
|
|
233
|
+
// signal across many requests leaks listeners and Node.js emits a
|
|
234
|
+
// MaxListenersExceededWarning. See https://github.com/nodejs/undici/issues/5285
|
|
235
|
+
const cleanupAbortListeners = () => {
|
|
236
|
+
removeAbortListener()
|
|
237
|
+
removeRequestAbortListener(requestObject)
|
|
238
|
+
}
|
|
239
|
+
|
|
231
240
|
// 12. Let handleFetchDone given response response be to finalize and
|
|
232
241
|
// report timing with response, globalObject, and "fetch".
|
|
233
242
|
// see function handleFetchDone
|
|
@@ -252,6 +261,7 @@ function fetch (input, init = undefined) {
|
|
|
252
261
|
// deserializedError.
|
|
253
262
|
|
|
254
263
|
abortFetch(p, request, responseObject, controller.serializedAbortReason, controller.controller)
|
|
264
|
+
cleanupAbortListeners()
|
|
255
265
|
return
|
|
256
266
|
}
|
|
257
267
|
|
|
@@ -259,6 +269,7 @@ function fetch (input, init = undefined) {
|
|
|
259
269
|
// and terminate these substeps.
|
|
260
270
|
if (response.type === 'error') {
|
|
261
271
|
p.reject(new TypeError('fetch failed', { cause: response.error }))
|
|
272
|
+
cleanupAbortListeners()
|
|
262
273
|
return
|
|
263
274
|
}
|
|
264
275
|
|
|
@@ -273,7 +284,10 @@ function fetch (input, init = undefined) {
|
|
|
273
284
|
|
|
274
285
|
controller = fetching({
|
|
275
286
|
request,
|
|
276
|
-
processResponseEndOfBody:
|
|
287
|
+
processResponseEndOfBody: (response) => {
|
|
288
|
+
handleFetchDone(response)
|
|
289
|
+
cleanupAbortListeners()
|
|
290
|
+
},
|
|
277
291
|
processResponse,
|
|
278
292
|
dispatcher: getRequestDispatcher(requestObject), // undici
|
|
279
293
|
// Keep requestObject alive to prevent its AbortController from being GC'd
|
|
@@ -97,6 +97,13 @@ class Request {
|
|
|
97
97
|
|
|
98
98
|
#state
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Removes the `abort` listener that makes this request's signal follow the
|
|
102
|
+
* passed signal. `null` when no such listener was registered.
|
|
103
|
+
* @type {(() => void) | null}
|
|
104
|
+
*/
|
|
105
|
+
#abortCleanup = null
|
|
106
|
+
|
|
100
107
|
// https://fetch.spec.whatwg.org/#dom-request
|
|
101
108
|
constructor (input, init = undefined) {
|
|
102
109
|
webidl.util.markAsUncloneable(this)
|
|
@@ -436,12 +443,23 @@ class Request {
|
|
|
436
443
|
setMaxListeners(1500, signal)
|
|
437
444
|
}
|
|
438
445
|
|
|
439
|
-
util.addAbortListener(signal, abort)
|
|
446
|
+
const removeAbortListener = util.addAbortListener(signal, abort)
|
|
440
447
|
// The third argument must be a registry key to be unregistered.
|
|
441
448
|
// Without it, you cannot unregister.
|
|
442
449
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry
|
|
443
450
|
// abort is used as the unregister key. (because it is unique)
|
|
444
451
|
requestFinalizer.register(ac, { signal, abort }, abort)
|
|
452
|
+
|
|
453
|
+
// Allow the listener to be removed deterministically once the fetch
|
|
454
|
+
// that owns this request has settled, instead of relying solely on the
|
|
455
|
+
// FinalizationRegistry (i.e. garbage collection). Reusing a single
|
|
456
|
+
// signal across many requests would otherwise leak listeners.
|
|
457
|
+
// See https://github.com/nodejs/undici/issues/5285
|
|
458
|
+
this.#abortCleanup = () => {
|
|
459
|
+
requestFinalizer.unregister(abort)
|
|
460
|
+
removeAbortListener()
|
|
461
|
+
this.#abortCleanup = null
|
|
462
|
+
}
|
|
445
463
|
}
|
|
446
464
|
}
|
|
447
465
|
|
|
@@ -868,15 +886,25 @@ class Request {
|
|
|
868
886
|
static setRequestState (request, newState) {
|
|
869
887
|
request.#state = newState
|
|
870
888
|
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Removes the `abort` listener that makes this request's signal follow the
|
|
892
|
+
* signal passed to its constructor, if any. Idempotent.
|
|
893
|
+
* @param {Request} request
|
|
894
|
+
*/
|
|
895
|
+
static removeRequestAbortListener (request) {
|
|
896
|
+
request.#abortCleanup?.()
|
|
897
|
+
}
|
|
871
898
|
}
|
|
872
899
|
|
|
873
|
-
const { setRequestSignal, getRequestDispatcher, setRequestDispatcher, setRequestHeaders, getRequestState, setRequestState } = Request
|
|
900
|
+
const { setRequestSignal, getRequestDispatcher, setRequestDispatcher, setRequestHeaders, getRequestState, setRequestState, removeRequestAbortListener } = Request
|
|
874
901
|
Reflect.deleteProperty(Request, 'setRequestSignal')
|
|
875
902
|
Reflect.deleteProperty(Request, 'getRequestDispatcher')
|
|
876
903
|
Reflect.deleteProperty(Request, 'setRequestDispatcher')
|
|
877
904
|
Reflect.deleteProperty(Request, 'setRequestHeaders')
|
|
878
905
|
Reflect.deleteProperty(Request, 'getRequestState')
|
|
879
906
|
Reflect.deleteProperty(Request, 'setRequestState')
|
|
907
|
+
Reflect.deleteProperty(Request, 'removeRequestAbortListener')
|
|
880
908
|
|
|
881
909
|
mixinBody(Request, getRequestState)
|
|
882
910
|
|
|
@@ -902,6 +930,7 @@ function makeRequest (init) {
|
|
|
902
930
|
referrerPolicy: init.referrerPolicy ?? '',
|
|
903
931
|
mode: init.mode ?? 'no-cors',
|
|
904
932
|
useCORSPreflightFlag: init.useCORSPreflightFlag ?? false,
|
|
933
|
+
// TODO: is this credentials mode? https://fetch.spec.whatwg.org/#concept-request-credentials-mode
|
|
905
934
|
credentials: init.credentials ?? 'same-origin',
|
|
906
935
|
useCredentials: init.useCredentials ?? false,
|
|
907
936
|
cache: init.cache ?? 'default',
|
|
@@ -1111,5 +1140,6 @@ module.exports = {
|
|
|
1111
1140
|
fromInnerRequest,
|
|
1112
1141
|
cloneRequest,
|
|
1113
1142
|
getRequestDispatcher,
|
|
1114
|
-
getRequestState
|
|
1143
|
+
getRequestState,
|
|
1144
|
+
removeRequestAbortListener
|
|
1115
1145
|
}
|
|
@@ -39,6 +39,9 @@ class ByteParser extends Writable {
|
|
|
39
39
|
/** @type {import('./websocket').Handler} */
|
|
40
40
|
#handler
|
|
41
41
|
|
|
42
|
+
/** @type {number} */
|
|
43
|
+
#maxFragments
|
|
44
|
+
|
|
42
45
|
/** @type {number} */
|
|
43
46
|
#maxPayloadSize
|
|
44
47
|
|
|
@@ -52,6 +55,7 @@ class ByteParser extends Writable {
|
|
|
52
55
|
|
|
53
56
|
this.#handler = handler
|
|
54
57
|
this.#extensions = extensions == null ? new Map() : extensions
|
|
58
|
+
this.#maxFragments = options.maxFragments ?? 0
|
|
55
59
|
this.#maxPayloadSize = options.maxPayloadSize ?? 0
|
|
56
60
|
|
|
57
61
|
if (this.#extensions.has('permessage-deflate')) {
|
|
@@ -75,7 +79,7 @@ class ByteParser extends Writable {
|
|
|
75
79
|
if (
|
|
76
80
|
this.#maxPayloadSize > 0 &&
|
|
77
81
|
!isControlFrame(this.#info.opcode) &&
|
|
78
|
-
this.#info.payloadLength > this.#maxPayloadSize
|
|
82
|
+
this.#info.payloadLength + this.#fragmentsBytes > this.#maxPayloadSize
|
|
79
83
|
) {
|
|
80
84
|
failWebsocketConnection(this.#handler, 1009, 'Payload size exceeds maximum allowed size')
|
|
81
85
|
return false
|
|
@@ -242,7 +246,9 @@ class ByteParser extends Writable {
|
|
|
242
246
|
this.#state = parserStates.INFO
|
|
243
247
|
} else {
|
|
244
248
|
if (!this.#info.compressed) {
|
|
245
|
-
this.writeFragments(body)
|
|
249
|
+
if (!this.writeFragments(body)) {
|
|
250
|
+
return
|
|
251
|
+
}
|
|
246
252
|
|
|
247
253
|
// If the frame is not fragmented, a message has been received.
|
|
248
254
|
// If the frame is fragmented, it will terminate with a fin bit set
|
|
@@ -264,7 +270,9 @@ class ByteParser extends Writable {
|
|
|
264
270
|
return
|
|
265
271
|
}
|
|
266
272
|
|
|
267
|
-
this.writeFragments(data)
|
|
273
|
+
if (!this.writeFragments(data)) {
|
|
274
|
+
return
|
|
275
|
+
}
|
|
268
276
|
|
|
269
277
|
// Check cumulative fragment size
|
|
270
278
|
if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) {
|
|
@@ -345,8 +353,17 @@ class ByteParser extends Writable {
|
|
|
345
353
|
}
|
|
346
354
|
|
|
347
355
|
writeFragments (fragment) {
|
|
356
|
+
if (
|
|
357
|
+
this.#maxFragments > 0 &&
|
|
358
|
+
this.#fragments.length === this.#maxFragments
|
|
359
|
+
) {
|
|
360
|
+
failWebsocketConnection(this.#handler, 1008, 'Too many message fragments')
|
|
361
|
+
return false
|
|
362
|
+
}
|
|
363
|
+
|
|
348
364
|
this.#fragmentsBytes += fragment.length
|
|
349
365
|
this.#fragments.push(fragment)
|
|
366
|
+
return true
|
|
350
367
|
}
|
|
351
368
|
|
|
352
369
|
consumeFragments () {
|
|
@@ -258,7 +258,14 @@ class WebSocketStream {
|
|
|
258
258
|
#onConnectionEstablished (response, parsedExtensions) {
|
|
259
259
|
this.#handler.socket = response.socket
|
|
260
260
|
|
|
261
|
-
|
|
261
|
+
// Get options from dispatcher options
|
|
262
|
+
const maxFragments = this.#handler.controller.dispatcher?.webSocketOptions?.maxFragments
|
|
263
|
+
const maxPayloadSize = this.#handler.controller.dispatcher?.webSocketOptions?.maxPayloadSize
|
|
264
|
+
|
|
265
|
+
const parser = new ByteParser(this.#handler, parsedExtensions, {
|
|
266
|
+
maxFragments,
|
|
267
|
+
maxPayloadSize
|
|
268
|
+
})
|
|
262
269
|
parser.on('drain', () => this.#handler.onParserDrain())
|
|
263
270
|
parser.on('error', (err) => this.#handler.onParserError(err))
|
|
264
271
|
|
|
@@ -468,10 +468,12 @@ class WebSocket extends EventTarget {
|
|
|
468
468
|
// once this happens, the connection is open
|
|
469
469
|
this.#handler.socket = response.socket
|
|
470
470
|
|
|
471
|
-
// Get
|
|
471
|
+
// Get options from dispatcher options
|
|
472
|
+
const maxFragments = this.#handler.controller.dispatcher?.webSocketOptions?.maxFragments
|
|
472
473
|
const maxPayloadSize = this.#handler.controller.dispatcher?.webSocketOptions?.maxPayloadSize
|
|
473
474
|
|
|
474
475
|
const parser = new ByteParser(this.#handler, parsedExtensions, {
|
|
476
|
+
maxFragments,
|
|
475
477
|
maxPayloadSize
|
|
476
478
|
})
|
|
477
479
|
parser.on('drain', () => this.#handler.onParserDrain())
|
|
@@ -116,6 +116,11 @@ export declare namespace Client {
|
|
|
116
116
|
bytesRead?: number
|
|
117
117
|
}
|
|
118
118
|
export interface WebSocketOptions {
|
|
119
|
+
/**
|
|
120
|
+
* Maximum number of fragments in a message. Set to 0 to disable the limit.
|
|
121
|
+
* @default 131072
|
|
122
|
+
*/
|
|
123
|
+
maxFragments?: number;
|
|
119
124
|
/**
|
|
120
125
|
* Maximum allowed payload size in bytes for WebSocket messages.
|
|
121
126
|
* Applied to uncompressed messages, compressed frame payloads, and decompressed (permessage-deflate) messages.
|
|
@@ -7,6 +7,7 @@ declare function buildConnector (options?: buildConnector.BuildOptions): buildCo
|
|
|
7
7
|
declare namespace buildConnector {
|
|
8
8
|
export type BuildOptions = (ConnectionOptions | TcpNetConnectOpts | IpcNetConnectOpts) & {
|
|
9
9
|
allowH2?: boolean;
|
|
10
|
+
preferH2?: boolean;
|
|
10
11
|
maxCachedSessions?: number | null;
|
|
11
12
|
socketPath?: string | null;
|
|
12
13
|
timeout?: number | null;
|