@mswjs/interceptors 0.41.3 → 0.41.5

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 (165) hide show
  1. package/lib/browser/{XMLHttpRequest-BACqefB-.cjs → XMLHttpRequest-DSAhl6_a.cjs} +10 -22
  2. package/lib/browser/XMLHttpRequest-DSAhl6_a.cjs.map +1 -0
  3. package/lib/browser/{XMLHttpRequest-BvxZV0WU.mjs → XMLHttpRequest-DYyDAIJh.mjs} +10 -22
  4. package/lib/browser/XMLHttpRequest-DYyDAIJh.mjs.map +1 -0
  5. package/lib/browser/{createRequestId-Cs4oXfa1.cjs → createRequestId-DOf8Ktjs.cjs} +1 -1
  6. package/lib/browser/{createRequestId-Cs4oXfa1.cjs.map → createRequestId-DOf8Ktjs.cjs.map} +1 -1
  7. package/lib/browser/{createRequestId-DQcIlohW.mjs → createRequestId-DYCsFHOi.mjs} +1 -1
  8. package/lib/browser/{createRequestId-DQcIlohW.mjs.map → createRequestId-DYCsFHOi.mjs.map} +1 -1
  9. package/lib/browser/{fetch-U3v3Y4ap.cjs → fetch-BMC2en2x.cjs} +11 -26
  10. package/lib/browser/fetch-BMC2en2x.cjs.map +1 -0
  11. package/lib/browser/{fetch-DdKEdDOR.mjs → fetch-D5LGhx5i.mjs} +11 -26
  12. package/lib/browser/fetch-D5LGhx5i.mjs.map +1 -0
  13. package/lib/browser/{getRawRequest-zx8rUJL2.cjs → getRawRequest-B9kRTvjs.cjs} +81 -9
  14. package/lib/browser/getRawRequest-B9kRTvjs.cjs.map +1 -0
  15. package/lib/browser/{getRawRequest-BTaNLFr0.mjs → getRawRequest-BEw5hEOW.mjs} +78 -6
  16. package/lib/browser/getRawRequest-BEw5hEOW.mjs.map +1 -0
  17. package/lib/browser/{glossary-BdLS4k1H.d.cts → glossary-1lhZx6Aw.d.cts} +2 -3
  18. package/lib/browser/{glossary-DYwOrogs.d.mts → glossary-nkHWcwvY.d.mts} +2 -3
  19. package/lib/browser/{handleRequest-CvX2G-Lz.cjs → handleRequest-BCtqvFSS.cjs} +3 -3
  20. package/lib/browser/{handleRequest-CvX2G-Lz.cjs.map → handleRequest-BCtqvFSS.cjs.map} +1 -1
  21. package/lib/browser/{handleRequest-D7kpTI5U.mjs → handleRequest-DuUoGpfA.mjs} +3 -3
  22. package/lib/browser/{handleRequest-D7kpTI5U.mjs.map → handleRequest-DuUoGpfA.mjs.map} +1 -1
  23. package/lib/browser/hasConfigurableGlobal-B39W0thh.mjs +98 -0
  24. package/lib/browser/hasConfigurableGlobal-B39W0thh.mjs.map +1 -0
  25. package/lib/browser/hasConfigurableGlobal-B5o6PHq3.cjs +115 -0
  26. package/lib/browser/hasConfigurableGlobal-B5o6PHq3.cjs.map +1 -0
  27. package/lib/browser/index.cjs +3 -3
  28. package/lib/browser/index.d.cts +21 -2
  29. package/lib/browser/index.d.mts +21 -2
  30. package/lib/browser/index.mjs +3 -3
  31. package/lib/browser/interceptors/WebSocket/index.cjs +6 -10
  32. package/lib/browser/interceptors/WebSocket/index.cjs.map +1 -1
  33. package/lib/browser/interceptors/WebSocket/index.mjs +6 -10
  34. package/lib/browser/interceptors/WebSocket/index.mjs.map +1 -1
  35. package/lib/browser/interceptors/XMLHttpRequest/index.cjs +5 -4
  36. package/lib/browser/interceptors/XMLHttpRequest/index.d.cts +1 -1
  37. package/lib/browser/interceptors/XMLHttpRequest/index.d.mts +1 -1
  38. package/lib/browser/interceptors/XMLHttpRequest/index.mjs +5 -4
  39. package/lib/browser/interceptors/fetch/index.cjs +5 -4
  40. package/lib/browser/interceptors/fetch/index.d.cts +1 -1
  41. package/lib/browser/interceptors/fetch/index.d.mts +1 -1
  42. package/lib/browser/interceptors/fetch/index.mjs +5 -4
  43. package/lib/browser/presets/browser.cjs +6 -5
  44. package/lib/browser/presets/browser.cjs.map +1 -1
  45. package/lib/browser/presets/browser.mjs +6 -5
  46. package/lib/browser/presets/browser.mjs.map +1 -1
  47. package/lib/node/{BatchInterceptor-3LnAnLTx.cjs → BatchInterceptor-AZr7q8p_.cjs} +2 -2
  48. package/lib/node/{BatchInterceptor-3LnAnLTx.cjs.map → BatchInterceptor-AZr7q8p_.cjs.map} +1 -1
  49. package/lib/node/{BatchInterceptor-DFaBPilf.mjs → BatchInterceptor-B2YAn5m9.mjs} +2 -2
  50. package/lib/node/{BatchInterceptor-DFaBPilf.mjs.map → BatchInterceptor-B2YAn5m9.mjs.map} +1 -1
  51. package/lib/node/{BatchInterceptor-D_YqR8qU.d.cts → BatchInterceptor-KKF8Q47I.d.cts} +2 -2
  52. package/lib/node/{BatchInterceptor-D7mXzHcQ.d.mts → BatchInterceptor-rSr-NH_H.d.mts} +2 -2
  53. package/lib/node/{ClientRequest-Ca8Qykuv.mjs → ClientRequest-5WjHvs9Y.mjs} +20 -6
  54. package/lib/node/ClientRequest-5WjHvs9Y.mjs.map +1 -0
  55. package/lib/node/{ClientRequest-2rDe54Ui.cjs → ClientRequest-BgwQG-9G.cjs} +20 -6
  56. package/lib/node/ClientRequest-BgwQG-9G.cjs.map +1 -0
  57. package/lib/node/{Interceptor-DEazpLJd.d.mts → Interceptor-BsZ21ue0.d.cts} +2 -3
  58. package/lib/node/{Interceptor-DJ2akVWI.d.cts → Interceptor-soD-WpQO.d.mts} +2 -3
  59. package/lib/node/RemoteHttpInterceptor.cjs +10 -9
  60. package/lib/node/RemoteHttpInterceptor.cjs.map +1 -1
  61. package/lib/node/RemoteHttpInterceptor.d.cts +3 -3
  62. package/lib/node/RemoteHttpInterceptor.d.mts +3 -3
  63. package/lib/node/RemoteHttpInterceptor.mjs +10 -9
  64. package/lib/node/RemoteHttpInterceptor.mjs.map +1 -1
  65. package/lib/node/{XMLHttpRequest-B7kJdYYI.cjs → XMLHttpRequest-B7sloBex.cjs} +11 -24
  66. package/lib/node/XMLHttpRequest-B7sloBex.cjs.map +1 -0
  67. package/lib/node/{XMLHttpRequest-C8dIZpds.mjs → XMLHttpRequest-DmsdUGmj.mjs} +11 -24
  68. package/lib/node/XMLHttpRequest-DmsdUGmj.mjs.map +1 -0
  69. package/lib/node/{bufferUtils-_8XfKIfX.mjs → bufferUtils-DxPxwff_.mjs} +1 -1
  70. package/lib/node/{bufferUtils-_8XfKIfX.mjs.map → bufferUtils-DxPxwff_.mjs.map} +1 -1
  71. package/lib/node/{bufferUtils-DiCTqG-7.cjs → bufferUtils-S5_-2eN4.cjs} +1 -1
  72. package/lib/node/{bufferUtils-DiCTqG-7.cjs.map → bufferUtils-S5_-2eN4.cjs.map} +1 -1
  73. package/lib/node/{fetch-G1DVwDKG.mjs → fetch-DDAGTtZi.mjs} +11 -27
  74. package/lib/node/fetch-DDAGTtZi.mjs.map +1 -0
  75. package/lib/node/{fetch-BmXpK10r.cjs → fetch-uc7pNtPg.cjs} +11 -27
  76. package/lib/node/fetch-uc7pNtPg.cjs.map +1 -0
  77. package/lib/node/{fetchUtils-CoU35g3M.mjs → fetchUtils-BJxD7wvl.mjs} +78 -2
  78. package/lib/node/{fetchUtils-BaY5iWXw.cjs.map → fetchUtils-BJxD7wvl.mjs.map} +1 -1
  79. package/lib/node/{fetchUtils-BaY5iWXw.cjs → fetchUtils-Dw6kQghF.cjs} +83 -1
  80. package/lib/node/fetchUtils-Dw6kQghF.cjs.map +1 -0
  81. package/lib/node/{getRawRequest-BavnMWh_.cjs → getRawRequest-B6znU6il.cjs} +1 -1
  82. package/lib/node/{getRawRequest-BavnMWh_.cjs.map → getRawRequest-B6znU6il.cjs.map} +1 -1
  83. package/lib/node/{getRawRequest-DnwmXyOW.mjs → getRawRequest-C2-1urzA.mjs} +1 -1
  84. package/lib/node/{getRawRequest-DnwmXyOW.mjs.map → getRawRequest-C2-1urzA.mjs.map} +1 -1
  85. package/lib/node/{handleRequest-Y97UwBbF.mjs → handleRequest-DGfUg9bm.mjs} +2 -2
  86. package/lib/node/{handleRequest-Y97UwBbF.mjs.map → handleRequest-DGfUg9bm.mjs.map} +1 -1
  87. package/lib/node/{handleRequest-Bb7Y-XLw.cjs → handleRequest-Dzg1d3e5.cjs} +2 -2
  88. package/lib/node/{handleRequest-Bb7Y-XLw.cjs.map → handleRequest-Dzg1d3e5.cjs.map} +1 -1
  89. package/lib/node/hasConfigurableGlobal-Befl_QJD.cjs +97 -0
  90. package/lib/node/hasConfigurableGlobal-Befl_QJD.cjs.map +1 -0
  91. package/lib/node/hasConfigurableGlobal-jN_-v3gp.mjs +85 -0
  92. package/lib/node/hasConfigurableGlobal-jN_-v3gp.mjs.map +1 -0
  93. package/lib/node/{index-BMbJ8FXL.d.cts → index-BJ5E5aW-.d.cts} +2 -2
  94. package/lib/node/{index-C0YAQ36w.d.mts → index-DfoF45ih.d.mts} +2 -2
  95. package/lib/node/index.cjs +5 -6
  96. package/lib/node/index.cjs.map +1 -1
  97. package/lib/node/index.d.cts +22 -3
  98. package/lib/node/index.d.mts +22 -3
  99. package/lib/node/index.mjs +5 -6
  100. package/lib/node/index.mjs.map +1 -1
  101. package/lib/node/interceptors/ClientRequest/index.cjs +4 -4
  102. package/lib/node/interceptors/ClientRequest/index.d.cts +1 -1
  103. package/lib/node/interceptors/ClientRequest/index.d.mts +2 -2
  104. package/lib/node/interceptors/ClientRequest/index.mjs +4 -4
  105. package/lib/node/interceptors/XMLHttpRequest/index.cjs +5 -4
  106. package/lib/node/interceptors/XMLHttpRequest/index.d.cts +1 -1
  107. package/lib/node/interceptors/XMLHttpRequest/index.d.mts +1 -1
  108. package/lib/node/interceptors/XMLHttpRequest/index.mjs +5 -4
  109. package/lib/node/interceptors/fetch/index.cjs +4 -3
  110. package/lib/node/interceptors/fetch/index.d.cts +1 -1
  111. package/lib/node/interceptors/fetch/index.d.mts +1 -1
  112. package/lib/node/interceptors/fetch/index.mjs +4 -3
  113. package/lib/node/{node-dKdAf3tC.cjs → node-DIKcnzhK.cjs} +2 -2
  114. package/lib/node/{node-dKdAf3tC.cjs.map → node-DIKcnzhK.cjs.map} +1 -1
  115. package/lib/node/{node-DwCc6iuP.mjs → node-lsdNwZEW.mjs} +2 -2
  116. package/lib/node/{node-DwCc6iuP.mjs.map → node-lsdNwZEW.mjs.map} +1 -1
  117. package/lib/node/presets/node.cjs +8 -7
  118. package/lib/node/presets/node.cjs.map +1 -1
  119. package/lib/node/presets/node.d.cts +1 -1
  120. package/lib/node/presets/node.d.mts +2 -2
  121. package/lib/node/presets/node.mjs +8 -7
  122. package/lib/node/presets/node.mjs.map +1 -1
  123. package/lib/node/utils/node/index.cjs +1 -1
  124. package/lib/node/utils/node/index.mjs +1 -1
  125. package/package.json +1 -1
  126. package/src/RemoteHttpInterceptor.ts +2 -2
  127. package/src/glossary.ts +3 -5
  128. package/src/index.ts +1 -1
  129. package/src/interceptors/ClientRequest/MockHttpSocket.ts +2 -2
  130. package/src/interceptors/ClientRequest/utils/recordRawHeaders.ts +18 -0
  131. package/src/interceptors/WebSocket/index.ts +8 -15
  132. package/src/interceptors/XMLHttpRequest/XMLHttpRequestController.ts +2 -1
  133. package/src/interceptors/XMLHttpRequest/index.ts +12 -32
  134. package/src/interceptors/fetch/index.ts +10 -26
  135. package/src/utils/fetchUtils.test.ts +85 -0
  136. package/src/utils/fetchUtils.ts +139 -3
  137. package/src/utils/globalUtils.test.ts +144 -0
  138. package/src/utils/globalsRegistry.ts +107 -0
  139. package/src/utils/hasConfigurableGlobal.test.ts +11 -0
  140. package/src/utils/hasConfigurableGlobal.ts +9 -3
  141. package/lib/browser/XMLHttpRequest-BACqefB-.cjs.map +0 -1
  142. package/lib/browser/XMLHttpRequest-BvxZV0WU.mjs.map +0 -1
  143. package/lib/browser/fetch-DdKEdDOR.mjs.map +0 -1
  144. package/lib/browser/fetch-U3v3Y4ap.cjs.map +0 -1
  145. package/lib/browser/getRawRequest-BTaNLFr0.mjs.map +0 -1
  146. package/lib/browser/getRawRequest-zx8rUJL2.cjs.map +0 -1
  147. package/lib/browser/hasConfigurableGlobal-BvCTG97d.cjs +0 -45
  148. package/lib/browser/hasConfigurableGlobal-BvCTG97d.cjs.map +0 -1
  149. package/lib/browser/hasConfigurableGlobal-npXitu1-.mjs +0 -33
  150. package/lib/browser/hasConfigurableGlobal-npXitu1-.mjs.map +0 -1
  151. package/lib/node/ClientRequest-2rDe54Ui.cjs.map +0 -1
  152. package/lib/node/ClientRequest-Ca8Qykuv.mjs.map +0 -1
  153. package/lib/node/XMLHttpRequest-B7kJdYYI.cjs.map +0 -1
  154. package/lib/node/XMLHttpRequest-C8dIZpds.mjs.map +0 -1
  155. package/lib/node/fetch-BmXpK10r.cjs.map +0 -1
  156. package/lib/node/fetch-G1DVwDKG.mjs.map +0 -1
  157. package/lib/node/fetchUtils-CoU35g3M.mjs.map +0 -1
  158. package/lib/node/glossary-BLKRyLBd.cjs +0 -12
  159. package/lib/node/glossary-BLKRyLBd.cjs.map +0 -1
  160. package/lib/node/glossary-glQBRnVD.mjs +0 -6
  161. package/lib/node/glossary-glQBRnVD.mjs.map +0 -1
  162. package/lib/node/hasConfigurableGlobal-C97fWuaA.cjs +0 -26
  163. package/lib/node/hasConfigurableGlobal-C97fWuaA.cjs.map +0 -1
  164. package/lib/node/hasConfigurableGlobal-DBJA0vjm.mjs +0 -20
  165. package/lib/node/hasConfigurableGlobal-DBJA0vjm.mjs.map +0 -1
