undici 7.0.0-alpha.2 → 7.0.0-alpha.4

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 (56) hide show
  1. package/README.md +3 -2
  2. package/docs/docs/api/BalancedPool.md +1 -1
  3. package/docs/docs/api/CacheStore.md +100 -0
  4. package/docs/docs/api/Dispatcher.md +32 -2
  5. package/docs/docs/api/MockClient.md +1 -1
  6. package/docs/docs/api/Pool.md +1 -1
  7. package/docs/docs/api/api-lifecycle.md +2 -2
  8. package/docs/docs/best-practices/mocking-request.md +2 -2
  9. package/docs/docs/best-practices/proxy.md +1 -1
  10. package/index.d.ts +1 -1
  11. package/index.js +8 -2
  12. package/lib/api/api-request.js +2 -2
  13. package/lib/api/readable.js +6 -6
  14. package/lib/cache/memory-cache-store.js +325 -0
  15. package/lib/core/connect.js +5 -0
  16. package/lib/core/constants.js +24 -1
  17. package/lib/core/request.js +2 -2
  18. package/lib/core/util.js +13 -1
  19. package/lib/dispatcher/client-h1.js +100 -87
  20. package/lib/dispatcher/client-h2.js +168 -96
  21. package/lib/dispatcher/pool-base.js +3 -3
  22. package/lib/handler/cache-handler.js +389 -0
  23. package/lib/handler/cache-revalidation-handler.js +151 -0
  24. package/lib/handler/redirect-handler.js +5 -3
  25. package/lib/handler/retry-handler.js +3 -3
  26. package/lib/interceptor/cache.js +192 -0
  27. package/lib/interceptor/dns.js +71 -48
  28. package/lib/util/cache.js +249 -0
  29. package/lib/web/cache/cache.js +1 -0
  30. package/lib/web/cache/cachestorage.js +2 -0
  31. package/lib/web/cookies/index.js +12 -1
  32. package/lib/web/cookies/parse.js +6 -1
  33. package/lib/web/eventsource/eventsource.js +2 -0
  34. package/lib/web/fetch/body.js +1 -5
  35. package/lib/web/fetch/constants.js +12 -5
  36. package/lib/web/fetch/data-url.js +2 -2
  37. package/lib/web/fetch/formdata-parser.js +70 -43
  38. package/lib/web/fetch/formdata.js +3 -1
  39. package/lib/web/fetch/headers.js +3 -1
  40. package/lib/web/fetch/index.js +4 -6
  41. package/lib/web/fetch/request.js +3 -1
  42. package/lib/web/fetch/response.js +3 -1
  43. package/lib/web/fetch/util.js +171 -47
  44. package/lib/web/fetch/webidl.js +28 -16
  45. package/lib/web/websocket/constants.js +67 -6
  46. package/lib/web/websocket/events.js +4 -0
  47. package/lib/web/websocket/stream/websocketerror.js +1 -1
  48. package/lib/web/websocket/websocket.js +2 -0
  49. package/package.json +8 -5
  50. package/types/cache-interceptor.d.ts +101 -0
  51. package/types/cookies.d.ts +2 -0
  52. package/types/dispatcher.d.ts +1 -1
  53. package/types/fetch.d.ts +9 -8
  54. package/types/index.d.ts +3 -1
  55. package/types/interceptors.d.ts +4 -1
  56. package/types/webidl.d.ts +7 -1
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { Transform } = require('node:stream')
4
4
  const zlib = require('node:zlib')
5
- const { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = require('./constants')
5
+ const { redirectStatusSet, referrerPolicyTokens, badPortsSet } = require('./constants')
6
6
  const { getGlobalOrigin } = require('./global')
7
7
  const { collectASequenceOfCodePoints, collectAnHTTPQuotedString, removeChars, parseMIMEType } = require('./data-url')
8
8
  const { performance } = require('node:perf_hooks')
@@ -170,29 +170,24 @@ function isValidHeaderValue (potentialValue) {
170
170
  ) === false
171
171
  }
172
172
 
