undici 7.0.0-alpha.1 → 7.0.0-alpha.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 (71) hide show
  1. package/README.md +2 -2
  2. package/docs/docs/api/Client.md +1 -1
  3. package/docs/docs/api/Debug.md +1 -1
  4. package/docs/docs/api/Dispatcher.md +53 -2
  5. package/docs/docs/api/MockAgent.md +2 -0
  6. package/docs/docs/api/MockPool.md +2 -1
  7. package/docs/docs/api/RetryAgent.md +1 -1
  8. package/docs/docs/api/RetryHandler.md +1 -1
  9. package/docs/docs/api/WebSocket.md +45 -3
  10. package/index.js +6 -2
  11. package/lib/api/abort-signal.js +2 -0
  12. package/lib/api/api-pipeline.js +4 -2
  13. package/lib/api/api-request.js +4 -2
  14. package/lib/api/api-stream.js +3 -1
  15. package/lib/api/api-upgrade.js +2 -2
  16. package/lib/api/readable.js +194 -41
  17. package/lib/api/util.js +2 -0
  18. package/lib/core/connect.js +49 -22
  19. package/lib/core/constants.js +11 -9
  20. package/lib/core/diagnostics.js +122 -128
  21. package/lib/core/request.js +4 -4
  22. package/lib/core/symbols.js +2 -0
  23. package/lib/core/tree.js +4 -2
  24. package/lib/core/util.js +220 -39
  25. package/lib/dispatcher/client-h1.js +299 -60
  26. package/lib/dispatcher/client-h2.js +1 -1
  27. package/lib/dispatcher/client.js +24 -7
  28. package/lib/dispatcher/fixed-queue.js +91 -49
  29. package/lib/dispatcher/pool-stats.js +2 -0
  30. package/lib/dispatcher/proxy-agent.js +3 -1
  31. package/lib/handler/redirect-handler.js +2 -2
  32. package/lib/handler/retry-handler.js +2 -2
  33. package/lib/interceptor/dns.js +346 -0
  34. package/lib/mock/mock-agent.js +5 -8
  35. package/lib/mock/mock-client.js +7 -2
  36. package/lib/mock/mock-errors.js +3 -1
  37. package/lib/mock/mock-interceptor.js +8 -6
  38. package/lib/mock/mock-pool.js +7 -2
  39. package/lib/mock/mock-symbols.js +2 -1
  40. package/lib/mock/mock-utils.js +33 -5
  41. package/lib/util/timers.js +50 -6
  42. package/lib/web/cache/cache.js +24 -21
  43. package/lib/web/cache/cachestorage.js +1 -1
  44. package/lib/web/cookies/index.js +6 -4
  45. package/lib/web/fetch/body.js +42 -34
  46. package/lib/web/fetch/constants.js +35 -26
  47. package/lib/web/fetch/formdata-parser.js +14 -3
  48. package/lib/web/fetch/formdata.js +40 -20
  49. package/lib/web/fetch/headers.js +116 -84
  50. package/lib/web/fetch/index.js +65 -59
  51. package/lib/web/fetch/request.js +130 -55
  52. package/lib/web/fetch/response.js +79 -36
  53. package/lib/web/fetch/util.js +104 -57
  54. package/lib/web/fetch/webidl.js +38 -14
  55. package/lib/web/websocket/connection.js +92 -15
  56. package/lib/web/websocket/constants.js +2 -3
  57. package/lib/web/websocket/events.js +4 -2
  58. package/lib/web/websocket/receiver.js +20 -26
  59. package/lib/web/websocket/stream/websocketerror.js +83 -0
  60. package/lib/web/websocket/stream/websocketstream.js +485 -0
  61. package/lib/web/websocket/util.js +115 -10
  62. package/lib/web/websocket/websocket.js +45 -170
  63. package/package.json +6 -6
  64. package/types/interceptors.d.ts +14 -0
  65. package/types/mock-agent.d.ts +3 -0
  66. package/types/readable.d.ts +10 -7
  67. package/types/webidl.d.ts +24 -4
  68. package/types/websocket.d.ts +33 -0
  69. package/lib/mock/pluralizer.js +0 -29
  70. package/lib/web/cache/symbols.js +0 -5
  71. package/lib/web/fetch/symbols.js +0 -8
