undici 7.11.0 → 7.12.0

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/README.md CHANGED
@@ -114,8 +114,10 @@ const response = await fetch('https://api.example.com/data');
114
114
  #### Use Built-in Fetch When:
115
115
  - You want zero dependencies
116
116
  - Building isomorphic code that runs in browsers and Node.js
117
+ - Publishing to npm and want to maximize compatibility with JS runtimes
117
118
  - Simple HTTP requests without advanced configuration
118
- - You're okay with the undici version bundled in your Node.js version
119
+ - You're publishing to npm and you want to maximize compatiblity
120
+ - You don't depend on features from a specific version of undici
119
121
 
120
122
  #### Use Undici Module When:
121
123
  - You need the latest undici features and performance improvements
@@ -209,7 +211,7 @@ The `install()` function adds the following classes to `globalThis`:
209
211
  - `fetch` - The fetch function
210
212
  - `Headers` - HTTP headers management
211
213
  - `Response` - HTTP response representation
212
- - `Request` - HTTP request representation
214
+ - `Request` - HTTP request representation
213
215
  - `FormData` - Form data handling
214
216
  - `WebSocket` - WebSocket client
215
217
  - `CloseEvent`, `ErrorEvent`, `MessageEvent` - WebSocket events
@@ -169,10 +169,11 @@ This message is published after the client has successfully connected to a serve
169
169
  ```js
170
170
  import diagnosticsChannel from 'diagnostics_channel'
171
171
 
172
- diagnosticsChannel.channel('undici:websocket:open').subscribe(({ address, protocol, extensions }) => {
172
+ diagnosticsChannel.channel('undici:websocket:open').subscribe(({ address, protocol, extensions, websocket }) => {
173
173
  console.log(address) // address, family, and port
174
174
  console.log(protocol) // negotiated subprotocols
175
175
  console.log(extensions) // negotiated extensions
176
+ console.log(websocket) // the WebSocket instance
176
177
  })
177
178
  ```
178
179
 
@@ -184,7 +185,7 @@ This message is published after the connection has closed.
184
185
  import diagnosticsChannel from 'diagnostics_channel'
185
186
 
186
187
  diagnosticsChannel.channel('undici:websocket:close').subscribe(({ websocket, code, reason }) => {
187
- console.log(websocket) // the WebSocket object
188
+ console.log(websocket) // the WebSocket instance
188
189
  console.log(code) // the closing status code
189
190
  console.log(reason) // the closing reason
190
191
  })
@@ -209,9 +210,10 @@ This message is published after the client receives a ping frame, if the connect
209
210
  ```js
210
211
  import diagnosticsChannel from 'diagnostics_channel'
211
212
 
212
- diagnosticsChannel.channel('undici:websocket:ping').subscribe(({ payload }) => {
213
+ diagnosticsChannel.channel('undici:websocket:ping').subscribe(({ payload, websocket }) => {
213
214
  // a Buffer or undefined, containing the optional application data of the frame
214
215
  console.log(payload)
216
+ console.log(websocket) // the WebSocket instance
215
217
  })
216
218
  ```
217
219
 
@@ -222,8 +224,9 @@ This message is published after the client receives a pong frame.
222
224
  ```js
223
225
  import diagnosticsChannel from 'diagnostics_channel'
224
226
 
225
- diagnosticsChannel.channel('undici:websocket:pong').subscribe(({ payload }) => {
227
+ diagnosticsChannel.channel('undici:websocket:pong').subscribe(({ payload, websocket }) => {
226
228
  // a Buffer or undefined, containing the optional application data of the frame
227
229
  console.log(payload)
230
+ console.log(websocket) // the WebSocket instance
228
231
  })
229
232
  ```
@@ -1103,8 +1103,8 @@ The `cache` interceptor implements client-side response caching as described in
1103
1103
 