@@ -1,10 +1,11 @@
1
- import "../fetchUtils-CoU35g3M.mjs";
2
- import "../bufferUtils-_8XfKIfX.mjs";
3
- import { t as ClientRequestInterceptor } from "../ClientRequest-Ca8Qykuv.mjs";
4
- import "../handleRequest-Y97UwBbF.mjs";
5
- import "../node-DwCc6iuP.mjs";
6
- import { t as XMLHttpRequestInterceptor } from "../XMLHttpRequest-C8dIZpds.mjs";
7
- import { t as FetchInterceptor } from "../fetch-G1DVwDKG.mjs";
1
+ import "../fetchUtils-BJxD7wvl.mjs";
2
+ import "../bufferUtils-DxPxwff_.mjs";
3
+ import { t as ClientRequestInterceptor } from "../ClientRequest-5WjHvs9Y.mjs";
4
+ import "../handleRequest-DGfUg9bm.mjs";
5
+ import "../node-lsdNwZEW.mjs";
6
+ import { t as XMLHttpRequestInterceptor } from "../XMLHttpRequest-DmsdUGmj.mjs";
7
+ import "../hasConfigurableGlobal-jN_-v3gp.mjs";
8
+ import { t as FetchInterceptor } from "../fetch-DDAGTtZi.mjs";
8
9
 
