@openclaw/slack 2026.9.8 → 2026.10.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/.setup/{account-inspect-DWBXpER6.mjs → account-inspect-Cs-7DXXW.mjs} +1 -1
  2. package/dist/.setup/{accounts-D_N9IqNA.mjs → accounts-CDgkV7Cm.mjs} +4 -16
  3. package/dist/.setup/{action-runtime-DfWvuiZd.mjs → action-runtime-DJ1daRAZ.mjs} +5 -7
  4. package/dist/.setup/action-runtime.runtime-CdWL2mLC.mjs +2 -0
  5. package/dist/.setup/{actions-Df0CzcDl.mjs → actions-DDoAJnrH.mjs} +16 -35
  6. package/dist/.setup/{approval-handler.runtime-Ed6Sw5VK.mjs → approval-handler.runtime-BcE_shWc.mjs} +5 -5
  7. package/dist/.setup/{approval-message-updates-BadvtA7R.mjs → approval-message-updates-EgKGmFXx.mjs} +1 -1
  8. package/dist/.setup/{channel-C7bgPSTE.mjs → channel-DgKSu8Iv.mjs} +46 -48
  9. package/dist/.setup/{channel-type-ClOttrZ5.mjs → channel-type-B9zYYzBU.mjs} +4 -4
  10. package/dist/.setup/{channel.setup-Dh2jzAjN.mjs → channel.setup-BYIlwbQ7.mjs} +27 -27
  11. package/dist/.setup/{config-schema-BZCxmHKG.mjs → config-schema-BH0K9-Um.mjs} +4 -0
  12. package/dist/.setup/{directory-config-BOUWH3hR.mjs → directory-config-B_by7zrc.mjs} +2 -2
  13. package/dist/.setup/{directory-live-B2O4B_Ho.mjs → directory-live-C48wazJt.mjs} +3 -3
  14. package/dist/.setup/{doctor-contract-CRN1Z_c7.mjs → doctor-contract-Cd4-VzIM.mjs} +28 -28
  15. package/dist/.setup/{message-tool-api-Cu4lwlGy.mjs → message-tool-api-CcjLPN3v.mjs} +2 -2
  16. package/dist/.setup/{monitor-BPVfkumU.mjs → monitor-BuYBDmm7.mjs} +190 -315
  17. package/dist/.setup/{outbound-adapter-Bv48XUjq.mjs → outbound-adapter-BZFkK-mw.mjs} +6 -17
  18. package/dist/.setup/{pipeline.runtime-B1H63Frf.mjs → pipeline.runtime-CIepKmZt.mjs} +241 -247
  19. package/dist/.setup/{policy-D-jfM174.mjs → policy-KKTqEiDv.mjs} +12 -22
  20. package/dist/.setup/{probe-B2Y9qc_z.mjs → probe-BVlJ3dp0.mjs} +4 -7
  21. package/dist/.setup/{relay-source-BpKdjsll.mjs → relay-source-CC3h6M7y.mjs} +2 -2
  22. package/dist/.setup/{replies-BAnUtr2f.mjs → replies-DHbuthIR.mjs} +12 -26
  23. package/dist/.setup/{reply-blocks-SE1kTE3I.mjs → reply-blocks-CKnO4BSG.mjs} +4 -29
  24. package/dist/.setup/{resolve-channels-XXBn8UU_.mjs → resolve-channels-HR0TgArR.mjs} +2 -2
  25. package/dist/.setup/{resolve-users-DW0ngD03.mjs → resolve-users-BNYBhF0q.mjs} +4 -4
  26. package/dist/.setup/rolldown-runtime-B4FMCO8f.mjs +28 -0
  27. package/dist/.setup/{scopes-CasuDvaa.mjs → scopes-DrDbyUH2.mjs} +1 -1
  28. package/dist/.setup/secret-contract-B-Qm6aQQ.mjs +65 -0
  29. package/dist/.setup/{secret-contract-api-Dp6290Vg.mjs → secret-contract-api-DmUVxIRs.mjs} +1 -1
  30. package/dist/.setup/{security-audit-BqDc-6VL.mjs → security-audit-C1nOGzJa.mjs} +1 -1
  31. package/dist/.setup/{send-BOVLQi3n.mjs → send-CgPI3Zj8.mjs} +22 -53
  32. package/dist/.setup/{session-status-DscajIsd.mjs → session-status-D46GHwOV.mjs} +39 -49
  33. package/dist/.setup/{setup-plugin-api-DTtbTKNk.mjs → setup-plugin-api-ZrHs0N4U.mjs} +1 -1
  34. package/dist/.setup/{setup-surface-Dn7QgWRE.mjs → setup-surface-83lxvE2y.mjs} +10 -13
  35. package/dist/.setup/{shared-qau-uDGl.mjs → shared-VtmYNj-v.mjs} +53 -57
  36. package/dist/.setup/{slash-dispatch.runtime--AEzLVBF.mjs → slash-dispatch.runtime-gBj_uaLM.mjs} +1 -1
  37. package/dist/account-inspect-api.js +1 -1
  38. package/dist/api.js +13 -13
  39. package/dist/channel-config-api.js +1 -1
  40. package/dist/channel-plugin-api.js +1 -1
  41. package/dist/control-ui/2f4b1e827be6b68ced2ea0d8b7da8529a4eafbe72be27ee37e1064bdd530ec10/index.js +1 -0
  42. package/dist/directory-contract-api.js +1 -1
  43. package/dist/doctor-contract-api.js +1 -1
  44. package/dist/message-tool-api.js +1 -1
  45. package/dist/runtime-api.js +10 -10
  46. package/dist/secret-contract-api.js +1 -1
  47. package/dist/security-contract-api.js +1 -1
  48. package/dist/setup-entry.js +2 -2
  49. package/dist/setup-plugin-api.js +1 -1
  50. package/node_modules/undici/README.md +10 -1
  51. package/node_modules/undici/docs/docs/api/Agent.md +8 -8
  52. package/node_modules/undici/docs/docs/api/DiagnosticsChannel.md +9 -6
  53. package/node_modules/undici/docs/docs/api/Dispatcher.md +9 -0
  54. package/node_modules/undici/docs/docs/api/Errors.md +25 -0
  55. package/node_modules/undici/docs/docs/api/Fetch.md +10 -0
  56. package/node_modules/undici/docs/docs/api/Interceptors.md +4 -3
  57. package/node_modules/undici/docs/docs/api/Pool.md +5 -6
  58. package/node_modules/undici/docs/docs/index.md +10 -1
  59. package/node_modules/undici/lib/api/readable.js +1 -2
  60. package/node_modules/undici/lib/core/request.js +23 -2
  61. package/node_modules/undici/lib/core/util.js +0 -39
  62. package/node_modules/undici/lib/dispatcher/client-h1.js +11 -4
  63. package/node_modules/undici/lib/dispatcher/client-h2.js +52 -8
  64. package/node_modules/undici/lib/dispatcher/client.js +6 -1
  65. package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +21 -6
  66. package/node_modules/undici/lib/dispatcher/pool-base.js +63 -2
  67. package/node_modules/undici/lib/dispatcher/pool.js +90 -7
  68. package/node_modules/undici/lib/dispatcher/proxy-agent.js +16 -3
  69. package/node_modules/undici/lib/handler/deduplication-handler.js +24 -11
  70. package/node_modules/undici/lib/handler/redirect-handler.js +5 -0
  71. package/node_modules/undici/lib/handler/retry-handler.js +72 -13
  72. package/node_modules/undici/lib/interceptor/cache.js +4 -1
  73. package/node_modules/undici/lib/interceptor/decompress.js +236 -69
  74. package/node_modules/undici/lib/web/cache/cache.js +17 -8
  75. package/node_modules/undici/lib/web/cache/cachestorage.js +11 -5
  76. package/node_modules/undici/lib/web/cookies/index.js +19 -7
  77. package/node_modules/undici/lib/web/cookies/util.js +3 -1
  78. package/node_modules/undici/lib/web/eventsource/eventsource.js +25 -1
  79. package/node_modules/undici/lib/web/fetch/body.js +22 -15
  80. package/node_modules/undici/lib/web/fetch/data-url.js +6 -6
  81. package/node_modules/undici/lib/web/fetch/formdata.js +30 -36
  82. package/node_modules/undici/lib/web/fetch/headers.js +34 -31
  83. package/node_modules/undici/lib/web/fetch/index.js +46 -25
  84. package/node_modules/undici/lib/web/fetch/request.js +74 -79
  85. package/node_modules/undici/lib/web/fetch/response.js +43 -44
  86. package/node_modules/undici/lib/web/fetch/util.js +7 -7
  87. package/node_modules/undici/lib/web/infra/index.js +16 -1
  88. package/node_modules/undici/lib/web/webidl/index.js +2 -14
  89. package/node_modules/undici/lib/web/websocket/connection.js +33 -12
  90. package/node_modules/undici/lib/web/websocket/events.js +43 -26
  91. package/node_modules/undici/lib/web/websocket/receiver.js +2 -0
  92. package/node_modules/undici/lib/web/websocket/stream/websocketerror.js +13 -10
  93. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +19 -4
  94. package/node_modules/undici/lib/web/websocket/websocket.js +44 -41
  95. package/node_modules/undici/package.json +1 -1
  96. package/node_modules/undici/types/diagnostics-channel.d.ts +2 -1
  97. package/node_modules/undici/types/interceptors.d.ts +1 -1
  98. package/node_modules/undici/types/webidl.d.ts +13 -7
  99. package/openclaw.plugin.json +4 -1
  100. package/package.json +14 -6
  101. package/dist/.setup/action-runtime.runtime-Ck4bAWOX.mjs +0 -2
  102. package/dist/.setup/secret-contract-BaZcu6P_.mjs +0 -82
  103. package/dist/.setup/streaming-compat-C5Wut626.mjs +0 -62