173
- // https://w3c.github.io/webappsec-referrer-policy/#set-requests-referrer-policy-on-redirect
174
- function setRequestReferrerPolicyOnRedirect (request, actualResponse) {
175
- // Given a request request and a response actualResponse, this algorithm
176
- // updates request’s referrer policy according to the Referrer-Policy
177
- // header (if any) in actualResponse.
178
-
179
- // 1. Let policy be the result of executing § 8.1 Parse a referrer policy
180
- // from a Referrer-Policy header on actualResponse.
181
-
182
- // 8.1 Parse a referrer policy from a Referrer-Policy header
173
+ /**
174
+ * Parse a referrer policy from a Referrer-Policy header
175
+ * @see https://w3c.github.io/webappsec-referrer-policy/#parse-referrer-policy-from-header
176
+ */
177
+ function parseReferrerPolicy (actualResponse) {
183
178
  // 1. Let policy-tokens be the result of extracting header list values given `Referrer-Policy` and response’s header list.
184
- const { headersList } = actualResponse
179
+ const policyHeader = (actualResponse.headersList.get('referrer-policy', true) ?? '').split(',')
180
+
185
181
  // 2. Let policy be the empty string.
182
+ let policy = ''
183
+
186
184
  // 3. For each token in policy-tokens, if token is a referrer policy and token is not the empty string, then set policy to token.
187
- // 4. Return policy.
188
- const policyHeader = (headersList.get('referrer-policy', true) ?? '').split(',')
189
185
 
190
186
  // Note: As the referrer-policy can contain multiple policies
191
187
  // separated by comma, we need to loop through all of them
192
188
  // and pick the first valid one.
193
189
  // Ref: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy#specify_a_fallback_policy
194
- let policy = ''
195
- if (policyHeader.length > 0) {
190
+ if (policyHeader.length) {
196
191
  // The right-most policy takes precedence.
197
192
  // The left-most policy is the fallback.
198
193
  for (let i = policyHeader.length; i !== 0; i--) {
@@ -204,6 +199,23 @@ function setRequestReferrerPolicyOnRedirect (request, actualResponse) {
204
199
  }
205
200
  }
206
201
 
202
+ // 4. Return policy.
203
+ return policy
204
+ }
205
+
206
+ /**
207
+ * Given a request request and a response actualResponse, this algorithm
208
+ * updates request’s referrer policy according to the Referrer-Policy
209
+ * header (if any) in actualResponse.
210
+ * @see https://w3c.github.io/webappsec-referrer-policy/#set-requests-referrer-policy-on-redirect
211
+ * @param {import('./request').Request} request
212
+ * @param {import('./response').Response} actualResponse
213
+ */
214
+ function setRequestReferrerPolicyOnRedirect (request, actualResponse) {
215
+ // 1. Let policy be the result of executing § 8.1 Parse a referrer policy
216
+ // from a Referrer-Policy header on actualResponse.
217
+ const policy = parseReferrerPolicy(actualResponse)
218
+
207
219
  // 2. If policy is not the empty string, then set request’s referrer policy to policy.
208
220
  if (policy !== '') {
209
221
  request.referrerPolicy = policy
@@ -374,8 +386,16 @@ function clonePolicyContainer (policyContainer) {
374
386
  }
375
387
  }
376
388
 
377
- // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
389
+ /**
390
+ * Determine request’s Referrer
391
+ *
392
+ * @see https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
393
+ */
378
394
  function determineRequestsReferrer (request) {
395
+ // Given a request request, we can determine the correct referrer information
396
+ // to send by examining its referrer policy as detailed in the following
397
+ // steps, which return either no referrer or a URL:
398
+
379
399
  // 1. Let policy be request's referrer policy.
380
400
  const policy = request.referrerPolicy
381
401
 
@@ -387,6 +407,8 @@ function determineRequestsReferrer (request) {
387
407
  let referrerSource = null
388
408
 
389
409
  // 3. Switch on request’s referrer:
410
+
411
+ // "client"
390
412
  if (request.referrer === 'client') {
391
413
  // Note: node isn't a browser and doesn't implement document/iframes,
392
414
  // so we bypass this step and replace it with our own.
@@ -397,8 +419,9 @@ function determineRequestsReferrer (request) {
397
419
  return 'no-referrer'
398
420
  }
399
421
 
400
- // note: we need to clone it as it's mutated
422
+ // Note: we need to clone it as it's mutated
401
423
  referrerSource = new URL(globalOrigin)
424
+ // a URL
402
425
  } else if (webidl.is.URL(request.referrer)) {
403
426
  // Let referrerSource be request’s referrer.
404
427
  referrerSource = request.referrer
@@ -500,18 +523,26 @@ function determineRequestsReferrer (request) {
500
523
  }
501
524
 
502
525
  /**
526
+ * Certain portions of URLs must not be included when sending a URL as the
527
+ * value of a `Referer` header: a URLs fragment, username, and password
528
+ * components must be stripped from the URL before it’s sent out. This
529
+ * algorithm accepts a origin-only flag, which defaults to false. If set to
530
+ * true, the algorithm will additionally remove the URL’s path and query
531
+ * components, leaving only the scheme, host, and port.
532
+ *
503
533
  * @see https://w3c.github.io/webappsec-referrer-policy/#strip-url
504
534
  * @param {URL} url
505
- * @param {boolean} [originOnly]
535
+ * @param {boolean} [originOnly=false]
506
536
  */
507
- function stripURLForReferrer (url, originOnly) {
537
+ function stripURLForReferrer (url, originOnly = false) {
508
538
  // 1. Assert: url is a URL.
509
539
  assert(webidl.is.URL(url))
510
540
 
541
+ // Note: Create a new URL instance to avoid mutating the original URL.
511
542
  url = new URL(url)
512
543
 
513
544
  // 2. If url’s scheme is a local scheme, then return no referrer.
514
- if (url.protocol === 'file:' || url.protocol === 'about:' || url.protocol === 'blank:') {
545
+ if (urlIsLocal(url)) {
515
546
  return 'no-referrer'
516
547
  }
517
548
 
@@ -525,7 +556,7 @@ function stripURLForReferrer (url, originOnly) {
525
556
  url.hash = ''
526
557
 
527
558
  // 6. If the origin-only flag is true, then:
528
- if (originOnly) {
559
+ if (originOnly === true) {
529
560
  // 1. Set url’s path to « the empty string ».
530
561
  url.pathname = ''
531
562
 
@@ -537,45 +568,134 @@ function stripURLForReferrer (url, originOnly) {
537
568
  return url
538
569
  }
539
570
 
540
- function isURLPotentiallyTrustworthy (url) {
541
- if (!webidl.is.URL(url)) {
571
+ const potentialleTrustworthyIPv4RegExp = new RegExp('^(?:' +
572
+ '(?:127\\.)' +
573
+ '(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){2}' +
574
+ '(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[1-9])' +
575
+ ')$')
576
+
577
+ const potentialleTrustworthyIPv6RegExp = new RegExp('^(?:' +
578
+ '(?:(?:0{1,4}):){7}(?:(?:0{0,3}1))|' +
579
+ '(?:(?:0{1,4}):){1,6}(?::(?:0{0,3}1))|' +
580
+ '(?:::(?:0{0,3}1))|' +
581
+ ')$')
582
+
583
+ /**
584
+ * Check if host matches one of the CIDR notations 127.0.0.0/8 or ::1/128.
585
+ *
586
+ * @param {string} origin
587
+ * @returns {boolean}
588
+ */
589
+ function isOriginIPPotentiallyTrustworthy (origin) {
590
+ // IPv6
591
+ if (origin.includes(':')) {
592
+ // Remove brackets from IPv6 addresses
593
+ if (origin[0] === '[' && origin[origin.length - 1] === ']') {
594
+ origin = origin.slice(1, -1)
595
+ }
596
+ return potentialleTrustworthyIPv6RegExp.test(origin)
597
+ }
598
+
599
+ // IPv4
600
+ return potentialleTrustworthyIPv4RegExp.test(origin)
601
+ }
602
+
603
+ /**
604
+ * A potentially trustworthy origin is one which a user agent can generally
605
+ * trust as delivering data securely.
606
+ *
607
+ * Return value `true` means `Potentially Trustworthy`.
608
+ * Return value `false` means `Not Trustworthy`.
609
+ *
610
+ * @see https://w3c.github.io/webappsec-secure-contexts/#is-origin-trustworthy
611
+ * @param {string} origin
612
+ * @returns {boolean}
613
+ */
614
+ function isOriginPotentiallyTrustworthy (origin) {
615
+ // 1. If origin is an opaque origin, return "Not Trustworthy".
616
+ if (origin == null || origin === 'null') {
542
617
  return false
543
618
  }
544
619
 
545
- // If child of about, return true
546
- if (url.href === 'about:blank' || url.href === 'about:srcdoc') {
620
+ // 2. Assert: origin is a tuple origin.
621
+ origin = new URL(origin)
622
+
623
+ // 3. If origin’s scheme is either "https" or "wss",
624
+ // return "Potentially Trustworthy".
625
+ if (origin.protocol === 'https:' || origin.protocol === 'wss:') {
547
626
  return true
548
627
  }
549
628
 
550
- // If scheme is data, return true
551
- if (url.protocol === 'data:') return true
629
+ // 4. If origin’s host matches one of the CIDR notations 127.0.0.0/8 or
630
+ // ::1/128 [RFC4632], return "Potentially Trustworthy".
631
+ if (isOriginIPPotentiallyTrustworthy(origin.hostname)) {
632
+ return true
633
+ }
552
634
 
553
- // If file, return true
554
- if (url.protocol === 'file:') return true
635
+ // 5. If the user agent conforms to the name resolution rules in
636
+ // [let-localhost-be-localhost] and one of the following is true:
555
637
 
556
- return isOriginPotentiallyTrustworthy(url.origin)
638
+ // origin’s host is "localhost" or "localhost."
639
+ if (origin.hostname === 'localhost' || origin.hostname === 'localhost.') {
640
+ return true
641
+ }
557
642
 
558
- function isOriginPotentiallyTrustworthy (origin) {
559
- // If origin is explicitly null, return false
560
- if (origin == null || origin === 'null') return false
643
+ // origin’s host ends with ".localhost" or ".localhost."
644
+ if (origin.hostname.endsWith('.localhost') || origin.hostname.endsWith('.localhost.')) {
645
+ return true
646
+ }
561
647
 
562
- const originAsURL = new URL(origin)
648
+ // 6. If origin’s scheme is "file", return "Potentially Trustworthy".
649
+ if (origin.protocol === 'file:') {
650
+ return true
651
+ }
563
652
 
564
- // If secure, return true
565
- if (originAsURL.protocol === 'https:' || originAsURL.protocol === 'wss:') {
566
- return true
567
- }
653
+ // 7. If origin’s scheme component is one which the user agent considers to
654
+ // be authenticated, return "Potentially Trustworthy".
568
655
 
569
- // If localhost or variants, return true
570
- if (/^127(?:\.[0-9]+){0,2}\.[0-9]+$|^\[(?:0*:)*?:?0*1\]$/.test(originAsURL.hostname) ||
571
- (originAsURL.hostname === 'localhost' || originAsURL.hostname.includes('localhost.')) ||
572
- (originAsURL.hostname.endsWith('.localhost'))) {
573
- return true
574
- }
656
+ // 8. If origin has been configured as a trustworthy origin, return
657
+ // "Potentially Trustworthy".
575
658
 
576
- // If any other, return false
659
+ // 9. Return "Not Trustworthy".
660
+ return false
661
+ }
662
+
663
+ /**
664
+ * A potentially trustworthy URL is one which either inherits context from its
665
+ * creator (about:blank, about:srcdoc, data) or one whose origin is a
666
+ * potentially trustworthy origin.
667
+ *
668
+ * Return value `true` means `Potentially Trustworthy`.
669
+ * Return value `false` means `Not Trustworthy`.
670
+ *
671
+ * @see https://www.w3.org/TR/secure-contexts/#is-url-trustworthy
672
+ * @param {URL} url
673
+ * @returns {boolean}
674
+ */
675
+ function isURLPotentiallyTrustworthy (url) {
676
+ // Given a URL record (url), the following algorithm returns "Potentially
677
+ // Trustworthy" or "Not Trustworthy" as appropriate:
678
+ if (!webidl.is.URL(url)) {
577
679
  return false
578
680
  }
681
+
682
+ // 1. If url is "about:blank" or "about:srcdoc",
683
+ // return "Potentially Trustworthy".
684
+ if (url.href === 'about:blank' || url.href === 'about:srcdoc') {
685
+ return true
686
+ }
687
+
688
+ // 2. If url’s scheme is "data", return "Potentially Trustworthy".
689
+ if (url.protocol === 'data:') return true
690
+
691
+ // Note: The origin of blob: URLs is the origin of the context in which they
692
+ // were created. Therefore, blobs created in a trustworthy origin will
693
+ // themselves be potentially trustworthy.
694
+ if (url.protocol === 'blob:') return true
695
+
696
+ // 3. Return the result of executing § 3.1 Is origin potentially trustworthy?
697
+ // on url’s origin.
698
+ return isOriginPotentiallyTrustworthy(url.origin)
579
699
  }
580
700
 
581
701
  /**
@@ -1161,12 +1281,15 @@ async function readAllBytes (reader, successSteps, failureSteps) {
1161
1281
  /**
1162
1282
  * @see https://fetch.spec.whatwg.org/#is-local
1163
1283
  * @param {URL} url
1284
+ * @returns {boolean}
1164
1285
  */
1165
1286
  function urlIsLocal (url) {
1166
1287
  assert('protocol' in url) // ensure it's a url object
1167
1288
 
1168
1289
  const protocol = url.protocol
1169
1290
 
1291
+ // A URL is local if its scheme is a local scheme.
1292
+ // A local scheme is "about", "blob", or "data".
1170
1293
  return protocol === 'about:' || protocol === 'blob:' || protocol === 'data:'
1171
1294
  }
1172
1295
 
@@ -1654,5 +1777,6 @@ module.exports = {
1654
1777
  extractMimeType,
1655
1778
  getDecodeSplit,
1656
1779
  utf8DecodeBytes,
1657
- environmentSettingsObject
1780
+ environmentSettingsObject,
1781
+ isOriginIPPotentiallyTrustworthy
1658
1782
  }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const { types, inspect } = require('node:util')
4
+ const { markAsUncloneable } = require('node:worker_threads')
4
5
  const { toUSVString } = require('../../core/util')
5
6
 
6
7
  const UNDEFINED = 1
@@ -12,6 +13,8 @@ const BIGINT = 6
12
13
  const NULL = 7
13
14
  const OBJECT = 8 // function and object
14
15
 
16
+ const FunctionPrototypeSymbolHasInstance = Function.call.bind(Function.prototype[Symbol.hasInstance])
17
+
15
18
  /** @type {import('../../../types/webidl').Webidl} */
16
19
  const webidl = {
17
20
  converters: {},
@@ -45,7 +48,7 @@ webidl.errors.invalidArgument = function (context) {
45
48
 
46
49
  // https://webidl.spec.whatwg.org/#implements
47
50
  webidl.brandCheck = function (V, I) {
48
- if (!I.prototype.isPrototypeOf(V)) { // eslint-disable-line no-prototype-builtins
51
+ if (!FunctionPrototypeSymbolHasInstance(I, V)) {
49
52
  const err = new TypeError('Illegal invocation')
50
53
  err.code = 'ERR_INVALID_THIS' // node compat.
51
54
  throw err
@@ -53,7 +56,7 @@ webidl.brandCheck = function (V, I) {
53
56
  }
54
57
 
55
58
  webidl.brandCheckMultiple = function (List) {
56
- const prototypes = List.map((c) => webidl.util.MakeTypeAssertion(c.prototype))
59
+ const prototypes = List.map((c) => webidl.util.MakeTypeAssertion(c))
57
60
 
58
61
  return (V) => {
59
62
  if (prototypes.every(typeCheck => !typeCheck(V))) {
@@ -81,9 +84,8 @@ webidl.illegalConstructor = function () {
81
84
  })
82
85
  }
83
86
 
84
- const isPrototypeOf = Object.prototype.isPrototypeOf
85
- webidl.util.MakeTypeAssertion = function (Prototype) {
86
- return (O) => isPrototypeOf.call(Prototype, O)
87
+ webidl.util.MakeTypeAssertion = function (I) {
88
+ return (O) => FunctionPrototypeSymbolHasInstance(I, O)
87
89
  }
88
90
 
89
91
  // https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values
@@ -130,6 +132,8 @@ webidl.util.TypeValueToString = function (o) {
130
132
  }
131
133
  }
132
134
 
135
+ webidl.util.markAsUncloneable = markAsUncloneable || (() => {})
136
+
133
137
  // https://webidl.spec.whatwg.org/#abstract-opdef-converttoint
134
138
  webidl.util.ConvertToInt = function (V, bitLength, signedness, opts) {
135
139
  let upperBound
@@ -341,12 +345,14 @@ webidl.recordConverter = function (keyConverter, valueConverter) {
341
345
  const keys = [...Object.getOwnPropertyNames(O), ...Object.getOwnPropertySymbols(O)]
342
346
 
343
347
  for (const key of keys) {
348
+ const keyName = webidl.util.Stringify(key)
349
+
344
350
  // 1. Let typedKey be key converted to an IDL value of type K.
345
- const typedKey = keyConverter(key, prefix, argument)
351
+ const typedKey = keyConverter(key, prefix, `Key ${keyName} in ${argument}`)
346
352
 
347
353
  // 2. Let value be ? Get(O, key).
348
354
  // 3. Let typedValue be value converted to an IDL value of type V.
349
- const typedValue = valueConverter(O[key], prefix, argument)
355
+ const typedValue = valueConverter(O[key], prefix, `${argument}[${keyName}]`)
350
356
 
351
357
  // 4. Set result[typedKey] to typedValue.
352
358
  result[typedKey] = typedValue
@@ -462,13 +468,13 @@ webidl.nullableConverter = function (converter) {
462
468
  }
463
469
  }
464
470
 
465
- webidl.is.ReadableStream = webidl.util.MakeTypeAssertion(ReadableStream.prototype)
466
- webidl.is.Blob = webidl.util.MakeTypeAssertion(Blob.prototype)
467
- webidl.is.URLSearchParams = webidl.util.MakeTypeAssertion(URLSearchParams.prototype)
468
- webidl.is.File = webidl.util.MakeTypeAssertion((globalThis.File ?? require('node:buffer').File).prototype)
469
- webidl.is.URL = webidl.util.MakeTypeAssertion(URL.prototype)
470
- webidl.is.AbortSignal = webidl.util.MakeTypeAssertion(AbortSignal.prototype)
471
- webidl.is.MessagePort = webidl.util.MakeTypeAssertion(MessagePort.prototype)
471
+ webidl.is.ReadableStream = webidl.util.MakeTypeAssertion(ReadableStream)
472
+ webidl.is.Blob = webidl.util.MakeTypeAssertion(Blob)
473
+ webidl.is.URLSearchParams = webidl.util.MakeTypeAssertion(URLSearchParams)
474
+ webidl.is.File = webidl.util.MakeTypeAssertion(globalThis.File ?? require('node:buffer').File)
475
+ webidl.is.URL = webidl.util.MakeTypeAssertion(URL)
476
+ webidl.is.AbortSignal = webidl.util.MakeTypeAssertion(AbortSignal)
477
+ webidl.is.MessagePort = webidl.util.MakeTypeAssertion(MessagePort)
472
478
 
473
479
  // https://webidl.spec.whatwg.org/#es-DOMString
474
480
  webidl.converters.DOMString = function (V, prefix, argument, opts) {
@@ -497,8 +503,14 @@ webidl.converters.DOMString = function (V, prefix, argument, opts) {
497
503
  // https://webidl.spec.whatwg.org/#es-ByteString
498
504
  webidl.converters.ByteString = function (V, prefix, argument) {
499
505
  // 1. Let x be ? ToString(V).
500
- // Note: DOMString converter perform ? ToString(V)
501
- const x = webidl.converters.DOMString(V, prefix, argument)
506
+ if (typeof V === 'symbol') {
507
+ throw webidl.errors.exception({
508
+ header: prefix,
509
+ message: `${argument} is a symbol, which cannot be converted to a ByteString.`
510
+ })
511
+ }
512
+
513
+ const x = String(V)
502
514
 
503
515
  // 2. If the value of any element of x is greater than
504
516
  // 255, then throw a TypeError.
@@ -1,18 +1,32 @@
1
1
  'use strict'
2
2
 
3
- // This is a Globally Unique Identifier unique used
4
- // to validate that the endpoint accepts websocket
5
- // connections.
6
- // See https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3
3
+ /**
4
+ * This is a Globally Unique Identifier unique used to validate that the
5
+ * endpoint accepts websocket connections.
6
+ * @see https://www.rfc-editor.org/rfc/rfc6455.html#section-1.3
7
+ * @type {'258EAFA5-E914-47DA-95CA-C5AB0DC85B11'}
8
+ */
7
9
  const uid = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
8
10
 
9
- /** @type {PropertyDescriptor} */
11
+ /**
12
+ * @type {PropertyDescriptor}
13
+ */
10
14
  const staticPropertyDescriptors = {
11
15
  enumerable: true,
12
16
  writable: false,
13
17
  configurable: false
14
18
  }
15
19
 
20
+ /**
21
+ * The states of the WebSocket connection.
22
+ *
23
+ * @readonly
24
+ * @enum
25
+ * @property {0} CONNECTING
26
+ * @property {1} OPEN
27
+ * @property {2} CLOSING
28
+ * @property {3} CLOSED
29
+ */
16
30
  const states = {
17
31
  CONNECTING: 0,
18
32
  OPEN: 1,
@@ -20,11 +34,31 @@ const states = {
20
34
  CLOSED: 3
21
35
  }
22
36
 
37
+ /**
38
+ * @readonly
39
+ * @enum
40
+ * @property {0} NOT_SENT
41
+ * @property {1} PROCESSING
42
+ * @property {2} SENT
43
+ */
23
44
  const sentCloseFrameState = {
24
45
  SENT: 1,
25
46
  RECEIVED: 2
26
47
  }
27
48
 
49
+ /**
50
+ * The WebSocket opcodes.
51
+ *
52
+ * @readonly
53
+ * @enum
54
+ * @property {0x0} CONTINUATION
55
+ * @property {0x1} TEXT
56
+ * @property {0x2} BINARY
57
+ * @property {0x8} CLOSE
58
+ * @property {0x9} PING
59
+ * @property {0xA} PONG
60
+ * @see https://datatracker.ietf.org/doc/html/rfc6455#section-5.2
61
+ */
28
62
  const opcodes = {
29
63
  CONTINUATION: 0x0,
30
64
  TEXT: 0x1,
@@ -34,8 +68,23 @@ const opcodes = {
34
68
  PONG: 0xA
35
69
  }
36
70
 
37
- const maxUnsigned16Bit = 2 ** 16 - 1 // 65535
71
+ /**
72
+ * The maximum value for an unsigned 16-bit integer.
73
+ *
74
+ * @type {65535} 2 ** 16 - 1
75
+ */
76
+ const maxUnsigned16Bit = 65535
38
77
 
78
+ /**
79
+ * The states of the parser.
80
+ *
81
+ * @readonly
82
+ * @enum
83
+ * @property {0} INFO
84
+ * @property {2} PAYLOADLENGTH_16
85
+ * @property {3} PAYLOADLENGTH_64
86
+ * @property {4} READ_DATA
87
+ */
39
88
  const parserStates = {
40
89
  INFO: 0,
41
90
  PAYLOADLENGTH_16: 2,
@@ -43,8 +92,20 @@ const parserStates = {
43
92
  READ_DATA: 4
44
93
  }
45
94
 
95
+ /**
96
+ * An empty buffer.
97
+ *
98
+ * @type {Buffer}
99
+ */
46
100
  const emptyBuffer = Buffer.allocUnsafe(0)
47
101
 
102
+ /**
103
+ * @readonly
104
+ * @property {1} text
105
+ * @property {2} typedArray
106
+ * @property {3} arrayBuffer
107
+ * @property {4} blob
108
+ */
48
109
  const sendHints = {
49
110
  text: 1,
50
111
  typedArray: 2,
@@ -13,6 +13,7 @@ class MessageEvent extends Event {
13
13
  constructor (type, eventInitDict = {}) {
14
14
  if (type === kConstruct) {
15
15
  super(arguments[1], arguments[2])
16
+ webidl.util.markAsUncloneable(this)
16
17
  return
17
18
  }
18
19
 
@@ -25,6 +26,7 @@ class MessageEvent extends Event {
25
26
  super(type, eventInitDict)
26
27
 
27
28
  this.#eventInit = eventInitDict
29
+ webidl.util.markAsUncloneable(this)
28
30
  }
29
31
 
30
32
  get data () {
@@ -111,6 +113,7 @@ class CloseEvent extends Event {
111
113
  super(type, eventInitDict)
112
114
 
113
115
  this.#eventInit = eventInitDict
116
+ webidl.util.markAsUncloneable(this)
114
117
  }
115
118
 
116
119
  get wasClean () {
@@ -141,6 +144,7 @@ class ErrorEvent extends Event {
141
144
  webidl.argumentLengthCheck(arguments, 1, prefix)
142
145
 
143
146
  super(type, eventInitDict)
147
+ webidl.util.markAsUncloneable(this)
144
148
 
145
149
  type = webidl.converters.DOMString(type, prefix, 'type')
146
150
  eventInitDict = webidl.converters.ErrorEventInit(eventInitDict ?? {})
@@ -78,6 +78,6 @@ Object.defineProperties(WebSocketError.prototype, {
78
78
  }
79
79
  })
80
80
 
81
- webidl.is.WebSocketError = webidl.util.MakeTypeAssertion(WebSocketError.prototype)
81
+ webidl.is.WebSocketError = webidl.util.MakeTypeAssertion(WebSocketError)
82
82
 
83
83
  module.exports = { WebSocketError, createUnvalidatedWebSocketError }
@@ -100,6 +100,8 @@ class WebSocket extends EventTarget {
100
100
  constructor (url, protocols = []) {
101
101
  super()
102
102
 
103
+ webidl.util.markAsUncloneable(this)
104
+
103
105
  const prefix = 'WebSocket constructor'
104
106
  webidl.argumentLengthCheck(arguments, 1, prefix)
105
107
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "undici",
3
- "version": "7.0.0-alpha.2",
3
+ "version": "7.0.0-alpha.4",
4
4
  "description": "An HTTP/1.1 client, written from scratch for Node.js",
5
5
  "homepage": "https://undici.nodejs.org",
6
6
  "bugs": {
@@ -63,21 +63,24 @@
63
63
  "types": "index.d.ts",
64
64
  "scripts": {
65
65
  "build:node": "esbuild index-fetch.js --bundle --platform=node --outfile=undici-fetch.js --define:esbuildDetection=1 --keep-names && node scripts/strip-comments.js",
66
- "prebuild:wasm": "node build/wasm.js --prebuild",
67
66
  "build:wasm": "node build/wasm.js --docker",
68
67
  "generate-pem": "node scripts/generate-pem.js",
69
68
  "lint": "eslint --cache",
70
69
  "lint:fix": "eslint --fix --cache",
71
70
  "test": "npm run test:javascript && cross-env NODE_V8_COVERAGE= npm run test:typescript",
72
71
  "test:javascript": "npm run test:javascript:no-jest && npm run test:jest",
73
- "test:javascript:no-jest": "npm run generate-pem && npm run test:unit && npm run test:node-fetch && npm run test:cache && npm run test:interceptors && npm run test:fetch && npm run test:cookies && npm run test:eventsource && npm run test:wpt && npm run test:websocket && npm run test:node-test",
72
+ "test:javascript:no-jest": "npm run generate-pem && npm run test:unit && npm run test:node-fetch && npm run test:cache && npm run test:cache-interceptor && npm run test:interceptors && npm run test:fetch && npm run test:cookies && npm run test:eventsource && npm run test:wpt && npm run test:websocket && npm run test:node-test",
74
73
  "test:javascript:without-intl": "npm run test:javascript:no-jest",
75
74
  "test:busboy": "borp -p \"test/busboy/*.js\"",
76
75
  "test:cache": "borp -p \"test/cache/*.js\"",
76
+ "test:cache-interceptor": "borp -p \"test/cache-interceptor/*.js\"",
77
77
  "test:cookies": "borp -p \"test/cookie/*.js\"",
78
78
  "test:eventsource": "npm run build:node && borp --expose-gc -p \"test/eventsource/*.js\"",
79
79
  "test:fuzzing": "node test/fuzzing/fuzzing.test.js",
80
80
  "test:fetch": "npm run build:node && borp --timeout 180000 --expose-gc --concurrency 1 -p \"test/fetch/*.js\" && npm run test:webidl && npm run test:busboy",
81
+ "test:h2": "npm run test:h2:core && npm run test:h2:fetch",
82
+ "test:h2:core": "borp -p \"test/http2*.js\"",
83
+ "test:h2:fetch": "npm run build:node && borp -p \"test/fetch/http2*.js\"",
81
84
  "test:interceptors": "borp -p \"test/interceptors/*.js\"",
82
85
  "test:jest": "cross-env NODE_V8_COVERAGE= jest",
83
86
  "test:unit": "borp --expose-gc -p \"test/*.js\"",
@@ -104,10 +107,10 @@
104
107
  "devDependencies": {
105
108
  "@fastify/busboy": "3.0.0",
106
109
  "@matteo.collina/tspl": "^0.1.1",
107
- "@sinonjs/fake-timers": "^11.1.0",
110
+ "@sinonjs/fake-timers": "^12.0.0",
108
111
  "@types/node": "^18.19.50",
109
112
  "abort-controller": "^3.0.0",
110
- "borp": "^0.17.0",
113
+ "borp": "^0.18.0",
111
114
  "c8": "^10.0.0",
112
115
  "cross-env": "^7.0.3",
113
116
  "dns-packet": "^5.4.0",