undici 7.0.0-alpha.1 → 7.0.0-alpha.10

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 (113) hide show
  1. package/README.md +24 -38
  2. package/docs/docs/api/Agent.md +14 -14
  3. package/docs/docs/api/BalancedPool.md +16 -16
  4. package/docs/docs/api/CacheStore.md +131 -0
  5. package/docs/docs/api/Client.md +12 -12
  6. package/docs/docs/api/Debug.md +1 -1
  7. package/docs/docs/api/Dispatcher.md +98 -193
  8. package/docs/docs/api/EnvHttpProxyAgent.md +12 -12
  9. package/docs/docs/api/MockAgent.md +5 -3
  10. package/docs/docs/api/MockClient.md +5 -5
  11. package/docs/docs/api/MockPool.md +4 -3
  12. package/docs/docs/api/Pool.md +15 -15
  13. package/docs/docs/api/PoolStats.md +1 -1
  14. package/docs/docs/api/ProxyAgent.md +3 -3
  15. package/docs/docs/api/RedirectHandler.md +1 -1
  16. package/docs/docs/api/RetryAgent.md +1 -1
  17. package/docs/docs/api/RetryHandler.md +4 -4
  18. package/docs/docs/api/WebSocket.md +46 -4
  19. package/docs/docs/api/api-lifecycle.md +11 -11
  20. package/docs/docs/best-practices/mocking-request.md +2 -2
  21. package/docs/docs/best-practices/proxy.md +1 -1
  22. package/index.d.ts +1 -1
  23. package/index.js +23 -3
  24. package/lib/api/abort-signal.js +2 -0
  25. package/lib/api/api-pipeline.js +4 -2
  26. package/lib/api/api-request.js +6 -4
  27. package/lib/api/api-stream.js +3 -1
  28. package/lib/api/api-upgrade.js +2 -2
  29. package/lib/api/readable.js +200 -47
  30. package/lib/api/util.js +2 -0
  31. package/lib/cache/memory-cache-store.js +177 -0
  32. package/lib/cache/sqlite-cache-store.js +446 -0
  33. package/lib/core/connect.js +54 -22
  34. package/lib/core/constants.js +35 -10
  35. package/lib/core/diagnostics.js +122 -128
  36. package/lib/core/errors.js +2 -2
  37. package/lib/core/request.js +6 -6
  38. package/lib/core/symbols.js +2 -0
  39. package/lib/core/tree.js +4 -2
  40. package/lib/core/util.js +238 -40
  41. package/lib/dispatcher/client-h1.js +405 -142
  42. package/lib/dispatcher/client-h2.js +212 -109
  43. package/lib/dispatcher/client.js +24 -7
  44. package/lib/dispatcher/dispatcher-base.js +4 -1
  45. package/lib/dispatcher/dispatcher.js +4 -0
  46. package/lib/dispatcher/fixed-queue.js +91 -49
  47. package/lib/dispatcher/pool-base.js +3 -3
  48. package/lib/dispatcher/pool-stats.js +2 -0
  49. package/lib/dispatcher/proxy-agent.js +3 -1
  50. package/lib/handler/cache-handler.js +393 -0
  51. package/lib/handler/cache-revalidation-handler.js +124 -0
  52. package/lib/handler/decorator-handler.js +3 -0
  53. package/lib/handler/redirect-handler.js +45 -59
  54. package/lib/handler/retry-handler.js +68 -109
  55. package/lib/handler/unwrap-handler.js +96 -0
  56. package/lib/handler/wrap-handler.js +98 -0
  57. package/lib/interceptor/cache.js +350 -0
  58. package/lib/interceptor/dns.js +375 -0
  59. package/lib/interceptor/response-error.js +15 -7
  60. package/lib/mock/mock-agent.js +5 -8
  61. package/lib/mock/mock-client.js +7 -2
  62. package/lib/mock/mock-errors.js +3 -1
  63. package/lib/mock/mock-interceptor.js +8 -6
  64. package/lib/mock/mock-pool.js +7 -2
  65. package/lib/mock/mock-symbols.js +2 -1
  66. package/lib/mock/mock-utils.js +33 -5
  67. package/lib/util/cache.js +360 -0
  68. package/lib/util/timers.js +50 -6
  69. package/lib/web/cache/cache.js +25 -21
  70. package/lib/web/cache/cachestorage.js +3 -1
  71. package/lib/web/cookies/index.js +18 -5
  72. package/lib/web/cookies/parse.js +6 -1
  73. package/lib/web/eventsource/eventsource.js +2 -0
  74. package/lib/web/fetch/body.js +43 -39
  75. package/lib/web/fetch/constants.js +45 -29
  76. package/lib/web/fetch/data-url.js +2 -2
  77. package/lib/web/fetch/formdata-parser.js +84 -46
  78. package/lib/web/fetch/formdata.js +42 -20
  79. package/lib/web/fetch/headers.js +119 -85
  80. package/lib/web/fetch/index.js +69 -65
  81. package/lib/web/fetch/request.js +132 -55
  82. package/lib/web/fetch/response.js +81 -36
  83. package/lib/web/fetch/util.js +274 -103
  84. package/lib/web/fetch/webidl.js +54 -18
  85. package/lib/web/websocket/connection.js +92 -15
  86. package/lib/web/websocket/constants.js +69 -9
  87. package/lib/web/websocket/events.js +8 -2
  88. package/lib/web/websocket/receiver.js +20 -26
  89. package/lib/web/websocket/stream/websocketerror.js +83 -0
  90. package/lib/web/websocket/stream/websocketstream.js +485 -0
  91. package/lib/web/websocket/util.js +115 -10
  92. package/lib/web/websocket/websocket.js +47 -170
  93. package/package.json +15 -11
  94. package/types/agent.d.ts +1 -1
  95. package/types/cache-interceptor.d.ts +172 -0
  96. package/types/cookies.d.ts +2 -0
  97. package/types/dispatcher.d.ts +29 -4
  98. package/types/env-http-proxy-agent.d.ts +1 -1
  99. package/types/fetch.d.ts +9 -8
  100. package/types/handlers.d.ts +4 -4
  101. package/types/index.d.ts +3 -1
  102. package/types/interceptors.d.ts +18 -1
  103. package/types/mock-agent.d.ts +4 -1
  104. package/types/mock-client.d.ts +1 -1
  105. package/types/mock-pool.d.ts +1 -1
  106. package/types/proxy-agent.d.ts +1 -1
  107. package/types/readable.d.ts +10 -7
  108. package/types/retry-handler.d.ts +3 -3
  109. package/types/webidl.d.ts +30 -4
  110. package/types/websocket.d.ts +33 -0
  111. package/lib/mock/pluralizer.js +0 -29
  112. package/lib/web/cache/symbols.js +0 -5
  113. package/lib/web/fetch/symbols.js +0 -8
