@openclaw/discord 2026.6.11 → 2026.6.34
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-4GFMoWu0.js → api-CjnGBhM3.js} +4 -1
- package/dist/api.js +14 -14
- package/dist/{approval-handler.runtime-SsFtZQA6.js → approval-handler.runtime-BWPQrzpP.js} +9 -4
- package/dist/{audit-CAnmyf2A.js → audit-BwJ_2OjL.js} +3 -3
- package/dist/{channel-YA7AbYP3.js → channel-DU4jnQgl.js} +15 -15
- package/dist/{channel-actions-BJ3n5Z1l.js → channel-actions-CwmIqnYN.js} +2 -2
- package/dist/{channel-actions.runtime-D2QTRgZ9.js → channel-actions.runtime-DvpTfaJ4.js} +5 -5
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-B1zDEAR7.js → channel.setup-glZ5Y98a.js} +2 -2
- package/dist/{components-Dm4c_ce6.js → components-j6lTZBsT.js} +1 -1
- package/dist/{conversation-identity-DZ0BD7xO.js → conversation-identity-36FFBwm5.js} +2 -2
- package/dist/{directory-config-BK1OhHa3.js → directory-config-BYMFzL29.js} +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-DP3CmwGf.js → directory-live-9JtJCiu8.js} +2 -2
- package/dist/{handle-action.guild-admin-B2cOoU2D.js → handle-action.guild-admin-xxGYrp-I.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{manager.runtime-CPHxr9B3.js → manager.runtime-NxCd-PVt.js} +3 -3
- package/dist/{message-handler-CKaTgBIV.js → message-handler-cizxbaDc.js} +7 -6
- package/dist/{message-handler.preflight--eAiaewz.js → message-handler.preflight-CbD0u7U7.js} +10 -10
- package/dist/{message-handler.process-PhKAmrEd.js → message-handler.process-Do4EM591.js} +10 -10
- package/dist/{message-utils-O1vK3kPu.js → message-utils-CJeAoISH.js} +1 -1
- package/dist/{outbound-adapter-fO_7hbTh.js → outbound-adapter-Dxs6iKEq.js} +62 -131
- package/dist/{pluralkit-B3MzPaPU.js → pluralkit-DI6RYaVj.js} +1 -1
- package/dist/presence-cache-z1N8MbJ3.js +45 -0
- package/dist/{probe-CxnDikWm.js → probe-esE_Oqdm.js} +1 -1
- package/dist/{probe.runtime-DLFkSDVB.js → probe.runtime-C3Atgpvr.js} +1 -1
- package/dist/{provider-BJaJ20MY.js → provider-B-s93q9s.js} +76 -26
- package/dist/{provider-session.runtime-D6xc-60s.js → provider-session.runtime-BKMOqHpd.js} +3 -3
- package/dist/provider.runtime-CaTJrpnl.js +2 -0
- package/dist/{resolve-allowlist-common-BDpBb8dF.js → resolve-allowlist-common-3gB2Gpmm.js} +1 -1
- package/dist/{resolve-channels-iJIjYfRw.js → resolve-channels-B3gQf8QL.js} +3 -3
- package/dist/{resolve-users-_fv1mm1f.js → resolve-users-BO10y5fJ.js} +3 -3
- package/dist/{runtime-ywXByivr.js → runtime-CFlR3L9X.js} +8 -8
- package/dist/runtime-api.actions.js +2 -2
- package/dist/runtime-api.js +20 -20
- package/dist/runtime-api.lookup.js +5 -5
- package/dist/runtime-api.monitor-CRiBIQEI.js +6 -0
- package/dist/runtime-api.monitor.js +6 -5
- package/dist/runtime-api.send.js +5 -5
- package/dist/runtime-api.threads.js +3 -3
- package/dist/{send-Dc5uQX5H.js → send-JHxfT4Pk.js} +6 -4
- package/dist/{send.components-D4bl20xr.js → send.components-CN35E2Ck.js} +11 -6
- package/dist/{send.outbound-5axvwLkl.js → send.outbound-B-cA1Esv.js} +15 -8
- package/dist/{send.receipt-B21MspvT.js → send.receipt-CGecJDin.js} +10 -1
- package/dist/{send.shared-9082A2sO.js → send.shared-vcbfThdy.js} +107 -16
- package/dist/session-binding-contract-api.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{subagent-hooks-NTv6B4up.js → subagent-hooks-20wXhVzZ.js} +2 -2
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/{system-events-BzaI1WpN.js → system-events-DR27TE7p.js} +1 -1
- package/dist/{target-resolver-agnOrtOU.js → target-resolver-CDi1gI90.js} +2 -2
- package/dist/targets-C6yd3y8R.js +3 -0
- package/dist/{thread-bindings-DNitaHVh.js → thread-bindings-DU4T6nDo.js} +4 -4
- package/dist/{thread-bindings.discord-api-CjYNuvZa.js → thread-bindings.discord-api-CYkr-3Gj.js} +4 -4
- package/dist/{thread-bindings.manager-PZvJ4TJx.js → thread-bindings.manager-BqWs1UE2.js} +3 -3
- package/dist/{transcripts-source-Bi8N6h5X.js → transcripts-source-D-lBI5ZD.js} +1 -1
- package/dist/transcripts-source-api.js +1 -1
- package/dist/{typing-BdRqXUN3.js → typing-xr05bL-r.js} +1 -1
- package/node_modules/undici/README.md +8 -2
- package/node_modules/undici/docs/docs/api/Agent.md +248 -44
- package/node_modules/undici/docs/docs/api/BalancedPool.md +246 -48
- package/node_modules/undici/docs/docs/api/CacheStorage.md +171 -13
- package/node_modules/undici/docs/docs/api/CacheStore.md +294 -98
- package/node_modules/undici/docs/docs/api/Client.md +369 -179
- package/node_modules/undici/docs/docs/api/ClientStats.md +80 -14
- package/node_modules/undici/docs/docs/api/Connector.md +118 -36
- package/node_modules/undici/docs/docs/api/ContentType.md +65 -25
- package/node_modules/undici/docs/docs/api/Cookies.md +122 -71
- package/node_modules/undici/docs/docs/api/Debug.md +34 -18
- package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +364 -164
- package/node_modules/undici/docs/docs/api/Dispatcher.md +485 -1102
- package/node_modules/undici/docs/docs/api/EnvHttpProxyAgent.md +101 -87
- package/node_modules/undici/docs/docs/api/Errors.md +503 -40
- package/node_modules/undici/docs/docs/api/EventSource.md +294 -32
- package/node_modules/undici/docs/docs/api/Fetch.md +680 -31
- package/node_modules/undici/docs/docs/api/GlobalInstallation.md +78 -98
- package/node_modules/undici/docs/docs/api/H2CClient.md +298 -176
- package/node_modules/undici/docs/docs/api/Interceptors.md +414 -0
- package/node_modules/undici/docs/docs/api/MockAgent.md +333 -314
- package/node_modules/undici/docs/docs/api/MockCallHistory.md +272 -98
- package/node_modules/undici/docs/docs/api/MockCallHistoryLog.md +189 -26
- package/node_modules/undici/docs/docs/api/MockClient.md +151 -33
- package/node_modules/undici/docs/docs/api/MockErrors.md +56 -5
- package/node_modules/undici/docs/docs/api/MockPool.md +321 -258
- package/node_modules/undici/docs/docs/api/Pool.md +235 -43
- package/node_modules/undici/docs/docs/api/PoolStats.md +119 -13
- package/node_modules/undici/docs/docs/api/ProxyAgent.md +179 -160
- package/node_modules/undici/docs/docs/api/RedirectHandler.md +238 -63
- package/node_modules/undici/docs/docs/api/RetryAgent.md +113 -26
- package/node_modules/undici/docs/docs/api/RetryHandler.md +161 -77
- package/node_modules/undici/docs/docs/api/RoundRobinPool.md +166 -72
- package/node_modules/undici/docs/docs/api/SnapshotAgent.md +264 -542
- package/node_modules/undici/docs/docs/api/Socks5ProxyAgent.md +162 -187
- package/node_modules/undici/docs/docs/api/Util.md +68 -11
- package/node_modules/undici/docs/docs/api/WebSocket.md +475 -80
- package/node_modules/undici/docs/docs/api/api-lifecycle.md +100 -32
- package/node_modules/undici/docs/docs/best-practices/client-certificate.md +2 -0
- package/node_modules/undici/docs/docs/best-practices/crawling.md +3 -1
- package/node_modules/undici/docs/docs/best-practices/migrating-from-v7-to-v8.md +6 -4
- package/node_modules/undici/docs/docs/best-practices/mocking-request.md +9 -7
- package/node_modules/undici/docs/docs/best-practices/proxy.md +3 -1
- package/node_modules/undici/docs/docs/best-practices/undici-vs-builtin-fetch.md +10 -8
- package/node_modules/undici/docs/docs/best-practices/writing-tests.md +2 -0
- package/node_modules/undici/docs/docs/{GettingStarted.md → getting-started.md} +22 -19
- package/node_modules/undici/docs/docs/index.md +784 -0
- package/node_modules/undici/docs/docs/site.json +125 -0
- package/node_modules/undici/docs/docs/type-map.json +79 -0
- package/node_modules/undici/lib/api/api-request.js +7 -1
- package/node_modules/undici/lib/api/readable.js +47 -2
- package/node_modules/undici/lib/cache/memory-cache-store.js +54 -9
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
- package/node_modules/undici/lib/core/errors.js +20 -0
- package/node_modules/undici/lib/core/request.js +14 -3
- package/node_modules/undici/lib/core/util.js +30 -2
- package/node_modules/undici/lib/dispatcher/agent.js +3 -3
- package/node_modules/undici/lib/dispatcher/client-h1.js +65 -8
- package/node_modules/undici/lib/dispatcher/client-h2.js +265 -142
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +40 -6
- package/node_modules/undici/lib/global.js +36 -16
- package/node_modules/undici/lib/handler/cache-handler.js +269 -61
- package/node_modules/undici/lib/handler/cache-revalidation-handler.js +13 -3
- package/node_modules/undici/lib/handler/redirect-handler.js +6 -2
- package/node_modules/undici/lib/handler/retry-handler.js +87 -23
- package/node_modules/undici/lib/interceptor/cache.js +159 -52
- package/node_modules/undici/lib/interceptor/decompress.js +9 -2
- package/node_modules/undici/lib/mock/mock-interceptor.js +25 -7
- package/node_modules/undici/lib/mock/mock-utils.js +39 -10
- package/node_modules/undici/lib/util/cache.js +372 -68
- package/node_modules/undici/lib/util/date.js +23 -6
- package/node_modules/undici/lib/web/cookies/parse.js +3 -2
- package/node_modules/undici/lib/web/cookies/util.js +79 -9
- package/node_modules/undici/lib/web/eventsource/util.js +1 -1
- package/node_modules/undici/lib/web/fetch/body.js +2 -1
- package/node_modules/undici/lib/web/fetch/constants.js +1 -1
- package/node_modules/undici/lib/web/fetch/index.js +11 -2
- package/node_modules/undici/lib/web/fetch/response.js +1 -3
- package/node_modules/undici/lib/web/fetch/util.js +4 -1
- package/node_modules/undici/package.json +2 -2
- package/node_modules/undici/types/client.d.ts +3 -3
- package/node_modules/undici/types/cookies.d.ts +1 -1
- package/node_modules/undici/types/dispatcher.d.ts +3 -3
- package/node_modules/undici/types/errors.d.ts +10 -0
- package/node_modules/undici/types/handlers.d.ts +2 -0
- package/node_modules/undici/types/mock-interceptor.d.ts +5 -1
- package/node_modules/undici/types/proxy-agent.d.ts +7 -0
- package/npm-shrinkwrap.json +7 -7
- package/package.json +5 -5
- package/dist/gateway-registry-DPxmW0Db.js +0 -74
- package/dist/provider.runtime-jNlHxUSW.js +0 -2
- package/dist/runtime-api.monitor-Bb5AaRzg.js +0 -6
- package/dist/targets-ClUPljCU.js +0 -3
|
@@ -292,25 +292,54 @@ function mockDispatch (opts, handler) {
|
|
|
292
292
|
// Get mock dispatch from built key
|
|
293
293
|
const key = buildKey(opts)
|
|
294
294
|
const mockDispatch = getMockDispatch(this[kDispatches], key)
|
|
295
|
+
const mockDispatches = this[kDispatches]
|
|
295
296
|
|
|
296
297
|
mockDispatch.timesInvoked++
|
|
297
298
|
|
|
299
|
+
const { timesInvoked, times } = mockDispatch
|
|
300
|
+
|
|
301
|
+
// If it's used up and not persistent, mark as consumed
|
|
302
|
+
mockDispatch.consumed = !mockDispatch.persist && timesInvoked >= times
|
|
303
|
+
mockDispatch.pending = timesInvoked < times
|
|
304
|
+
|
|
298
305
|
// Here's where we resolve a callback if a callback is present for the dispatch data.
|
|
299
306
|
if (mockDispatch.data.callback) {
|
|
300
|
-
|
|
307
|
+
const callbackResult = mockDispatch.data.callback(opts)
|
|
308
|
+
|
|
309
|
+
// An asynchronous reply options callback resolves to the reply data, so
|
|
310
|
+
// the dispatch can only continue once the returned promise settles.
|
|
311
|
+
// A rejection cannot be thrown synchronously from the dispatch at that
|
|
312
|
+
// point, so it is surfaced as a response error instead.
|
|
313
|
+
if (isPromise(callbackResult)) {
|
|
314
|
+
callbackResult.then(
|
|
315
|
+
(resolvedData) => {
|
|
316
|
+
mockDispatch.data = { ...mockDispatch.data, ...resolvedData }
|
|
317
|
+
dispatchMockReply(mockDispatches, mockDispatch, key, opts, handler)
|
|
318
|
+
},
|
|
319
|
+
(error) => {
|
|
320
|
+
deleteMockDispatch(mockDispatches, key)
|
|
321
|
+
handler.onResponseError(null, error)
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
return true
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
mockDispatch.data = { ...mockDispatch.data, ...callbackResult }
|
|
301
328
|
}
|
|
302
329
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const { timesInvoked, times } = mockDispatch
|
|
330
|
+
return dispatchMockReply(mockDispatches, mockDispatch, key, opts, handler)
|
|
331
|
+
}
|
|
306
332
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
333
|
+
/**
|
|
334
|
+
* Replies to a request once the mock dispatch data is fully resolved
|
|
335
|
+
*/
|
|
336
|
+
function dispatchMockReply (mockDispatches, mockDispatch, key, opts, handler) {
|
|
337
|
+
// Parse mockDispatch data
|
|
338
|
+
const { data: { statusCode, data, headers, trailers, error }, delay } = mockDispatch
|
|
310
339
|
|
|
311
340
|
// If specified, trigger dispatch error
|
|
312
341
|
if (error !== null) {
|
|
313
|
-
deleteMockDispatch(
|
|
342
|
+
deleteMockDispatch(mockDispatches, key)
|
|
314
343
|
handler.onResponseError(null, error)
|
|
315
344
|
return true
|
|
316
345
|
}
|
|
@@ -353,10 +382,10 @@ function mockDispatch (opts, handler) {
|
|
|
353
382
|
if (typeof delay === 'number' && delay > 0) {
|
|
354
383
|
timer = setTimeout(() => {
|
|
355
384
|
timer = null
|
|
356
|
-
handleReply(
|
|
385
|
+
handleReply(mockDispatches)
|
|
357
386
|
}, delay)
|
|
358
387
|
} else {
|
|
359
|
-
handleReply(
|
|
388
|
+
handleReply(mockDispatches)
|
|
360
389
|
}
|
|
361
390
|
|
|
362
391
|
function handleReply (mockDispatches, _data = data) {
|
|
@@ -3,11 +3,147 @@
|
|
|
3
3
|
const {
|
|
4
4
|
safeHTTPMethods,
|
|
5
5
|
pathHasQueryOrFragment,
|
|
6
|
-
hasSafeIterator
|
|
6
|
+
hasSafeIterator,
|
|
7
|
+
isValidHTTPToken
|
|
7
8
|
} = require('../core/util')
|
|
8
9
|
|
|
9
10
|
const { serializePathWithQuery } = require('../core/util')
|
|
10
11
|
|
|
12
|
+
const MAX_DELTA_SECONDS = 2147483647
|
|
13
|
+
const RESTRICTIVE_DIRECTIVE_NAMES = ['no-store', 'private', 'no-cache']
|
|
14
|
+
const kInvalidCacheControlDirectives = Symbol('invalid cache-control directives')
|
|
15
|
+
|
|
16
|
+
function trimOWS (value) {
|
|
17
|
+
return value.replace(/^[\t ]+|[\t ]+$/g, '')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function arrayIncludes (array, value) {
|
|
21
|
+
for (let i = 0; i < array.length; i++) {
|
|
22
|
+
if (array[i] === value) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return false
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function trimOWSStart (value) {
|
|
31
|
+
return value.replace(/^[\t ]+/, '')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function trimOWSEnd (value) {
|
|
35
|
+
return value.replace(/[\t ]+$/, '')
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function findUnescapedQuote (value, start) {
|
|
39
|
+
let escaped = false
|
|
40
|
+
for (let i = start; i < value.length; i++) {
|
|
41
|
+
if (escaped) {
|
|
42
|
+
escaped = false
|
|
43
|
+
} else if (value[i] === '\\') {
|
|
44
|
+
escaped = true
|
|
45
|
+
} else if (value[i] === '"') {
|
|
46
|
+
return i
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return -1
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function splitCacheControlHeaderValue (value) {
|
|
54
|
+
const directives = []
|
|
55
|
+
let start = 0
|
|
56
|
+
let quoteStart = -1
|
|
57
|
+
let inQuote = false
|
|
58
|
+
let escaped = false
|
|
59
|
+
|
|
60
|
+
for (let i = 0; i < value.length; i++) {
|
|
61
|
+
if (inQuote) {
|
|
62
|
+
if (escaped) {
|
|
63
|
+
escaped = false
|
|
64
|
+
} else if (value[i] === '\\') {
|
|
65
|
+
escaped = true
|
|
66
|
+
} else if (value[i] === '"') {
|
|
67
|
+
inQuote = false
|
|
68
|
+
quoteStart = -1
|
|
69
|
+
}
|
|
70
|
+
} else if (value[i] === '"') {
|
|
71
|
+
inQuote = true
|
|
72
|
+
quoteStart = i
|
|
73
|
+
} else if (value[i] === ',') {
|
|
74
|
+
directives.push({ value: value.substring(start, i), fromMalformedQuote: false })
|
|
75
|
+
start = i + 1
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!inQuote) {
|
|
80
|
+
directives.push({ value: value.substring(start), fromMalformedQuote: false })
|
|
81
|
+
return directives
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const tail = value.substring(start)
|
|
85
|
+
const quoteOffset = quoteStart - start
|
|
86
|
+
let tailStart = 0
|
|
87
|
+
for (let i = 0; i < tail.length; i++) {
|
|
88
|
+
if (tail[i] === ',') {
|
|
89
|
+
directives.push({
|
|
90
|
+
value: tail.substring(tailStart, i),
|
|
91
|
+
fromMalformedQuote: tailStart > quoteOffset
|
|
92
|
+
})
|
|
93
|
+
tailStart = i + 1
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
directives.push({
|
|
98
|
+
value: tail.substring(tailStart),
|
|
99
|
+
fromMalformedQuote: tailStart > quoteOffset
|
|
100
|
+
})
|
|
101
|
+
return directives
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function markInvalidCacheControlDirective (directives, key) {
|
|
105
|
+
let invalidDirectives = directives[kInvalidCacheControlDirectives]
|
|
106
|
+
|
|
107
|
+
if (invalidDirectives === undefined) {
|
|
108
|
+
invalidDirectives = new Set()
|
|
109
|
+
Object.defineProperty(directives, kInvalidCacheControlDirectives, {
|
|
110
|
+
value: invalidDirectives
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
invalidDirectives.add(key)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function hasInvalidCacheControlDirective (directives, key) {
|
|
118
|
+
return directives[kInvalidCacheControlDirectives]?.has(key) === true
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function getMalformedRestrictiveDirectiveName (key) {
|
|
122
|
+
for (const directiveName of RESTRICTIVE_DIRECTIVE_NAMES) {
|
|
123
|
+
if (
|
|
124
|
+
key.startsWith(directiveName) &&
|
|
125
|
+
key.length > directiveName.length &&
|
|
126
|
+
!isValidHTTPToken(key[directiveName.length])
|
|
127
|
+
) {
|
|
128
|
+
return directiveName
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
let tokenOnlyKey = ''
|
|
133
|
+
let hasInvalidTokenChar = false
|
|
134
|
+
for (let i = 0; i < key.length; i++) {
|
|
135
|
+
if (isValidHTTPToken(key[i])) {
|
|
136
|
+
tokenOnlyKey += key[i]
|
|
137
|
+
} else {
|
|
138
|
+
hasInvalidTokenChar = true
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (hasInvalidTokenChar && arrayIncludes(RESTRICTIVE_DIRECTIVE_NAMES, tokenOnlyKey)) {
|
|
143
|
+
return tokenOnlyKey
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
11
147
|
/**
|
|
12
148
|
* @param {import('../../types/dispatcher.d.ts').default.DispatchOptions} opts
|
|
13
149
|
*/
|
|
@@ -30,6 +166,20 @@ function makeCacheKey (opts) {
|
|
|
30
166
|
}
|
|
31
167
|
}
|
|
32
168
|
|
|
169
|
+
function appendHeader (headers, key, val) {
|
|
170
|
+
const headerName = key.toLowerCase()
|
|
171
|
+
const current = headers[headerName]
|
|
172
|
+
const values = Array.isArray(val) ? val : [val]
|
|
173
|
+
|
|
174
|
+
if (current === undefined) {
|
|
175
|
+
headers[headerName] = Array.isArray(val) ? val.slice() : val
|
|
176
|
+
} else if (Array.isArray(current)) {
|
|
177
|
+
current.push(...values)
|
|
178
|
+
} else {
|
|
179
|
+
headers[headerName] = [current, ...values]
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
33
183
|
/**
|
|
34
184
|
* @param {Record<string, string[] | string>}
|
|
35
185
|
* @returns {Record<string, string[] | string>}
|
|
@@ -42,19 +192,61 @@ function normalizeHeaders (opts) {
|
|
|
42
192
|
headers = {}
|
|
43
193
|
|
|
44
194
|
if (hasSafeIterator(opts.headers)) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
195
|
+
if (Array.isArray(opts.headers)) {
|
|
196
|
+
// Array format: could be flat alternating [k, v, k, v, ...]
|
|
197
|
+
// or array-of-pairs [[k, v], ...]
|
|
198
|
+
const first = opts.headers[0]
|
|
199
|
+
if (Array.isArray(first)) {
|
|
200
|
+
for (const x of opts.headers) {
|
|
201
|
+
if (!Array.isArray(x)) {
|
|
202
|
+
throw new Error('opts.headers is not a valid header map')
|
|
203
|
+
}
|
|
204
|
+
const [key, val] = x
|
|
205
|
+
if (typeof key !== 'string' || typeof val !== 'string') {
|
|
206
|
+
throw new Error('opts.headers is not a valid header map')
|
|
207
|
+
}
|
|
208
|
+
appendHeader(headers, key, val)
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
// Flat alternating array [k, v, k, v, ...]
|
|
212
|
+
const len = opts.headers.length
|
|
213
|
+
if (len % 2 !== 0) {
|
|
214
|
+
throw new Error('opts.headers is not a valid header map')
|
|
215
|
+
}
|
|
216
|
+
for (let i = 0; i < len; i += 2) {
|
|
217
|
+
const key = opts.headers[i]
|
|
218
|
+
const val = opts.headers[i + 1]
|
|
219
|
+
if (typeof key !== 'string' || (typeof val !== 'string' && !Array.isArray(val))) {
|
|
220
|
+
throw new Error('opts.headers is not a valid header map')
|
|
221
|
+
}
|
|
222
|
+
if (typeof val === 'string') {
|
|
223
|
+
appendHeader(headers, key, val)
|
|
224
|
+
} else {
|
|
225
|
+
const mapped = []
|
|
226
|
+
for (let j = 0; j < val.length; j++) {
|
|
227
|
+
const v = val[j]
|
|
228
|
+
mapped.push(typeof v === 'string' ? v : v.toString('latin1'))
|
|
229
|
+
}
|
|
230
|
+
appendHeader(headers, key, mapped)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
48
233
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
234
|
+
} else {
|
|
235
|
+
// Non-array iterable (e.g. Map) — use original iteration logic
|
|
236
|
+
for (const x of opts.headers) {
|
|
237
|
+
if (!Array.isArray(x)) {
|
|
238
|
+
throw new Error('opts.headers is not a valid header map')
|
|
239
|
+
}
|
|
240
|
+
const [key, val] = x
|
|
241
|
+
if (typeof key !== 'string' || typeof val !== 'string') {
|
|
242
|
+
throw new Error('opts.headers is not a valid header map')
|
|
243
|
+
}
|
|
244
|
+
appendHeader(headers, key, val)
|
|
52
245
|
}
|
|
53
|
-
headers[key.toLowerCase()] = val
|
|
54
246
|
}
|
|
55
247
|
} else {
|
|
56
248
|
for (const key of Object.keys(opts.headers)) {
|
|
57
|
-
headers
|
|
249
|
+
appendHeader(headers, key, opts.headers[key])
|
|
58
250
|
}
|
|
59
251
|
}
|
|
60
252
|
} else {
|
|
@@ -126,29 +318,37 @@ function parseCacheControlHeader (header) {
|
|
|
126
318
|
* @type {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives}
|
|
127
319
|
*/
|
|
128
320
|
const output = {}
|
|
321
|
+
const invalidNumericDirectives = new Set()
|
|
322
|
+
const invalidNoArgumentDirectives = new Set()
|
|
129
323
|
|
|
130
|
-
|
|
131
|
-
if (Array.isArray(header)) {
|
|
132
|
-
directives = []
|
|
133
|
-
|
|
134
|
-
for (const directive of header) {
|
|
135
|
-
directives.push(...directive.split(','))
|
|
136
|
-
}
|
|
137
|
-
} else {
|
|
138
|
-
directives = header.split(',')
|
|
139
|
-
}
|
|
324
|
+
const directives = splitCacheControlHeaderValue(Array.isArray(header) ? header.join(',') : header)
|
|
140
325
|
|
|
141
326
|
for (let i = 0; i < directives.length; i++) {
|
|
142
|
-
const
|
|
327
|
+
const directiveRecord = directives[i]
|
|
328
|
+
const directive = directiveRecord.value.toLowerCase()
|
|
329
|
+
const fromMalformedQuote = directiveRecord.fromMalformedQuote
|
|
143
330
|
const keyValueDelimiter = directive.indexOf('=')
|
|
144
331
|
|
|
145
332
|
let key
|
|
146
333
|
let value
|
|
334
|
+
let keyHasTrailingWhitespace = false
|
|
335
|
+
let valueHasLeadingWhitespace = false
|
|
147
336
|
if (keyValueDelimiter !== -1) {
|
|
148
|
-
|
|
149
|
-
|
|
337
|
+
const rawKey = directive.substring(0, keyValueDelimiter)
|
|
338
|
+
const rawValue = directive.substring(keyValueDelimiter + 1)
|
|
339
|
+
|
|
340
|
+
keyHasTrailingWhitespace = trimOWSEnd(rawKey) !== rawKey
|
|
341
|
+
valueHasLeadingWhitespace = trimOWSStart(rawValue) !== rawValue
|
|
342
|
+
key = trimOWS(rawKey)
|
|
343
|
+
value = trimOWSStart(rawValue)
|
|
150
344
|
} else {
|
|
151
|
-
key = directive
|
|
345
|
+
key = trimOWS(directive)
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const malformedRestrictiveDirectiveName = getMalformedRestrictiveDirectiveName(key)
|
|
349
|
+
if (malformedRestrictiveDirectiveName !== undefined) {
|
|
350
|
+
output[malformedRestrictiveDirectiveName] = true
|
|
351
|
+
continue
|
|
152
352
|
}
|
|
153
353
|
|
|
154
354
|
switch (key) {
|
|
@@ -158,7 +358,14 @@ function parseCacheControlHeader (header) {
|
|
|
158
358
|
case 's-maxage':
|
|
159
359
|
case 'stale-while-revalidate':
|
|
160
360
|
case 'stale-if-error': {
|
|
161
|
-
if (
|
|
361
|
+
if (fromMalformedQuote || invalidNumericDirectives.has(key)) {
|
|
362
|
+
continue
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (value === undefined || keyHasTrailingWhitespace || valueHasLeadingWhitespace) {
|
|
366
|
+
delete output[key]
|
|
367
|
+
invalidNumericDirectives.add(key)
|
|
368
|
+
markInvalidCacheControlDirective(output, key)
|
|
162
369
|
continue
|
|
163
370
|
}
|
|
164
371
|
|
|
@@ -170,22 +377,37 @@ function parseCacheControlHeader (header) {
|
|
|
170
377
|
value = value.substring(1, value.length - 1)
|
|
171
378
|
}
|
|
172
379
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
380
|
+
if (!/^[0-9]+$/.test(value)) {
|
|
381
|
+
delete output[key]
|
|
382
|
+
invalidNumericDirectives.add(key)
|
|
383
|
+
markInvalidCacheControlDirective(output, key)
|
|
176
384
|
continue
|
|
177
385
|
}
|
|
178
386
|
|
|
179
|
-
|
|
180
|
-
continue
|
|
181
|
-
}
|
|
387
|
+
const parsedValue = Math.min(parseInt(value, 10), MAX_DELTA_SECONDS)
|
|
182
388
|
|
|
183
|
-
|
|
389
|
+
if (key === 'min-fresh') {
|
|
390
|
+
if (!(key in output) || output[key] < parsedValue) {
|
|
391
|
+
output[key] = parsedValue
|
|
392
|
+
}
|
|
393
|
+
} else if (!(key in output) || output[key] > parsedValue) {
|
|
394
|
+
output[key] = parsedValue
|
|
395
|
+
}
|
|
184
396
|
|
|
185
397
|
break
|
|
186
398
|
}
|
|
187
399
|
case 'private':
|
|
188
400
|
case 'no-cache': {
|
|
401
|
+
if (fromMalformedQuote) {
|
|
402
|
+
output[key] = true
|
|
403
|
+
break
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (value !== undefined && value.length === 0) {
|
|
407
|
+
output[key] = true
|
|
408
|
+
break
|
|
409
|
+
}
|
|
410
|
+
|
|
189
411
|
if (value) {
|
|
190
412
|
// The private and no-cache directives can be unqualified (aka just
|
|
191
413
|
// `private` or `no-cache`) or qualified (w/ a value). When they're
|
|
@@ -193,45 +415,64 @@ function parseCacheControlHeader (header) {
|
|
|
193
415
|
// `no-cache="header1"`, or `no-cache="header1, header2"`
|
|
194
416
|
// If we're given multiple headers, the comma messes us up since
|
|
195
417
|
// we split the full header by commas. So, let's loop through the
|
|
196
|
-
// remaining parts in front of us until we find one that
|
|
197
|
-
// quote. We can then
|
|
198
|
-
//
|
|
199
|
-
// and continue parsing like normal.
|
|
418
|
+
// remaining parts in front of us until we find one that contains a
|
|
419
|
+
// closing quote. We can then skip the consumed quoted-list fragments and
|
|
420
|
+
// continue parsing like normal.
|
|
200
421
|
// https://www.rfc-editor.org/rfc/rfc9111.html#name-no-cache-2
|
|
201
422
|
if (value[0] === '"') {
|
|
202
423
|
// Something like `no-cache="some-header"` OR `no-cache="some-header, another-header"`.
|
|
424
|
+
value = trimOWSEnd(value)
|
|
203
425
|
|
|
204
|
-
|
|
205
|
-
|
|
426
|
+
let fieldList = ''
|
|
427
|
+
let lastQuotedPart = i
|
|
428
|
+
let foundEndingQuote = false
|
|
429
|
+
const closingQuote = findUnescapedQuote(value, 1)
|
|
206
430
|
|
|
207
|
-
|
|
208
|
-
|
|
431
|
+
if (closingQuote !== -1) {
|
|
432
|
+
fieldList = value.substring(1, closingQuote)
|
|
433
|
+
foundEndingQuote = true
|
|
434
|
+
} else {
|
|
209
435
|
// Something like `no-cache="some-header, another-header"`
|
|
210
436
|
// This can still be something invalid, e.g. `no-cache="some-header, ...`
|
|
437
|
+
const fieldListParts = [value.substring(1)]
|
|
438
|
+
|
|
211
439
|
for (let j = i + 1; j < directives.length; j++) {
|
|
212
|
-
const nextPart = directives[j]
|
|
213
|
-
const
|
|
440
|
+
const nextPart = trimOWS(directives[j].value)
|
|
441
|
+
const closingQuote = findUnescapedQuote(nextPart, 0)
|
|
214
442
|
|
|
215
|
-
|
|
443
|
+
lastQuotedPart = j
|
|
216
444
|
|
|
217
|
-
if (
|
|
445
|
+
if (closingQuote !== -1) {
|
|
446
|
+
fieldListParts.push(nextPart.substring(0, closingQuote))
|
|
218
447
|
foundEndingQuote = true
|
|
219
448
|
break
|
|
220
449
|
}
|
|
450
|
+
|
|
451
|
+
fieldListParts.push(nextPart)
|
|
221
452
|
}
|
|
453
|
+
|
|
454
|
+
fieldList = fieldListParts.join(',')
|
|
222
455
|
}
|
|
223
456
|
|
|
224
|
-
if (foundEndingQuote) {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
headers[headers.length - 1] = lastHeader
|
|
229
|
-
}
|
|
457
|
+
if (!foundEndingQuote) {
|
|
458
|
+
output[key] = true
|
|
459
|
+
break
|
|
460
|
+
}
|
|
230
461
|
|
|
231
|
-
|
|
232
|
-
|
|
462
|
+
i = lastQuotedPart
|
|
463
|
+
|
|
464
|
+
const headers = fieldList.split(',')
|
|
465
|
+
let validFieldNames = true
|
|
466
|
+
for (let j = 0; j < headers.length; j++) {
|
|
467
|
+
headers[j] = trimOWS(headers[j])
|
|
468
|
+
if (!isValidHTTPToken(headers[j])) {
|
|
469
|
+
validFieldNames = false
|
|
233
470
|
}
|
|
471
|
+
}
|
|
234
472
|
|
|
473
|
+
if (!validFieldNames) {
|
|
474
|
+
output[key] = true
|
|
475
|
+
} else if (output[key] !== true) {
|
|
235
476
|
if (key in output) {
|
|
236
477
|
output[key] = output[key].concat(headers)
|
|
237
478
|
} else {
|
|
@@ -239,13 +480,17 @@ function parseCacheControlHeader (header) {
|
|
|
239
480
|
}
|
|
240
481
|
}
|
|
241
482
|
} else {
|
|
242
|
-
// Something like `no-cache=
|
|
243
|
-
const fieldName = value
|
|
483
|
+
// Something like `no-cache=some-header`
|
|
484
|
+
const fieldName = trimOWS(value)
|
|
244
485
|
|
|
245
|
-
if (
|
|
246
|
-
output[key] =
|
|
247
|
-
} else {
|
|
248
|
-
|
|
486
|
+
if (!isValidHTTPToken(fieldName)) {
|
|
487
|
+
output[key] = true
|
|
488
|
+
} else if (output[key] !== true) {
|
|
489
|
+
if (key in output) {
|
|
490
|
+
output[key] = output[key].concat(fieldName)
|
|
491
|
+
} else {
|
|
492
|
+
output[key] = [fieldName]
|
|
493
|
+
}
|
|
249
494
|
}
|
|
250
495
|
}
|
|
251
496
|
|
|
@@ -254,19 +499,27 @@ function parseCacheControlHeader (header) {
|
|
|
254
499
|
}
|
|
255
500
|
// eslint-disable-next-line no-fallthrough
|
|
256
501
|
case 'public':
|
|
257
|
-
case 'no-store':
|
|
258
502
|
case 'must-revalidate':
|
|
259
503
|
case 'proxy-revalidate':
|
|
260
504
|
case 'immutable':
|
|
261
505
|
case 'no-transform':
|
|
262
506
|
case 'must-understand':
|
|
263
507
|
case 'only-if-cached':
|
|
264
|
-
if (
|
|
508
|
+
if (fromMalformedQuote || invalidNoArgumentDirectives.has(key)) {
|
|
509
|
+
continue
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
if (value !== undefined) {
|
|
265
513
|
// These are qualified (something like `public=...`) when they aren't
|
|
266
|
-
// allowed to be, skip
|
|
514
|
+
// allowed to be, skip all instances of the malformed directive.
|
|
515
|
+
delete output[key]
|
|
516
|
+
invalidNoArgumentDirectives.add(key)
|
|
267
517
|
continue
|
|
268
518
|
}
|
|
269
519
|
|
|
520
|
+
output[key] = true
|
|
521
|
+
break
|
|
522
|
+
case 'no-store':
|
|
270
523
|
output[key] = true
|
|
271
524
|
break
|
|
272
525
|
default:
|
|
@@ -278,31 +531,79 @@ function parseCacheControlHeader (header) {
|
|
|
278
531
|
return output
|
|
279
532
|
}
|
|
280
533
|
|
|
534
|
+
/**
|
|
535
|
+
* @param {string | string[]} varyHeader Vary header from the server
|
|
536
|
+
* @returns {string[]}
|
|
537
|
+
*/
|
|
538
|
+
function splitVaryHeader (varyHeader) {
|
|
539
|
+
const values = Array.isArray(varyHeader) ? varyHeader : [varyHeader]
|
|
540
|
+
const output = []
|
|
541
|
+
|
|
542
|
+
for (let i = 0; i < values.length; i++) {
|
|
543
|
+
const parts = values[i].split(',')
|
|
544
|
+
for (let j = 0; j < parts.length; j++) {
|
|
545
|
+
output.push(parts[j])
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
return output
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/**
|
|
553
|
+
* @param {string | string[]} varyHeader Vary header from the server
|
|
554
|
+
* @returns {boolean}
|
|
555
|
+
*/
|
|
556
|
+
function hasVaryStar (varyHeader) {
|
|
557
|
+
const values = splitVaryHeader(varyHeader)
|
|
558
|
+
for (let i = 0; i < values.length; i++) {
|
|
559
|
+
if (trimOWS(values[i]).indexOf('*') !== -1) {
|
|
560
|
+
return true
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return false
|
|
565
|
+
}
|
|
566
|
+
|
|
281
567
|
/**
|
|
282
568
|
* @param {string | string[]} varyHeader Vary header from the server
|
|
283
569
|
* @param {Record<string, string | string[]>} headers Request headers
|
|
284
|
-
* @returns {Record<string, string | string[]>}
|
|
570
|
+
* @returns {Record<string, string | string[] | null> | undefined}
|
|
285
571
|
*/
|
|
286
572
|
function parseVaryHeader (varyHeader, headers) {
|
|
287
|
-
if (
|
|
573
|
+
if (hasVaryStar(varyHeader)) {
|
|
288
574
|
return headers
|
|
289
575
|
}
|
|
290
576
|
|
|
291
577
|
const output = /** @type {Record<string, string | string[] | null>} */ ({})
|
|
292
578
|
|
|
293
|
-
const varyingHeaders =
|
|
294
|
-
? varyHeader.split(',')
|
|
295
|
-
: varyHeader
|
|
579
|
+
const varyingHeaders = splitVaryHeader(varyHeader)
|
|
296
580
|
|
|
297
581
|
for (const header of varyingHeaders) {
|
|
298
|
-
const trimmedHeader = header
|
|
582
|
+
const trimmedHeader = trimOWS(header).toLowerCase()
|
|
583
|
+
|
|
584
|
+
if (trimmedHeader.length === 0) {
|
|
585
|
+
continue
|
|
586
|
+
}
|
|
299
587
|
|
|
300
|
-
|
|
588
|
+
if (!isValidHTTPToken(trimmedHeader)) {
|
|
589
|
+
return undefined
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const headerValue = headers[trimmedHeader]
|
|
593
|
+
output[trimmedHeader] = Array.isArray(headerValue) ? headerValue.slice() : headerValue ?? null
|
|
301
594
|
}
|
|
302
595
|
|
|
303
596
|
return output
|
|
304
597
|
}
|
|
305
598
|
|
|
599
|
+
/**
|
|
600
|
+
* @param {string | string[]} varyHeader Vary header from the server
|
|
601
|
+
* @returns {boolean}
|
|
602
|
+
*/
|
|
603
|
+
function isInvalidOrWildcardVaryHeader (varyHeader) {
|
|
604
|
+
return hasVaryStar(varyHeader) || parseVaryHeader(varyHeader, {}) === undefined
|
|
605
|
+
}
|
|
606
|
+
|
|
306
607
|
/**
|
|
307
608
|
* Note: this deviates from the spec a little. Empty etags ("", W/"") are valid,
|
|
308
609
|
* however, including them in cached resposnes serves little to no purpose.
|
|
@@ -366,7 +667,7 @@ function assertCacheMethods (methods, name = 'CacheMethods') {
|
|
|
366
667
|
}
|
|
367
668
|
|
|
368
669
|
for (const method of methods) {
|
|
369
|
-
if (!safeHTTPMethods
|
|
670
|
+
if (!arrayIncludes(safeHTTPMethods, method)) {
|
|
370
671
|
throw new TypeError(`element of ${name}-array needs to be one of following values: ${safeHTTPMethods.join(', ')}, got ${method}`)
|
|
371
672
|
}
|
|
372
673
|
}
|
|
@@ -406,7 +707,10 @@ module.exports = {
|
|
|
406
707
|
assertCacheKey,
|
|
407
708
|
assertCacheValue,
|
|
408
709
|
parseCacheControlHeader,
|
|
710
|
+
hasInvalidCacheControlDirective,
|
|
409
711
|
parseVaryHeader,
|
|
712
|
+
hasVaryStar,
|
|
713
|
+
isInvalidOrWildcardVaryHeader,
|
|
410
714
|
isEtagUsable,
|
|
411
715
|
assertCacheMethods,
|
|
412
716
|
assertCacheStore,
|