@@ -23,7 +23,6 @@ const {
23
23
  requestDuplex
24
24
  } = require('./constants')
25
25
  const { kEnumerableProperty, normalizedMethodRecordsBase, normalizedMethodRecords } = util
26
- const { kHeaders, kSignal, kState, kDispatcher } = require('./symbols')
27
26
  const { webidl } = require('./webidl')
28
27
  const { URLSerializer } = require('./data-url')
29
28
  const { kConstruct } = require('../../core/symbols')
@@ -80,6 +79,17 @@ let patchMethodWarning = false
80
79
 
81
80
  // https://fetch.spec.whatwg.org/#request-class
82
81
  class Request {
82
+ /** @type {AbortSignal} */
83
+ #signal
84
+
85
+ /** @type {import('../../dispatcher/dispatcher')} */
86
+ #dispatcher
87
+
88
+ /** @type {Headers} */
89
+ #headers
90
+
91
+ #state
92
+
83
93
  // https://fetch.spec.whatwg.org/#dom-request
84
94
  constructor (input, init = undefined) {
85
95
  if (input === kConstruct) {
@@ -106,7 +116,7 @@ class Request {
106
116
 
107
117
  // 5. If input is a string, then:
108
118
  if (typeof input === 'string') {
109
- this[kDispatcher] = init.dispatcher
119
+ this.#dispatcher = init.dispatcher
110
120
 
111
121
  // 1. Let parsedURL be the result of parsing input with baseURL.
112
122
  // 2. If parsedURL is failure, then throw a TypeError.
@@ -131,18 +141,18 @@ class Request {
131
141
  // 5. Set fallbackMode to "cors".
132
142
  fallbackMode = 'cors'
133
143
  } else {
134
- this[kDispatcher] = init.dispatcher || input[kDispatcher]
135
-
136
144
  // 6. Otherwise:
137
145
 
138
146
  // 7. Assert: input is a Request object.
139
- assert(input instanceof Request)
147
+ assert(webidl.is.Request(input))
140
148
 
141
149
  // 8. Set request to input’s request.
142
- request = input[kState]
150
+ request = input.#state
143
151
 
144
152
  // 9. Set signal to input’s signal.
145
- signal = input[kSignal]
153
+ signal = input.#signal
154
+
155
+ this.#dispatcher = init.dispatcher || input.#dispatcher
146
156
  }
147
157
 
148
158
  // 7. Let origin be this’s relevant settings object’s origin.
@@ -389,14 +399,14 @@ class Request {
389
399
  }
390
400
 
391
401
  // 27. Set this’s request to request.
392
- this[kState] = request
402
+ this.#state = request
393
403
 
394
404
  // 28. Set this’s signal to a new AbortSignal object with this’s relevant
395
405
  // Realm.
396
406
  // TODO: could this be simplified with AbortSignal.any
397
407
  // (https://dom.spec.whatwg.org/#dom-abortsignal-any)
398
408
  const ac = new AbortController()
399
- this[kSignal] = ac.signal
409
+ this.#signal = ac.signal
400
410
 
401
411
  // 29. If signal is not null, then make this’s signal follow signal.
402
412
  if (signal != null) {
@@ -434,9 +444,9 @@ class Request {
434
444
  // 30. Set this’s headers to a new Headers object with this’s relevant
435
445
  // Realm, whose header list is request’s header list and guard is
436
446
  // "request".
437
- this[kHeaders] = new Headers(kConstruct)
438
- setHeadersList(this[kHeaders], request.headersList)
439
- setHeadersGuard(this[kHeaders], 'request')
447
+ this.#headers = new Headers(kConstruct)
448
+ setHeadersList(this.#headers, request.headersList)
449
+ setHeadersGuard(this.#headers, 'request')
440
450
 
441
451
  // 31. If this’s request’s mode is "no-cors", then:
442
452
  if (mode === 'no-cors') {
@@ -449,13 +459,13 @@ class Request {
449
459
  }
450
460
 
451
461
  // 2. Set this’s headers’s guard to "request-no-cors".
452
- setHeadersGuard(this[kHeaders], 'request-no-cors')
462
+ setHeadersGuard(this.#headers, 'request-no-cors')
453
463
  }
454
464
 
455
465
  // 32. If init is not empty, then:
456
466
  if (initHasKey) {
457
467
  /** @type {HeadersList} */
458
- const headersList = getHeadersList(this[kHeaders])
468
+ const headersList = getHeadersList(this.#headers)
459
469
  // 1. Let headers be a copy of this’s headers and its associated header
460
470
  // list.
461
471
  // 2. If init["headers"] exists, then set headers to init["headers"].
@@ -474,13 +484,13 @@ class Request {
474
484
  headersList.cookies = headers.cookies
475
485
  } else {
476
486
  // 5. Otherwise, fill this’s headers with headers.
477
- fillHeaders(this[kHeaders], headers)
487
+ fillHeaders(this.#headers, headers)
478
488
  }
479
489
  }
480
490
 
481
491
  // 33. Let inputBody be input’s request’s body if input is a Request
482
492
  // object; otherwise null.
483
- const inputBody = input instanceof Request ? input[kState].body : null
493
+ const inputBody = webidl.is.Request(input) ? input.#state.body : null
484
494
 
485
495
  // 34. If either init["body"] exists and is non-null or inputBody is
486
496
  // non-null, and request’s method is `GET` or `HEAD`, then throw a
@@ -509,8 +519,8 @@ class Request {
509
519
  // 3, If Content-Type is non-null and this’s headers’s header list does
510
520
  // not contain `Content-Type`, then append `Content-Type`/Content-Type to
511
521
  // this’s headers.
512
- if (contentType && !getHeadersList(this[kHeaders]).contains('content-type', true)) {
513
- this[kHeaders].append('content-type', contentType, true)
522
+ if (contentType && !getHeadersList(this.#headers).contains('content-type', true)) {
523
+ this.#headers.append('content-type', contentType, true)
514
524
  }
515
525
  }
516
526
 
@@ -545,7 +555,7 @@ class Request {
545
555
  // 40. If initBody is null and inputBody is non-null, then:
546
556
  if (initBody == null && inputBody != null) {
547
557
  // 1. If input is unusable, then throw a TypeError.
548
- if (bodyUnusable(input)) {
558
+ if (bodyUnusable(input.#state)) {
549
559
  throw new TypeError(
550
560
  'Cannot construct a Request with a Request object that has already been used.'
551
561
  )
@@ -563,7 +573,7 @@ class Request {
563
573
  }
564
574
 
565
575
  // 41. Set this’s request’s body to finalBody.
566
- this[kState].body = finalBody
576
+ this.#state.body = finalBody
567
577
  }
568
578
 
569
579
  // Returns request’s HTTP method, which is "GET" by default.
@@ -571,7 +581,7 @@ class Request {
571
581
  webidl.brandCheck(this, Request)
572
582
 
573
583
  // The method getter steps are to return this’s request’s method.
574
- return this[kState].method
584
+ return this.#state.method
575
585
  }
576
586
 
577
587
  // Returns the URL of request as a string.
@@ -579,7 +589,7 @@ class Request {
579
589
  webidl.brandCheck(this, Request)
580
590
 
581
591
  // The url getter steps are to return this’s request’s URL, serialized.
582
- return URLSerializer(this[kState].url)
592
+ return URLSerializer(this.#state.url)
583
593
  }
584
594
 
585
595
  // Returns a Headers object consisting of the headers associated with request.
@@ -589,7 +599,7 @@ class Request {
589
599
  webidl.brandCheck(this, Request)
590
600
 
591
601
  // The headers getter steps are to return this’s headers.
592
- return this[kHeaders]
602
+ return this.#headers
593
603
  }
594
604
 
595
605
  // Returns the kind of resource requested by request, e.g., "document"
@@ -598,7 +608,7 @@ class Request {
598
608
  webidl.brandCheck(this, Request)
599
609
 
600
610
  // The destination getter are to return this’s request’s destination.
601
- return this[kState].destination
611
+ return this.#state.destination
602
612
  }
603
613
 
604
614
  // Returns the referrer of request. Its value can be a same-origin URL if
@@ -611,18 +621,18 @@ class Request {
611
621
 
612
622
  // 1. If this’s request’s referrer is "no-referrer", then return the
613
623
  // empty string.
614
- if (this[kState].referrer === 'no-referrer') {
624
+ if (this.#state.referrer === 'no-referrer') {
615
625
  return ''
616
626
  }
617
627
 
618
628
  // 2. If this’s request’s referrer is "client", then return
619
629
  // "about:client".
620
- if (this[kState].referrer === 'client') {
630
+ if (this.#state.referrer === 'client') {
621
631
  return 'about:client'
622
632
  }
623
633
 
624
634
  // Return this’s request’s referrer, serialized.
625
- return this[kState].referrer.toString()
635
+ return this.#state.referrer.toString()
626
636
  }
627
637
 
628
638
  // Returns the referrer policy associated with request.
@@ -632,7 +642,7 @@ class Request {
632
642
  webidl.brandCheck(this, Request)
633
643
 
634
644
  // The referrerPolicy getter steps are to return this’s request’s referrer policy.
635
- return this[kState].referrerPolicy
645
+ return this.#state.referrerPolicy
636
646
  }
637
647
 
638
648
  // Returns the mode associated with request, which is a string indicating
@@ -642,15 +652,17 @@ class Request {
642
652
  webidl.brandCheck(this, Request)
643
653
 
644
654
  // The mode getter steps are to return this’s request’s mode.
645
- return this[kState].mode
655
+ return this.#state.mode
646
656
  }
647
657
 
648
658
  // Returns the credentials mode associated with request,
649
659
  // which is a string indicating whether credentials will be sent with the
650
660
  // request always, never, or only when sent to a same-origin URL.
651
661
  get credentials () {
662
+ webidl.brandCheck(this, Request)
663
+
652
664
  // The credentials getter steps are to return this’s request’s credentials mode.
653
- return this[kState].credentials
665
+ return this.#state.credentials
654
666
  }
655
667
 
656
668
  // Returns the cache mode associated with request,
@@ -660,7 +672,7 @@ class Request {
660
672
  webidl.brandCheck(this, Request)
661
673
 
662
674
  // The cache getter steps are to return this’s request’s cache mode.
663
- return this[kState].cache
675
+ return this.#state.cache
664
676
  }
665
677
 
666
678
  // Returns the redirect mode associated with request,
@@ -671,7 +683,7 @@ class Request {
671
683
  webidl.brandCheck(this, Request)
672
684
 
673
685
  // The redirect getter steps are to return this’s request’s redirect mode.
674
- return this[kState].redirect
686
+ return this.#state.redirect
675
687
  }
676
688
 
677
689
  // Returns request’s subresource integrity metadata, which is a
@@ -682,7 +694,7 @@ class Request {
682
694
 
683
695
  // The integrity getter steps are to return this’s request’s integrity
684
696
  // metadata.
685
- return this[kState].integrity
697
+ return this.#state.integrity
686
698
  }
687
699
 
688
700
  // Returns a boolean indicating whether or not request can outlive the
@@ -691,7 +703,7 @@ class Request {
691
703
  webidl.brandCheck(this, Request)
692
704
 
693
705
  // The keepalive getter steps are to return this’s request’s keepalive.
694
- return this[kState].keepalive
706
+ return this.#state.keepalive
695
707
  }
696
708
 
697
709
  // Returns a boolean indicating whether or not request is for a reload
@@ -701,7 +713,7 @@ class Request {
701
713
 
702
714
  // The isReloadNavigation getter steps are to return true if this’s
703
715
  // request’s reload-navigation flag is set; otherwise false.
704
- return this[kState].reloadNavigation
716
+ return this.#state.reloadNavigation
705
717
  }
706
718
 
707
719
  // Returns a boolean indicating whether or not request is for a history
@@ -711,7 +723,7 @@ class Request {
711
723
 
712
724
  // The isHistoryNavigation getter steps are to return true if this’s request’s
713
725
  // history-navigation flag is set; otherwise false.
714
- return this[kState].historyNavigation
726
+ return this.#state.historyNavigation
715
727
  }
716
728
 
717
729
  // Returns the signal associated with request, which is an AbortSignal
@@ -721,19 +733,19 @@ class Request {
721
733
  webidl.brandCheck(this, Request)
722
734
 
723
735
  // The signal getter steps are to return this’s signal.
724
- return this[kSignal]
736
+ return this.#signal
725
737
  }
726
738
 
727
739
  get body () {
728
740
  webidl.brandCheck(this, Request)
729
741
 
730
- return this[kState].body ? this[kState].body.stream : null
742
+ return this.#state.body ? this.#state.body.stream : null
731
743
  }
732
744
 
733
745
  get bodyUsed () {
734
746
  webidl.brandCheck(this, Request)
735
747
 
736
- return !!this[kState].body && util.isDisturbed(this[kState].body.stream)
748
+ return !!this.#state.body && util.isDisturbed(this.#state.body.stream)
737
749
  }
738
750
 
739
751
  get duplex () {
@@ -747,12 +759,12 @@ class Request {
747
759
  webidl.brandCheck(this, Request)
748
760
 
749
761
  // 1. If this is unusable, then throw a TypeError.
750
- if (bodyUnusable(this)) {
762
+ if (bodyUnusable(this.#state)) {
751
763
  throw new TypeError('unusable')
752
764
  }
753
765
 
754
766
  // 2. Let clonedRequest be the result of cloning this’s request.
755
- const clonedRequest = cloneRequest(this[kState])
767
+ const clonedRequest = cloneRequest(this.#state)
756
768
 
757
769
  // 3. Let clonedRequestObject be the result of creating a Request object,
758
770
  // given clonedRequest, this’s headers’s guard, and this’s relevant Realm.
@@ -775,7 +787,7 @@ class Request {
775
787
  }
776
788
 
777
789
  // 4. Return clonedRequestObject.
778
- return fromInnerRequest(clonedRequest, ac.signal, getHeadersGuard(this[kHeaders]))
790
+ return fromInnerRequest(clonedRequest, this.#dispatcher, ac.signal, getHeadersGuard(this.#headers))
779
791
  }
780
792
 
781
793
  [nodeUtil.inspect.custom] (depth, options) {
@@ -805,9 +817,64 @@ class Request {
805
817
 
806
818
  return `Request ${nodeUtil.formatWithOptions(options, properties)}`
807
819
  }
820
+
821
+ /**
822
+ * @param {Request} request
823
+ * @param {AbortSignal} newSignal
824
+ */
825
+ static setRequestSignal (request, newSignal) {
826
+ request.#signal = newSignal
827
+ return request
828
+ }
829
+
830
+ /**
831
+ * @param {Request} request
832
+ */
833
+ static getRequestDispatcher (request) {
834
+ return request.#dispatcher
835
+ }
836
+
837
+ /**
838
+ * @param {Request} request
839
+ * @param {import('../../dispatcher/dispatcher')} newDispatcher
840
+ */
841
+ static setRequestDispatcher (request, newDispatcher) {
842
+ request.#dispatcher = newDispatcher
843
+ }
844
+
845
+ /**
846
+ * @param {Request} request
847
+ * @param {Headers} newHeaders
848
+ */
849
+ static setRequestHeaders (request, newHeaders) {
850
+ request.#headers = newHeaders
851
+ }
852
+
853
+ /**
854
+ * @param {Request} request
855
+ */
856
+ static getRequestState (request) {
857
+ return request.#state
858
+ }
859
+
860
+ /**
861
+ * @param {Request} request
862
+ * @param {any} newState
863
+ */
864
+ static setRequestState (request, newState) {
865
+ request.#state = newState
866
+ }
808
867
  }
809
868
 
810
- mixinBody(Request)
869
+ const { setRequestSignal, getRequestDispatcher, setRequestDispatcher, setRequestHeaders, getRequestState, setRequestState } = Request
870
+ Reflect.deleteProperty(Request, 'setRequestSignal')
871
+ Reflect.deleteProperty(Request, 'getRequestDispatcher')
872
+ Reflect.deleteProperty(Request, 'setRequestDispatcher')
873
+ Reflect.deleteProperty(Request, 'setRequestHeaders')
874
+ Reflect.deleteProperty(Request, 'getRequestState')
875
+ Reflect.deleteProperty(Request, 'setRequestState')
876
+
877
+ mixinBody(Request, getRequestState)
811
878
 
812
879
  // https://fetch.spec.whatwg.org/#requests
813
880
  function makeRequest (init) {
@@ -875,17 +942,20 @@ function cloneRequest (request) {
875
942
  /**
876
943
  * @see https://fetch.spec.whatwg.org/#request-create
877
944
  * @param {any} innerRequest
945
+ * @param {import('../../dispatcher/agent')} dispatcher
878
946
  * @param {AbortSignal} signal
879
947
  * @param {'request' | 'immutable' | 'request-no-cors' | 'response' | 'none'} guard
880
948
  * @returns {Request}
881
949
  */
882
- function fromInnerRequest (innerRequest, signal, guard) {
950
+ function fromInnerRequest (innerRequest, dispatcher, signal, guard) {
883
951
  const request = new Request(kConstruct)
884
- request[kState] = innerRequest
885
- request[kSignal] = signal
886
- request[kHeaders] = new Headers(kConstruct)
887
- setHeadersList(request[kHeaders], innerRequest.headersList)
888
- setHeadersGuard(request[kHeaders], guard)
952
+ setRequestState(request, innerRequest)
953
+ setRequestDispatcher(request, dispatcher)
954
+ setRequestSignal(request, signal)
955
+ const headers = new Headers(kConstruct)
956
+ setRequestHeaders(request, headers)
957
+ setHeadersList(headers, innerRequest.headersList)
958
+ setHeadersGuard(headers, guard)
889
959
  return request
890
960
  }
891
961
 
@@ -916,23 +986,21 @@ Object.defineProperties(Request.prototype, {
916
986
  }
917
987
  })
918
988
 
989
+ webidl.is.Request = webidl.util.MakeTypeAssertion(Request.prototype)
990
+
919
991
  // https://fetch.spec.whatwg.org/#requestinfo
920
992
  webidl.converters.RequestInfo = function (V, prefix, argument) {
921
993
  if (typeof V === 'string') {
922
994
  return webidl.converters.USVString(V)
923
995
  }
924
996
 
925
- if (V instanceof Request) {
997
+ if (webidl.is.Request(V)) {
926
998
  return V
927
999
  }
928
1000
 
929
1001
  return webidl.converters.USVString(V)
930
1002
  }
931
1003
 
932
- webidl.converters.AbortSignal = webidl.interfaceConverter(
933
- AbortSignal
934
- )
935
-
936
1004
  // https://fetch.spec.whatwg.org/#requestinit
937
1005
  webidl.converters.RequestInit = webidl.dictionaryConverter([
938
1006
  {
@@ -1016,4 +1084,11 @@ webidl.converters.RequestInit = webidl.dictionaryConverter([
1016
1084
  }
1017
1085
  ])
1018
1086
 
1019
- module.exports = { Request, makeRequest, fromInnerRequest, cloneRequest }
1087
+ module.exports = {
1088
+ Request,
1089
+ makeRequest,
1090
+ fromInnerRequest,
1091
+ cloneRequest,
1092
+ getRequestDispatcher,
1093
+ getRequestState
1094
+ }