9
10
  //#region src/presets/node.ts
10
11
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"node.mjs","names":[],"sources":["../../../src/presets/node.ts"],"sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\nimport { FetchInterceptor } from '../interceptors/fetch'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (http/https/XMLHttpRequest).\n */\nexport default [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n new FetchInterceptor(),\n] as const\n"],"mappings":";;;;;;;;;;;;;AAQA,mBAAe;CACb,IAAI,0BAA0B;CAC9B,IAAI,2BAA2B;CAC/B,IAAI,kBAAkB;CACvB"}
1
+ {"version":3,"file":"node.mjs","names":[],"sources":["../../../src/presets/node.ts"],"sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\nimport { FetchInterceptor } from '../interceptors/fetch'\n\n/**\n * The default preset provisions the interception of requests\n * regardless of their type (http/https/XMLHttpRequest).\n */\nexport default [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n new FetchInterceptor(),\n] as const\n"],"mappings":";;;;;;;;;;;;;;AAQA,mBAAe;CACb,IAAI,0BAA0B;CAC9B,IAAI,2BAA2B;CAC/B,IAAI,kBAAkB;CACvB"}
@@ -1,4 +1,4 @@
1
- const require_node = require('../../node-dKdAf3tC.cjs');
1
+ const require_node = require('../../node-DIKcnzhK.cjs');
2
2
 
