@openclaw/discord 2026.6.33 → 2026.6.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action-runtime-api.js +1 -1
- package/dist/{api-CjnGBhM3.js → api-1GXlSrYP.js} +42 -21
- package/dist/api.js +14 -14
- package/dist/{approval-handler.runtime-BWPQrzpP.js → approval-handler.runtime-Dv4p7REU.js} +3 -3
- package/dist/{audit-BwJ_2OjL.js → audit-DEVi9nIs.js} +3 -3
- package/dist/{channel-Ddnonoy4.js → channel-CQIRiosn.js} +15 -15
- package/dist/{channel-actions-CwmIqnYN.js → channel-actions-JziPEcBU.js} +2 -2
- package/dist/{channel-actions.runtime-DvpTfaJ4.js → channel-actions.runtime-D7L47LY3.js} +5 -5
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-glZ5Y98a.js → channel.setup-oMeR19Cc.js} +2 -2
- package/dist/{components-j6lTZBsT.js → components-_s5UPJqU.js} +1 -1
- package/dist/{conversation-identity-36FFBwm5.js → conversation-identity-B0k94-bz.js} +2 -2
- package/dist/{directory-config-BYMFzL29.js → directory-config-CD1svkyN.js} +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-9JtJCiu8.js → directory-live-DBTsSRxl.js} +5 -5
- package/dist/{handle-action.guild-admin-xxGYrp-I.js → handle-action.guild-admin-CYIFMxh-.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{manager.runtime-BK6cf2Zu.js → manager.runtime-BZVdGX2d.js} +17 -9
- package/dist/{message-handler-BqpJIavO.js → message-handler-DZd9Bpq8.js} +7 -6
- package/dist/{message-handler.preflight-C90MxCcv.js → message-handler.preflight-Axv9J9EO.js} +12 -11
- package/dist/{message-handler.process-CeQ7Bd_3.js → message-handler.process-CG0zFS-Z.js} +10 -10
- package/dist/{message-utils-CJeAoISH.js → message-utils-Dbuw27gd.js} +1 -1
- package/dist/{outbound-adapter-Dxs6iKEq.js → outbound-adapter-CKC_kmUN.js} +6 -6
- package/dist/pluralkit-CfTReLl3.js +40 -0
- package/dist/{probe-esE_Oqdm.js → probe-DcgZIpyF.js} +3 -2
- package/dist/{probe.runtime-C3Atgpvr.js → probe.runtime-CVwM9L5E.js} +1 -1
- package/dist/{provider-C7376XFH.js → provider-CwwSXIIj.js} +102 -37
- package/dist/{provider-session.runtime-CCdqogGf.js → provider-session.runtime-reBWkqHZ.js} +3 -3
- package/dist/provider.runtime-BsmTLYS_.js +2 -0
- package/dist/{resolve-allowlist-common-3gB2Gpmm.js → resolve-allowlist-common-D7bZqAw3.js} +3 -3
- package/dist/{resolve-channels-B3gQf8QL.js → resolve-channels--oE-RnO6.js} +6 -6
- package/dist/{resolve-users-BO10y5fJ.js → resolve-users-QXo8CXBU.js} +5 -5
- package/dist/{runtime-CFlR3L9X.js → runtime-CF7ramAs.js} +7 -7
- 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-CzF8MUl_.js +6 -0
- package/dist/runtime-api.monitor.js +5 -5
- package/dist/runtime-api.send.js +5 -5
- package/dist/runtime-api.threads.js +3 -3
- package/dist/{send-JHxfT4Pk.js → send-Bb295iHT.js} +5 -5
- package/dist/{send.components-CN35E2Ck.js → send.components-COkDUO3B.js} +4 -4
- package/dist/{send.outbound-B-cA1Esv.js → send.outbound-B_sk0hNe.js} +3 -3
- package/dist/{send.receipt-CGecJDin.js → send.receipt-Cli6_9Sn.js} +19 -7
- package/dist/{send.shared-vcbfThdy.js → send.shared-BCG7MWnP.js} +2 -2
- package/dist/session-binding-contract-api.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{subagent-hooks-20wXhVzZ.js → subagent-hooks-CtqoWK4x.js} +2 -2
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/{system-events-DR27TE7p.js → system-events-BxGNk_wE.js} +1 -1
- package/dist/{target-resolver-CDi1gI90.js → target-resolver-BcoK6b0g.js} +2 -2
- package/dist/targets-Q-ZoP7K4.js +3 -0
- package/dist/{thread-bindings-DU4T6nDo.js → thread-bindings-DJ_HT6GJ.js} +4 -4
- package/dist/{thread-bindings.discord-api-CYkr-3Gj.js → thread-bindings.discord-api-OPyjvgyz.js} +4 -4
- package/dist/{thread-bindings.manager-BqWs1UE2.js → thread-bindings.manager-Cd2HAVw_.js} +3 -3
- package/dist/{transcripts-source-D-lBI5ZD.js → transcripts-source-CPf5gURy.js} +1 -1
- package/dist/transcripts-source-api.js +1 -1
- package/dist/{typing-xr05bL-r.js → typing-DY0cwLdg.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 +386 -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 +102 -87
- package/node_modules/undici/docs/docs/api/Errors.md +503 -40
- package/node_modules/undici/docs/docs/api/EventSource.md +298 -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 +418 -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 +177 -196
- 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 +42 -7
- package/node_modules/undici/lib/cache/memory-cache-store.js +56 -11
- package/node_modules/undici/lib/cache/sqlite-cache-store.js +7 -1
- package/node_modules/undici/lib/core/connect.js +16 -2
- 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/symbols.js +3 -0
- package/node_modules/undici/lib/core/util.js +30 -2
- package/node_modules/undici/lib/dispatcher/agent.js +10 -5
- package/node_modules/undici/lib/dispatcher/balanced-pool.js +7 -4
- package/node_modules/undici/lib/dispatcher/client-h1.js +74 -9
- package/node_modules/undici/lib/dispatcher/client-h2.js +483 -151
- package/node_modules/undici/lib/dispatcher/client.js +76 -30
- package/node_modules/undici/lib/dispatcher/dispatcher-base.js +13 -1
- package/node_modules/undici/lib/dispatcher/dispatcher.js +15 -1
- package/node_modules/undici/lib/dispatcher/dispatcher1-wrapper.js +3 -0
- package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +37 -8
- package/node_modules/undici/lib/dispatcher/proxy-agent.js +58 -7
- package/node_modules/undici/lib/dispatcher/retry-agent.js +3 -0
- package/node_modules/undici/lib/dispatcher/round-robin-pool.js +1 -1
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +106 -22
- package/node_modules/undici/lib/global.js +36 -16
- package/node_modules/undici/lib/handler/cache-handler.js +297 -65
- package/node_modules/undici/lib/handler/cache-revalidation-handler.js +13 -3
- package/node_modules/undici/lib/handler/decorator-handler.js +7 -1
- package/node_modules/undici/lib/handler/deduplication-handler.js +12 -6
- package/node_modules/undici/lib/handler/redirect-handler.js +26 -5
- package/node_modules/undici/lib/handler/retry-handler.js +238 -51
- package/node_modules/undici/lib/interceptor/cache.js +221 -58
- package/node_modules/undici/lib/interceptor/decompress.js +124 -15
- package/node_modules/undici/lib/interceptor/deduplicate.js +5 -4
- package/node_modules/undici/lib/interceptor/dns.js +7 -0
- package/node_modules/undici/lib/interceptor/dump.js +10 -23
- package/node_modules/undici/lib/mock/mock-agent.js +13 -1
- package/node_modules/undici/lib/mock/mock-interceptor.js +25 -7
- package/node_modules/undici/lib/mock/mock-utils.js +246 -27
- package/node_modules/undici/lib/util/cache.js +415 -71
- package/node_modules/undici/lib/util/date.js +23 -6
- package/node_modules/undici/lib/web/cookies/parse.js +150 -146
- package/node_modules/undici/lib/web/cookies/util.js +79 -9
- package/node_modules/undici/lib/web/eventsource/eventsource-stream.js +28 -1
- package/node_modules/undici/lib/web/eventsource/eventsource.js +13 -3
- 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 +17 -2
- package/node_modules/undici/lib/web/fetch/request.js +2 -3
- package/node_modules/undici/lib/web/fetch/response.js +1 -3
- package/node_modules/undici/lib/web/fetch/util.js +10 -2
- package/node_modules/undici/lib/web/webidl/index.js +3 -3
- package/node_modules/undici/lib/web/websocket/connection.js +1 -1
- package/node_modules/undici/lib/web/websocket/permessage-deflate.js +5 -0
- package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +8 -10
- package/node_modules/undici/lib/web/websocket/websocket.js +22 -0
- package/node_modules/undici/package.json +4 -4
- package/node_modules/undici/types/client.d.ts +53 -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/interceptors.d.ts +2 -0
- package/node_modules/undici/types/mock-agent.d.ts +11 -10
- package/node_modules/undici/types/mock-interceptor.d.ts +5 -1
- package/node_modules/undici/types/proxy-agent.d.ts +7 -0
- package/node_modules/undici/types/socks5-proxy-agent.d.ts +2 -0
- package/npm-shrinkwrap.json +7 -7
- package/package.json +6 -5
- package/dist/pluralkit-DI6RYaVj.js +0 -24
- package/dist/provider.runtime-D1m66kDS.js +0 -2
- package/dist/runtime-api.monitor-4oc58TSk.js +0 -6
- package/dist/targets-C6yd3y8R.js +0 -3
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
const util = require('../core/util')
|
|
4
4
|
const {
|
|
5
5
|
parseCacheControlHeader,
|
|
6
|
+
hasInvalidCacheControlDirective,
|
|
6
7
|
parseVaryHeader,
|
|
8
|
+
hasVaryStar,
|
|
9
|
+
isInvalidOrWildcardVaryHeader,
|
|
7
10
|
isEtagUsable
|
|
8
11
|
} = require('../util/cache')
|
|
9
12
|
const { parseHttpDate } = require('../util/date.js')
|
|
@@ -26,6 +29,95 @@ const NOT_UNDERSTOOD_STATUS_CODES = [
|
|
|
26
29
|
|
|
27
30
|
const MAX_RESPONSE_AGE = 2147483647000
|
|
28
31
|
|
|
32
|
+
// Retention for revalidation-only entries (zero freshness lifetime but a
|
|
33
|
+
// validator present); each successful revalidation re-stores the entry.
|
|
34
|
+
const REVALIDATION_ONLY_RETENTION = 86400000 // 24 hours
|
|
35
|
+
|
|
36
|
+
function trimOWS (value) {
|
|
37
|
+
return value.replace(/^[\t ]+|[\t ]+$/g, '')
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function arrayIncludes (array, value) {
|
|
41
|
+
for (let i = 0; i < array.length; i++) {
|
|
42
|
+
if (array[i] === value) {
|
|
43
|
+
return true
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function appendConnectionHeaderTokens (headersToRemove, connectionHeader) {
|
|
51
|
+
const values = Array.isArray(connectionHeader) ? connectionHeader : [connectionHeader]
|
|
52
|
+
|
|
53
|
+
for (let i = 0; i < values.length; i++) {
|
|
54
|
+
const tokens = values[i].split(',')
|
|
55
|
+
for (let j = 0; j < tokens.length; j++) {
|
|
56
|
+
headersToRemove.push(trimOWS(tokens[j]).toLowerCase())
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function getSameOriginPath (cacheKey, location) {
|
|
62
|
+
if (typeof location !== 'string') {
|
|
63
|
+
return undefined
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let originUrl
|
|
67
|
+
let requestUrl
|
|
68
|
+
let locationUrl
|
|
69
|
+
try {
|
|
70
|
+
originUrl = new URL(cacheKey.origin)
|
|
71
|
+
requestUrl = new URL(cacheKey.path, originUrl)
|
|
72
|
+
locationUrl = new URL(location, requestUrl)
|
|
73
|
+
} catch {
|
|
74
|
+
return undefined
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (locationUrl.origin !== originUrl.origin) {
|
|
78
|
+
return undefined
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return locationUrl.pathname + locationUrl.search
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function deleteCachedUri (store, cacheKey, path) {
|
|
85
|
+
deleteCachedValue(store, {
|
|
86
|
+
...cacheKey,
|
|
87
|
+
path
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
for (let i = 0; i < util.safeHTTPMethods.length; i++) {
|
|
91
|
+
const method = util.safeHTTPMethods[i]
|
|
92
|
+
if (method !== cacheKey.method) {
|
|
93
|
+
deleteCachedValue(store, {
|
|
94
|
+
...cacheKey,
|
|
95
|
+
method,
|
|
96
|
+
path
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function deleteLocationTargets (store, cacheKey, headerValue) {
|
|
103
|
+
if (headerValue === undefined) {
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const values = Array.isArray(headerValue) ? headerValue : [headerValue]
|
|
108
|
+
for (let i = 0; i < values.length; i++) {
|
|
109
|
+
const path = getSameOriginPath(cacheKey, values[i])
|
|
110
|
+
if (path !== undefined) {
|
|
111
|
+
deleteCachedUri(store, cacheKey, path)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function invalidateUnsafeRequest (store, cacheKey, resHeaders) {
|
|
117
|
+
deleteCachedUri(store, cacheKey, cacheKey.path)
|
|
118
|
+
deleteLocationTargets(store, cacheKey, resHeaders.location)
|
|
119
|
+
deleteLocationTargets(store, cacheKey, resHeaders['content-location'])
|
|
120
|
+
}
|
|
29
121
|
/**
|
|
30
122
|
* @typedef {import('../../types/dispatcher.d.ts').default.DispatchHandler} DispatchHandler
|
|
31
123
|
*
|
|
@@ -81,6 +173,14 @@ class CacheHandler {
|
|
|
81
173
|
this.#handler.onRequestStart?.(controller, context)
|
|
82
174
|
}
|
|
83
175
|
|
|
176
|
+
onBodySent (chunk) {
|
|
177
|
+
this.#handler.onBodySent?.(chunk)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
onRequestSent () {
|
|
181
|
+
this.#handler.onRequestSent?.()
|
|
182
|
+
}
|
|
183
|
+
|
|
84
184
|
onRequestUpgrade (controller, statusCode, headers, socket) {
|
|
85
185
|
this.#handler.onRequestUpgrade?.(controller, statusCode, headers, socket)
|
|
86
186
|
}
|
|
@@ -107,60 +207,89 @@ class CacheHandler {
|
|
|
107
207
|
const handler = this
|
|
108
208
|
|
|
109
209
|
if (
|
|
110
|
-
!util.safeHTTPMethods
|
|
210
|
+
!arrayIncludes(util.safeHTTPMethods, this.#cacheKey.method) &&
|
|
111
211
|
statusCode >= 200 &&
|
|
112
212
|
statusCode <= 399
|
|
113
213
|
) {
|
|
114
214
|
// Successful response to an unsafe method, delete it from cache
|
|
115
215
|
// https://www.rfc-editor.org/rfc/rfc9111.html#name-invalidating-stored-response
|
|
116
|
-
|
|
117
|
-
this.#store.delete(this.#cacheKey)?.catch?.(noop)
|
|
118
|
-
} catch {
|
|
119
|
-
// Fail silently
|
|
120
|
-
}
|
|
216
|
+
invalidateUnsafeRequest(this.#store, this.#cacheKey, resHeaders)
|
|
121
217
|
return downstreamOnHeaders()
|
|
122
218
|
}
|
|
123
219
|
|
|
124
220
|
const cacheControlHeader = resHeaders['cache-control']
|
|
125
|
-
const
|
|
221
|
+
const cacheControlDirectives = cacheControlHeader ? parseCacheControlHeader(cacheControlHeader) : {}
|
|
222
|
+
|
|
223
|
+
if (revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives)) {
|
|
224
|
+
deleteCachedValue(this.#store, this.#cacheKey)
|
|
225
|
+
return downstreamOnHeaders()
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const heuristicallyCacheable = resHeaders['last-modified'] && arrayIncludes(HEURISTICALLY_CACHEABLE_STATUS_CODES, statusCode)
|
|
126
229
|
if (
|
|
127
230
|
!cacheControlHeader &&
|
|
128
231
|
!resHeaders['expires'] &&
|
|
129
232
|
!heuristicallyCacheable &&
|
|
130
233
|
!this.#cacheByDefault
|
|
131
234
|
) {
|
|
235
|
+
if (statusCode === 304 && resHeaders.vary && isInvalidOrWildcardVaryHeader(resHeaders.vary)) {
|
|
236
|
+
deleteCachedValue(this.#store, this.#cacheKey)
|
|
237
|
+
}
|
|
238
|
+
|
|
132
239
|
// Don't have anything to tell us this response is cachable and we're not
|
|
133
240
|
// caching by default
|
|
134
241
|
return downstreamOnHeaders()
|
|
135
242
|
}
|
|
136
243
|
|
|
137
|
-
|
|
138
|
-
|
|
244
|
+
if (!canCacheResponse(this.#cacheType, this.#cacheKey.method, statusCode, resHeaders, cacheControlDirectives, this.#cacheKey.headers)) {
|
|
245
|
+
if (statusCode === 304 && (cacheControlHeader || revalidationResponseDisallowsCachedReuse(this.#cacheType, resHeaders, cacheControlDirectives))) {
|
|
246
|
+
deleteCachedValue(this.#store, this.#cacheKey)
|
|
247
|
+
}
|
|
248
|
+
|
|
139
249
|
return downstreamOnHeaders()
|
|
140
250
|
}
|
|
141
251
|
|
|
142
252
|
const now = Date.now()
|
|
143
|
-
const resAge = resHeaders
|
|
144
|
-
if (resAge && resAge >= MAX_RESPONSE_AGE) {
|
|
253
|
+
const resAge = Object.hasOwn(resHeaders, 'age') ? getAge(resHeaders.age) : undefined
|
|
254
|
+
if (resAge !== undefined && resAge >= MAX_RESPONSE_AGE) {
|
|
145
255
|
// Response considered stale
|
|
256
|
+
deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey)
|
|
146
257
|
return downstreamOnHeaders()
|
|
147
258
|
}
|
|
148
259
|
|
|
149
|
-
const resDate =
|
|
150
|
-
|
|
151
|
-
|
|
260
|
+
const resDate = Object.hasOwn(resHeaders, 'date') ? getDate(resHeaders.date) : undefined
|
|
261
|
+
if (resDate === null) {
|
|
262
|
+
deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey)
|
|
263
|
+
return downstreamOnHeaders()
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const apparentAge = resDate ? Math.max(0, now - resDate.getTime()) : 0
|
|
267
|
+
const currentAge = Math.max(apparentAge, resAge ?? 0)
|
|
268
|
+
|
|
269
|
+
const hasValidator =
|
|
270
|
+
(typeof resHeaders.etag === 'string' && isEtagUsable(resHeaders.etag)) ||
|
|
271
|
+
typeof resHeaders['last-modified'] === 'string'
|
|
152
272
|
|
|
153
273
|
const staleAt =
|
|
154
|
-
determineStaleAt(this.#cacheType, now, resAge, resHeaders, resDate, cacheControlDirectives) ??
|
|
274
|
+
determineStaleAt(this.#cacheType, now, resAge, resHeaders, resDate, cacheControlDirectives, hasValidator) ??
|
|
155
275
|
this.#cacheByDefault
|
|
156
|
-
|
|
276
|
+
// Zero freshness lifetime but a validator: stale from the start, yet still
|
|
277
|
+
// storable since each reuse is preceded by a revalidation request.
|
|
278
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#section-5.2.2.4
|
|
279
|
+
const revalidationOnly = staleAt === 0 && hasValidator
|
|
280
|
+
if (staleAt === undefined || (currentAge >= staleAt && !revalidationOnly)) {
|
|
281
|
+
if (cacheControlHeader || staleAt !== undefined) {
|
|
282
|
+
deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey)
|
|
283
|
+
}
|
|
284
|
+
|
|
157
285
|
return downstreamOnHeaders()
|
|
158
286
|
}
|
|
159
287
|
|
|
160
|
-
const baseTime =
|
|
288
|
+
const baseTime = now - currentAge
|
|
161
289
|
const absoluteStaleAt = staleAt + baseTime
|
|
162
|
-
if (now >= absoluteStaleAt) {
|
|
290
|
+
if (now >= absoluteStaleAt && !revalidationOnly) {
|
|
163
291
|
// Response is already stale
|
|
292
|
+
deleteCachedValueIfNotModified(statusCode, this.#store, this.#cacheKey)
|
|
164
293
|
return downstreamOnHeaders()
|
|
165
294
|
}
|
|
166
295
|
|
|
@@ -173,8 +302,8 @@ class CacheHandler {
|
|
|
173
302
|
}
|
|
174
303
|
}
|
|
175
304
|
|
|
176
|
-
const cachedAt =
|
|
177
|
-
const deleteAt = determineDeleteAt(baseTime,
|
|
305
|
+
const cachedAt = baseTime
|
|
306
|
+
const deleteAt = determineDeleteAt(baseTime, now, cacheControlDirectives, absoluteStaleAt)
|
|
178
307
|
const strippedHeaders = stripNecessaryHeaders(resHeaders, cacheControlDirectives)
|
|
179
308
|
|
|
180
309
|
/**
|
|
@@ -204,6 +333,7 @@ class CacheHandler {
|
|
|
204
333
|
value.statusCode = cachedValue.statusCode
|
|
205
334
|
value.statusMessage = cachedValue.statusMessage
|
|
206
335
|
value.etag = cachedValue.etag
|
|
336
|
+
value.vary = varyDirectives ?? cachedValue.vary
|
|
207
337
|
value.headers = { ...cachedValue.headers, ...strippedHeaders }
|
|
208
338
|
|
|
209
339
|
downstreamOnHeaders()
|
|
@@ -334,23 +464,60 @@ class CacheHandler {
|
|
|
334
464
|
}
|
|
335
465
|
}
|
|
336
466
|
|
|
467
|
+
/**
|
|
468
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheStore} store
|
|
469
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheKey} cacheKey
|
|
470
|
+
*/
|
|
471
|
+
function deleteCachedValue (store, cacheKey) {
|
|
472
|
+
try {
|
|
473
|
+
store.delete(cacheKey)?.catch?.(noop)
|
|
474
|
+
} catch {
|
|
475
|
+
// Fail silently
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function deleteCachedValueIfNotModified (statusCode, store, cacheKey) {
|
|
480
|
+
if (statusCode === 304) {
|
|
481
|
+
deleteCachedValue(store, cacheKey)
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheOptions['type']} cacheType
|
|
487
|
+
* @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders
|
|
488
|
+
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
489
|
+
* @returns {boolean}
|
|
490
|
+
*/
|
|
491
|
+
function revalidationResponseDisallowsCachedReuse (cacheType, resHeaders, cacheControlDirectives) {
|
|
492
|
+
return cacheControlDirectives['no-store'] === true ||
|
|
493
|
+
(cacheType === 'shared' && (
|
|
494
|
+
cacheControlDirectives.private === true ||
|
|
495
|
+
Object.hasOwn(resHeaders, 'set-cookie')
|
|
496
|
+
)) ||
|
|
497
|
+
(resHeaders.vary ? isInvalidOrWildcardVaryHeader(resHeaders.vary) : false)
|
|
498
|
+
}
|
|
499
|
+
|
|
337
500
|
/**
|
|
338
501
|
* @see https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-to-authen
|
|
339
502
|
*
|
|
340
503
|
* @param {import('../../types/cache-interceptor.d.ts').default.CacheOptions['type']} cacheType
|
|
504
|
+
* @param {string} method
|
|
341
505
|
* @param {number} statusCode
|
|
342
506
|
* @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders
|
|
343
507
|
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
344
508
|
* @param {import('../../types/header.d.ts').IncomingHttpHeaders} [reqHeaders]
|
|
345
509
|
*/
|
|
346
|
-
function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirectives, reqHeaders) {
|
|
510
|
+
function canCacheResponse (cacheType, method, statusCode, resHeaders, cacheControlDirectives, reqHeaders) {
|
|
511
|
+
if (!arrayIncludes(util.safeHTTPMethods, method)) {
|
|
512
|
+
return false
|
|
513
|
+
}
|
|
347
514
|
// Status code must be final and understood.
|
|
348
|
-
if (statusCode < 200 || NOT_UNDERSTOOD_STATUS_CODES
|
|
515
|
+
if (statusCode < 200 || arrayIncludes(NOT_UNDERSTOOD_STATUS_CODES, statusCode)) {
|
|
349
516
|
return false
|
|
350
517
|
}
|
|
351
518
|
// Responses with neither status codes that are heuristically cacheable, nor "explicit enough" caching
|
|
352
519
|
// directives, are not cacheable. "Explicit enough": see https://www.rfc-editor.org/rfc/rfc9111.html#section-3
|
|
353
|
-
if (!HEURISTICALLY_CACHEABLE_STATUS_CODES
|
|
520
|
+
if (!arrayIncludes(HEURISTICALLY_CACHEABLE_STATUS_CODES, statusCode) && !resHeaders['expires'] &&
|
|
354
521
|
!cacheControlDirectives.public &&
|
|
355
522
|
cacheControlDirectives['max-age'] === undefined &&
|
|
356
523
|
// RFC 9111: a private response directive, if the cache is not shared
|
|
@@ -364,17 +531,20 @@ function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirect
|
|
|
364
531
|
return false
|
|
365
532
|
}
|
|
366
533
|
|
|
367
|
-
if (cacheType === 'shared' &&
|
|
534
|
+
if (cacheType === 'shared' && (
|
|
535
|
+
cacheControlDirectives.private === true ||
|
|
536
|
+
Object.hasOwn(resHeaders, 'set-cookie')
|
|
537
|
+
)) {
|
|
368
538
|
return false
|
|
369
539
|
}
|
|
370
540
|
|
|
371
541
|
// https://www.rfc-editor.org/rfc/rfc9111.html#section-4.1-5
|
|
372
|
-
if (resHeaders.vary
|
|
542
|
+
if (resHeaders.vary && hasVaryStar(resHeaders.vary)) {
|
|
373
543
|
return false
|
|
374
544
|
}
|
|
375
545
|
|
|
376
546
|
// https://www.rfc-editor.org/rfc/rfc9111.html#name-storing-responses-to-authen
|
|
377
|
-
if (reqHeaders
|
|
547
|
+
if (reqHeaders != null && Object.hasOwn(reqHeaders, 'authorization')) {
|
|
378
548
|
if (
|
|
379
549
|
!cacheControlDirectives.public &&
|
|
380
550
|
!cacheControlDirectives['s-maxage'] &&
|
|
@@ -389,14 +559,14 @@ function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirect
|
|
|
389
559
|
|
|
390
560
|
if (
|
|
391
561
|
Array.isArray(cacheControlDirectives['no-cache']) &&
|
|
392
|
-
cacheControlDirectives['no-cache']
|
|
562
|
+
arrayIncludes(cacheControlDirectives['no-cache'], 'authorization')
|
|
393
563
|
) {
|
|
394
564
|
return false
|
|
395
565
|
}
|
|
396
566
|
|
|
397
567
|
if (
|
|
398
568
|
Array.isArray(cacheControlDirectives['private']) &&
|
|
399
|
-
cacheControlDirectives['private']
|
|
569
|
+
arrayIncludes(cacheControlDirectives['private'], 'authorization')
|
|
400
570
|
) {
|
|
401
571
|
return false
|
|
402
572
|
}
|
|
@@ -405,14 +575,51 @@ function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirect
|
|
|
405
575
|
return true
|
|
406
576
|
}
|
|
407
577
|
|
|
578
|
+
/**
|
|
579
|
+
* @param {string | string[]} dateHeader
|
|
580
|
+
* @returns {Date | null | undefined}
|
|
581
|
+
*/
|
|
582
|
+
function getDate (dateHeader) {
|
|
583
|
+
let dateValue = dateHeader
|
|
584
|
+
if (Array.isArray(dateValue)) {
|
|
585
|
+
if (dateValue.length !== 1) {
|
|
586
|
+
return null
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
dateValue = dateValue[0]
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (typeof dateValue !== 'string') {
|
|
593
|
+
return null
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
return parseHttpDate(dateValue)
|
|
597
|
+
}
|
|
598
|
+
|
|
408
599
|
/**
|
|
409
600
|
* @param {string | string[]} ageHeader
|
|
410
601
|
* @returns {number | undefined}
|
|
411
602
|
*/
|
|
412
603
|
function getAge (ageHeader) {
|
|
413
|
-
|
|
604
|
+
let ageValue = ageHeader
|
|
605
|
+
if (Array.isArray(ageValue)) {
|
|
606
|
+
if (ageValue.length !== 1) {
|
|
607
|
+
return MAX_RESPONSE_AGE
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
ageValue = ageValue[0]
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (typeof ageValue !== 'string' || !/^[\t ]*[0-9]+[\t ]*$/.test(ageValue)) {
|
|
614
|
+
return MAX_RESPONSE_AGE
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const age = BigInt(ageValue.replace(/^[\t ]+|[\t ]+$/g, ''))
|
|
618
|
+
if (age >= BigInt(MAX_RESPONSE_AGE / 1000)) {
|
|
619
|
+
return MAX_RESPONSE_AGE
|
|
620
|
+
}
|
|
414
621
|
|
|
415
|
-
return
|
|
622
|
+
return Number(age) * 1000
|
|
416
623
|
}
|
|
417
624
|
|
|
418
625
|
/**
|
|
@@ -422,51 +629,80 @@ function getAge (ageHeader) {
|
|
|
422
629
|
* @param {import('../../types/header.d.ts').IncomingHttpHeaders} resHeaders
|
|
423
630
|
* @param {Date | undefined} responseDate
|
|
424
631
|
* @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
|
|
632
|
+
* @param {boolean} hasValidator whether the response has a validator (etag or
|
|
633
|
+
* last-modified) that revalidation requests can be made with
|
|
425
634
|
*
|
|
426
635
|
* @returns {number | undefined} time that the value is stale at in seconds or undefined if it shouldn't be cached
|
|
427
636
|
*/
|
|
428
|
-
function determineStaleAt (cacheType, now, age, resHeaders, responseDate, cacheControlDirectives) {
|
|
637
|
+
function determineStaleAt (cacheType, now, age, resHeaders, responseDate, cacheControlDirectives, hasValidator) {
|
|
429
638
|
if (cacheType === 'shared') {
|
|
430
639
|
// Prioritize s-maxage since we're a shared cache
|
|
431
640
|
// s-maxage > max-age > Expire
|
|
432
641
|
// https://www.rfc-editor.org/rfc/rfc9111.html#section-5.2.2.10-3
|
|
642
|
+
if (hasInvalidCacheControlDirective(cacheControlDirectives, 's-maxage')) {
|
|
643
|
+
return 0
|
|
644
|
+
}
|
|
645
|
+
|
|
433
646
|
const sMaxAge = cacheControlDirectives['s-maxage']
|
|
434
647
|
if (sMaxAge !== undefined) {
|
|
435
|
-
|
|
648
|
+
if (sMaxAge > 0) {
|
|
649
|
+
return sMaxAge * 1000
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Immediately stale, but storable if we can revalidate it before reuse.
|
|
653
|
+
return 0
|
|
436
654
|
}
|
|
437
655
|
}
|
|
438
656
|
|
|
657
|
+
if (hasInvalidCacheControlDirective(cacheControlDirectives, 'max-age')) {
|
|
658
|
+
return 0
|
|
659
|
+
}
|
|
660
|
+
|
|
439
661
|
const maxAge = cacheControlDirectives['max-age']
|
|
440
662
|
if (maxAge !== undefined) {
|
|
441
|
-
|
|
663
|
+
if (maxAge > 0) {
|
|
664
|
+
return maxAge * 1000
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Immediately stale, but storable if we can revalidate it before reuse.
|
|
668
|
+
return 0
|
|
442
669
|
}
|
|
443
670
|
|
|
444
|
-
if (
|
|
671
|
+
if (Object.hasOwn(resHeaders, 'expires')) {
|
|
445
672
|
// https://www.rfc-editor.org/rfc/rfc9111.html#section-5.3
|
|
673
|
+
if (typeof resHeaders.expires !== 'string') {
|
|
674
|
+
return 0
|
|
675
|
+
}
|
|
676
|
+
|
|
446
677
|
const expiresDate = parseHttpDate(resHeaders.expires)
|
|
447
|
-
if (expiresDate) {
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
}
|
|
678
|
+
if (!expiresDate) {
|
|
679
|
+
return 0
|
|
680
|
+
}
|
|
451
681
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
682
|
+
if (now >= expiresDate.getTime()) {
|
|
683
|
+
return 0
|
|
684
|
+
}
|
|
456
685
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
686
|
+
if (responseDate) {
|
|
687
|
+
if (responseDate >= expiresDate) {
|
|
688
|
+
return 0
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
const freshnessLifetime = expiresDate.getTime() - responseDate.getTime()
|
|
692
|
+
if (age !== undefined && age >= freshnessLifetime) {
|
|
693
|
+
return 0
|
|
460
694
|
}
|
|
461
695
|
|
|
462
|
-
return
|
|
696
|
+
return freshnessLifetime
|
|
463
697
|
}
|
|
698
|
+
|
|
699
|
+
return expiresDate.getTime() - now
|
|
464
700
|
}
|
|
465
701
|
|
|
466
702
|
if (typeof resHeaders['last-modified'] === 'string') {
|
|
467
703
|
// https://www.rfc-editor.org/rfc/rfc9111.html#name-calculating-heuristic-fresh
|
|
468
|
-
const lastModified =
|
|
469
|
-
if (
|
|
704
|
+
const lastModified = parseHttpDate(resHeaders['last-modified'])
|
|
705
|
+
if (lastModified) {
|
|
470
706
|
if (lastModified.getTime() >= now) {
|
|
471
707
|
return undefined
|
|
472
708
|
}
|
|
@@ -482,6 +718,12 @@ function determineStaleAt (cacheType, now, age, resHeaders, responseDate, cacheC
|
|
|
482
718
|
return 31536000000
|
|
483
719
|
}
|
|
484
720
|
|
|
721
|
+
if (cacheControlDirectives['no-cache'] === true && hasValidator) {
|
|
722
|
+
// No freshness source, but a validator lets us revalidate before reuse.
|
|
723
|
+
// https://www.rfc-editor.org/rfc/rfc9111.html#section-5.2.2.4
|
|
724
|
+
return 0
|
|
725
|
+
}
|
|
726
|
+
|
|
485
727
|
return undefined
|
|
486
728
|
}
|
|
487
729
|
|
|
@@ -518,6 +760,11 @@ function determineDeleteAt (baseTime, cachedAt, cacheControlDirectives, staleAt)
|
|
|
518
760
|
// revalidated.
|
|
519
761
|
if (staleWhileRevalidate === -Infinity && staleIfError === -Infinity && immutable === -Infinity) {
|
|
520
762
|
const freshnessLifetime = staleAt - baseTime
|
|
763
|
+
if (freshnessLifetime <= 0) {
|
|
764
|
+
// Revalidation-only entry: no freshness lifetime to size the buffer on,
|
|
765
|
+
// so retain it for a bounded window instead.
|
|
766
|
+
return cachedAt + REVALIDATION_ONLY_RETENTION
|
|
767
|
+
}
|
|
521
768
|
const datePrecisionPadding = Math.min(Math.max(cachedAt - baseTime, 0), 1000)
|
|
522
769
|
return staleAt + freshnessLifetime + datePrecisionPadding
|
|
523
770
|
}
|
|
@@ -546,14 +793,7 @@ function stripNecessaryHeaders (resHeaders, cacheControlDirectives) {
|
|
|
546
793
|
]
|
|
547
794
|
|
|
548
795
|
if (resHeaders['connection']) {
|
|
549
|
-
|
|
550
|
-
// connection: a
|
|
551
|
-
// connection: b
|
|
552
|
-
headersToRemove.push(...resHeaders['connection'].map(header => header.trim()))
|
|
553
|
-
} else {
|
|
554
|
-
// connection: a, b
|
|
555
|
-
headersToRemove.push(...resHeaders['connection'].split(',').map(header => header.trim()))
|
|
556
|
-
}
|
|
796
|
+
appendConnectionHeaderTokens(headersToRemove, resHeaders['connection'])
|
|
557
797
|
}
|
|
558
798
|
|
|
559
799
|
if (Array.isArray(cacheControlDirectives['no-cache'])) {
|
|
@@ -566,7 +806,7 @@ function stripNecessaryHeaders (resHeaders, cacheControlDirectives) {
|
|
|
566
806
|
|
|
567
807
|
let strippedHeaders
|
|
568
808
|
for (const headerName of headersToRemove) {
|
|
569
|
-
if (resHeaders
|
|
809
|
+
if (Object.hasOwn(resHeaders, headerName)) {
|
|
570
810
|
strippedHeaders ??= { ...resHeaders }
|
|
571
811
|
delete strippedHeaders[headerName]
|
|
572
812
|
}
|
|
@@ -575,12 +815,4 @@ function stripNecessaryHeaders (resHeaders, cacheControlDirectives) {
|
|
|
575
815
|
return strippedHeaders ?? resHeaders
|
|
576
816
|
}
|
|
577
817
|
|
|
578
|
-
/**
|
|
579
|
-
* @param {Date} date
|
|
580
|
-
* @returns {boolean}
|
|
581
|
-
*/
|
|
582
|
-
function isValidDate (date) {
|
|
583
|
-
return date instanceof Date && Number.isFinite(date.valueOf())
|
|
584
|
-
}
|
|
585
|
-
|
|
586
818
|
module.exports = CacheHandler
|
|
@@ -19,7 +19,7 @@ class CacheRevalidationHandler {
|
|
|
19
19
|
#successful = false
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* @type {((boolean, any) => void) | null}
|
|
22
|
+
* @type {((success: boolean, context?: any, statusCode?: number, headers?: import('../../types/header.d.ts').IncomingHttpHeaders) => void) | null}
|
|
23
23
|
*/
|
|
24
24
|
#callback
|
|
25
25
|
|
|
@@ -36,7 +36,7 @@ class CacheRevalidationHandler {
|
|
|
36
36
|
#allowErrorStatusCodes
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* @param {(boolean) => void} callback Function to call if the cached value is valid
|
|
39
|
+
* @param {(success: boolean, context?: any, statusCode?: number, headers?: import('../../types/header.d.ts').IncomingHttpHeaders) => void} callback Function to call if the cached value is valid
|
|
40
40
|
* @param {import('../../types/dispatcher.d.ts').default.DispatchHandlers} handler
|
|
41
41
|
* @param {boolean} allowErrorStatusCodes
|
|
42
42
|
*/
|
|
@@ -71,7 +71,7 @@ class CacheRevalidationHandler {
|
|
|
71
71
|
// https://datatracker.ietf.org/doc/html/rfc5861#section-4
|
|
72
72
|
this.#successful = statusCode === 304 ||
|
|
73
73
|
(this.#allowErrorStatusCodes && statusCode >= 500 && statusCode <= 504)
|
|
74
|
-
this.#callback(this.#successful, this.#context)
|
|
74
|
+
this.#callback(this.#successful, this.#context, statusCode, headers)
|
|
75
75
|
this.#callback = null
|
|
76
76
|
|
|
77
77
|
if (this.#successful) {
|
|
@@ -109,6 +109,16 @@ class CacheRevalidationHandler {
|
|
|
109
109
|
}
|
|
110
110
|
|
|
111
111
|
if (this.#callback) {
|
|
112
|
+
// Serve the stale cached response on a connection error, per stale-if-error:
|
|
113
|
+
// RFC 5861 counts an unreachable origin (a would-be 5xx) as an error.
|
|
114
|
+
// https://datatracker.ietf.org/doc/html/rfc5861#section-4
|
|
115
|
+
if (this.#allowErrorStatusCodes) {
|
|
116
|
+
this.#successful = true
|
|
117
|
+
this.#callback(true, this.#context)
|
|
118
|
+
this.#callback = null
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
112
122
|
this.#callback(false)
|
|
113
123
|
this.#callback = null
|
|
114
124
|
}
|
|
@@ -62,5 +62,11 @@ module.exports = class DecoratorHandler {
|
|
|
62
62
|
/**
|
|
63
63
|
* @deprecated
|
|
64
64
|
*/
|
|
65
|
-
onBodySent () {
|
|
65
|
+
onBodySent (...args) {
|
|
66
|
+
return this.#handler.onBodySent?.(...args)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
onRequestSent (...args) {
|
|
70
|
+
return this.#handler.onRequestSent?.(...args)
|
|
71
|
+
}
|
|
66
72
|
}
|
|
@@ -365,12 +365,22 @@ class DeduplicationHandler {
|
|
|
365
365
|
get aborted () { return state.aborted },
|
|
366
366
|
get reason () { return state.reason },
|
|
367
367
|
abort: (reason) => {
|
|
368
|
+
if (state.aborted) {
|
|
369
|
+
return
|
|
370
|
+
}
|
|
371
|
+
|
|
368
372
|
state.aborted = true
|
|
369
373
|
state.reason = reason ?? null
|
|
370
374
|
waitingHandler.done = true
|
|
371
375
|
waitingHandler.pendingTrailers = null
|
|
372
376
|
waitingHandler.bufferedChunks = []
|
|
373
377
|
waitingHandler.bufferedBytes = 0
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
handler.onResponseError?.(waitingHandler.controller, state.reason ?? new RequestAbortedError())
|
|
381
|
+
} catch {
|
|
382
|
+
// Ignore errors from waiting handlers
|
|
383
|
+
}
|
|
374
384
|
}
|
|
375
385
|
}
|
|
376
386
|
|
|
@@ -444,12 +454,8 @@ class DeduplicationHandler {
|
|
|
444
454
|
waitingHandler.bufferedChunks = []
|
|
445
455
|
waitingHandler.bufferedBytes = 0
|
|
446
456
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
waitingHandler.handler.onResponseError?.(waitingHandler.controller, err)
|
|
450
|
-
} catch {
|
|
451
|
-
// Ignore errors from waiting handlers
|
|
452
|
-
}
|
|
457
|
+
// controller.abort(err) notifies the handler via onResponseError
|
|
458
|
+
waitingHandler.controller.abort(err)
|
|
453
459
|
}
|
|
454
460
|
|
|
455
461
|
#pruneDoneWaitingHandlers () {
|