@@ -4,6 +4,7 @@ const { maxNameValuePairSize, maxAttributeValueSize } = require('./constants')
4
4
  const { isCTLExcludingHtab } = require('./util')
5
5
  const { collectASequenceOfCodePointsFast } = require('../fetch/data-url')
6
6
  const assert = require('node:assert')
7
+ const { unescape } = require('node:querystring')
7
8
 
8
9
  /**
9
10
  * @description Parses the field-value attributes of a set-cookie header string.
@@ -76,8 +77,12 @@ function parseSetCookie (header) {
76
77
 
77
78
  // 6. The cookie-name is the name string, and the cookie-value is the
78
79
  // value string.
80
+ // https://datatracker.ietf.org/doc/html/rfc6265
81
+ // To maximize compatibility with user agents, servers that wish to
82
+ // store arbitrary data in a cookie-value SHOULD encode that data, for
83
+ // example, using Base64 [RFC4648].
79
84
  return {
80
- name, value, ...parseUnparsedAttributes(unparsedAttributes)
85
+ name, value: unescape(value), ...parseUnparsedAttributes(unparsedAttributes)
81
86
  }
82
87
  }
83
88
 
@@ -109,6 +109,8 @@ class EventSource extends EventTarget {
109
109
  // 1. Let ev be a new EventSource object.
110
110
  super()
111
111
 
112
+ webidl.util.markAsUncloneable(this)
113
+
112
114
  const prefix = 'EventSource constructor'
113
115
  webidl.argumentLengthCheck(arguments, 1, prefix)
114
116
 
@@ -9,8 +9,7 @@ const {
9
9
  extractMimeType,
10
10
  utf8DecodeBytes
11
11
  } = require('./util')
12
- const { FormData } = require('./formdata')
13
- const { kState } = require('./symbols')
12
+ const { FormData, setFormDataState } = require('./formdata')
14
13
  const { webidl } = require('./webidl')
15
14
  const { Blob } = require('node:buffer')
16
15
  const assert = require('node:assert')
@@ -40,9 +39,9 @@ function extractBody (object, keepalive = false) {
40
39
  let stream = null
41
40
 
42
41
  // 2. If object is a ReadableStream object, then set stream to object.
43
- if (object instanceof ReadableStream) {
42
+ if (webidl.is.ReadableStream(object)) {
44
43
  stream = object
45
- } else if (object instanceof Blob) {
44
+ } else if (webidl.is.Blob(object)) {
46
45
  // 3. Otherwise, if object is a Blob object, set stream to the
47
46
  // result of running object’s get stream.
48
47
  stream = object.stream()
@@ -65,7 +64,7 @@ function extractBody (object, keepalive = false) {
65
64
  }
66
65
 
67
66
  // 5. Assert: stream is a ReadableStream object.
68
- assert(stream instanceof ReadableStream)
67
+ assert(webidl.is.ReadableStream(stream))
69
68
 
70
69
  // 6. Let action be null.
71
70
  let action = null
@@ -87,7 +86,7 @@ function extractBody (object, keepalive = false) {
87
86
 
88
87
  // Set type to `text/plain;charset=UTF-8`.
89
88
  type = 'text/plain;charset=UTF-8'
90
- } else if (object instanceof URLSearchParams) {
89
+ } else if (webidl.is.URLSearchParams(object)) {
91
90
  // URLSearchParams
92
91
 
93
92
  // spec says to run application/x-www-form-urlencoded on body.list
@@ -110,7 +109,7 @@ function extractBody (object, keepalive = false) {
110
109
 
111
110
  // Set source to a copy of the bytes held by object.
112
111
  source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength))
113
- } else if (object instanceof FormData) {
112
+ } else if (webidl.is.FormData(object)) {
114
113
  const boundary = `----formdata-undici-0${`${Math.floor(Math.random() * 1e11)}`.padStart(11, '0')}`
115
114
  const prefix = `--${boundary}\r\nContent-Disposition: form-data`
116
115
 
@@ -152,7 +151,10 @@ function extractBody (object, keepalive = false) {
152
151
  }
153
152
  }
154
153
 
155
- const chunk = textEncoder.encode(`--${boundary}--`)
154
+ // CRLF is appended to the body to function with legacy servers and match other implementations.
155
+ // https://github.com/curl/curl/blob/3434c6b46e682452973972e8313613dfa58cd690/lib/mime.c#L1029-L1030
156
+ // https://github.com/form-data/form-data/issues/63
157
+ const chunk = textEncoder.encode(`--${boundary}--\r\n`)
156
158
  blobParts.push(chunk)
157
159
  length += chunk.byteLength
158
160
  if (hasUnknownSizeValue) {
@@ -176,7 +178,7 @@ function extractBody (object, keepalive = false) {
176
178
  // followed by the multipart/form-data boundary string generated
177
179
  // by the multipart/form-data encoding algorithm.
178
180
  type = `multipart/form-data; boundary=${boundary}`
179
- } else if (object instanceof Blob) {
181
+ } else if (webidl.is.Blob(object)) {
180
182
  // Blob
181
183
 
182
184
  // Set source to object.
@@ -204,7 +206,7 @@ function extractBody (object, keepalive = false) {
204
206
  }
205
207
 
206
208
  stream =
207
- object instanceof ReadableStream ? object : ReadableStreamFrom(object)
209
+ webidl.is.ReadableStream(object) ? object : ReadableStreamFrom(object)
208
210
  }
209
211
 
210
212
  // 11. If source is a byte sequence, then set action to a
@@ -263,7 +265,7 @@ function safelyExtractBody (object, keepalive = false) {
263
265
  // a byte sequence or BodyInit object object, run these steps:
264
266
 
265
267
  // 1. If object is a ReadableStream object, then:
266
- if (object instanceof ReadableStream) {
268
+ if (webidl.is.ReadableStream(object)) {
267
269
  // Assert: object is neither disturbed nor locked.
268
270
  // istanbul ignore next
269
271
  assert(!util.isDisturbed(object), 'The body has already been consumed.')
@@ -304,7 +306,7 @@ function throwIfAborted (state) {
304
306
  }
305
307
  }
306
308
 
307
- function bodyMixinMethods (instance) {
309
+ function bodyMixinMethods (instance, getInternalState) {
308
310
  const methods = {
309
311
  blob () {
310
312
  // The blob() method steps are to return the result of
@@ -313,7 +315,7 @@ function bodyMixinMethods (instance) {
313
315
  // contents are bytes and whose type attribute is this’s
314
316
  // MIME type.
315
317
  return consumeBody(this, (bytes) => {
316
- let mimeType = bodyMimeType(this)
318
+ let mimeType = bodyMimeType(getInternalState(this))
317
319
 
318
320
  if (mimeType === null) {
319
321
  mimeType = ''
@@ -324,7 +326,7 @@ function bodyMixinMethods (instance) {
324
326
  // Return a Blob whose contents are bytes and type attribute
325
327
  // is mimeType.
326
328
  return new Blob([bytes], { type: mimeType })
327
- }, instance)
329
+ }, instance, getInternalState)
328
330
  },
329
331
 
330
332
  arrayBuffer () {
@@ -334,19 +336,19 @@ function bodyMixinMethods (instance) {
334
336
  // whose contents are bytes.
335
337
  return consumeBody(this, (bytes) => {
336
338
  return new Uint8Array(bytes).buffer
337
- }, instance)
339
+ }, instance, getInternalState)
338
340
  },
339
341
 
340
342
  text () {
341
343
  // The text() method steps are to return the result of running
342
344
  // consume body with this and UTF-8 decode.
343
- return consumeBody(this, utf8DecodeBytes, instance)
345
+ return consumeBody(this, utf8DecodeBytes, instance, getInternalState)
344
346
  },
345
347
 
346
348
  json () {
347
349
  // The json() method steps are to return the result of running
348
350
  // consume body with this and parse JSON from bytes.
349
- return consumeBody(this, parseJSONFromBytes, instance)
351
+ return consumeBody(this, parseJSONFromBytes, instance, getInternalState)
350
352
  },
351
353
 
352
354
  formData () {
@@ -354,7 +356,7 @@ function bodyMixinMethods (instance) {
354
356
  // consume body with this and the following step given a byte sequence bytes:
355
357
  return consumeBody(this, (value) => {
356
358
  // 1. Let mimeType be the result of get the MIME type with this.
357
- const mimeType = bodyMimeType(this)
359
+ const mimeType = bodyMimeType(getInternalState(this))
358
360
 
359
361
  // 2. If mimeType is non-null, then switch on mimeType’s essence and run
360
362
  // the corresponding steps:
@@ -362,17 +364,13 @@ function bodyMixinMethods (instance) {
362
364
  switch (mimeType.essence) {
363
365
  case 'multipart/form-data': {
364
366
  // 1. ... [long step]
365
- const parsed = multipartFormDataParser(value, mimeType)
366
-
367
367
  // 2. If that fails for some reason, then throw a TypeError.
368
- if (parsed === 'failure') {
369
- throw new TypeError('Failed to parse body as FormData.')
370
- }
368
+ const parsed = multipartFormDataParser(value, mimeType)
371
369
 
372
370
  // 3. Return a new FormData object, appending each entry,
373
371
  // resulting from the parsing operation, to its entry list.
374
372
  const fd = new FormData()
375
- fd[kState] = parsed
373
+ setFormDataState(fd, parsed)
376
374
 
377
375
  return fd
378
376
  }
@@ -398,7 +396,7 @@ function bodyMixinMethods (instance) {
398
396
  throw new TypeError(
399
397
  'Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".'
400
398
  )
401
- }, instance)
399
+ }, instance, getInternalState)
402
400
  },
403
401
 
404
402
  bytes () {
@@ -407,33 +405,36 @@ function bodyMixinMethods (instance) {
407
405
  // result of creating a Uint8Array from bytes in this’s relevant realm.
408
406
  return consumeBody(this, (bytes) => {
409
407
  return new Uint8Array(bytes)
410
- }, instance)
408
+ }, instance, getInternalState)
411
409
  }
412
410
  }
413
411
 
414
412
  return methods
415
413
  }
416
414
 
417
- function mixinBody (prototype) {
418
- Object.assign(prototype.prototype, bodyMixinMethods(prototype))
415
+ function mixinBody (prototype, getInternalState) {
416
+ Object.assign(prototype.prototype, bodyMixinMethods(prototype, getInternalState))
419
417
  }
420
418
 
421
419
  /**
422
420
  * @see https://fetch.spec.whatwg.org/#concept-body-consume-body
423
- * @param {Response|Request} object
421
+ * @param {any} object internal state
424
422
  * @param {(value: unknown) => unknown} convertBytesToJSValue
425
- * @param {Response|Request} instance
423
+ * @param {any} instance
424
+ * @param {(target: any) => any} getInternalState
426
425
  */
