@mswjs/interceptors 0.33.3 → 0.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,6 @@
1
1
  import { ClientRequestInterceptor } from '../interceptors/ClientRequest/index.js';
2
2
  import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest/index.js';
3
+ import { FetchInterceptor } from '../interceptors/fetch/index.js';
3
4
  import '../Interceptor-a31b1217.js';
4
5
  import '@open-draft/deferred-promise';
5
6
  import '@open-draft/logger';
@@ -10,6 +11,6 @@ import 'node:net';
10
11
  * The default preset provisions the interception of requests
11
12
  * regardless of their type (http/https/XMLHttpRequest).
12
13
  */
13
- declare const _default: readonly [ClientRequestInterceptor, XMLHttpRequestInterceptor];
14
+ declare const _default: readonly [ClientRequestInterceptor, XMLHttpRequestInterceptor, FetchInterceptor];
14
15
 
15
16
  export { _default as default };
@@ -5,6 +5,9 @@ var _chunkI57YSVAVjs = require('../chunk-I57YSVAV.js');
5
5
 
6
6
  var _chunkT34TGCMRjs = require('../chunk-T34TGCMR.js');
7
7
  require('../chunk-LK6DILFK.js');
8
+
9
+
10
+ var _chunkUN335ZTDjs = require('../chunk-UN335ZTD.js');
8
11
  require('../chunk-IDEEMJ3F.js');
9
12
  require('../chunk-5WWNCLB3.js');
10
13
  require('../chunk-YGM3BCJU.js');
@@ -12,7 +15,8 @@ require('../chunk-YGM3BCJU.js');
12
15
  // src/presets/node.ts
13
16
  var node_default = [
14
17
  new (0, _chunkI57YSVAVjs.ClientRequestInterceptor)(),
15
- new (0, _chunkT34TGCMRjs.XMLHttpRequestInterceptor)()
18
+ new (0, _chunkT34TGCMRjs.XMLHttpRequestInterceptor)(),
19
+ new (0, _chunkUN335ZTDjs.FetchInterceptor)()
16
20
  ];
17
21
 
18
22
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presets/node.ts"],"names":[],"mappings":";;;;;;;;;;;;AAOA,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAChC","sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\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] as const\n"]}
1
+ {"version":3,"sources":["../../../src/presets/node.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAQA,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAAA,EAC9B,IAAI,iBAAiB;AACvB","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"]}
@@ -5,6 +5,9 @@ import {
5
5
  XMLHttpRequestInterceptor
6
6
  } from "../chunk-RJGP7FQP.mjs";
7
7
  import "../chunk-6HYIRFX2.mjs";
8
+ import {
9
+ FetchInterceptor
10
+ } from "../chunk-RTGLFNO3.mjs";
8
11
  import "../chunk-BZ3Y7YV5.mjs";
9
12
  import "../chunk-KY3RJ2M3.mjs";
10
13
  import "../chunk-BUCULLYM.mjs";
@@ -12,7 +15,8 @@ import "../chunk-BUCULLYM.mjs";
12
15
  // src/presets/node.ts
13
16
  var node_default = [
14
17
  new ClientRequestInterceptor(),
15
- new XMLHttpRequestInterceptor()
18
+ new XMLHttpRequestInterceptor(),
19
+ new FetchInterceptor()
16
20
  ];