@@ -9,8 +9,63 @@ const DecoratorHandler = require('../handler/decorator-handler')
9
9
  /** @typedef {import('node:stream').Transform} Controller */
10
10
  /** @typedef {Transform&import('node:zlib').Zlib} DecompressorStream */
11
11
 
12
+ class DecompressController {
13
+ #onPause
14
+ #onResume
15
+ #onAbort
16
+ #paused = false
17
+
18
+ constructor (onPause, onResume, onAbort) {
19
+ this.#onPause = onPause
20
+ this.#onResume = onResume
21
+ this.#onAbort = onAbort
22
+ this.target = null
23
+ }
24
+
25
+ pause () {
26
+ if (this.#paused) {
27
+ return
28
+ }
29
+
30
+ this.#paused = true
31
+ this.#onPause()
32
+ }
33
+
34
+ resume () {
35
+ if (!this.#paused) {
36
+ return
37
+ }
38
+
39
+ this.#paused = false
40
+ this.#onResume()
41
+ }
42
+
43
+ abort (reason) {
44
+ this.target?.abort(reason)
45
+ this.#onAbort(reason)
46
+ }
47
+
48
+ get paused () { return this.#paused }
49
+ get aborted () { return this.target?.aborted ?? false }
50
+ get reason () { return this.target?.reason ?? null }
51
+ get rawHeaders () { return this.target?.rawHeaders ?? null }
52
+ set rawHeaders (value) {
53
+ if (this.target) {
54
+ this.target.rawHeaders = value
55
+ }
56
+ }
57
+
58
+ get rawTrailers () { return this.target?.rawTrailers ?? null }
59
+ set rawTrailers (value) {
60
+ if (this.target) {
61
+ this.target.rawTrailers = value
62
+ }
63
+ }
64
+ }
65
+
12
66
  /** @type {Record<string, () => DecompressorStream>} */
13
67
  const supportedEncodings = {
68
+ __proto__: null,
14
69
  gzip: createGunzip,
15
70
  'x-gzip': createGunzip,
16
71
  br: createBrotliDecompress,
@@ -21,7 +76,7 @@ const supportedEncodings = {
21
76
  }
22
77
 
23
78
  const defaultSkipStatusCodes = /** @type {const} */ ([204, 304])
24
- const defaultMaxSize = 64 * 1024 * 1024
79
+ const defaultMaxSize = 0
25
80
 
26
81
  /**
27
82
  * Limits the output of one stage in a decompression chain.
@@ -53,7 +108,7 @@ let warningEmitted = /** @type {boolean} */ (false)
53
108
  * @typedef {Object} DecompressHandlerOptions
54
109
  * @property {number[]|Readonly<number[]>} [skipStatusCodes=[204, 304]] - List of status codes to skip decompression for
55
110
  * @property {boolean} [skipErrorResponses] - Whether to skip decompression for error responses (status codes >= 400)
56
- * @property {number} [maxSize=67108864] - Maximum decompressed response size in bytes
111
+ * @property {number} [maxSize=0] - Maximum decompressed response size in bytes. 0 disables the limit
57
112
  */
58
113
 
59
114
  class DecompressHandler extends DecoratorHandler {
@@ -73,16 +128,130 @@ class DecompressHandler extends DecoratorHandler {
73
128
  #terminated = false
74
129
  /** @type {boolean} */
75
130
  #inputEnded = false
131
+ /** @type {boolean} */
132
+ #inputBackpressured = false
133
+ /** @type {boolean} */
134
+ #upstreamPaused = false
135
+ /** @type {boolean} */
136
+ #draining = false
137
+ /** @type {boolean} */
138
+ #drainRequested = false
139
+ /** @type {boolean} */
140
+ #completionPending = false
141
+ /** @type {DecompressorStream | undefined} */
142
+ #finalDecompressor
143
+ /** @type {DecompressController} */
144
+ #controller
76
145
 
77
146
  constructor (handler, { skipStatusCodes = defaultSkipStatusCodes, skipErrorResponses = true, maxSize = defaultMaxSize } = {}) {
78
- if (!Number.isSafeInteger(maxSize) || maxSize < 1) {
79
- throw new InvalidArgumentError('maxSize must be a positive integer')
147
+ if (!Number.isSafeInteger(maxSize) || maxSize < 0) {
148
+ throw new InvalidArgumentError('maxSize must be a non-negative integer')
80
149
  }
81
150
 
82
151
  super(handler)
83
152
  this.#skipStatusCodes = skipStatusCodes
84
153
  this.#skipErrorResponses = skipErrorResponses
85
154
  this.#maxSize = maxSize
155
+ this.#controller = new DecompressController(
156
+ () => this.#onDownstreamPause(),
157
+ () => this.#onDownstreamResume(),
158
+ reason => {
159
+ if (this.#inputEnded && !this.#terminated) {
160
+ this.onResponseError(this.#controller, reason)
161
+ }
162
+ }
163
+ )
164
+ }
165
+
166
+ #onDownstreamPause () {
167
+ this.#pauseUpstream()
168
+ }
169
+
170
+ #onDownstreamResume () {
171
+ const drainWasDeferred = this.#draining
172
+ this.#drainOutput()
173
+ if (!drainWasDeferred) {
174
+ this.#resumeUpstreamIfNeeded()
175
+ this.#finishIfReady()
176
+ }
177
+ }
178
+
179
+ #pauseUpstream () {
180
+ if (!this.#upstreamPaused && !this.#terminated) {
181
+ this.#upstreamPaused = true
182
+ this.#controller.target?.pause()
183
+ }
184
+ }
185
+
186
+ #resumeUpstreamIfNeeded () {
187
+ if (this.#upstreamPaused && !this.#controller.paused && !this.#inputBackpressured) {
188
+ this.#upstreamPaused = false
189
+ if (!this.#inputEnded) {
190
+ this.#controller.target?.resume()
191
+ }
192
+ }
193
+ }
194
+
195
+ #drainOutput () {
196
+ if (this.#terminated || this.#controller.paused || !this.#finalDecompressor) {
197
+ return
198
+ }
199
+
200
+ if (this.#draining) {
201
+ this.#drainRequested = true
202
+ return
203
+ }
204
+
205
+ this.#draining = true
206
+ try {
207
+ do {
208
+ this.#drainRequested = false
209
+ let chunk
210
+ while (!this.#terminated && !this.#controller.paused && (chunk = this.#finalDecompressor.read()) !== null) {
211
+ if (this.#maxSize > 0) {
212
+ const decompressedSize = this.#decompressedSize + chunk.length
213
+ if (decompressedSize > this.#maxSize) {
214
+ this.#fail(new ResponseExceededMaxSizeError(
215
+ `Decompressed response size (${decompressedSize}) exceeded maxSize (${this.#maxSize})`
216
+ ))
217
+ return
218
+ }
219
+
220
+ this.#decompressedSize = decompressedSize
221
+ }
222
+
223
+ const result = super.onResponseData(this.#controller, chunk)
224
+ if (result === false && !this.#controller.paused) {
225
+ this.#controller.pause()
226
+ }
227
+ }
228
+ } while (this.#drainRequested && !this.#terminated && !this.#controller.paused)
229
+ } finally {
230
+ this.#draining = false
231
+ }
232
+
233
+ this.#resumeUpstreamIfNeeded()
234
+ this.#finishIfReady()
235
+ }
236
+
237
+ #finishIfReady () {
238
+ if (this.#terminated || !this.#completionPending || this.#controller.paused || this.#draining) {
239
+ return
240
+ }
241
+
242
+ this.#terminated = true
243
+ this.#cleanupDecompressors()
244
+ super.onResponseEnd(this.#controller, this.#trailers)
245
+ }
246
+
247
+ #onDecompressionEnd () {
248
+ if (this.#terminated) {
249
+ return
250
+ }
251
+
252
+ this.#completionPending = true
253
+ this.#drainOutput()
254
+ this.#finishIfReady()
86
255
  }