3
3
  exports.getClientRequestBodyStream = require_node.getClientRequestBodyStream;
4
4
  exports.setRawRequestBodyStream = require_node.setRawRequestBodyStream;
@@ -1,3 +1,3 @@
1
- import { n as setRawRequestBodyStream, t as getClientRequestBodyStream } from "../../node-DwCc6iuP.mjs";
1
+ import { n as setRawRequestBodyStream, t as getClientRequestBodyStream } from "../../node-lsdNwZEW.mjs";
2
2
 
3
3
  export { getClientRequestBodyStream, setRawRequestBodyStream };
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "commonjs",
3
3
  "name": "@mswjs/interceptors",
4
4
  "description": "Low-level HTTP/HTTPS/XHR/fetch request interception library.",
5
- "version": "0.41.3",
5
+ "version": "0.41.5",
6
6
  "main": "./lib/node/index.cjs",
7
7
  "module": "./lib/node/index.mjs",
8
8
  "types": "./lib/node/index.d.cts",
@@ -7,7 +7,7 @@ import { XMLHttpRequestInterceptor } from './interceptors/XMLHttpRequest'
7
7
  import { FetchInterceptor } from './interceptors/fetch'
8
8
  import { handleRequest } from './utils/handleRequest'
9
9
  import { RequestController } from './RequestController'
10
- import { FetchResponse } from './utils/fetchUtils'
10
+ import { FetchRequest, FetchResponse } from './utils/fetchUtils'
11
11
  import { isResponseError } from './utils/responseUtils'
12
12
 