17
21
  export {
18
22
  node_default as default
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/presets/node.ts"],"sourcesContent":["import { ClientRequestInterceptor } from '../interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'\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] as const\n"],"mappings":";;;;;;;;;;;;AAOA,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAChC;","names":[]}
1
+ {"version":3,"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,IAAO,eAAQ;AAAA,EACb,IAAI,yBAAyB;AAAA,EAC7B,IAAI,0BAA0B;AAAA,EAC9B,IAAI,iBAAiB;AACvB;","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mswjs/interceptors",
3
3
  "description": "Low-level HTTP/HTTPS/XHR/fetch request interception library.",
4
- "version": "0.33.3",
4
+ "version": "0.34.0",
5
5
  "main": "./lib/node/index.js",
6
6
  "module": "./lib/node/index.mjs",
7
7
  "types": "./lib/node/index.d.ts",
@@ -2,6 +2,7 @@ import { invariant } from 'outvariant'
2
2
  import type { WebSocketData } from './WebSocketTransport'
3
3
  import { bindEvent } from './utils/bindEvent'
4
4
  import { CloseEvent } from './utils/events'
5
+ import { DeferredPromise } from '@open-draft/deferred-promise'
5
6
 
6
7
  export type WebSocketEventListener<
7
8
  EventType extends WebSocketEventMap[keyof WebSocketEventMap] = Event
@@ -10,6 +11,7 @@ export type WebSocketEventListener<
10
11
  const WEBSOCKET_CLOSE_CODE_RANGE_ERROR =
11
12
  'InvalidAccessError: close code out of user configurable range'
12
13
 
14
+ export const kPassthroughPromise = Symbol('kPassthroughPromise')
13
15
  export const kOnSend = Symbol('kOnSend')
14
16
  export const kClose = Symbol('kClose')
15
17
 
@@ -37,6 +39,7 @@ export class WebSocketOverride extends EventTarget implements WebSocket {
37
39
  private _onerror: WebSocketEventListener | null = null
38
40
  private _onclose: WebSocketEventListener<CloseEvent> | null = null
39
41
 
42
+ private [kPassthroughPromise]: DeferredPromise<boolean>
40
43
  private [kOnSend]?: (data: WebSocketData) => void
41
44
 
42
45
  constructor(url: string | URL, protocols?: string | Array<string>) {
@@ -48,9 +51,15 @@ export class WebSocketOverride extends EventTarget implements WebSocket {
48
51
  this.readyState = this.CONNECTING
49
52
  this.bufferedAmount = 0
50
53
 
51
- Reflect.set(this, 'readyState', this.CONNECTING)
52
- queueMicrotask(() => {
53
- Reflect.set(this, 'readyState', this.OPEN)
54
+ this[kPassthroughPromise] = new DeferredPromise<boolean>()
55
+
56
+ queueMicrotask(async () => {
57
+ if (await this[kPassthroughPromise]) {
58
+ return
59
+ }
60
+
61
+ this.readyState = this.OPEN
62
+
54
63
  this.protocol =
55
64
  typeof protocols === 'string'
56
65
  ? protocols
@@ -151,26 +160,24 @@ export class WebSocketOverride extends EventTarget implements WebSocket {
151
160
  WEBSOCKET_CLOSE_CODE_RANGE_ERROR
152
161
  )
153
162
 
154
- if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {
155
- return
156
- }
157
-
158
163
  this[kClose](code, reason)
159
164
  }
160
165
 
161
166
  private [kClose](code: number = 1000, reason?: string): void {
167
+ /**
168
+ * @note Move this check here so that even internall closures,
169
+ * like those triggered by the `server` connection, are not
170
+ * performed twice.
171
+ */
172
+ if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {
173
+ return
174
+ }
175
+
162
176
  this.readyState = this.CLOSING
163
177
 
164
178
  queueMicrotask(() => {
165
179
  this.readyState = this.CLOSED
166
180
 
167
- // Non-user-configurable close status codes
168
- // represent connection termination and must
169
- // emit the "error" event before closing.
170
- if (code > 1000 && code <= 1015) {
171
- this.dispatchEvent(bindEvent(this, new Event('error')))
172
- }
173
-
174
181
  this.dispatchEvent(
175
182
  bindEvent(
176
183
  this,
@@ -5,7 +5,8 @@ import {
5
5
  } from './WebSocketClientConnection'
6
6
  import { WebSocketServerConnection } from './WebSocketServerConnection'
7
7
  import { WebSocketClassTransport } from './WebSocketClassTransport'
8
- import { WebSocketOverride } from './WebSocketOverride'
8
+ import { kPassthroughPromise, WebSocketOverride } from './WebSocketOverride'
9
+ import { bindEvent } from './utils/bindEvent'
9
10
 
10
11
  export { type WebSocketData, WebSocketTransport } from './WebSocketTransport'
11
12
  export {
@@ -82,20 +83,42 @@ export class WebSocketInterceptor extends Interceptor<WebSocketEventMap> {
82
83
  // so the client can modify WebSocket options, like "binaryType"
83
84
  // while the connection is already pending.
84
85
  queueMicrotask(() => {
86
+ const server = new WebSocketServerConnection(
87
+ socket,
88
+ transport,
89
+ createConnection
90
+ )
91
+
85
92
  // The "globalThis.WebSocket" class stands for
86
93
  // the client-side connection. Assume it's established
87
94
  // as soon as the WebSocket instance is constructed.
88
- this.emitter.emit('connection', {
95
+ const hasConnectionListeners = this.emitter.emit('connection', {
89
96
  client: new WebSocketClientConnection(socket, transport),
90
- server: new WebSocketServerConnection(
91
- socket,
92
- transport,
93
- createConnection
94
- ),
97
+ server,
95
98
  info: {
96
99
  protocols,
97
100
  },
98
101
  })
102
+
103
+ if (hasConnectionListeners) {
104
+ socket[kPassthroughPromise].resolve(false)
105
+ } else {
106
+ socket[kPassthroughPromise].resolve(true)
107
+
108
+ server.connect()
109
+
110
+ // Forward the "open" event from the original server
111
+ // to the mock WebSocket client in the case of a passthrough connection.
112
+ server.addEventListener('open', () => {
113
+ socket.dispatchEvent(bindEvent(socket, new Event('open')))
114
+
115
+ // Forward the original connection protocol to the
116
+ // mock WebSocket client.
117
+ if (server['realWebSocket']) {
118
+ socket.protocol = server['realWebSocket'].protocol
119
+ }
120
+ })
121
+ }
99
122
  })
100
123
 
101
124
  return socket
@@ -1,5 +1,6 @@
1
1
  import { ClientRequestInterceptor } from '../interceptors/ClientRequest'
2
2
  import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'
3
+ import { FetchInterceptor } from '../interceptors/fetch'
3
4
 
4
5
  /**
5
6
  * The default preset provisions the interception of requests
@@ -8,4 +9,5 @@ import { XMLHttpRequestInterceptor } from '../interceptors/XMLHttpRequest'
8
9
  export default [
9
10
  new ClientRequestInterceptor(),
10
11
  new XMLHttpRequestInterceptor(),
12
+ new FetchInterceptor(),
11
13
  ] as const