87
256
 
88
257
  /**
@@ -138,7 +307,7 @@ class DecompressHandler extends DecoratorHandler {
138
307
  const streams = []
139
308
  for (let i = 0; i < decompressors.length; i++) {
140
309
  streams.push(decompressors[i])
141
- if (i < decompressors.length - 1) {
310
+ if (i < decompressors.length - 1 && this.#maxSize > 0) {
142
311
  streams.push(createMaxSizeLimiter(this.#maxSize))
143
312
  }
144
313
  }
@@ -148,11 +317,10 @@ class DecompressHandler extends DecoratorHandler {
148
317
 
149
318
  /**
150
319
  * Stops decompression and reports an error.
151
- * @param {Controller} controller - The controller to coordinate with
152
320
  * @param {Error} error - The decompression error
153
321
  * @returns {void}
154
322
  */
155
- #fail (controller, error) {
323
+ #fail (error) {
156
324
  if (this.#terminated) {
157
325
  return
158
326
  }
@@ -160,75 +328,41 @@ class DecompressHandler extends DecoratorHandler {
160
328
  if (this.#inputEnded) {
161
329
  // The request is already marked complete once the compressed input ends,
162
330
  // so controller.abort() can no longer propagate decoder flush errors.
163
- this.onResponseError(controller, error)
331
+ this.onResponseError(this.#controller, error)
164
332
  } else {
165
- controller.abort(error)
333
+ this.#controller.abort(error)
166
334
  }
167
335
  }
168
336
 
169
337
  /**
170
- * Sets up event handlers for a decompressor stream using readable events
338
+ * Sets up event handlers for the final decompressor stream.
171
339
  * @param {DecompressorStream} decompressor - The decompressor stream
172
- * @param {Controller} controller - The controller to coordinate with
173
340
  * @returns {void}
174
341
  */
175
- #setupDecompressorEvents (decompressor, controller) {
176
- decompressor.on('readable', () => {
177
- if (this.#terminated) {
178
- return
179
- }
180
-
181
- let chunk
182
- while ((chunk = decompressor.read()) !== null) {
183
- const decompressedSize = this.#decompressedSize + chunk.length
184
- if (decompressedSize > this.#maxSize) {
185
- this.#fail(controller, new ResponseExceededMaxSizeError(
186
- `Decompressed response size (${decompressedSize}) exceeded maxSize (${this.#maxSize})`
187
- ))
188
- return
189
- }
190
-
191
- this.#decompressedSize = decompressedSize
192
- const result = super.onResponseData(controller, chunk)
193
- if (result === false) {
194
- break
195
- }
196
- }
197
- })
198
-
199
- decompressor.on('error', (error) => {
200
- this.#fail(controller, error)
201
- })
342
+ #setupDecompressorEvents (decompressor) {
343
+ this.#finalDecompressor = decompressor
344
+ decompressor.on('readable', () => this.#drainOutput())
345
+ decompressor.on('error', (error) => this.#fail(error))
202
346
  }
203
347
 
204
348
  /**
205
349
  * Sets up event handling for a single decompressor
206
- * @param {Controller} controller - The controller to handle events
207
350
  * @returns {void}
208
351
  */
209
- #setupSingleDecompressor (controller) {
352
+ #setupSingleDecompressor () {
210
353
  const decompressor = this.#decompressors[0]
211
- this.#setupDecompressorEvents(decompressor, controller)
354
+ this.#setupDecompressorEvents(decompressor)
212
355
 
213
- decompressor.on('end', () => {
214
- if (this.#terminated) {
215
- return
216
- }
217
-
218
- this.#terminated = true
219
- this.#cleanupDecompressors()
220
- super.onResponseEnd(controller, this.#trailers)
221
- })
356
+ decompressor.on('end', () => this.#onDecompressionEnd())
222
357
  }
223
358
 
224
359
  /**
225
360
  * Sets up event handling for multiple chained decompressors using pipeline
226
- * @param {Controller} controller - The controller to handle events
227
361
  * @returns {void}
228
362
  */
229
- #setupMultipleDecompressors (controller) {
363
+ #setupMultipleDecompressors () {
230
364
  const lastDecompressor = this.#decompressors[this.#decompressors.length - 1]
231
- this.#setupDecompressorEvents(lastDecompressor, controller)
365
+ this.#setupDecompressorEvents(lastDecompressor)
232
366
 
233
367
  pipeline(this.#decompressors, (err) => {
234
368
  if (this.#terminated) {
@@ -236,13 +370,26 @@ class DecompressHandler extends DecoratorHandler {
236
370
  }
237
371
 
238
372
  if (err) {
239
- this.#fail(controller, err)
373
+ this.#fail(err)
240
374
  return
241
375
  }
242
376
 
243
- this.#terminated = true
244
- this.#cleanupDecompressors()
245
- super.onResponseEnd(controller, this.#trailers)
377
+ this.#onDecompressionEnd()
378
+ })
379
+ }
380
+
381
+ #setupInputBackpressure () {
382
+ const decompressor = this.#decompressors[0]
383
+ decompressor.on('drain', () => {
384
+ if (this.#terminated) {
385
+ return
386
+ }
387
+
388
+ this.#inputBackpressured = false
389
+ if (!this.#controller.paused) {
390
+ this.#drainOutput()
391
+ this.#resumeUpstreamIfNeeded()
392
+ }
246
393
  })
247
394
  }
248
395
 
@@ -252,6 +399,16 @@ class DecompressHandler extends DecoratorHandler {
252
399
  */
253
400
  #cleanupDecompressors () {
254
401
  this.#decompressors.length = 0
402
+ this.#finalDecompressor = undefined
403
+ }
404
+
405
+ onRequestStart (controller, context) {
406
+ this.#controller.target = controller
407
+ return super.onRequestStart(this.#controller, context)
408
+ }
409
+
410
+ onRequestUpgrade (controller, statusCode, headers, socket) {
411
+ return super.onRequestUpgrade(this.#controller, statusCode, headers, socket)
255
412
  }
256
413
 
257
414
  /**
@@ -262,18 +419,24 @@ class DecompressHandler extends DecoratorHandler {
262
419
  * @returns {void}
263
420
  */
264
421
  onResponseStart (controller, statusCode, headers, statusMessage) {
265
- const contentEncoding = headers['content-encoding']
422
+ // Repeated field lines reach us as an array. RFC 9110 section 5.3 lets a
423
+ // recipient join them with commas, which yields the single-line form the
424
+ // decompression chain already handles.
425
+ const rawContentEncoding = headers['content-encoding']
426
+ const contentEncoding = Array.isArray(rawContentEncoding)
427
+ ? rawContentEncoding.join(',')
428
+ : rawContentEncoding
266
429
 
267
430
  // If content encoding is not supported or status code is in skip list
268
431
  if (this.#shouldSkipDecompression(contentEncoding, statusCode)) {
269
- return super.onResponseStart(controller, statusCode, headers, statusMessage)
432
+ return super.onResponseStart(this.#controller, statusCode, headers, statusMessage)
270
433
  }
271
434
 
272
435
  const decompressors = this.#createDecompressionChain(contentEncoding.toLowerCase())
273
436
 
274
437
  if (decompressors.length === 0) {
275
438
  this.#cleanupDecompressors()
276
- return super.onResponseStart(controller, statusCode, headers, statusMessage)
439
+ return super.onResponseStart(this.#controller, statusCode, headers, statusMessage)
277
440
  }
278
441
 
279
442
  this.#decompressors = decompressors
@@ -281,8 +444,8 @@ class DecompressHandler extends DecoratorHandler {
281
444
  // Remove compression headers since we're decompressing
282
445
  const { 'content-encoding': _, 'content-length': __, ...newHeaders } = headers
283
446
 
284
- if (controller?.rawHeaders) {
285
- const rawHeaders = controller.rawHeaders
447
+ if (this.#controller.rawHeaders) {
448
+ const rawHeaders = this.#controller.rawHeaders
286
449
 
287
450
  if (Array.isArray(rawHeaders)) {
288
451
  const filteredHeaders = []
@@ -308,13 +471,14 @@ class DecompressHandler extends DecoratorHandler {
308
471
  }
309
472
  }
310
473
 
474
+ this.#setupInputBackpressure()
311
475
  if (this.#decompressors.length === 1) {
312
- this.#setupSingleDecompressor(controller)
476
+ this.#setupSingleDecompressor()
313
477
  } else {
314
- this.#setupMultipleDecompressors(controller)
478
+ this.#setupMultipleDecompressors()
315
479
  }
316
480
 
317
- return super.onResponseStart(controller, statusCode, newHeaders, statusMessage)
481
+ return super.onResponseStart(this.#controller, statusCode, newHeaders, statusMessage)
318
482
  }
319
483
 
320
484
  /**
@@ -324,10 +488,13 @@ class DecompressHandler extends DecoratorHandler {
324
488
  */
325
489
  onResponseData (controller, chunk) {
326
490
  if (this.#decompressors.length > 0) {
327
- this.#decompressors[0].write(chunk)
491
+ if (!this.#decompressors[0].write(chunk)) {
492
+ this.#inputBackpressured = true
493
+ this.#pauseUpstream()
494
+ }
328
495
  return
329
496
  }
330
- super.onResponseData(controller, chunk)
497
+ return super.onResponseData(this.#controller, chunk)
331
498
  }
332
499
 
333
500
  /**
@@ -342,7 +509,7 @@ class DecompressHandler extends DecoratorHandler {
342
509
  this.#decompressors[0].end()
343
510
  return
344
511
  }
345
- super.onResponseEnd(controller, trailers)
512
+ return super.onResponseEnd(this.#controller, trailers)
346
513
  }
347
514
 
348
515
  /**
@@ -360,7 +527,7 @@ class DecompressHandler extends DecoratorHandler {
360
527
  decompressor.destroy()
361
528
  }
362
529
  this.#cleanupDecompressors()
363
- super.onResponseError(controller, err)
530
+ super.onResponseError(this.#controller, err)
364
531
  }
365
532
  }
366
533
 
@@ -41,7 +41,7 @@ class Cache {
41
41
  }
42
42
 
43
43
  async match (request, options = {}) {
44
- webidl.brandCheck(this, Cache)
44
+ webidl.brandCheck(this, webidl.is.Cache)
45
45
 
46
46
  const prefix = 'Cache.match'
47
47
  webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -59,7 +59,7 @@ class Cache {
59
59
  }
60
60
 
61
61
  async matchAll (request = undefined, options = {}) {
62
- webidl.brandCheck(this, Cache)
62
+ webidl.brandCheck(this, webidl.is.Cache)
63
63
 
64
64
  const prefix = 'Cache.matchAll'
65
65
  if (request !== undefined) request = webidl.converters.RequestInfo(request)
@@ -69,7 +69,7 @@ class Cache {
69
69
  }
70
70
 
71
71
  async add (request) {
72
- webidl.brandCheck(this, Cache)
72
+ webidl.brandCheck(this, webidl.is.Cache)
73
73
 
74
74
  const prefix = 'Cache.add'
75
75
  webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -87,7 +87,7 @@ class Cache {
87
87
  }
88
88
 
89
89
  async addAll (requests) {
90
- webidl.brandCheck(this, Cache)
90
+ webidl.brandCheck(this, webidl.is.Cache)
91
91
 
92
92
  const prefix = 'Cache.addAll'
93
93
  webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -185,7 +185,10 @@ class Cache {
185
185
  }
186
186
  }
187
187
  },
188
- processResponseEndOfBody (response) {
188
+ // Possible spec bug. If the body is never read, `processResponseEndOfBody` (which is attached to a TransformStream's flush hook)
189
+ // never runs, so this would hang. This hook, on the other hand, always reads the body.
190
+ // https://github.com/nodejs/undici/issues/5615
191
+ processResponseConsumeBody (response) {
189
192
  // 1.
190
193
  if (response.aborted) {
191
194
  responsePromise.reject(new DOMException('aborted', 'AbortError'))
@@ -257,7 +260,7 @@ class Cache {
257
260
  }
258
261
 
259
262
  async put (request, response) {
260
- webidl.brandCheck(this, Cache)
263
+ webidl.brandCheck(this, webidl.is.Cache)
261
264
 
262
265
  const prefix = 'Cache.put'
263
266
  webidl.argumentLengthCheck(arguments, 2, prefix)
@@ -388,7 +391,7 @@ class Cache {
388
391
  }
389
392
 
390
393
  async delete (request, options = {}) {
391
- webidl.brandCheck(this, Cache)
394
+ webidl.brandCheck(this, webidl.is.Cache)
392
395
 
393
396
  const prefix = 'Cache.delete'
394
397
  webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -454,7 +457,7 @@ class Cache {
454
457
  * @returns {Promise<readonly Request[]>}
455
458
  */
456
459
  async keys (request = undefined, options = {}) {
457
- webidl.brandCheck(this, Cache)
460
+ webidl.brandCheck(this, webidl.is.Cache)
458
461
 
459
462
  const prefix = 'Cache.keys'
460
463
 
@@ -804,6 +807,12 @@ class Cache {
804
807
  // 6.
805
808
  return Object.freeze(responseList)
806
809
  }
810
+
811
+ static {
812
+ webidl.is.Cache = (arg) => {
813
+ return arg != null && typeof arg === 'object' && #relevantRequestResponseList in arg
814
+ }
815
+ }
807
816
  }
808
817
 
809
818
  Object.defineProperties(Cache.prototype, {
@@ -21,7 +21,7 @@ class CacheStorage {
21
21
  }
22
22
 
23
23
  async match (request, options = {}) {
24
- webidl.brandCheck(this, CacheStorage)
24
+ webidl.brandCheck(this, webidl.is.CacheStorage)
25
25
  webidl.argumentLengthCheck(arguments, 1, 'CacheStorage.match')
26
26
 
27
27
  request = webidl.converters.RequestInfo(request)
@@ -58,7 +58,7 @@ class CacheStorage {
58
58
  * @returns {Promise<boolean>}
59
59
  */
60
60
  async has (cacheName) {
61
- webidl.brandCheck(this, CacheStorage)
61
+ webidl.brandCheck(this, webidl.is.CacheStorage)
62
62
 
63
63
  const prefix = 'CacheStorage.has'
64
64
  webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -76,7 +76,7 @@ class CacheStorage {
76
76
  * @returns {Promise<Cache>}
77
77
  */
78
78
  async open (cacheName) {
79
- webidl.brandCheck(this, CacheStorage)
79
+ webidl.brandCheck(this, webidl.is.CacheStorage)
80
80
 
81
81
  const prefix = 'CacheStorage.open'
82
82
  webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -110,7 +110,7 @@ class CacheStorage {
110
110
  * @returns {Promise<boolean>}
111
111
  */
112
112
  async delete (cacheName) {
113
- webidl.brandCheck(this, CacheStorage)
113
+ webidl.brandCheck(this, webidl.is.CacheStorage)
114
114
 
115
115
  const prefix = 'CacheStorage.delete'
116
116
  webidl.argumentLengthCheck(arguments, 1, prefix)
@@ -125,7 +125,7 @@ class CacheStorage {
125
125
  * @returns {Promise<string[]>}
126
126
  */
127
127
  async keys () {
128
- webidl.brandCheck(this, CacheStorage)
128
+ webidl.brandCheck(this, webidl.is.CacheStorage)
129
129
 
130
130
  // 2.1
131
131
  const keys = this.#caches.keys()
@@ -133,6 +133,12 @@ class CacheStorage {
133
133
  // 2.2
134
134
  return [...keys]
135
135
  }
136
+
137
+ static {
138
+ webidl.is.CacheStorage = (arg) => {
139
+ return arg != null && typeof arg === 'object' && #caches in arg
140
+ }
141
+ }
136
142
  }
137
143
 
138
144
  Object.defineProperties(CacheStorage.prototype, {
@@ -3,9 +3,19 @@
3
3
  const { parseSetCookie } = require('./parse')
4
4
  const { stringify } = require('./util')
5
5
  const { webidl } = require('../webidl')
6
- const { Headers } = require('../fetch/headers')
7
6
 
8
- const brandChecks = webidl.brandCheckMultiple([Headers, globalThis.Headers].filter(Boolean))
7
+ const globalHeadersBrandCheck = (arg) => webidl.brandCheck(arg, webidl.util.MakeTypeAssertion(globalThis.Headers))
8
+ const undiciHeadersBrandCheck = (arg) => webidl.brandCheck(arg, webidl.is.Headers)
9
+
10
+ function brandCheckHeaders (arg) {
11
+ try {
12
+ undiciHeadersBrandCheck(arg)
13
+ return
14
+ } catch {
15
+ }
16
+
17
+ globalHeadersBrandCheck(arg)
18
+ }
9
19
 
10
20
  /**
11
21
  * @typedef {Object} Cookie
@@ -28,12 +38,14 @@ const brandChecks = webidl.brandCheckMultiple([Headers, globalThis.Headers].filt
28
38
  function getCookies (headers) {
29
39
  webidl.argumentLengthCheck(arguments, 1, 'getCookies')
30
40
 
31
- brandChecks(headers)
41
+ brandCheckHeaders(headers)
32
42
 
33
43
  const cookie = headers.get('cookie')
34
44
 
45
+ // A null prototype keeps a cookie named `__proto__` from hitting the
46
+ // Object.prototype setter, which would silently drop it.
35
47
  /** @type {Record<string, string>} */
36
- const out = {}
48
+ const out = { __proto__: null }
37
49
 
38
50
  if (!cookie) {
39
51
  return out
@@ -55,7 +67,7 @@ function getCookies (headers) {
55
67
  * @returns {void}
56
68
  */
57
69
  function deleteCookie (headers, name, attributes) {
58
- brandChecks(headers)
70
+ brandCheckHeaders(headers)
59
71
 
60
72
  const prefix = 'deleteCookie'
61
73
  webidl.argumentLengthCheck(arguments, 2, prefix)
@@ -80,7 +92,7 @@ function deleteCookie (headers, name, attributes) {
80
92
  function getSetCookies (headers) {
81
93
  webidl.argumentLengthCheck(arguments, 1, 'getSetCookies')
82
94
 
83
- brandChecks(headers)
95
+ brandCheckHeaders(headers)
84
96
 
85
97
  const cookies = headers.getSetCookie()
86
98
 
@@ -109,7 +121,7 @@ function parseCookie (cookie) {
109
121
  function setCookie (headers, cookie) {
110
122
  webidl.argumentLengthCheck(arguments, 2, 'setCookie')
111
123
 
112
- brandChecks(headers)
124
+ brandCheckHeaders(headers)
113
125
 
114
126
  cookie = webidl.converters.Cookie(cookie)
115
127
 
@@ -315,7 +315,9 @@ function stringify (cookie) {
315
315
  out.push(`Path=${cookie.path}`)
316
316
  }
317
317
 
318
- if (cookie.expires && cookie.expires.toString() !== 'Invalid Date') {
318
+ // A numeric 0 is the Unix epoch, not an absent value -- the same reason the
319
+ // Max-Age check above tests the type rather than truthiness.
320
+ if (cookie.expires != null && cookie.expires.toString() !== 'Invalid Date') {
319
321
  out.push(`Expires=${toIMFDate(cookie.expires)}`)
320
322
  }
321
323