1104
1104
  - `store` - The [`CacheStore`](/docs/docs/api/CacheStore.md) to store and retrieve responses from. Default is [`MemoryCacheStore`](/docs/docs/api/CacheStore.md#memorycachestore).
1105
1105
  - `methods` - The [**safe** HTTP methods](https://www.rfc-editor.org/rfc/rfc9110#section-9.2.1) to cache the response of.
1106
- - `cacheByDefault` - The default expiration time to cache responses by if they don't have an explicit expiration. If this isn't present, responses without explicit expiration will not be cached. Default `undefined`.
1107
- - `type` - The type of cache for Undici to act as. Can be `shared` or `private`. Default `shared`.
1106
+ - `cacheByDefault` - The default expiration time to cache responses by if they don't have an explicit expiration and cannot have an heuristic expiry computed. If this isn't present, responses neither with an explicit expiration nor heuristically cacheable will not be cached. Default `undefined`.
1107
+ - `type` - The [type of cache](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching#types_of_caches) for Undici to act as. Can be `shared` or `private`. Default `shared`. `private` implies privately cacheable responses will be cached and potentially shared with other users of your application.
1108
1108
 
1109
1109
  ## Instance Events
1110
1110
 
@@ -78,6 +78,33 @@ setInterval(() => write(), 5000)
78
78
 
79
79
  ```
80
80
 
81
+ ## ping(websocket, payload)
82
+ Arguments:
83
+
84
+ * **websocket** `WebSocket` - The WebSocket instance to send the ping frame on
85
+ * **payload** `Buffer|undefined` (optional) - Optional payload data to include with the ping frame. Must not exceed 125 bytes.
86
+
87
+ Sends a ping frame to the WebSocket server. The server must respond with a pong frame containing the same payload data. This can be used for keepalive purposes or to verify that the connection is still active.
88
+
89
+ ### Example:
90
+
91
+ ```js
92
+ import { WebSocket, ping } from 'undici'
93
+
94
+ const ws = new WebSocket('wss://echo.websocket.events')
95
+
96
+ ws.addEventListener('open', () => {
97
+ // Send ping with no payload
98
+ ping(ws)
99
+
100
+ // Send ping with payload
101
+ const payload = Buffer.from('hello')
102
+ ping(ws, payload)
103
+ })
104
+ ```
105
+
106
+ **Note**: A ping frame cannot have a payload larger than 125 bytes. The ping will only be sent if the WebSocket connection is in the OPEN state.
107
+
81
108
  ## Read More
82
109
 
83
110
  - [MDN - WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket)
package/index.js CHANGED
@@ -157,10 +157,12 @@ module.exports.parseMIMEType = parseMIMEType
157
157
  module.exports.serializeAMimeType = serializeAMimeType
158
158
 
159
159
  const { CloseEvent, ErrorEvent, MessageEvent } = require('./lib/web/websocket/events')
160
- module.exports.WebSocket = require('./lib/web/websocket/websocket').WebSocket
160
+ const { WebSocket, ping } = require('./lib/web/websocket/websocket')
161
+ module.exports.WebSocket = WebSocket
161
162
  module.exports.CloseEvent = CloseEvent
162
163
  module.exports.ErrorEvent = ErrorEvent
163
164
  module.exports.MessageEvent = MessageEvent
165
+ module.exports.ping = ping
164
166
 
165
167
  module.exports.WebSocketStream = require('./lib/web/websocket/stream/websocketstream').WebSocketStream
166
168
  module.exports.WebSocketError = require('./lib/web/websocket/stream/websocketerror').WebSocketError
@@ -89,9 +89,7 @@ class BodyReadable extends Readable {
89
89
  // promise (i.e micro tick) for installing an 'error' listener will
90
90
  // never get a chance and will always encounter an unhandled exception.
91
91
  if (!this[kUsed]) {
92
- setImmediate(() => {
93
- callback(err)
94
- })
92
+ setImmediate(callback, err)
95
93
  } else {
96
94
  callback(err)
97
95
  }
@@ -42,7 +42,8 @@ class Request {
42
42
  reset,
43
43
  expectContinue,
44
44
  servername,
45
- throwOnError
45
+ throwOnError,
46
+ maxRedirections
46
47
  }, handler) {
47
48
  if (typeof path !== 'string') {
48
49
  throw new InvalidArgumentError('path must be a string')
@@ -86,6 +87,10 @@ class Request {
86
87
  throw new InvalidArgumentError('invalid throwOnError')
87
88
  }
88
89
 
90
+ if (maxRedirections != null && maxRedirections !== 0) {
91
+ throw new InvalidArgumentError('maxRedirections is not supported, use the redirect interceptor')
92
+ }
93
+
89
94
  this.headersTimeout = headersTimeout
90
95
 
91
96
  this.bodyTimeout = bodyTimeout
package/lib/core/tree.js CHANGED
@@ -86,7 +86,7 @@ class TstNode {
86
86
 
87
87
  /**
88
88
  * @param {Uint8Array} key
89
- * @return {TstNode | null}
89
+ * @returns {TstNode | null}
90
90
  */
91
91
  search (key) {
92
92
  const keylength = key.length
@@ -60,12 +60,12 @@ const removeAllListeners = util.removeAllListeners
60
60
 
61
61
  let extractBody
62
62
 
63
- async function lazyllhttp () {
63
+ function lazyllhttp () {
64
64
  const llhttpWasmData = process.env.JEST_WORKER_ID ? require('../llhttp/llhttp-wasm.js') : undefined
65
65
 
66
66
  let mod
67
67
  try {
68
- mod = await WebAssembly.compile(require('../llhttp/llhttp_simd-wasm.js'))
68
+ mod = new WebAssembly.Module(require('../llhttp/llhttp_simd-wasm.js'))
69
69
  } catch (e) {
70
70
  /* istanbul ignore next */
71
71
 
@@ -73,10 +73,10 @@ async function lazyllhttp () {
73
73
  // being enabled, but the occurring of this other error
74
74
  // * https://github.com/emscripten-core/emscripten/issues/11495
75
75
  // got me to remove that check to avoid breaking Node 12.
76
- mod = await WebAssembly.compile(llhttpWasmData || require('../llhttp/llhttp-wasm.js'))
76
+ mod = new WebAssembly.Module(llhttpWasmData || require('../llhttp/llhttp-wasm.js'))
77
77
  }
78
78
 
79
- return await WebAssembly.instantiate(mod, {
79
+ return new WebAssembly.Instance(mod, {
80
80
  env: {
81
81
  /**
82
82
  * @param {number} p
@@ -165,11 +165,6 @@ async function lazyllhttp () {
165
165
  }
166
166
 
167
167
  let llhttpInstance = null
168
- /**
169
- * @type {Promise<WebAssembly.Instance>|null}
170
- */
171
- let llhttpPromise = lazyllhttp()
172
- llhttpPromise.catch()
173
168
 
174
169
  /**
175
170
  * @type {Parser|null}
@@ -732,7 +727,7 @@ class Parser {
732
727
  // We must wait a full event loop cycle to reuse this socket to make sure
733
728
  // that non-spec compliant servers are not closing the connection even if they
734
729
  // said they won't.
735
- setImmediate(() => client[kResume]())
730
+ setImmediate(client[kResume])
736
731
  } else {
737
732
  client[kResume]()
738
733
  }
@@ -769,11 +764,7 @@ async function connectH1 (client, socket) {
769
764
  client[kSocket] = socket
770
765
 
771
766
  if (!llhttpInstance) {
772
- const noop = () => {}
773
- socket.on('error', noop)
774
- llhttpInstance = await llhttpPromise
775
- llhttpPromise = null
776
- socket.off('error', noop)
767
+ llhttpInstance = lazyllhttp()
777
768
  }
778
769
 
779
770
  if (socket.errored) {
@@ -1297,9 +1288,9 @@ function writeStream (abort, body, client, request, socket, contentLength, heade
1297
1288
  .on('error', onFinished)
1298
1289
 
1299
1290
  if (body.errorEmitted ?? body.errored) {
1300
- setImmediate(() => onFinished(body.errored))
1291
+ setImmediate(onFinished, body.errored)
1301
1292
  } else if (body.endEmitted ?? body.readableEnded) {
1302
- setImmediate(() => onFinished(null))
1293
+ setImmediate(onFinished, null)
1303
1294
  }
1304
1295
 
1305
1296
  if (body.closeEmitted ?? body.closed) {
@@ -241,7 +241,10 @@ class CacheHandler {
241
241
  * @param {import('../../types/cache-interceptor.d.ts').default.CacheControlDirectives} cacheControlDirectives
242
242
  */
243
243
  function canCacheResponse (cacheType, statusCode, resHeaders, cacheControlDirectives) {
244
- if (statusCode !== 200 && statusCode !== 307) {
244
+ // Allow caching for status codes 200 and 307 (original behavior)
245
+ // Also allow caching for other status codes that are heuristically cacheable
246
+ // when they have explicit cache directives
247
+ if (statusCode !== 200 && statusCode !== 307 && !HEURISTICALLY_CACHEABLE_STATUS_CODES.includes(statusCode)) {
245
248
  return false
246
249
  }
247
250
 
@@ -42,7 +42,8 @@ class RedirectHandler {
42
42
 
43
43
  this.dispatch = dispatch
44
44
  this.location = null
45
- this.opts = { ...opts, maxRedirections: 0 } // opts must be a copy
45
+ const { maxRedirections: _, ...cleanOpts } = opts
46
+ this.opts = cleanOpts // opts must be a copy, exclude maxRedirections
46
47
  this.maxRedirections = maxRedirections
47
48
  this.handler = handler
48
49
  this.history = []
@@ -138,7 +139,6 @@ class RedirectHandler {
138
139
  this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin)
139
140
  this.opts.path = path
140
141
  this.opts.origin = origin
141
- this.opts.maxRedirections = 0
142
142
  this.opts.query = null
143
143
  }
144
144
 
@@ -301,11 +301,11 @@ module.exports = (opts = {}) => {
301
301
  assertCacheMethods(methods, 'opts.methods')
302
302
 
303
303
  if (typeof cacheByDefault !== 'undefined' && typeof cacheByDefault !== 'number') {
304
- throw new TypeError(`exepcted opts.cacheByDefault to be number or undefined, got ${typeof cacheByDefault}`)
304
+ throw new TypeError(`expected opts.cacheByDefault to be number or undefined, got ${typeof cacheByDefault}`)
305
305
  }
306
306
 
307
307
  if (typeof type !== 'undefined' && type !== 'shared' && type !== 'private') {
308
- throw new TypeError(`exepcted opts.type to be shared, private, or undefined, got ${typeof type}`)
308
+ throw new TypeError(`expected opts.type to be shared, private, or undefined, got ${typeof type}`)
309
309
  }
310
310
 
311
311
  const globalOpts = {
@@ -11,7 +11,7 @@ function createRedirectInterceptor ({ maxRedirections: defaultMaxRedirections }
11
11
  return dispatch(opts, handler)
12
12
  }
13
13
 
14
- const dispatchOpts = { ...rest, maxRedirections: 0 } // Stop sub dispatcher from also redirecting.
14
+ const dispatchOpts = { ...rest } // Stop sub dispatcher from also redirecting.
15
15
  const redirectHandler = new RedirectHandler(dispatch, maxRedirections, dispatchOpts, handler)
16
16
  return dispatch(dispatchOpts, redirectHandler)
17
17
  }
package/lib/util/cache.js CHANGED
@@ -32,7 +32,7 @@ function makeCacheKey (opts) {
32
32
 
33
33
  /**
34
34
  * @param {Record<string, string[] | string>}
35
- * @return {Record<string, string[] | string>}
35
+ * @returns {Record<string, string[] | string>}
36
36
  */
37
37
  function normaliseHeaders (opts) {
38
38
  let headers
@@ -0,0 +1,28 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * @template {*} T
5
+ * @typedef {Object} DeferredPromise
6
+ * @property {Promise<T>} promise
7
+ * @property {(value?: T) => void} resolve
8
+ * @property {(reason?: any) => void} reject
9
+ */
10
+
11
+ /**
12
+ * @template {*} T
13
+ * @returns {DeferredPromise<T>} An object containing a promise and its resolve/reject methods.
14
+ */
15
+ function createDeferredPromise () {
16
+ let res
17
+ let rej
18
+ const promise = new Promise((resolve, reject) => {
19
+ res = resolve
20
+ rej = reject
21
+ })
22
+
23
+ return { promise, resolve: res, reject: rej }
24
+ }
25
+
26
+ module.exports = {
27
+ createDeferredPromise
28
+ }
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const assert = require('node:assert')
4
+
3
5
  const { kConstruct } = require('../../core/symbols')
4
6
  const { urlEquals, getFieldValues } = require('./util')
5
7
  const { kEnumerableProperty, isDisturbed } = require('../../core/util')
@@ -7,8 +9,8 @@ const { webidl } = require('../webidl')
7
9
  const { cloneResponse, fromInnerResponse, getResponseState } = require('../fetch/response')
8
10
  const { Request, fromInnerRequest, getRequestState } = require('../fetch/request')
9
11
  const { fetching } = require('../fetch/index')
10
- const { urlIsHttpHttpsScheme, createDeferredPromise, readAllBytes } = require('../fetch/util')
11
- const assert = require('node:assert')
12
+ const { urlIsHttpHttpsScheme, readAllBytes } = require('../fetch/util')
13
+ const { createDeferredPromise } = require('../../util/promise')
12
14
 
13
15
  /**
14
16
  * @see https://w3c.github.io/ServiceWorker/#dfn-cache-batch-operation
@@ -46,7 +48,7 @@ class Cache {
46
48
  const prefix = 'Cache.match'
47
49
  webidl.argumentLengthCheck(arguments, 1, prefix)
48
50
 
49
- request = webidl.converters.RequestInfo(request, prefix, 'request')
51
+ request = webidl.converters.RequestInfo(request)
50
52
  options = webidl.converters.CacheQueryOptions(options, prefix, 'options')
51
53
 
52
54
  const p = this.#internalMatchAll(request, options, 1)
@@ -62,7 +64,7 @@ class Cache {
62
64
  webidl.brandCheck(this, Cache)
63
65
 
64
66
  const prefix = 'Cache.matchAll'
65
- if (request !== undefined) request = webidl.converters.RequestInfo(request, prefix, 'request')
67
+ if (request !== undefined) request = webidl.converters.RequestInfo(request)
66
68
  options = webidl.converters.CacheQueryOptions(options, prefix, 'options')
67
69
 
68
70
  return this.#internalMatchAll(request, options)
@@ -74,7 +76,7 @@ class Cache {
74
76
  const prefix = 'Cache.add'
75
77
  webidl.argumentLengthCheck(arguments, 1, prefix)
76
78
 
77
- request = webidl.converters.RequestInfo(request, prefix, 'request')
79
+ request = webidl.converters.RequestInfo(request)
78
80
 
79
81
  // 1.
80
82
  const requests = [request]
@@ -262,7 +264,7 @@ class Cache {
262
264
  const prefix = 'Cache.put'
263
265
  webidl.argumentLengthCheck(arguments, 2, prefix)
264
266
 
265
- request = webidl.converters.RequestInfo(request, prefix, 'request')
267
+ request = webidl.converters.RequestInfo(request)
266
268
  response = webidl.converters.Response(response, prefix, 'response')
267
269
 
268
270
  // 1.
@@ -393,7 +395,7 @@ class Cache {
393
395
  const prefix = 'Cache.delete'
394
396
  webidl.argumentLengthCheck(arguments, 1, prefix)
395
397
 
396
- request = webidl.converters.RequestInfo(request, prefix, 'request')
398
+ request = webidl.converters.RequestInfo(request)
397
399
  options = webidl.converters.CacheQueryOptions(options, prefix, 'options')
398
400
 
399
401
  /**
@@ -458,7 +460,7 @@ class Cache {
458
460
 
459
461
  const prefix = 'Cache.keys'
460
462
 
461
- if (request !== undefined) request = webidl.converters.RequestInfo(request, prefix, 'request')
463
+ if (request !== undefined) request = webidl.converters.RequestInfo(request)
462
464
  options = webidl.converters.CacheQueryOptions(options, prefix, 'options')
463
465
 
464
466
  // 1.
@@ -4,7 +4,6 @@ const util = require('../../core/util')
4
4
  const {
5
5
  ReadableStreamFrom,
6
6
  readableStreamClose,
7
- createDeferredPromise,
8
7
  fullyReadBody,
9
8
  extractMimeType,
10
9
  utf8DecodeBytes
@@ -17,6 +16,8 @@ const { isErrored, isDisturbed } = require('node:stream')
17
16
  const { isArrayBuffer } = require('node:util/types')
18
17
  const { serializeAMimeType } = require('./data-url')
19
18
  const { multipartFormDataParser } = require('./formdata-parser')
19
+ const { createDeferredPromise } = require('../../util/promise')
20
+
20
21
  let random
21
22
 
22
23
  try {
@@ -29,19 +30,22 @@ try {
29
30
  const textEncoder = new TextEncoder()
30
31
  function noop () {}
31
32
 
32
- const hasFinalizationRegistry = globalThis.FinalizationRegistry
33
- let streamRegistry
34
-
35
- if (hasFinalizationRegistry) {
36
- streamRegistry = new FinalizationRegistry((weakRef) => {
37
- const stream = weakRef.deref()
38
- if (stream && !stream.locked && !isDisturbed(stream) && !isErrored(stream)) {
39
- stream.cancel('Response object has been garbage collected').catch(noop)
40
- }
41
- })
42
- }
33
+ const streamRegistry = new FinalizationRegistry((weakRef) => {
34
+ const stream = weakRef.deref()
35
+ if (stream && !stream.locked && !isDisturbed(stream) && !isErrored(stream)) {
36
+ stream.cancel('Response object has been garbage collected').catch(noop)
37
+ }
38
+ })
43
39
 
44
- // https://fetch.spec.whatwg.org/#concept-bodyinit-extract
40
+ /**
41
+ * Extract a body with type from a byte sequence or BodyInit object
42
+ *
43
+ * @param {import('../../../types').BodyInit} object - The BodyInit object to extract from
44
+ * @param {boolean} [keepalive=false] - If true, indicates that the body
45
+ * @returns {[{stream: ReadableStream, source: any, length: number | null}, string | null]} - Returns a tuple containing the body and its type
46
+ *
47
+ * @see https://fetch.spec.whatwg.org/#concept-bodyinit-extract
48
+ */
45
49
  function extractBody (object, keepalive = false) {
46
50
  // 1. Let stream be null.
47
51
  let stream = null
@@ -267,7 +271,22 @@ function extractBody (object, keepalive = false) {
267
271
  return [body, type]
268
272
  }
269
273
 
270
- // https://fetch.spec.whatwg.org/#bodyinit-safely-extract
274
+ /**
275
+ * @typedef {object} ExtractBodyResult
276
+ * @property {ReadableStream<Uint8Array<ArrayBuffer>>} stream - The ReadableStream containing the body data
277
+ * @property {any} source - The original source of the body data
278
+ * @property {number | null} length - The length of the body data, or null
279
+ */
280
+
281
+ /**
282
+ * Safely extract a body with type from a byte sequence or BodyInit object.
283
+ *
284
+ * @param {import('../../../types').BodyInit} object - The BodyInit object to extract from
285
+ * @param {boolean} [keepalive=false] - If true, indicates that the body
286
+ * @returns {[ExtractBodyResult, string | null]} - Returns a tuple containing the body and its type
287
+ *
288
+ * @see https://fetch.spec.whatwg.org/#bodyinit-safely-extract
289
+ */
271
290
  function safelyExtractBody (object, keepalive = false) {
272
291
  // To safely extract a body and a `Content-Type` value from
273
292
  // a byte sequence or BodyInit object object, run these steps:
@@ -275,9 +294,7 @@ function safelyExtractBody (object, keepalive = false) {
275
294
  // 1. If object is a ReadableStream object, then:
276
295
  if (webidl.is.ReadableStream(object)) {
277
296
  // Assert: object is neither disturbed nor locked.
278
- // istanbul ignore next
279
297
  assert(!util.isDisturbed(object), 'The body has already been consumed.')
280
- // istanbul ignore next
281
298
  assert(!object.locked, 'The stream is locked.')
282
299
  }
283
300
 
@@ -285,17 +302,13 @@ function safelyExtractBody (object, keepalive = false) {
285
302
  return extractBody(object, keepalive)
286
303
  }
287
304
 
288
- function cloneBody (instance, body) {
305
+ function cloneBody (body) {
289
306
  // To clone a body body, run these steps:
290
307
 
291
308
  // https://fetch.spec.whatwg.org/#concept-body-clone
292
309
 
293
310
  // 1. Let « out1, out2 » be the result of teeing body’s stream.
294
- const [out1, out2] = body.stream.tee()
295
-
296
- if (hasFinalizationRegistry) {
297
- streamRegistry.register(instance, new WeakRef(out1))
298
- }
311
+ const { 0: out1, 1: out2 } = body.stream.tee()
299
312
 
300
313
  // 2. Set body’s stream to out1.
301
314
  body.stream = out1
@@ -527,6 +540,5 @@ module.exports = {
527
540
  cloneBody,
528
541
  mixinBody,
529
542
  streamRegistry,
530
- hasFinalizationRegistry,
531
543
  bodyUnusable
532
544
  }