13
13
  export interface SerializedRequest {
@@ -172,7 +172,7 @@ export class RemoteHttpResolver extends Interceptor<HttpRequestEventMap> {
172
172
 
173
173
  logger.info('parsed intercepted request', requestJson)
174
174
 
175
- const request = new Request(requestJson.url, {
175
+ const request = new FetchRequest(requestJson.url, {
176
176
  method: requestJson.method,
177
177
  headers: new Headers(requestJson.headers),
178
178
  credentials: requestJson.credentials,
package/src/glossary.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  import type { RequestController } from './RequestController'
2
2
 
3
- export const IS_PATCHED_MODULE: unique symbol = Symbol('isPatchedModule')
4
-
5
3
  /**
6
4
  * @note Export `RequestController` as a type only.
7
5
  * It's never meant to be created in the userland.
@@ -16,7 +14,7 @@ export type HttpRequestEventMap = {
16
14
  request: Request
17
15
  requestId: string
18
16
  controller: RequestController
19
- }
17
+ },
20
18
  ]
21
19
  response: [
22
20
  args: {
@@ -24,7 +22,7 @@ export type HttpRequestEventMap = {
24
22
  isMockedResponse: boolean
25
23
  request: Request
26
24
  requestId: string
27
- }
25
+ },
28
26
  ]
29
27
  unhandledException: [
30
28
  args: {
@@ -32,6 +30,6 @@ export type HttpRequestEventMap = {
32
30
  request: Request
33
31
  requestId: string
34
32
  controller: RequestController
35
- }
33
+ },
36
34
  ]
37
35
  }
package/src/index.ts CHANGED
@@ -10,6 +10,6 @@ export {
10
10
  export { createRequestId } from './createRequestId'
11
11
  export { getCleanUrl } from './utils/getCleanUrl'
12
12
  export { encodeBuffer, decodeBuffer } from './utils/bufferUtils'
13
- export { FetchResponse } from './utils/fetchUtils'
13
+ export { FetchRequest, FetchResponse } from './utils/fetchUtils'
14
14
  export { getRawRequest } from './getRawRequest'
15
15
  export { resolveWebSocketUrl } from './utils/resolveWebSocketUrl'
@@ -15,7 +15,7 @@ import { isPropertyAccessible } from '../../utils/isPropertyAccessible'
15
15
  import { baseUrlFromConnectionOptions } from '../Socket/utils/baseUrlFromConnectionOptions'
16
16
  import { createRequestId } from '../../createRequestId'
17
17
  import { getRawFetchHeaders } from './utils/recordRawHeaders'
18
- import { FetchResponse } from '../../utils/fetchUtils'
18
+ import { FetchRequest, FetchResponse } from '../../utils/fetchUtils'
19
19
  import { setRawRequest } from '../../getRawRequest'
20
20
  import { setRawRequestBodyStream } from '../../utils/node'
21
21
  import { freeParser } from './utils/parserUtils'
@@ -576,7 +576,7 @@ export class MockHttpSocket extends MockSocket {
576
576
  })
577
577
 
578
578
  const requestId = createRequestId()
579
- this.request = new Request(url, {
579
+ this.request = new FetchRequest(url, {
580
580
  method,
581
581
  headers,
582
582
  credentials: 'same-origin',
@@ -1,3 +1,5 @@
1
+ import { FetchRequest, FetchResponse } from '../../../utils/fetchUtils'
2
+
1
3
  type HeaderTuple = [string, string]
2
4
  type RawHeaders = Array<HeaderTuple>
3
5
  type SetHeaderBehavior = 'set' | 'append'
@@ -92,6 +94,11 @@ export function recordRawFetchHeaders() {
92
94
  globalThis.Request = OriginalRequest
93
95
  globalThis.Response = OriginalResponse
94
96
 
97
+ Object.setPrototypeOf(FetchRequest, OriginalRequest)
98
+ Object.setPrototypeOf(FetchRequest.prototype, OriginalRequest.prototype)
99
+ Object.setPrototypeOf(FetchResponse, OriginalResponse)
100
+ Object.setPrototypeOf(FetchResponse.prototype, OriginalResponse.prototype)
101
+
95
102
  Reflect.deleteProperty(Headers, kRestorePatches)
96
103
  },
97
104
  enumerable: false,
@@ -222,6 +229,17 @@ export function recordRawFetchHeaders() {
222
229
  },
223
230
  }),
224
231
  })
232
+
233
+ /**
234
+ * Re-parent FetchRequest/FetchResponse so their `super()` calls go
235
+ * through the proxied globalThis.Request/Response above. Without this,
236
+ * FetchRequest extends the statically-captured (original) Request,
237
+ * bypassing the construct proxy that records raw headers.
238
+ */
239
+ Object.setPrototypeOf(FetchRequest, globalThis.Request)
240
+ Object.setPrototypeOf(FetchRequest.prototype, globalThis.Request.prototype)
241
+ Object.setPrototypeOf(FetchResponse, globalThis.Response)
242
+ Object.setPrototypeOf(FetchResponse.prototype, globalThis.Response.prototype)
225
243
  }
226
244
 
227
245
  export function restoreHeadersPrototype() {
@@ -18,6 +18,7 @@ import {
18
18
  import { bindEvent } from './utils/bindEvent'
19
19
  import { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'
20
20
  import { emitAsync } from '../../utils/emitAsync'
21
+ import { globalsRegistry } from '../../utils/globalsRegistry'
21
22
 
22
23
  export {
23
24
  type WebSocketData,
@@ -80,10 +81,7 @@ export class WebSocketInterceptor extends Interceptor<WebSocketEventMap> {
80
81
  }
81
82
 
82
83
  protected setup(): void {
83
- const originalWebSocketDescriptor = Object.getOwnPropertyDescriptor(
84
- globalThis,
85
- 'WebSocket'
86
- )
84
+ const logger = this.logger.extend('setup')
87
85
 
88
86
  const WebSocketProxy = new Proxy(globalThis.WebSocket, {
89
87
  construct: (
@@ -175,17 +173,12 @@ export class WebSocketInterceptor extends Interceptor<WebSocketEventMap> {
175
173
  },
176
174
  })
177
175
 
178
- Object.defineProperty(globalThis, 'WebSocket', {
179
- value: WebSocketProxy,
180
- configurable: true,
181
- })
176
+ logger.info('patching global WebSocket...')
182
177
 
183
- this.subscriptions.push(() => {
184
- Object.defineProperty(
185
- globalThis,
186
- 'WebSocket',
187
- originalWebSocketDescriptor!
188
- )
189
- })
178
+ this.subscriptions.push(
179
+ globalsRegistry.replaceGlobal('WebSocket', WebSocketProxy)
180
+ )
181
+
182
+ logger.info('global WebSocket patched!', globalThis.WebSocket.name)
190
183
  }
191
184
  }
@@ -16,6 +16,7 @@ import { INTERNAL_REQUEST_ID_HEADER_NAME } from '../../Interceptor'
16
16
  import { createRequestId } from '../../createRequestId'
17
17
  import { getBodyByteLength } from './utils/getBodyByteLength'
18
18
  import { setRawRequest } from '../../getRawRequest'
19
+ import { FetchRequest } from '../../utils/fetchUtils'
19
20
 
20
21
  const kIsRequestHandled = Symbol('kIsRequestHandled')
21
22
  const IS_NODE = isNodeProcess()
@@ -671,7 +672,7 @@ export class XMLHttpRequestController {
671
672
  const resolvedBody =
672
673
  body instanceof Document ? body.documentElement.innerText : body
673
674
 
674
- const fetchRequest = new Request(this.url.href, {
675
+ const fetchRequest = new FetchRequest(this.url.href, {
675
676
  method: this.method,
676
677
  headers: this.requestHeaders,
677
678
  /**
@@ -1,9 +1,9 @@
1
- import { invariant } from 'outvariant'
2
1
  import { Emitter } from 'strict-event-emitter'
3
- import { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'
2
+ import { HttpRequestEventMap } from '../../glossary'
4
3
  import { Interceptor } from '../../Interceptor'
5
4
  import { createXMLHttpRequestProxy } from './XMLHttpRequestProxy'
6
5
  import { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'
6
+ import { globalsRegistry } from '../../utils/globalsRegistry'
7
7
 
8
8
  export type XMLHttpRequestEmitter = Emitter<HttpRequestEventMap>
9
9
 
@@ -21,41 +21,21 @@ export class XMLHttpRequestInterceptor extends Interceptor<HttpRequestEventMap>
21
21
  protected setup() {
22
22
  const logger = this.logger.extend('setup')
23
23
 
24
- logger.info('patching "XMLHttpRequest" module...')
24
+ logger.info('patching global XMLHttpRequest...')
25
25
 
26
- const PureXMLHttpRequest = globalThis.XMLHttpRequest
27
-
28
- invariant(
29
- !(PureXMLHttpRequest as any)[IS_PATCHED_MODULE],
30
- 'Failed to patch the "XMLHttpRequest" module: already patched.'
26
+ this.subscriptions.push(
27
+ globalsRegistry.replaceGlobal(
28
+ 'XMLHttpRequest',
29
+ createXMLHttpRequestProxy({
30
+ emitter: this.emitter,
31
+ logger: this.logger,
32
+ })
33
+ )
31
34
  )
32
35
 
33
- globalThis.XMLHttpRequest = createXMLHttpRequestProxy({
34
- emitter: this.emitter,
35
- logger: this.logger,
36
- })
37
-
38
36
  logger.info(
39
- 'native "XMLHttpRequest" module patched!',
37
+ 'global XMLHttpRequest patched!',
40
38
  globalThis.XMLHttpRequest.name
41
39
  )
42
-
43
- Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {
44
- enumerable: true,
45
- configurable: true,
46
- value: true,
47
- })
48
-
49
- this.subscriptions.push(() => {
50
- Object.defineProperty(globalThis.XMLHttpRequest, IS_PATCHED_MODULE, {
51
- value: undefined,
52
- })
53
-
54
- globalThis.XMLHttpRequest = PureXMLHttpRequest
55
- logger.info(
56
- 'native "XMLHttpRequest" module restored!',
57
- globalThis.XMLHttpRequest.name
58
- )
59
- })
60
40
  }
61
41
  }
@@ -1,7 +1,6 @@
1
- import { invariant } from 'outvariant'
2
1
  import { until } from '@open-draft/until'
3
2
  import { DeferredPromise } from '@open-draft/deferred-promise'
4
- import { HttpRequestEventMap, IS_PATCHED_MODULE } from '../../glossary'
3
+ import { HttpRequestEventMap } from '../../glossary'
5
4
  import { Interceptor } from '../../Interceptor'
6
5
  import { RequestController } from '../../RequestController'
7
6
  import { emitAsync } from '../../utils/emitAsync'
@@ -12,9 +11,10 @@ import { createNetworkError } from './utils/createNetworkError'
12
11
  import { followFetchRedirect } from './utils/followRedirect'
13
12
  import { decompressResponse } from './utils/decompression'
14
13
  import { hasConfigurableGlobal } from '../../utils/hasConfigurableGlobal'
15
- import { FetchResponse } from '../../utils/fetchUtils'
14
+ import { FetchRequest, FetchResponse } from '../../utils/fetchUtils'
16
15
  import { setRawRequest } from '../../getRawRequest'
17
16
  import { isResponseError } from '../../utils/responseUtils'
17
+ import { globalsRegistry } from '../../utils/globalsRegistry'
18
18
 
19
19
  export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
20
20
  static symbol = Symbol('fetch')
@@ -28,14 +28,11 @@ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
28
28
  }
29
29
 
30
30
  protected async setup() {
31
- const pureFetch = globalThis.fetch
31
+ const logger = this.logger.extend('setup')
32
32
 
33
- invariant(
34
- !(pureFetch as any)[IS_PATCHED_MODULE],
35
- 'Failed to patch the "fetch" module: already patched.'
36
- )
33
+ const pureFetch = globalThis.fetch
37
34
 
38
- globalThis.fetch = async (input, init) => {
35
+ const fetchProxy: typeof fetch = async (input, init) => {
39
36
  const requestId = createRequestId()
40
37
 
41
38
  /**
@@ -51,7 +48,7 @@ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
51
48
  ? new URL(input, location.href)
52
49
  : input
53
50
 
54
- const request = new Request(resolvedInput, init)
51
+ const request = new FetchRequest(resolvedInput, init)
55
52
 
56
53
  /**
57
54
  * @note Set the raw request only if a Request instance was provided to fetch.
@@ -192,23 +189,10 @@ export class FetchInterceptor extends Interceptor<HttpRequestEventMap> {
192
189
  return responsePromise
193
190
  }
194
191
 
195
- Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {
196
- enumerable: true,
197
- configurable: true,
198
- value: true,
199
- })
200
-
201
- this.subscriptions.push(() => {
202
- Object.defineProperty(globalThis.fetch, IS_PATCHED_MODULE, {
203
- value: undefined,
204
- })
192
+ logger.info('patching global fetch...')
205
193
 
206
- globalThis.fetch = pureFetch
194
+ this.subscriptions.push(globalsRegistry.replaceGlobal('fetch', fetchProxy))
207
195
 
208
- this.logger.info(
209
- 'restored native "globalThis.fetch"!',
210
- globalThis.fetch.name
211
- )
212
- })
196
+ logger.info('global fetch patched!', globalThis.fetch.name)
213
197
  }
214
198
  }
@@ -0,0 +1,85 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { FetchRequest } from './fetchUtils'
3
+
4
+ describe('FetchRequest', () => {
5
+ const URL = 'https://example.com/'
6
+
7
+ it('passes instanceof check with the regular Request', () => {
8
+ expect(new FetchRequest(URL)).toBeInstanceOf(Request)
9
+ })
10
+
11
+ it('creates a request with a non-configurable method', () => {
12
+ expect
13
+ .soft(new FetchRequest(URL, { method: 'CONNECT' }))
14
+ .toHaveProperty('method', 'CONNECT')
15
+
16
+ expect
17
+ .soft(new FetchRequest(URL, { method: 'TRACE' }))
18
+ .toHaveProperty('method', 'TRACE')
19
+ expect
20
+ .soft(new FetchRequest(new FetchRequest(URL, { method: 'TRACE' })))
21
+ .toHaveProperty('method', 'TRACE')
22
+
23
+ expect
24
+ .soft(new FetchRequest(URL, { method: 'TRACK' }))
25
+ .toHaveProperty('method', 'TRACK')
26
+ expect
27
+ .soft(new FetchRequest(new FetchRequest(URL, { method: 'TRACK' })))
28
+ .toHaveProperty('method', 'TRACK')
29
+ })
30
+
31
+ it('creates a request with a non-configurable mode', () => {
32
+ expect
33
+ .soft(new FetchRequest(URL, { mode: 'navigate' }))
34
+ .toHaveProperty('mode', 'navigate')
35
+ expect
36
+ .soft(new FetchRequest(new FetchRequest(URL, { mode: 'navigate' })))
37
+ .toHaveProperty('mode', 'navigate')
38
+
39
+ expect
40
+ .soft(new FetchRequest(URL, { mode: 'websocket' }))
41
+ .toHaveProperty('mode', 'websocket')
42
+ expect
43
+ .soft(new FetchRequest(new FetchRequest(URL, { mode: 'websocket' })))
44
+ .toHaveProperty('mode', 'websocket')
45
+
46
+ expect
47
+ .soft(new FetchRequest(URL, { mode: 'webtransport' }))
48
+ .toHaveProperty('mode', 'webtransport')
49
+ expect
50
+ .soft(new FetchRequest(new FetchRequest(URL, { mode: 'webtransport' })))
51
+ .toHaveProperty('mode', 'webtransport')
52
+ })
53
+
54
+ it('ignores body for the requests without a body', () => {
55
+ expect
56
+ .soft(new FetchRequest(URL, { body: null }))
57
+ .toHaveProperty('body', null)
58
+ expect
59
+ .soft(new FetchRequest(URL, { body: undefined }))
60
+ .toHaveProperty('body', null)
61
+ expect
62
+ .soft(new FetchRequest(URL, { body: 'hello' }))
63
+ .toHaveProperty('body', null)
64
+
65
+ expect
66
+ .soft(new FetchRequest(URL, { method: 'GET', body: 'hello' }))
67
+ .toHaveProperty('body', null)
68
+ expect
69
+ .soft(new FetchRequest(URL, { method: 'HEAD', body: 'hello' }))
70
+ .toHaveProperty('body', null)
71
+ expect
72
+ .soft(new FetchRequest(URL, { method: 'CONNECT', body: 'hello' }))
73
+ .toHaveProperty('body', null)
74
+ expect
75
+ .soft(new FetchRequest(URL, { method: 'TRACE', body: 'hello' }))
76
+ .toHaveProperty('body', null)
77
+ expect
78
+ .soft(new FetchRequest(URL, { method: 'TRACK', body: 'hello' }))
79
+ .toHaveProperty('body', null)
80
+
81
+ expect
82
+ .soft(new FetchRequest(URL, { method: 'POST', body: 'hello' }))
83
+ .toHaveProperty('body', expect.any(ReadableStream))
84
+ })
85
+ })
@@ -1,11 +1,147 @@
1
1
  import { canParseUrl } from './canParseUrl'
2
2
  import { getValueBySymbol } from './getValueBySymbol'
3
3
 
4
+ interface UndiciRequestState extends RequestInit {}
5
+
6
+ interface FetchRequestInit extends Omit<RequestInit, 'mode'> {
7
+ mode?: RequestMode | 'websocket' | 'webtransport'
8
+ duplex?: 'half' | 'full'
9
+ }
10
+
11
+ export class FetchRequest extends Request {
12
+ static #resolveProperty<T extends keyof FetchRequestInit & keyof Request>(
13
+ input: RequestInfo | URL,
14
+ init: FetchRequestInit = {},
15
+ key: T
16
+ ): FetchRequestInit[T] {
17
+ return init[key] ?? (input instanceof Request ? input[key] : undefined)
18
+ }
19
+
20
+ /**
21
+ * Check if the given request method is configurable.
22
+ * @see https://fetch.spec.whatwg.org/#methods
23
+ */
24
+ static isConfigurableMethod(method: string): boolean {
25
+ return method !== 'CONNECT' && method !== 'TRACE' && method !== 'TRACK'
26
+ }
27
+
28
+ static isMethodWithBody(method: string): boolean {
29
+ return (
30
+ method !== 'HEAD' &&
31
+ method !== 'GET' &&
32
+ FetchRequest.isConfigurableMethod(method)
33
+ )
34
+ }
35
+
36
+ /**
37
+ * Check if the given request `mode` is configurable.
38
+ * @see https://fetch.spec.whatwg.org/#concept-request-mode
39
+ */
40
+ static isConfigurableMode(mode: string): boolean {
41
+ return (
42
+ mode !== 'navigate' && mode !== 'websocket' && mode !== 'webtransport'
43
+ )
44
+ }
45
+
46
+ constructor(input: URL | RequestInfo, init?: FetchRequestInit) {
47
+ const method = FetchRequest.#resolveProperty(input, init, 'method') || 'GET'
48
+ const safeMethod = FetchRequest.isConfigurableMethod(method)
49
+ ? method
50
+ : 'GET'
51
+
52
+ const hasExplicitBody = init != null && 'body' in init
53
+
54
+ /**
55
+ * Only include `body` in the super init when it needs to be overridden.
56
+ * When `input` is a Request and no explicit body is in `init`, let the
57
+ * Request constructor handle body transfer naturally so it properly
58
+ * marks the original request's body as consumed (bodyUsed = true).
59
+ */
60
+ const bodyInit: { body?: BodyInit | null } = !FetchRequest.isMethodWithBody(
61
+ method
62
+ )
63
+ ? { body: undefined }
64
+ : hasExplicitBody
65
+ ? { body: init.body }
66
+ : {}
67
+
68
+ const mode =
69
+ (FetchRequest.#resolveProperty(input, init, 'mode') as RequestMode) ??
70
+ undefined
71
+ const safeMode = FetchRequest.isConfigurableMode(mode) ? mode : undefined
72
+
73
+ super(input, {
74
+ ...(init || {}),
75
+ method: safeMethod,
76
+ mode: safeMode,
77
+ // @ts-expect-error Untyped Node.js property.
78
+ duplex:
79
+ init?.duplex ??
80
+ (FetchRequest.isMethodWithBody(method) ? 'half' : undefined),
81
+ ...bodyInit,
82
+ })
83
+
84
+ if (method !== safeMethod) {
85
+ this.#setInternalProperty('method', method)
86
+ }
87
+
88
+ if (method === 'CONNECT') {
89
+ const url = new URL(input instanceof Request ? input.url : input)
90
+
91
+ let authority: string
92
+
93
+ /**
94
+ * @note Node.js has a bug parsing raw CONNECT requests URLs like
95
+ * "http://127.0.0.1:1337/localhost:80". It would treat "localhost:" as a protocol.
96
+ */
97
+ if (url.protocol === 'localhost:') {
98
+ authority = url.href
99
+ } else {
100
+ authority = url.pathname.replace(/^\/+/, '')
101
+ }
102
+
103
+ /**
104
+ * @note Define "url" as a getter because Undici uses their own
105
+ * logic to resolve the "request.url" property. Simply reassigning
106
+ * its value doesn't do anything. This is a destructive action
107
+ * but it's safe because "CONNECT" requests are forbidden per fetch.
108
+ */
109
+ Object.defineProperty(this, 'url', {
110
+ get: () => authority,
111
+ enumerable: true,
112
+ configurable: true,
113
+ })
114
+ }
115
+
116
+ if (mode != null && mode !== safeMode) {
117
+ this.#setInternalProperty('mode', mode)
118
+ }
119
+ }
120
+
121
+ #setInternalProperty<T extends keyof Request>(
122
+ key: T,
123
+ value: Request[T]
124
+ ): void {
125
+ const internalState = getValueBySymbol<UndiciRequestState>('state', this)
126
+
127
+ if (internalState) {
128
+ Reflect.set(internalState, key, value)
129
+ } else {
130
+ Object.defineProperty(this, key, {
131
+ value,
132
+ enumerable: true,
133
+ configurable: true,
134
+ writable: false,
135
+ })
136
+ }
137
+ }
138
+ }
139
+
4
140
  export interface FetchResponseInit extends ResponseInit {
5
141
  url?: string
6
142
  }
7
143
 
8
- interface UndiciFetchInternalState {
144
+ interface UndiciResponseState {
9
145
  aborted: boolean
10
146
  rangeRequested: boolean
11
147
  timingAllowPassed: boolean
@@ -54,7 +190,7 @@ export class FetchResponse extends Response {
54
190
  return
55
191
  }
56
192
 
57
- const state = getValueBySymbol<UndiciFetchInternalState>('state', response)
193
+ const state = getValueBySymbol<UndiciResponseState>('state', response)
58
194
 
59
195
  if (state) {
60
196
  // In Undici, push the URL to the internal list of URLs.
@@ -100,7 +236,7 @@ export class FetchResponse extends Response {
100
236
  * @note Undici keeps an internal "Symbol(state)" that holds
101
237
  * the actual value of response status. Update that in Node.js.
102
238
  */
103
- const state = getValueBySymbol<UndiciFetchInternalState>('state', this)
239
+ const state = getValueBySymbol<UndiciResponseState>('state', this)
104
240
 
105
241
  if (state) {
106
242
  state.status = status