427
- async function consumeBody (object, convertBytesToJSValue, instance) {
426
+ async function consumeBody (object, convertBytesToJSValue, instance, getInternalState) {
428
427
  webidl.brandCheck(object, instance)
429
428
 
429
+ const state = getInternalState(object)
430
+
430
431
  // 1. If object is unusable, then return a promise rejected
431
432
  // with a TypeError.
432
- if (bodyUnusable(object)) {
433
+ if (bodyUnusable(state)) {
433
434
  throw new TypeError('Body is unusable: Body has already been read')
434
435
  }
435
436
 
436
- throwIfAborted(object[kState])
437
+ throwIfAborted(state)
437
438
 
438
439
  // 2. Let promise be a new promise.
439
440
  const promise = createDeferredPromise()
@@ -455,22 +456,25 @@ async function consumeBody (object, convertBytesToJSValue, instance) {
455
456
 
456
457
  // 5. If object’s body is null, then run successSteps with an
457
458
  // empty byte sequence.
458
- if (object[kState].body == null) {
459
+ if (state.body == null) {
459
460
  successSteps(Buffer.allocUnsafe(0))
460
461
  return promise.promise
461
462
  }
462
463
 
463
464
  // 6. Otherwise, fully read object’s body given successSteps,
464
465
  // errorSteps, and object’s relevant global object.
465
- await fullyReadBody(object[kState].body, successSteps, errorSteps)
466
+ fullyReadBody(state.body, successSteps, errorSteps)
466
467
 
467
468
  // 7. Return promise.
468
469
  return promise.promise
469
470
  }
470
471
 
471
- // https://fetch.spec.whatwg.org/#body-unusable
472
+ /**
473
+ * @see https://fetch.spec.whatwg.org/#body-unusable
474
+ * @param {any} object internal state
475
+ */
472
476
  function bodyUnusable (object) {
473
- const body = object[kState].body
477
+ const body = object.body
474
478
 
475
479
  // An object including the Body interface mixin is
476
480
  // said to be unusable if its body is non-null and
@@ -488,14 +492,14 @@ function parseJSONFromBytes (bytes) {
488
492
 
489
493
  /**
490
494
  * @see https://fetch.spec.whatwg.org/#concept-body-mime-type
491
- * @param {import('./response').Response|import('./request').Request} requestOrResponse
495
+ * @param {any} requestOrResponse internal state
492
496
  */
493
497
  function bodyMimeType (requestOrResponse) {
494
498
  // 1. Let headers be null.
495
499
  // 2. If requestOrResponse is a Request object, then set headers to requestOrResponse’s request’s header list.
496
500
  // 3. Otherwise, set headers to requestOrResponse’s response’s header list.
497
501
  /** @type {import('./headers').HeadersList} */
498
- const headers = requestOrResponse[kState].headersList
502
+ const headers = requestOrResponse.headersList
499
503
 
500
504
  // 4. Let mimeType be the result of extracting a MIME type from headers.
501
505
  const mimeType = extractMimeType(headers)
@@ -1,28 +1,30 @@
1
1
  'use strict'
2
2
 
3
- const corsSafeListedMethods = ['GET', 'HEAD', 'POST']
3
+ const corsSafeListedMethods = /** @type {const} */ (['GET', 'HEAD', 'POST'])
4
4
  const corsSafeListedMethodsSet = new Set(corsSafeListedMethods)
5
5
 
6
- const nullBodyStatus = [101, 204, 205, 304]
6
+ const nullBodyStatus = /** @type {const} */ ([101, 204, 205, 304])
7
7
 
8
- const redirectStatus = [301, 302, 303, 307, 308]
8
+ const redirectStatus = /** @type {const} */ ([301, 302, 303, 307, 308])
9
9
  const redirectStatusSet = new Set(redirectStatus)
10
10
 
11
- // https://fetch.spec.whatwg.org/#block-bad-port
12
- const badPorts = [
11
+ /**
12
+ * @see https://fetch.spec.whatwg.org/#block-bad-port
13
+ */
14
+ const badPorts = /** @type {const} */ ([
13
15
  '1', '7', '9', '11', '13', '15', '17', '19', '20', '21', '22', '23', '25', '37', '42', '43', '53', '69', '77', '79',
14
16
  '87', '95', '101', '102', '103', '104', '109', '110', '111', '113', '115', '117', '119', '123', '135', '137',
15
17
  '139', '143', '161', '179', '389', '427', '465', '512', '513', '514', '515', '526', '530', '531', '532',
16
18
  '540', '548', '554', '556', '563', '587', '601', '636', '989', '990', '993', '995', '1719', '1720', '1723',
17
19
  '2049', '3659', '4045', '4190', '5060', '5061', '6000', '6566', '6665', '6666', '6667', '6668', '6669', '6679',
18
20
  '6697', '10080'
19
- ]
20
-
21
+ ])
21
22
  const badPortsSet = new Set(badPorts)
22
23
 
23
- // https://w3c.github.io/webappsec-referrer-policy/#referrer-policies
24
- const referrerPolicy = [
25
- '',
24
+ /**
25
+ * @see https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-header
26
+ */
27
+ const referrerPolicyTokens = /** @type {const} */ ([
26
28
  'no-referrer',
27
29
  'no-referrer-when-downgrade',
28
30
  'same-origin',
@@ -31,29 +33,39 @@ const referrerPolicy = [
31
33
  'origin-when-cross-origin',
32
34
  'strict-origin-when-cross-origin',
33
35
  'unsafe-url'
34
- ]
35
- const referrerPolicySet = new Set(referrerPolicy)
36
+ ])
37
+
38
+ /**
39
+ * @see https://w3c.github.io/webappsec-referrer-policy/#referrer-policies
40
+ */
41
+ const referrerPolicy = /** @type {const} */ ([
42
+ '',
43
+ ...referrerPolicyTokens
44
+ ])
45
+ const referrerPolicyTokensSet = new Set(referrerPolicyTokens)
36
46
 
37
- const requestRedirect = ['follow', 'manual', 'error']
47
+ const requestRedirect = /** @type {const} */ (['follow', 'manual', 'error'])
38
48
 
39
- const safeMethods = ['GET', 'HEAD', 'OPTIONS', 'TRACE']
49
+ const safeMethods = /** @type {const} */ (['GET', 'HEAD', 'OPTIONS', 'TRACE'])
40
50
  const safeMethodsSet = new Set(safeMethods)
41
51
 
42
- const requestMode = ['navigate', 'same-origin', 'no-cors', 'cors']
52
+ const requestMode = /** @type {const} */ (['navigate', 'same-origin', 'no-cors', 'cors'])
43
53
 
44
- const requestCredentials = ['omit', 'same-origin', 'include']
54
+ const requestCredentials = /** @type {const} */ (['omit', 'same-origin', 'include'])
45
55
 
46
- const requestCache = [
56
+ const requestCache = /** @type {const} */ ([
47
57
  'default',
48
58
  'no-store',
49
59
  'reload',
50
60
  'no-cache',
51
61
  'force-cache',
52
62
  'only-if-cached'
53
- ]
63
+ ])
54
64
 
55
- // https://fetch.spec.whatwg.org/#request-body-header-name
56
- const requestBodyHeader = [
65
+ /**
66
+ * @see https://fetch.spec.whatwg.org/#request-body-header-name
67
+ */
68
+ const requestBodyHeader = /** @type {const} */ ([
57
69
  'content-encoding',
58
70
  'content-language',
59
71
  'content-location',
@@ -63,18 +75,22 @@ const requestBodyHeader = [
63
75
  // removed in the Headers implementation. However, undici doesn't
64
76
  // filter out headers, so we add it here.
65
77
  'content-length'
66
- ]
78
+ ])
67
79
 
68
- // https://fetch.spec.whatwg.org/#enumdef-requestduplex
69
- const requestDuplex = [
80
+ /**
81
+ * @see https://fetch.spec.whatwg.org/#enumdef-requestduplex
82
+ */
83
+ const requestDuplex = /** @type {const} */ ([
70
84
  'half'
71
- ]
85
+ ])
72
86
 
73
- // http://fetch.spec.whatwg.org/#forbidden-method
74
- const forbiddenMethods = ['CONNECT', 'TRACE', 'TRACK']
87
+ /**
88
+ * @see http://fetch.spec.whatwg.org/#forbidden-method
89
+ */
90
+ const forbiddenMethods = /** @type {const} */ (['CONNECT', 'TRACE', 'TRACK'])
75
91
  const forbiddenMethodsSet = new Set(forbiddenMethods)
76
92
 
77
- const subresource = [
93
+ const subresource = /** @type {const} */ ([
78
94
  'audio',
79
95
  'audioworklet',
80
96
  'font',
@@ -87,7 +103,7 @@ const subresource = [
87
103
  'video',
88
104
  'xslt',
89
105
  ''
90
- ]
106
+ ])
91
107
  const subresourceSet = new Set(subresource)
92
108
 
93
109
  module.exports = {
@@ -111,5 +127,5 @@ module.exports = {
111
127
  corsSafeListedMethodsSet,
112
128
  safeMethodsSet,
113
129
  forbiddenMethodsSet,
114
- referrerPolicySet
130
+ referrerPolicyTokens: referrerPolicyTokensSet
115
131
  }
@@ -471,9 +471,9 @@ function forgivingBase64 (data) {
471
471
  /**
472
472
  * @param {string} input
473
473
  * @param {{ position: number }} position
474
- * @param {boolean?} extractValue
474
+ * @param {boolean} [extractValue=false]
475
475
  */
476
- function collectAnHTTPQuotedString (input, position, extractValue) {
476
+ function collectAnHTTPQuotedString (input, position, extractValue = false) {
477
477
  // 1. Let positionStart be position.
478
478
  const positionStart = position.position
479
479