msw 2.14.4 → 2.14.6
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.
- package/lib/core/experimental/define-network.js +16 -6
- package/lib/core/experimental/define-network.js.map +1 -1
- package/lib/core/experimental/define-network.mjs +16 -6
- package/lib/core/experimental/define-network.mjs.map +1 -1
- package/lib/core/experimental/sources/interceptor-source.js +9 -0
- package/lib/core/experimental/sources/interceptor-source.js.map +1 -1
- package/lib/core/experimental/sources/interceptor-source.mjs +9 -0
- package/lib/core/experimental/sources/interceptor-source.mjs.map +1 -1
- package/lib/core/utils/internal/Disposable.js +19 -1
- package/lib/core/utils/internal/Disposable.js.map +1 -1
- package/lib/core/utils/internal/Disposable.mjs +19 -1
- package/lib/core/utils/internal/Disposable.mjs.map +1 -1
- package/lib/iife/index.js +42 -7
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +1 -1
- package/package.json +2 -2
- package/src/core/experimental/define-network.ts +30 -6
- package/src/core/experimental/sources/interceptor-source.ts +14 -0
- package/src/core/utils/internal/Disposable.ts +22 -1
|
@@ -29,6 +29,7 @@ var import_network_frame = require("./frames/network-frame");
|
|
|
29
29
|
var import_on_unhandled_frame = require("./on-unhandled-frame");
|
|
30
30
|
var import_handlers_controller = require("./handlers-controller");
|
|
31
31
|
var import_toReadonlyArray = require("../utils/internal/toReadonlyArray");
|
|
32
|
+
var import_Disposable = require("../utils/internal/Disposable");
|
|
32
33
|
function colorlessPromiseAll(values) {
|
|
33
34
|
const promises = [];
|
|
34
35
|
for (const value of values) {
|
|
@@ -49,6 +50,7 @@ var NetworkReadyState = /* @__PURE__ */ ((NetworkReadyState2) => {
|
|
|
49
50
|
function defineNetwork(options) {
|
|
50
51
|
let readyState = 0 /* DISABLED */;
|
|
51
52
|
const events = new import_rettime.Emitter();
|
|
53
|
+
const disposable = new import_Disposable.Disposable();
|
|
52
54
|
const deriveHandlersController = (handlers) => {
|
|
53
55
|
return handlers instanceof import_handlers_controller.HandlersController ? handlers : new import_handlers_controller.InMemoryHandlersController(handlers || []);
|
|
54
56
|
};
|
|
@@ -56,14 +58,16 @@ function defineNetwork(options) {
|
|
|
56
58
|
...options
|
|
57
59
|
};
|
|
58
60
|
let handlersController = deriveHandlersController(resolvedOptions.handlers);
|
|
59
|
-
let listenersController;
|
|
60
61
|
return {
|
|
61
62
|
get readyState() {
|
|
62
63
|
return readyState;
|
|
63
64
|
},
|
|
64
65
|
events,
|
|
65
66
|
configure(options2) {
|
|
66
|
-
(0, import_outvariant.invariant)(
|
|
67
|
+
(0, import_outvariant.invariant)(
|
|
68
|
+
readyState === 0 /* DISABLED */,
|
|
69
|
+
'Failed to call "configure()" on the network: cannot configure an already enabled network.'
|
|
70
|
+
);
|
|
67
71
|
if (options2.handlers && !Object.is(options2.handlers, resolvedOptions.handlers)) {
|
|
68
72
|
handlersController = deriveHandlersController(options2.handlers);
|
|
69
73
|
}
|
|
@@ -77,13 +81,19 @@ function defineNetwork(options) {
|
|
|
77
81
|
readyState === 0 /* DISABLED */,
|
|
78
82
|
'Failed to call "enable" on the network: already enabled'
|
|
79
83
|
);
|
|
80
|
-
listenersController = new AbortController();
|
|
81
84
|
readyState = 1 /* ENABLED */;
|
|
85
|
+
const session = { active: true };
|
|
86
|
+
disposable["subscriptions"].push(() => {
|
|
87
|
+
session.active = false;
|
|
88
|
+
});
|
|
82
89
|
const result = resolvedOptions.sources.map((source) => {
|
|
83
90
|
import_network_source.NetworkSource.prototype.disable.call(source);
|
|
84
91
|
source.on("frame", async ({ frame }) => {
|
|
85
|
-
frame.events.on("*", (event) =>
|
|
86
|
-
|
|
92
|
+
frame.events.on("*", (event) => {
|
|
93
|
+
if (!session.active) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
events.emit(event);
|
|
87
97
|
});
|
|
88
98
|
const handlers = frame.getHandlers(handlersController);
|
|
89
99
|
await frame.resolve(
|
|
@@ -101,8 +111,8 @@ function defineNetwork(options) {
|
|
|
101
111
|
readyState === 1 /* ENABLED */,
|
|
102
112
|
'Failed to call "disable" on the network: already disabled'
|
|
103
113
|
);
|
|
104
|
-
listenersController.abort();
|
|
105
114
|
readyState = 0 /* DISABLED */;
|
|
115
|
+
disposable.dispose();
|
|
106
116
|
return colorlessPromiseAll(
|
|
107
117
|
resolvedOptions.sources.map((source) => source.disable())
|
|
108
118
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/experimental/define-network.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter, type DefaultEventMap } from 'rettime'\nimport {\n NetworkSource,\n type ExtractSourceEvents,\n} from './sources/network-source'\nimport { type NetworkFrameResolutionContext } from './frames/network-frame'\nimport { type UnhandledFrameHandle } from './on-unhandled-frame'\nimport {\n HandlersController,\n InMemoryHandlersController,\n type AnyHandler,\n} from './handlers-controller'\nimport { toReadonlyArray } from '../utils/internal/toReadonlyArray'\n\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never\n\ntype MergeEventMaps<Sources extends Array<NetworkSource<any>>> =\n UnionToIntersection<ExtractSourceEvents<Sources[number]>> extends infer R\n ? R extends Record<string, any>\n ? R\n : DefaultEventMap\n : DefaultEventMap\n\ntype MaybePromise<T> =\n Extract<T, Promise<unknown>> extends never ? void : Promise<void>\n\nexport interface DefineNetworkOptions<\n Sources extends Array<NetworkSource<any>>,\n> {\n /**\n * List of the network sources.\n * Every network source emits frames, and every frame describes how\n * to handle the various network scenarios, like mocking a response,\n * erroring the request, or performing it as-is.\n */\n sources: Sources\n /**\n * List of handlers to describe the network.\n */\n handlers?: Array<AnyHandler> | HandlersController\n context?: NetworkFrameResolutionContext\n onUnhandledFrame?: UnhandledFrameHandle\n}\n\nexport interface NetworkApi<\n Sources extends Array<NetworkSource<any>>,\n> extends NetworkHandlersApi {\n readyState: NetworkReadyState\n /**\n * Enable the network interception and handling.\n */\n enable: () => MaybePromise<ReturnType<Sources[number]['enable']>>\n /**\n * Disable the network interception and handling.\n */\n disable: () => MaybePromise<ReturnType<Sources[number]['disable']>>\n /**\n * Configure the network instance with additional options.\n * The options provided in the `.configure()` call will override the same\n * options in the `defineNetwork()` call.\n */\n configure: (options: Partial<DefineNetworkOptions<Sources>>) => void\n events: Emitter<MergeEventMaps<Sources>>\n}\n\nexport interface NetworkHandlersApi {\n use: (...handlers: Array<AnyHandler>) => void\n resetHandlers: (...handlers: Array<AnyHandler>) => void\n restoreHandlers: () => void\n listHandlers: () => ReadonlyArray<AnyHandler>\n}\n\nfunction colorlessPromiseAll<T>(values: Array<T>): MaybePromise<T>\nfunction colorlessPromiseAll(values: Array<unknown>): Promise<void> | void {\n const promises: Array<Promise<void>> = []\n\n for (const value of values) {\n if (value instanceof Promise) {\n promises.push(value)\n }\n }\n\n if (promises.length > 0) {\n return Promise.all(promises).then(() => {})\n }\n}\n\nexport enum NetworkReadyState {\n DISABLED,\n ENABLED,\n}\n\n/**\n * Define a network instance with the given configuration.\n * @example\n * import { InterceptorSource } from 'msw/experimental'\n * import { handlers } from './handlers'\n *\n * const network = defineNetwork({\n * sources: [new InterceptorSource({ interceptors })],\n * handlers,\n * })\n * await network.enable()\n */\nexport function defineNetwork<Sources extends Array<NetworkSource<any>>>(\n options: DefineNetworkOptions<Sources>,\n): NetworkApi<Sources> {\n let readyState: NetworkReadyState = NetworkReadyState.DISABLED\n const events = new Emitter<MergeEventMaps<Sources>>()\n\n const deriveHandlersController = (\n handlers: DefineNetworkOptions<Sources>['handlers'],\n ) => {\n return handlers instanceof HandlersController\n ? handlers\n : new InMemoryHandlersController(handlers || [])\n }\n\n let resolvedOptions: DefineNetworkOptions<Sources> = {\n ...options,\n }\n\n /**\n * @note Create the handlers controller immediately because\n * certain setup APIs, like `setupServer`, don't await `.enable` (`.listen`).\n */\n let handlersController = deriveHandlersController(resolvedOptions.handlers)\n
|
|
1
|
+
{"version":3,"sources":["../../../src/core/experimental/define-network.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter, type DefaultEventMap } from 'rettime'\nimport {\n NetworkSource,\n type ExtractSourceEvents,\n} from './sources/network-source'\nimport { type NetworkFrameResolutionContext } from './frames/network-frame'\nimport { type UnhandledFrameHandle } from './on-unhandled-frame'\nimport {\n HandlersController,\n InMemoryHandlersController,\n type AnyHandler,\n} from './handlers-controller'\nimport { toReadonlyArray } from '../utils/internal/toReadonlyArray'\nimport { Disposable } from '../utils/internal/Disposable'\n\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never\n\ntype MergeEventMaps<Sources extends Array<NetworkSource<any>>> =\n UnionToIntersection<ExtractSourceEvents<Sources[number]>> extends infer R\n ? R extends Record<string, any>\n ? R\n : DefaultEventMap\n : DefaultEventMap\n\ntype MaybePromise<T> =\n Extract<T, Promise<unknown>> extends never ? void : Promise<void>\n\nexport interface DefineNetworkOptions<\n Sources extends Array<NetworkSource<any>>,\n> {\n /**\n * List of the network sources.\n * Every network source emits frames, and every frame describes how\n * to handle the various network scenarios, like mocking a response,\n * erroring the request, or performing it as-is.\n */\n sources: Sources\n /**\n * List of handlers to describe the network.\n */\n handlers?: Array<AnyHandler> | HandlersController\n context?: NetworkFrameResolutionContext\n onUnhandledFrame?: UnhandledFrameHandle\n}\n\nexport interface NetworkApi<\n Sources extends Array<NetworkSource<any>>,\n> extends NetworkHandlersApi {\n readyState: NetworkReadyState\n /**\n * Enable the network interception and handling.\n */\n enable: () => MaybePromise<ReturnType<Sources[number]['enable']>>\n /**\n * Disable the network interception and handling.\n */\n disable: () => MaybePromise<ReturnType<Sources[number]['disable']>>\n /**\n * Configure the network instance with additional options.\n * The options provided in the `.configure()` call will override the same\n * options in the `defineNetwork()` call.\n */\n configure: (options: Partial<DefineNetworkOptions<Sources>>) => void\n events: Emitter<MergeEventMaps<Sources>>\n}\n\nexport interface NetworkHandlersApi {\n use: (...handlers: Array<AnyHandler>) => void\n resetHandlers: (...handlers: Array<AnyHandler>) => void\n restoreHandlers: () => void\n listHandlers: () => ReadonlyArray<AnyHandler>\n}\n\nfunction colorlessPromiseAll<T>(values: Array<T>): MaybePromise<T>\nfunction colorlessPromiseAll(values: Array<unknown>): Promise<void> | void {\n const promises: Array<Promise<void>> = []\n\n for (const value of values) {\n if (value instanceof Promise) {\n promises.push(value)\n }\n }\n\n if (promises.length > 0) {\n return Promise.all(promises).then(() => {})\n }\n}\n\nexport enum NetworkReadyState {\n DISABLED,\n ENABLED,\n}\n\n/**\n * Define a network instance with the given configuration.\n * @example\n * import { InterceptorSource } from 'msw/experimental'\n * import { handlers } from './handlers'\n *\n * const network = defineNetwork({\n * sources: [new InterceptorSource({ interceptors })],\n * handlers,\n * })\n * await network.enable()\n */\nexport function defineNetwork<Sources extends Array<NetworkSource<any>>>(\n options: DefineNetworkOptions<Sources>,\n): NetworkApi<Sources> {\n let readyState: NetworkReadyState = NetworkReadyState.DISABLED\n const events = new Emitter<MergeEventMaps<Sources>>()\n const disposable = new Disposable()\n\n const deriveHandlersController = (\n handlers: DefineNetworkOptions<Sources>['handlers'],\n ) => {\n return handlers instanceof HandlersController\n ? handlers\n : new InMemoryHandlersController(handlers || [])\n }\n\n let resolvedOptions: DefineNetworkOptions<Sources> = {\n ...options,\n }\n\n /**\n * @note Create the handlers controller immediately because\n * certain setup APIs, like `setupServer`, don't await `.enable` (`.listen`).\n */\n let handlersController = deriveHandlersController(resolvedOptions.handlers)\n\n return {\n get readyState() {\n return readyState\n },\n events,\n configure(options) {\n invariant(\n readyState === NetworkReadyState.DISABLED,\n 'Failed to call \"configure()\" on the network: cannot configure an already enabled network.',\n )\n\n if (\n options.handlers &&\n !Object.is(options.handlers, resolvedOptions.handlers)\n ) {\n handlersController = deriveHandlersController(options.handlers)\n }\n\n resolvedOptions = {\n ...resolvedOptions,\n ...options,\n }\n },\n enable() {\n invariant(\n readyState === NetworkReadyState.DISABLED,\n 'Failed to call \"enable\" on the network: already enabled',\n )\n\n readyState = NetworkReadyState.ENABLED\n\n /**\n * @note Use a session object scoped to the current \"enable()\"\n * to prevent \"frame.events\" listeners from surviving across enable/disable cycles.\n * @see The note about `AbortController` below.\n */\n const session = { active: true }\n disposable['subscriptions'].push(() => {\n session.active = false\n })\n\n const result = resolvedOptions.sources.map((source) => {\n /**\n * @note Preemptively disable the network source before enabling.\n * This intentionally calls only the prototype method that clears the\n * event listeners and nothing else. This prevents the \"frame\" listeners\n * from accumulating across enable/disable in case the source is a singleton.\n */\n NetworkSource.prototype.disable.call(source)\n\n source.on('frame', async ({ frame }) => {\n frame.events.on('*', (event) => {\n /**\n * @note Prevent event forwarding manually and not via an AbortController\n * because certain runtimes, like Cloudflare, throw when referencing an\n * AbortController created in a different context. Bear in mind that the frame\n * events run in the patched request client context while the AbortController\n * is created outside, in the \"defineNetwork\" closure, which is a test context.\n */\n if (!session.active) {\n return\n }\n\n events.emit(event)\n })\n\n const handlers = frame.getHandlers(handlersController)\n\n await frame.resolve(\n handlers,\n resolvedOptions.onUnhandledFrame || 'warn',\n resolvedOptions.context,\n )\n })\n\n return source.enable()\n })\n\n return colorlessPromiseAll(result) as MaybePromise<\n ReturnType<Sources[number]['enable']>\n >\n },\n disable() {\n invariant(\n readyState === NetworkReadyState.ENABLED,\n 'Failed to call \"disable\" on the network: already disabled',\n )\n\n readyState = NetworkReadyState.DISABLED\n disposable.dispose()\n\n return colorlessPromiseAll(\n resolvedOptions.sources.map((source) => source.disable()),\n ) as MaybePromise<ReturnType<Sources[number]['disable']>>\n },\n use(...handlers) {\n handlersController.use(handlers)\n },\n resetHandlers(...handlers) {\n handlersController.reset(handlers)\n },\n restoreHandlers() {\n handlersController.restore()\n },\n listHandlers() {\n return toReadonlyArray(handlersController.currentHandlers())\n },\n }\n}\n"],"mappings":"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","names":["NetworkReadyState","options"]}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
InMemoryHandlersController
|
|
11
11
|
} from './handlers-controller.mjs';
|
|
12
12
|
import { toReadonlyArray } from '../utils/internal/toReadonlyArray.mjs';
|
|
13
|
+
import { Disposable } from '../utils/internal/Disposable.mjs';
|
|
13
14
|
function colorlessPromiseAll(values) {
|
|
14
15
|
const promises = [];
|
|
15
16
|
for (const value of values) {
|
|
@@ -30,6 +31,7 @@ var NetworkReadyState = /* @__PURE__ */ ((NetworkReadyState2) => {
|
|
|
30
31
|
function defineNetwork(options) {
|
|
31
32
|
let readyState = 0 /* DISABLED */;
|
|
32
33
|
const events = new Emitter();
|
|
34
|
+
const disposable = new Disposable();
|
|
33
35
|
const deriveHandlersController = (handlers) => {
|
|
34
36
|
return handlers instanceof HandlersController ? handlers : new InMemoryHandlersController(handlers || []);
|
|
35
37
|
};
|
|
@@ -37,14 +39,16 @@ function defineNetwork(options) {
|
|
|
37
39
|
...options
|
|
38
40
|
};
|
|
39
41
|
let handlersController = deriveHandlersController(resolvedOptions.handlers);
|
|
40
|
-
let listenersController;
|
|
41
42
|
return {
|
|
42
43
|
get readyState() {
|
|
43
44
|
return readyState;
|
|
44
45
|
},
|
|
45
46
|
events,
|
|
46
47
|
configure(options2) {
|
|
47
|
-
invariant(
|
|
48
|
+
invariant(
|
|
49
|
+
readyState === 0 /* DISABLED */,
|
|
50
|
+
'Failed to call "configure()" on the network: cannot configure an already enabled network.'
|
|
51
|
+
);
|
|
48
52
|
if (options2.handlers && !Object.is(options2.handlers, resolvedOptions.handlers)) {
|
|
49
53
|
handlersController = deriveHandlersController(options2.handlers);
|
|
50
54
|
}
|
|
@@ -58,13 +62,19 @@ function defineNetwork(options) {
|
|
|
58
62
|
readyState === 0 /* DISABLED */,
|
|
59
63
|
'Failed to call "enable" on the network: already enabled'
|
|
60
64
|
);
|
|
61
|
-
listenersController = new AbortController();
|
|
62
65
|
readyState = 1 /* ENABLED */;
|
|
66
|
+
const session = { active: true };
|
|
67
|
+
disposable["subscriptions"].push(() => {
|
|
68
|
+
session.active = false;
|
|
69
|
+
});
|
|
63
70
|
const result = resolvedOptions.sources.map((source) => {
|
|
64
71
|
NetworkSource.prototype.disable.call(source);
|
|
65
72
|
source.on("frame", async ({ frame }) => {
|
|
66
|
-
frame.events.on("*", (event) =>
|
|
67
|
-
|
|
73
|
+
frame.events.on("*", (event) => {
|
|
74
|
+
if (!session.active) {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
events.emit(event);
|
|
68
78
|
});
|
|
69
79
|
const handlers = frame.getHandlers(handlersController);
|
|
70
80
|
await frame.resolve(
|
|
@@ -82,8 +92,8 @@ function defineNetwork(options) {
|
|
|
82
92
|
readyState === 1 /* ENABLED */,
|
|
83
93
|
'Failed to call "disable" on the network: already disabled'
|
|
84
94
|
);
|
|
85
|
-
listenersController.abort();
|
|
86
95
|
readyState = 0 /* DISABLED */;
|
|
96
|
+
disposable.dispose();
|
|
87
97
|
return colorlessPromiseAll(
|
|
88
98
|
resolvedOptions.sources.map((source) => source.disable())
|
|
89
99
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/experimental/define-network.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter, type DefaultEventMap } from 'rettime'\nimport {\n NetworkSource,\n type ExtractSourceEvents,\n} from './sources/network-source'\nimport { type NetworkFrameResolutionContext } from './frames/network-frame'\nimport { type UnhandledFrameHandle } from './on-unhandled-frame'\nimport {\n HandlersController,\n InMemoryHandlersController,\n type AnyHandler,\n} from './handlers-controller'\nimport { toReadonlyArray } from '../utils/internal/toReadonlyArray'\n\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never\n\ntype MergeEventMaps<Sources extends Array<NetworkSource<any>>> =\n UnionToIntersection<ExtractSourceEvents<Sources[number]>> extends infer R\n ? R extends Record<string, any>\n ? R\n : DefaultEventMap\n : DefaultEventMap\n\ntype MaybePromise<T> =\n Extract<T, Promise<unknown>> extends never ? void : Promise<void>\n\nexport interface DefineNetworkOptions<\n Sources extends Array<NetworkSource<any>>,\n> {\n /**\n * List of the network sources.\n * Every network source emits frames, and every frame describes how\n * to handle the various network scenarios, like mocking a response,\n * erroring the request, or performing it as-is.\n */\n sources: Sources\n /**\n * List of handlers to describe the network.\n */\n handlers?: Array<AnyHandler> | HandlersController\n context?: NetworkFrameResolutionContext\n onUnhandledFrame?: UnhandledFrameHandle\n}\n\nexport interface NetworkApi<\n Sources extends Array<NetworkSource<any>>,\n> extends NetworkHandlersApi {\n readyState: NetworkReadyState\n /**\n * Enable the network interception and handling.\n */\n enable: () => MaybePromise<ReturnType<Sources[number]['enable']>>\n /**\n * Disable the network interception and handling.\n */\n disable: () => MaybePromise<ReturnType<Sources[number]['disable']>>\n /**\n * Configure the network instance with additional options.\n * The options provided in the `.configure()` call will override the same\n * options in the `defineNetwork()` call.\n */\n configure: (options: Partial<DefineNetworkOptions<Sources>>) => void\n events: Emitter<MergeEventMaps<Sources>>\n}\n\nexport interface NetworkHandlersApi {\n use: (...handlers: Array<AnyHandler>) => void\n resetHandlers: (...handlers: Array<AnyHandler>) => void\n restoreHandlers: () => void\n listHandlers: () => ReadonlyArray<AnyHandler>\n}\n\nfunction colorlessPromiseAll<T>(values: Array<T>): MaybePromise<T>\nfunction colorlessPromiseAll(values: Array<unknown>): Promise<void> | void {\n const promises: Array<Promise<void>> = []\n\n for (const value of values) {\n if (value instanceof Promise) {\n promises.push(value)\n }\n }\n\n if (promises.length > 0) {\n return Promise.all(promises).then(() => {})\n }\n}\n\nexport enum NetworkReadyState {\n DISABLED,\n ENABLED,\n}\n\n/**\n * Define a network instance with the given configuration.\n * @example\n * import { InterceptorSource } from 'msw/experimental'\n * import { handlers } from './handlers'\n *\n * const network = defineNetwork({\n * sources: [new InterceptorSource({ interceptors })],\n * handlers,\n * })\n * await network.enable()\n */\nexport function defineNetwork<Sources extends Array<NetworkSource<any>>>(\n options: DefineNetworkOptions<Sources>,\n): NetworkApi<Sources> {\n let readyState: NetworkReadyState = NetworkReadyState.DISABLED\n const events = new Emitter<MergeEventMaps<Sources>>()\n\n const deriveHandlersController = (\n handlers: DefineNetworkOptions<Sources>['handlers'],\n ) => {\n return handlers instanceof HandlersController\n ? handlers\n : new InMemoryHandlersController(handlers || [])\n }\n\n let resolvedOptions: DefineNetworkOptions<Sources> = {\n ...options,\n }\n\n /**\n * @note Create the handlers controller immediately because\n * certain setup APIs, like `setupServer`, don't await `.enable` (`.listen`).\n */\n let handlersController = deriveHandlersController(resolvedOptions.handlers)\n
|
|
1
|
+
{"version":3,"sources":["../../../src/core/experimental/define-network.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport { Emitter, type DefaultEventMap } from 'rettime'\nimport {\n NetworkSource,\n type ExtractSourceEvents,\n} from './sources/network-source'\nimport { type NetworkFrameResolutionContext } from './frames/network-frame'\nimport { type UnhandledFrameHandle } from './on-unhandled-frame'\nimport {\n HandlersController,\n InMemoryHandlersController,\n type AnyHandler,\n} from './handlers-controller'\nimport { toReadonlyArray } from '../utils/internal/toReadonlyArray'\nimport { Disposable } from '../utils/internal/Disposable'\n\ntype UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never\n\ntype MergeEventMaps<Sources extends Array<NetworkSource<any>>> =\n UnionToIntersection<ExtractSourceEvents<Sources[number]>> extends infer R\n ? R extends Record<string, any>\n ? R\n : DefaultEventMap\n : DefaultEventMap\n\ntype MaybePromise<T> =\n Extract<T, Promise<unknown>> extends never ? void : Promise<void>\n\nexport interface DefineNetworkOptions<\n Sources extends Array<NetworkSource<any>>,\n> {\n /**\n * List of the network sources.\n * Every network source emits frames, and every frame describes how\n * to handle the various network scenarios, like mocking a response,\n * erroring the request, or performing it as-is.\n */\n sources: Sources\n /**\n * List of handlers to describe the network.\n */\n handlers?: Array<AnyHandler> | HandlersController\n context?: NetworkFrameResolutionContext\n onUnhandledFrame?: UnhandledFrameHandle\n}\n\nexport interface NetworkApi<\n Sources extends Array<NetworkSource<any>>,\n> extends NetworkHandlersApi {\n readyState: NetworkReadyState\n /**\n * Enable the network interception and handling.\n */\n enable: () => MaybePromise<ReturnType<Sources[number]['enable']>>\n /**\n * Disable the network interception and handling.\n */\n disable: () => MaybePromise<ReturnType<Sources[number]['disable']>>\n /**\n * Configure the network instance with additional options.\n * The options provided in the `.configure()` call will override the same\n * options in the `defineNetwork()` call.\n */\n configure: (options: Partial<DefineNetworkOptions<Sources>>) => void\n events: Emitter<MergeEventMaps<Sources>>\n}\n\nexport interface NetworkHandlersApi {\n use: (...handlers: Array<AnyHandler>) => void\n resetHandlers: (...handlers: Array<AnyHandler>) => void\n restoreHandlers: () => void\n listHandlers: () => ReadonlyArray<AnyHandler>\n}\n\nfunction colorlessPromiseAll<T>(values: Array<T>): MaybePromise<T>\nfunction colorlessPromiseAll(values: Array<unknown>): Promise<void> | void {\n const promises: Array<Promise<void>> = []\n\n for (const value of values) {\n if (value instanceof Promise) {\n promises.push(value)\n }\n }\n\n if (promises.length > 0) {\n return Promise.all(promises).then(() => {})\n }\n}\n\nexport enum NetworkReadyState {\n DISABLED,\n ENABLED,\n}\n\n/**\n * Define a network instance with the given configuration.\n * @example\n * import { InterceptorSource } from 'msw/experimental'\n * import { handlers } from './handlers'\n *\n * const network = defineNetwork({\n * sources: [new InterceptorSource({ interceptors })],\n * handlers,\n * })\n * await network.enable()\n */\nexport function defineNetwork<Sources extends Array<NetworkSource<any>>>(\n options: DefineNetworkOptions<Sources>,\n): NetworkApi<Sources> {\n let readyState: NetworkReadyState = NetworkReadyState.DISABLED\n const events = new Emitter<MergeEventMaps<Sources>>()\n const disposable = new Disposable()\n\n const deriveHandlersController = (\n handlers: DefineNetworkOptions<Sources>['handlers'],\n ) => {\n return handlers instanceof HandlersController\n ? handlers\n : new InMemoryHandlersController(handlers || [])\n }\n\n let resolvedOptions: DefineNetworkOptions<Sources> = {\n ...options,\n }\n\n /**\n * @note Create the handlers controller immediately because\n * certain setup APIs, like `setupServer`, don't await `.enable` (`.listen`).\n */\n let handlersController = deriveHandlersController(resolvedOptions.handlers)\n\n return {\n get readyState() {\n return readyState\n },\n events,\n configure(options) {\n invariant(\n readyState === NetworkReadyState.DISABLED,\n 'Failed to call \"configure()\" on the network: cannot configure an already enabled network.',\n )\n\n if (\n options.handlers &&\n !Object.is(options.handlers, resolvedOptions.handlers)\n ) {\n handlersController = deriveHandlersController(options.handlers)\n }\n\n resolvedOptions = {\n ...resolvedOptions,\n ...options,\n }\n },\n enable() {\n invariant(\n readyState === NetworkReadyState.DISABLED,\n 'Failed to call \"enable\" on the network: already enabled',\n )\n\n readyState = NetworkReadyState.ENABLED\n\n /**\n * @note Use a session object scoped to the current \"enable()\"\n * to prevent \"frame.events\" listeners from surviving across enable/disable cycles.\n * @see The note about `AbortController` below.\n */\n const session = { active: true }\n disposable['subscriptions'].push(() => {\n session.active = false\n })\n\n const result = resolvedOptions.sources.map((source) => {\n /**\n * @note Preemptively disable the network source before enabling.\n * This intentionally calls only the prototype method that clears the\n * event listeners and nothing else. This prevents the \"frame\" listeners\n * from accumulating across enable/disable in case the source is a singleton.\n */\n NetworkSource.prototype.disable.call(source)\n\n source.on('frame', async ({ frame }) => {\n frame.events.on('*', (event) => {\n /**\n * @note Prevent event forwarding manually and not via an AbortController\n * because certain runtimes, like Cloudflare, throw when referencing an\n * AbortController created in a different context. Bear in mind that the frame\n * events run in the patched request client context while the AbortController\n * is created outside, in the \"defineNetwork\" closure, which is a test context.\n */\n if (!session.active) {\n return\n }\n\n events.emit(event)\n })\n\n const handlers = frame.getHandlers(handlersController)\n\n await frame.resolve(\n handlers,\n resolvedOptions.onUnhandledFrame || 'warn',\n resolvedOptions.context,\n )\n })\n\n return source.enable()\n })\n\n return colorlessPromiseAll(result) as MaybePromise<\n ReturnType<Sources[number]['enable']>\n >\n },\n disable() {\n invariant(\n readyState === NetworkReadyState.ENABLED,\n 'Failed to call \"disable\" on the network: already disabled',\n )\n\n readyState = NetworkReadyState.DISABLED\n disposable.dispose()\n\n return colorlessPromiseAll(\n resolvedOptions.sources.map((source) => source.disable()),\n ) as MaybePromise<ReturnType<Sources[number]['disable']>>\n },\n use(...handlers) {\n handlersController.use(handlers)\n },\n resetHandlers(...handlers) {\n handlersController.reset(handlers)\n },\n restoreHandlers() {\n handlersController.restore()\n },\n listHandlers() {\n return toReadonlyArray(handlersController.currentHandlers())\n },\n }\n}\n"],"mappings":"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","names":["NetworkReadyState","options"]}
|
|
@@ -126,6 +126,15 @@ class InterceptorHttpNetworkFrame extends import_http_frame.HttpNetworkFrame {
|
|
|
126
126
|
class InterceptorWebSocketNetworkFrame extends import_websocket_frame.WebSocketNetworkFrame {
|
|
127
127
|
constructor(args) {
|
|
128
128
|
super({ connection: args.connection });
|
|
129
|
+
args.connection.client.addEventListener(
|
|
130
|
+
"close",
|
|
131
|
+
() => {
|
|
132
|
+
this.events.removeAllListeners();
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
once: true
|
|
136
|
+
}
|
|
137
|
+
);
|
|
129
138
|
}
|
|
130
139
|
errorWith(reason) {
|
|
131
140
|
if (reason instanceof Error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/experimental/sources/interceptor-source.ts"],"sourcesContent":["import type { Interceptor, RequestController } from '@mswjs/interceptors'\nimport { BatchInterceptor, type HttpRequestEventMap } from '@mswjs/interceptors'\nimport type {\n WebSocketConnectionData,\n WebSocketEventMap,\n} from '@mswjs/interceptors/WebSocket'\nimport { NetworkSource } from './network-source'\nimport { InternalError } from '../../utils/internal/devUtils'\nimport { HttpNetworkFrame, ResponseEvent } from '../frames/http-frame'\nimport { WebSocketNetworkFrame } from '../frames/websocket-frame'\nimport { deleteRequestPassthroughHeader } from '../request-utils'\n\nexport interface InterceptorSourceOptions {\n interceptors: Array<Interceptor<HttpRequestEventMap | WebSocketEventMap>>\n}\n\n/**\n * Create a network source from the given list of interceptors.\n */\nexport class InterceptorSource extends NetworkSource {\n #interceptor: BatchInterceptor<\n InterceptorSourceOptions['interceptors'],\n HttpRequestEventMap | WebSocketEventMap\n >\n\n #frames: Map<string, HttpNetworkFrame>\n\n constructor(options: InterceptorSourceOptions) {\n super()\n\n this.#interceptor = new BatchInterceptor({\n name: 'interceptor-source',\n interceptors: options.interceptors,\n })\n this.#frames = new Map()\n }\n\n public enable(): void {\n this.#interceptor.apply()\n\n /**\n * @todo @fixme BatchInterceptor infers event types but not listener types.\n */\n this.#interceptor\n .on('request', this.#handleRequest.bind(this) as any)\n .on('response', this.#handleResponse.bind(this) as any)\n .on('connection', this.#handleWebSocketConnection.bind(this) as any)\n }\n\n public disable(): void {\n super.disable()\n this.#interceptor.dispose()\n\n /**\n * @todo We can also abort any pending frames here, given we implement\n * the `NetworkFrame.abort()` method.\n */\n this.#frames.clear()\n }\n\n async #handleRequest({\n requestId,\n request,\n controller,\n }: HttpRequestEventMap['request'][0]): Promise<void> {\n const httpFrame = new InterceptorHttpNetworkFrame({\n id: requestId,\n request,\n controller,\n })\n\n this.#frames.set(requestId, httpFrame)\n await this.queue(httpFrame)\n }\n\n async #handleResponse({\n requestId,\n request,\n response,\n isMockedResponse,\n }: HttpRequestEventMap['response'][0]): Promise<void> {\n const httpFrame = this.#frames.get(requestId)\n this.#frames.delete(requestId)\n\n if (httpFrame == null) {\n return\n }\n\n queueMicrotask(() => {\n try {\n httpFrame.events.emit(\n new ResponseEvent(\n isMockedResponse ? 'response:mocked' : 'response:bypass',\n {\n requestId,\n request,\n response,\n },\n ),\n )\n } finally {\n /**\n * @note Remove any listeners from this frame.\n * Past this point, it won't emit anything. The removal is crucial\n * to prevent \"rettime\" from keeping the abort cleanup listeners internally.\n * @see https://github.com/mswjs/msw/issues/2735\n */\n httpFrame.events.removeAllListeners()\n }\n })\n }\n\n async #handleWebSocketConnection(\n connection: WebSocketEventMap['connection'][0],\n ): Promise<void> {\n await this.queue(\n new InterceptorWebSocketNetworkFrame({\n connection,\n }),\n )\n }\n}\n\nclass InterceptorHttpNetworkFrame extends HttpNetworkFrame {\n #controller: RequestController\n\n constructor(options: {\n id: string\n request: Request\n controller: RequestController\n }) {\n super({\n id: options.id,\n request: options.request,\n })\n\n this.#controller = options.controller\n }\n\n public passthrough(): void {\n deleteRequestPassthroughHeader(this.data.request)\n }\n\n public respondWith(response?: Response): void {\n if (response) {\n this.#controller.respondWith(response)\n }\n }\n\n public errorWith(reason?: unknown): void {\n if (reason instanceof Response) {\n return this.respondWith(reason)\n }\n\n if (reason instanceof InternalError) {\n this.#controller.errorWith(reason)\n }\n\n throw reason\n }\n}\n\nclass InterceptorWebSocketNetworkFrame extends WebSocketNetworkFrame {\n constructor(args: { connection: WebSocketConnectionData }) {\n super({ connection: args.connection })\n }\n\n public errorWith(reason?: unknown): void {\n if (reason instanceof Error) {\n const { client } = this.data.connection\n\n /**\n * Use `client.errorWith(reason)` in the future.\n * @see https://github.com/mswjs/interceptors/issues/747\n */\n const errorEvent = new Event('error')\n\n Object.defineProperty(errorEvent, 'cause', {\n enumerable: true,\n configurable: false,\n value: reason,\n })\n\n client.socket.dispatchEvent(errorEvent)\n }\n }\n\n public passthrough() {\n this.data.connection.server.connect()\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAA2D;AAK3D,4BAA8B;AAC9B,sBAA8B;AAC9B,wBAAgD;AAChD,6BAAsC;AACtC,2BAA+C;AASxC,MAAM,0BAA0B,oCAAc;AAAA,EACnD;AAAA,EAKA;AAAA,EAEA,YAAY,SAAmC;AAC7C,UAAM;AAEN,SAAK,eAAe,IAAI,qCAAiB;AAAA,MACvC,MAAM;AAAA,MACN,cAAc,QAAQ;AAAA,IACxB,CAAC;AACD,SAAK,UAAU,oBAAI,IAAI;AAAA,EACzB;AAAA,EAEO,SAAe;AACpB,SAAK,aAAa,MAAM;AAKxB,SAAK,aACF,GAAG,WAAW,KAAK,eAAe,KAAK,IAAI,CAAQ,EACnD,GAAG,YAAY,KAAK,gBAAgB,KAAK,IAAI,CAAQ,EACrD,GAAG,cAAc,KAAK,2BAA2B,KAAK,IAAI,CAAQ;AAAA,EACvE;AAAA,EAEO,UAAgB;AACrB,UAAM,QAAQ;AACd,SAAK,aAAa,QAAQ;AAM1B,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,MAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAqD;AACnD,UAAM,YAAY,IAAI,4BAA4B;AAAA,MAChD,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,IAAI,WAAW,SAAS;AACrC,UAAM,KAAK,MAAM,SAAS;AAAA,EAC5B;AAAA,EAEA,MAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAsD;AACpD,UAAM,YAAY,KAAK,QAAQ,IAAI,SAAS;AAC5C,SAAK,QAAQ,OAAO,SAAS;AAE7B,QAAI,aAAa,MAAM;AACrB;AAAA,IACF;AAEA,mBAAe,MAAM;AACnB,UAAI;AACF,kBAAU,OAAO;AAAA,UACf,IAAI;AAAA,YACF,mBAAmB,oBAAoB;AAAA,YACvC;AAAA,cACE;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,UAAE;AAOA,kBAAU,OAAO,mBAAmB;AAAA,MACtC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,2BACJ,YACe;AACf,UAAM,KAAK;AAAA,MACT,IAAI,iCAAiC;AAAA,QACnC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,oCAAoC,mCAAiB;AAAA,EACzD;AAAA,EAEA,YAAY,SAIT;AACD,UAAM;AAAA,MACJ,IAAI,QAAQ;AAAA,MACZ,SAAS,QAAQ;AAAA,IACnB,CAAC;AAED,SAAK,cAAc,QAAQ;AAAA,EAC7B;AAAA,EAEO,cAAoB;AACzB,6DAA+B,KAAK,KAAK,OAAO;AAAA,EAClD;AAAA,EAEO,YAAY,UAA2B;AAC5C,QAAI,UAAU;AACZ,WAAK,YAAY,YAAY,QAAQ;AAAA,IACvC;AAAA,EACF;AAAA,EAEO,UAAU,QAAwB;AACvC,QAAI,kBAAkB,UAAU;AAC9B,aAAO,KAAK,YAAY,MAAM;AAAA,IAChC;AAEA,QAAI,kBAAkB,+BAAe;AACnC,WAAK,YAAY,UAAU,MAAM;AAAA,IACnC;AAEA,UAAM;AAAA,EACR;AACF;AAEA,MAAM,yCAAyC,6CAAsB;AAAA,EACnE,YAAY,MAA+C;AACzD,UAAM,EAAE,YAAY,KAAK,WAAW,CAAC;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/experimental/sources/interceptor-source.ts"],"sourcesContent":["import type { Interceptor, RequestController } from '@mswjs/interceptors'\nimport { BatchInterceptor, type HttpRequestEventMap } from '@mswjs/interceptors'\nimport type {\n WebSocketConnectionData,\n WebSocketEventMap,\n} from '@mswjs/interceptors/WebSocket'\nimport { NetworkSource } from './network-source'\nimport { InternalError } from '../../utils/internal/devUtils'\nimport { HttpNetworkFrame, ResponseEvent } from '../frames/http-frame'\nimport { WebSocketNetworkFrame } from '../frames/websocket-frame'\nimport { deleteRequestPassthroughHeader } from '../request-utils'\n\nexport interface InterceptorSourceOptions {\n interceptors: Array<Interceptor<HttpRequestEventMap | WebSocketEventMap>>\n}\n\n/**\n * Create a network source from the given list of interceptors.\n */\nexport class InterceptorSource extends NetworkSource {\n #interceptor: BatchInterceptor<\n InterceptorSourceOptions['interceptors'],\n HttpRequestEventMap | WebSocketEventMap\n >\n\n #frames: Map<string, HttpNetworkFrame>\n\n constructor(options: InterceptorSourceOptions) {\n super()\n\n this.#interceptor = new BatchInterceptor({\n name: 'interceptor-source',\n interceptors: options.interceptors,\n })\n this.#frames = new Map()\n }\n\n public enable(): void {\n this.#interceptor.apply()\n\n /**\n * @todo @fixme BatchInterceptor infers event types but not listener types.\n */\n this.#interceptor\n .on('request', this.#handleRequest.bind(this) as any)\n .on('response', this.#handleResponse.bind(this) as any)\n .on('connection', this.#handleWebSocketConnection.bind(this) as any)\n }\n\n public disable(): void {\n super.disable()\n this.#interceptor.dispose()\n\n /**\n * @todo We can also abort any pending frames here, given we implement\n * the `NetworkFrame.abort()` method.\n */\n this.#frames.clear()\n }\n\n async #handleRequest({\n requestId,\n request,\n controller,\n }: HttpRequestEventMap['request'][0]): Promise<void> {\n const httpFrame = new InterceptorHttpNetworkFrame({\n id: requestId,\n request,\n controller,\n })\n\n this.#frames.set(requestId, httpFrame)\n await this.queue(httpFrame)\n }\n\n async #handleResponse({\n requestId,\n request,\n response,\n isMockedResponse,\n }: HttpRequestEventMap['response'][0]): Promise<void> {\n const httpFrame = this.#frames.get(requestId)\n this.#frames.delete(requestId)\n\n if (httpFrame == null) {\n return\n }\n\n queueMicrotask(() => {\n try {\n httpFrame.events.emit(\n new ResponseEvent(\n isMockedResponse ? 'response:mocked' : 'response:bypass',\n {\n requestId,\n request,\n response,\n },\n ),\n )\n } finally {\n /**\n * @note Remove any listeners from this frame.\n * Past this point, it won't emit anything. The removal is crucial\n * to prevent \"rettime\" from keeping the abort cleanup listeners internally.\n * @see https://github.com/mswjs/msw/issues/2735\n */\n httpFrame.events.removeAllListeners()\n }\n })\n }\n\n async #handleWebSocketConnection(\n connection: WebSocketEventMap['connection'][0],\n ): Promise<void> {\n await this.queue(\n new InterceptorWebSocketNetworkFrame({\n connection,\n }),\n )\n }\n}\n\nclass InterceptorHttpNetworkFrame extends HttpNetworkFrame {\n #controller: RequestController\n\n constructor(options: {\n id: string\n request: Request\n controller: RequestController\n }) {\n super({\n id: options.id,\n request: options.request,\n })\n\n this.#controller = options.controller\n }\n\n public passthrough(): void {\n deleteRequestPassthroughHeader(this.data.request)\n }\n\n public respondWith(response?: Response): void {\n if (response) {\n this.#controller.respondWith(response)\n }\n }\n\n public errorWith(reason?: unknown): void {\n if (reason instanceof Response) {\n return this.respondWith(reason)\n }\n\n if (reason instanceof InternalError) {\n this.#controller.errorWith(reason)\n }\n\n throw reason\n }\n}\n\nclass InterceptorWebSocketNetworkFrame extends WebSocketNetworkFrame {\n constructor(args: { connection: WebSocketConnectionData }) {\n super({ connection: args.connection })\n\n /**\n * @note Provide a similar frame listener cleanup as for HTTP.\n * When the client connection closes, the handler can no longer be used.\n */\n args.connection.client.addEventListener(\n 'close',\n () => {\n this.events.removeAllListeners()\n },\n {\n once: true,\n },\n )\n }\n\n public errorWith(reason?: unknown): void {\n if (reason instanceof Error) {\n const { client } = this.data.connection\n\n /**\n * Use `client.errorWith(reason)` in the future.\n * @see https://github.com/mswjs/interceptors/issues/747\n */\n const errorEvent = new Event('error')\n\n Object.defineProperty(errorEvent, 'cause', {\n enumerable: true,\n configurable: false,\n value: reason,\n })\n\n client.socket.dispatchEvent(errorEvent)\n }\n }\n\n public passthrough() {\n this.data.connection.server.connect()\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAA2D;AAK3D,4BAA8B;AAC9B,sBAA8B;AAC9B,wBAAgD;AAChD,6BAAsC;AACtC,2BAA+C;AASxC,MAAM,0BAA0B,oCAAc;AAAA,EACnD;AAAA,EAKA;AAAA,EAEA,YAAY,SAAmC;AAC7C,UAAM;AAEN,SAAK,eAAe,IAAI,qCAAiB;AAAA,MACvC,MAAM;AAAA,MACN,cAAc,QAAQ;AAAA,IACxB,CAAC;AACD,SAAK,UAAU,oBAAI,IAAI;AAAA,EACzB;AAAA,EAEO,SAAe;AACpB,SAAK,aAAa,MAAM;AAKxB,SAAK,aACF,GAAG,WAAW,KAAK,eAAe,KAAK,IAAI,CAAQ,EACnD,GAAG,YAAY,KAAK,gBAAgB,KAAK,IAAI,CAAQ,EACrD,GAAG,cAAc,KAAK,2BAA2B,KAAK,IAAI,CAAQ;AAAA,EACvE;AAAA,EAEO,UAAgB;AACrB,UAAM,QAAQ;AACd,SAAK,aAAa,QAAQ;AAM1B,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,MAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAqD;AACnD,UAAM,YAAY,IAAI,4BAA4B;AAAA,MAChD,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,IAAI,WAAW,SAAS;AACrC,UAAM,KAAK,MAAM,SAAS;AAAA,EAC5B;AAAA,EAEA,MAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAsD;AACpD,UAAM,YAAY,KAAK,QAAQ,IAAI,SAAS;AAC5C,SAAK,QAAQ,OAAO,SAAS;AAE7B,QAAI,aAAa,MAAM;AACrB;AAAA,IACF;AAEA,mBAAe,MAAM;AACnB,UAAI;AACF,kBAAU,OAAO;AAAA,UACf,IAAI;AAAA,YACF,mBAAmB,oBAAoB;AAAA,YACvC;AAAA,cACE;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,UAAE;AAOA,kBAAU,OAAO,mBAAmB;AAAA,MACtC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,2BACJ,YACe;AACf,UAAM,KAAK;AAAA,MACT,IAAI,iCAAiC;AAAA,QACnC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,oCAAoC,mCAAiB;AAAA,EACzD;AAAA,EAEA,YAAY,SAIT;AACD,UAAM;AAAA,MACJ,IAAI,QAAQ;AAAA,MACZ,SAAS,QAAQ;AAAA,IACnB,CAAC;AAED,SAAK,cAAc,QAAQ;AAAA,EAC7B;AAAA,EAEO,cAAoB;AACzB,6DAA+B,KAAK,KAAK,OAAO;AAAA,EAClD;AAAA,EAEO,YAAY,UAA2B;AAC5C,QAAI,UAAU;AACZ,WAAK,YAAY,YAAY,QAAQ;AAAA,IACvC;AAAA,EACF;AAAA,EAEO,UAAU,QAAwB;AACvC,QAAI,kBAAkB,UAAU;AAC9B,aAAO,KAAK,YAAY,MAAM;AAAA,IAChC;AAEA,QAAI,kBAAkB,+BAAe;AACnC,WAAK,YAAY,UAAU,MAAM;AAAA,IACnC;AAEA,UAAM;AAAA,EACR;AACF;AAEA,MAAM,yCAAyC,6CAAsB;AAAA,EACnE,YAAY,MAA+C;AACzD,UAAM,EAAE,YAAY,KAAK,WAAW,CAAC;AAMrC,SAAK,WAAW,OAAO;AAAA,MACrB;AAAA,MACA,MAAM;AACJ,aAAK,OAAO,mBAAmB;AAAA,MACjC;AAAA,MACA;AAAA,QACE,MAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEO,UAAU,QAAwB;AACvC,QAAI,kBAAkB,OAAO;AAC3B,YAAM,EAAE,OAAO,IAAI,KAAK,KAAK;AAM7B,YAAM,aAAa,IAAI,MAAM,OAAO;AAEpC,aAAO,eAAe,YAAY,SAAS;AAAA,QACzC,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,OAAO;AAAA,MACT,CAAC;AAED,aAAO,OAAO,cAAc,UAAU;AAAA,IACxC;AAAA,EACF;AAAA,EAEO,cAAc;AACnB,SAAK,KAAK,WAAW,OAAO,QAAQ;AAAA,EACtC;AACF;","names":[]}
|
|
@@ -103,6 +103,15 @@ class InterceptorHttpNetworkFrame extends HttpNetworkFrame {
|
|
|
103
103
|
class InterceptorWebSocketNetworkFrame extends WebSocketNetworkFrame {
|
|
104
104
|
constructor(args) {
|
|
105
105
|
super({ connection: args.connection });
|
|
106
|
+
args.connection.client.addEventListener(
|
|
107
|
+
"close",
|
|
108
|
+
() => {
|
|
109
|
+
this.events.removeAllListeners();
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
once: true
|
|
113
|
+
}
|
|
114
|
+
);
|
|
106
115
|
}
|
|
107
116
|
errorWith(reason) {
|
|
108
117
|
if (reason instanceof Error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/experimental/sources/interceptor-source.ts"],"sourcesContent":["import type { Interceptor, RequestController } from '@mswjs/interceptors'\nimport { BatchInterceptor, type HttpRequestEventMap } from '@mswjs/interceptors'\nimport type {\n WebSocketConnectionData,\n WebSocketEventMap,\n} from '@mswjs/interceptors/WebSocket'\nimport { NetworkSource } from './network-source'\nimport { InternalError } from '../../utils/internal/devUtils'\nimport { HttpNetworkFrame, ResponseEvent } from '../frames/http-frame'\nimport { WebSocketNetworkFrame } from '../frames/websocket-frame'\nimport { deleteRequestPassthroughHeader } from '../request-utils'\n\nexport interface InterceptorSourceOptions {\n interceptors: Array<Interceptor<HttpRequestEventMap | WebSocketEventMap>>\n}\n\n/**\n * Create a network source from the given list of interceptors.\n */\nexport class InterceptorSource extends NetworkSource {\n #interceptor: BatchInterceptor<\n InterceptorSourceOptions['interceptors'],\n HttpRequestEventMap | WebSocketEventMap\n >\n\n #frames: Map<string, HttpNetworkFrame>\n\n constructor(options: InterceptorSourceOptions) {\n super()\n\n this.#interceptor = new BatchInterceptor({\n name: 'interceptor-source',\n interceptors: options.interceptors,\n })\n this.#frames = new Map()\n }\n\n public enable(): void {\n this.#interceptor.apply()\n\n /**\n * @todo @fixme BatchInterceptor infers event types but not listener types.\n */\n this.#interceptor\n .on('request', this.#handleRequest.bind(this) as any)\n .on('response', this.#handleResponse.bind(this) as any)\n .on('connection', this.#handleWebSocketConnection.bind(this) as any)\n }\n\n public disable(): void {\n super.disable()\n this.#interceptor.dispose()\n\n /**\n * @todo We can also abort any pending frames here, given we implement\n * the `NetworkFrame.abort()` method.\n */\n this.#frames.clear()\n }\n\n async #handleRequest({\n requestId,\n request,\n controller,\n }: HttpRequestEventMap['request'][0]): Promise<void> {\n const httpFrame = new InterceptorHttpNetworkFrame({\n id: requestId,\n request,\n controller,\n })\n\n this.#frames.set(requestId, httpFrame)\n await this.queue(httpFrame)\n }\n\n async #handleResponse({\n requestId,\n request,\n response,\n isMockedResponse,\n }: HttpRequestEventMap['response'][0]): Promise<void> {\n const httpFrame = this.#frames.get(requestId)\n this.#frames.delete(requestId)\n\n if (httpFrame == null) {\n return\n }\n\n queueMicrotask(() => {\n try {\n httpFrame.events.emit(\n new ResponseEvent(\n isMockedResponse ? 'response:mocked' : 'response:bypass',\n {\n requestId,\n request,\n response,\n },\n ),\n )\n } finally {\n /**\n * @note Remove any listeners from this frame.\n * Past this point, it won't emit anything. The removal is crucial\n * to prevent \"rettime\" from keeping the abort cleanup listeners internally.\n * @see https://github.com/mswjs/msw/issues/2735\n */\n httpFrame.events.removeAllListeners()\n }\n })\n }\n\n async #handleWebSocketConnection(\n connection: WebSocketEventMap['connection'][0],\n ): Promise<void> {\n await this.queue(\n new InterceptorWebSocketNetworkFrame({\n connection,\n }),\n )\n }\n}\n\nclass InterceptorHttpNetworkFrame extends HttpNetworkFrame {\n #controller: RequestController\n\n constructor(options: {\n id: string\n request: Request\n controller: RequestController\n }) {\n super({\n id: options.id,\n request: options.request,\n })\n\n this.#controller = options.controller\n }\n\n public passthrough(): void {\n deleteRequestPassthroughHeader(this.data.request)\n }\n\n public respondWith(response?: Response): void {\n if (response) {\n this.#controller.respondWith(response)\n }\n }\n\n public errorWith(reason?: unknown): void {\n if (reason instanceof Response) {\n return this.respondWith(reason)\n }\n\n if (reason instanceof InternalError) {\n this.#controller.errorWith(reason)\n }\n\n throw reason\n }\n}\n\nclass InterceptorWebSocketNetworkFrame extends WebSocketNetworkFrame {\n constructor(args: { connection: WebSocketConnectionData }) {\n super({ connection: args.connection })\n }\n\n public errorWith(reason?: unknown): void {\n if (reason instanceof Error) {\n const { client } = this.data.connection\n\n /**\n * Use `client.errorWith(reason)` in the future.\n * @see https://github.com/mswjs/interceptors/issues/747\n */\n const errorEvent = new Event('error')\n\n Object.defineProperty(errorEvent, 'cause', {\n enumerable: true,\n configurable: false,\n value: reason,\n })\n\n client.socket.dispatchEvent(errorEvent)\n }\n }\n\n public passthrough() {\n this.data.connection.server.connect()\n }\n}\n"],"mappings":"AACA,SAAS,wBAAkD;AAK3D,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,qBAAqB;AAChD,SAAS,6BAA6B;AACtC,SAAS,sCAAsC;AASxC,MAAM,0BAA0B,cAAc;AAAA,EACnD;AAAA,EAKA;AAAA,EAEA,YAAY,SAAmC;AAC7C,UAAM;AAEN,SAAK,eAAe,IAAI,iBAAiB;AAAA,MACvC,MAAM;AAAA,MACN,cAAc,QAAQ;AAAA,IACxB,CAAC;AACD,SAAK,UAAU,oBAAI,IAAI;AAAA,EACzB;AAAA,EAEO,SAAe;AACpB,SAAK,aAAa,MAAM;AAKxB,SAAK,aACF,GAAG,WAAW,KAAK,eAAe,KAAK,IAAI,CAAQ,EACnD,GAAG,YAAY,KAAK,gBAAgB,KAAK,IAAI,CAAQ,EACrD,GAAG,cAAc,KAAK,2BAA2B,KAAK,IAAI,CAAQ;AAAA,EACvE;AAAA,EAEO,UAAgB;AACrB,UAAM,QAAQ;AACd,SAAK,aAAa,QAAQ;AAM1B,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA,EAEA,MAAM,eAAe;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAqD;AACnD,UAAM,YAAY,IAAI,4BAA4B;AAAA,MAChD,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,IAAI,WAAW,SAAS;AACrC,UAAM,KAAK,MAAM,SAAS;AAAA,EAC5B;AAAA,EAEA,MAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GAAsD;AACpD,UAAM,YAAY,KAAK,QAAQ,IAAI,SAAS;AAC5C,SAAK,QAAQ,OAAO,SAAS;AAE7B,QAAI,aAAa,MAAM;AACrB;AAAA,IACF;AAEA,mBAAe,MAAM;AACnB,UAAI;AACF,kBAAU,OAAO;AAAA,UACf,IAAI;AAAA,YACF,mBAAmB,oBAAoB;AAAA,YACvC;AAAA,cACE;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,UAAE;AAOA,kBAAU,OAAO,mBAAmB;AAAA,MACtC;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,2BACJ,YACe;AACf,UAAM,KAAK;AAAA,MACT,IAAI,iCAAiC;AAAA,QACnC;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,oCAAoC,iBAAiB;AAAA,EACzD;AAAA,EAEA,YAAY,SAIT;AACD,UAAM;AAAA,MACJ,IAAI,QAAQ;AAAA,MACZ,SAAS,QAAQ;AAAA,IACnB,CAAC;AAED,SAAK,cAAc,QAAQ;AAAA,EAC7B;AAAA,EAEO,cAAoB;AACzB,mCAA+B,KAAK,KAAK,OAAO;AAAA,EAClD;AAAA,EAEO,YAAY,UAA2B;AAC5C,QAAI,UAAU;AACZ,WAAK,YAAY,YAAY,QAAQ;AAAA,IACvC;AAAA,EACF;AAAA,EAEO,UAAU,QAAwB;AACvC,QAAI,kBAAkB,UAAU;AAC9B,aAAO,KAAK,YAAY,MAAM;AAAA,IAChC;AAEA,QAAI,kBAAkB,eAAe;AACnC,WAAK,YAAY,UAAU,MAAM;AAAA,IACnC;AAEA,UAAM;AAAA,EACR;AACF;AAEA,MAAM,yCAAyC,sBAAsB;AAAA,EACnE,YAAY,MAA+C;AACzD,UAAM,EAAE,YAAY,KAAK,WAAW,CAAC;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/experimental/sources/interceptor-source.ts"],"sourcesContent":["import type { Interceptor, RequestController } from '@mswjs/interceptors'\nimport { BatchInterceptor, type HttpRequestEventMap } from '@mswjs/interceptors'\nimport type {\n WebSocketConnectionData,\n WebSocketEventMap,\n} from '@mswjs/interceptors/WebSocket'\nimport { NetworkSource } from './network-source'\nimport { InternalError } from '../../utils/internal/devUtils'\nimport { HttpNetworkFrame, ResponseEvent } from '../frames/http-frame'\nimport { WebSocketNetworkFrame } from '../frames/websocket-frame'\nimport { deleteRequestPassthroughHeader } from '../request-utils'\n\nexport interface InterceptorSourceOptions {\n interceptors: Array<Interceptor<HttpRequestEventMap | WebSocketEventMap>>\n}\n\n/**\n * Create a network source from the given list of interceptors.\n */\nexport class InterceptorSource extends NetworkSource {\n #interceptor: BatchInterceptor<\n InterceptorSourceOptions['interceptors'],\n HttpRequestEventMap | WebSocketEventMap\n >\n\n #frames: Map<string, HttpNetworkFrame>\n\n constructor(options: InterceptorSourceOptions) {\n super()\n\n this.#interceptor = new BatchInterceptor({\n name: 'interceptor-source',\n interceptors: options.interceptors,\n })\n this.#frames = new Map()\n }\n\n public enable(): void {\n this.#interceptor.apply()\n\n /**\n * @todo @fixme BatchInterceptor infers event types but not listener types.\n */\n this.#interceptor\n .on('request', this.#handleRequest.bind(this) as any)\n .on('response', this.#handleResponse.bind(this) as any)\n .on('connection', this.#handleWebSocketConnection.bind(this) as any)\n }\n\n public disable(): void {\n super.disable()\n this.#interceptor.dispose()\n\n /**\n * @todo We can also abort any pending frames here, given we implement\n * the `NetworkFrame.abort()` method.\n */\n this.#frames.clear()\n }\n\n async #handleRequest({\n requestId,\n request,\n controller,\n }: HttpRequestEventMap['request'][0]): Promise<void> {\n const httpFrame = new InterceptorHttpNetworkFrame({\n id: requestId,\n request,\n controller,\n })\n\n this.#frames.set(requestId, httpFrame)\n await this.queue(httpFrame)\n }\n\n async #handleResponse({\n requestId,\n request,\n response,\n isMockedResponse,\n }: HttpRequestEventMap['response'][0]): Promise<void> {\n const httpFrame = this.#frames.get(requestId)\n this.#frames.delete(requestId)\n\n if (httpFrame == null) {\n return\n }\n\n queueMicrotask(() => {\n try {\n httpFrame.events.emit(\n new ResponseEvent(\n isMockedResponse ? 'response:mocked' : 'response:bypass',\n {\n requestId,\n request,\n response,\n },\n ),\n )\n } finally {\n /**\n * @note Remove any listeners from this frame.\n * Past this point, it won't emit anything. The removal is crucial\n * to prevent \"rettime\" from keeping the abort cleanup listeners internally.\n * @see https://github.com/mswjs/msw/issues/2735\n */\n httpFrame.events.removeAllListeners()\n }\n })\n }\n\n async #handleWebSocketConnection(\n connection: WebSocketEventMap['connection'][0],\n ): Promise<void> {\n await this.queue(\n new InterceptorWebSocketNetworkFrame({\n connection,\n }),\n )\n }\n}\n\nclass InterceptorHttpNetworkFrame extends HttpNetworkFrame {\n #controller: RequestController\n\n constructor(options: {\n id: string\n request: Request\n controller: RequestController\n }) {\n super({\n id: options.id,\n request: options.request,\n })\n\n this.#controller = options.controller\n }\n\n public passthrough(): void {\n deleteRequestPassthroughHeader(this.data.request)\n }\n\n public respondWith(response?: Response): void {\n if (response) {\n this.#controller.respondWith(response)\n }\n }\n\n public errorWith(reason?: unknown): void {\n if (reason instanceof Response) {\n return this.respondWith(reason)\n }\n\n if (reason instanceof InternalError) {\n this.#controller.errorWith(reason)\n }\n\n throw reason\n }\n}\n\nclass InterceptorWebSocketNetworkFrame extends WebSocketNetworkFrame {\n constructor(args: { connection: WebSocketConnectionData }) {\n super({ connection: args.connection })\n\n /**\n * @note Provide a similar frame listener cleanup as for HTTP.\n * When the client connection closes, the handler can no longer be used.\n */\n args.connection.client.addEventListener(\n 'close',\n () => {\n this.events.removeAllListeners()\n },\n {\n once: true,\n },\n )\n }\n\n public errorWith(reason?: unknown): void {\n if (reason instanceof Error) {\n const { client } = this.data.connection\n\n /**\n * Use `client.errorWith(reason)` in the future.\n * @see https://github.com/mswjs/interceptors/issues/747\n */\n const errorEvent = new Event('error')\n\n Object.defineProperty(errorEvent, 'cause', {\n enumerable: true,\n configurable: false,\n value: reason,\n })\n\n client.socket.dispatchEvent(errorEvent)\n }\n }\n\n public passthrough() {\n this.data.connection.server.connect()\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -21,12 +21,30 @@ __export(Disposable_exports, {
|
|
|
21
21
|
Disposable: () => Disposable
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(Disposable_exports);
|
|
24
|
+
var import_devUtils = require("./devUtils");
|
|
24
25
|
class Disposable {
|
|
25
26
|
subscriptions = [];
|
|
26
27
|
dispose() {
|
|
27
28
|
let subscription;
|
|
29
|
+
const errors = [];
|
|
28
30
|
while (subscription = this.subscriptions.shift()) {
|
|
29
|
-
|
|
31
|
+
try {
|
|
32
|
+
subscription();
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (error instanceof Error) {
|
|
35
|
+
errors.push(error);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (errors.length > 0) {
|
|
40
|
+
console.error(
|
|
41
|
+
new AggregateError(
|
|
42
|
+
errors,
|
|
43
|
+
import_devUtils.devUtils.formatMessage(
|
|
44
|
+
"Failed to dispose of some side effects. This is likely an issue with MSW, please report it on GitHub: https://github.com/mswjs/msw/issues"
|
|
45
|
+
)
|
|
46
|
+
)
|
|
47
|
+
);
|
|
30
48
|
}
|
|
31
49
|
}
|
|
32
50
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/internal/Disposable.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/internal/Disposable.ts"],"sourcesContent":["import { devUtils } from './devUtils'\n\nexport type DisposableSubscription = () => void\n\nexport class Disposable {\n protected subscriptions: Array<DisposableSubscription> = []\n\n public dispose() {\n let subscription: DisposableSubscription | undefined\n const errors: Array<Error> = []\n\n while ((subscription = this.subscriptions.shift())) {\n try {\n subscription()\n } catch (error) {\n if (error instanceof Error) {\n errors.push(error)\n }\n }\n }\n\n if (errors.length > 0) {\n console.error(\n new AggregateError(\n errors,\n devUtils.formatMessage(\n 'Failed to dispose of some side effects. This is likely an issue with MSW, please report it on GitHub: https://github.com/mswjs/msw/issues',\n ),\n ),\n )\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAyB;AAIlB,MAAM,WAAW;AAAA,EACZ,gBAA+C,CAAC;AAAA,EAEnD,UAAU;AACf,QAAI;AACJ,UAAM,SAAuB,CAAC;AAE9B,WAAQ,eAAe,KAAK,cAAc,MAAM,GAAI;AAClD,UAAI;AACF,qBAAa;AAAA,MACf,SAAS,OAAO;AACd,YAAI,iBAAiB,OAAO;AAC1B,iBAAO,KAAK,KAAK;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,GAAG;AACrB,cAAQ;AAAA,QACN,IAAI;AAAA,UACF;AAAA,UACA,yBAAS;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,9 +1,27 @@
|
|
|
1
|
+
import { devUtils } from './devUtils.mjs';
|
|
1
2
|
class Disposable {
|
|
2
3
|
subscriptions = [];
|
|
3
4
|
dispose() {
|
|
4
5
|
let subscription;
|
|
6
|
+
const errors = [];
|
|
5
7
|
while (subscription = this.subscriptions.shift()) {
|
|
6
|
-
|
|
8
|
+
try {
|
|
9
|
+
subscription();
|
|
10
|
+
} catch (error) {
|
|
11
|
+
if (error instanceof Error) {
|
|
12
|
+
errors.push(error);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (errors.length > 0) {
|
|
17
|
+
console.error(
|
|
18
|
+
new AggregateError(
|
|
19
|
+
errors,
|
|
20
|
+
devUtils.formatMessage(
|
|
21
|
+
"Failed to dispose of some side effects. This is likely an issue with MSW, please report it on GitHub: https://github.com/mswjs/msw/issues"
|
|
22
|
+
)
|
|
23
|
+
)
|
|
24
|
+
);
|
|
7
25
|
}
|
|
8
26
|
}
|
|
9
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/internal/Disposable.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/internal/Disposable.ts"],"sourcesContent":["import { devUtils } from './devUtils'\n\nexport type DisposableSubscription = () => void\n\nexport class Disposable {\n protected subscriptions: Array<DisposableSubscription> = []\n\n public dispose() {\n let subscription: DisposableSubscription | undefined\n const errors: Array<Error> = []\n\n while ((subscription = this.subscriptions.shift())) {\n try {\n subscription()\n } catch (error) {\n if (error instanceof Error) {\n errors.push(error)\n }\n }\n }\n\n if (errors.length > 0) {\n console.error(\n new AggregateError(\n errors,\n devUtils.formatMessage(\n 'Failed to dispose of some side effects. This is likely an issue with MSW, please report it on GitHub: https://github.com/mswjs/msw/issues',\n ),\n ),\n )\n }\n }\n}\n"],"mappings":"AAAA,SAAS,gBAAgB;AAIlB,MAAM,WAAW;AAAA,EACZ,gBAA+C,CAAC;AAAA,EAEnD,UAAU;AACf,QAAI;AACJ,UAAM,SAAuB,CAAC;AAE9B,WAAQ,eAAe,KAAK,cAAc,MAAM,GAAI;AAClD,UAAI;AACF,qBAAa;AAAA,MACf,SAAS,OAAO;AACd,YAAI,iBAAiB,OAAO;AAC1B,iBAAO,KAAK,KAAK;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,SAAS,GAAG;AACrB,cAAQ;AAAA,QACN,IAAI;AAAA,UACF;AAAA,UACA,SAAS;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
|
package/lib/iife/index.js
CHANGED
|
@@ -17355,8 +17355,25 @@ ${operationTypes.join("\n")}
|
|
|
17355
17355
|
subscriptions = [];
|
|
17356
17356
|
dispose() {
|
|
17357
17357
|
let subscription;
|
|
17358
|
+
const errors = [];
|
|
17358
17359
|
while (subscription = this.subscriptions.shift()) {
|
|
17359
|
-
|
|
17360
|
+
try {
|
|
17361
|
+
subscription();
|
|
17362
|
+
} catch (error3) {
|
|
17363
|
+
if (error3 instanceof Error) {
|
|
17364
|
+
errors.push(error3);
|
|
17365
|
+
}
|
|
17366
|
+
}
|
|
17367
|
+
}
|
|
17368
|
+
if (errors.length > 0) {
|
|
17369
|
+
console.error(
|
|
17370
|
+
new AggregateError(
|
|
17371
|
+
errors,
|
|
17372
|
+
devUtils.formatMessage(
|
|
17373
|
+
"Failed to dispose of some side effects. This is likely an issue with MSW, please report it on GitHub: https://github.com/mswjs/msw/issues"
|
|
17374
|
+
)
|
|
17375
|
+
)
|
|
17376
|
+
);
|
|
17360
17377
|
}
|
|
17361
17378
|
}
|
|
17362
17379
|
};
|
|
@@ -22841,6 +22858,7 @@ Read more: https://mswjs.io/docs/http/intercepting-requests`;
|
|
|
22841
22858
|
function defineNetwork(options) {
|
|
22842
22859
|
let readyState = 0 /* DISABLED */;
|
|
22843
22860
|
const events = new Emitter();
|
|
22861
|
+
const disposable = new Disposable();
|
|
22844
22862
|
const deriveHandlersController = (handlers) => {
|
|
22845
22863
|
return handlers instanceof HandlersController ? handlers : new InMemoryHandlersController(handlers || []);
|
|
22846
22864
|
};
|
|
@@ -22848,14 +22866,16 @@ Read more: https://mswjs.io/docs/http/intercepting-requests`;
|
|
|
22848
22866
|
...options
|
|
22849
22867
|
};
|
|
22850
22868
|
let handlersController = deriveHandlersController(resolvedOptions.handlers);
|
|
22851
|
-
let listenersController;
|
|
22852
22869
|
return {
|
|
22853
22870
|
get readyState() {
|
|
22854
22871
|
return readyState;
|
|
22855
22872
|
},
|
|
22856
22873
|
events,
|
|
22857
22874
|
configure(options2) {
|
|
22858
|
-
invariant(
|
|
22875
|
+
invariant(
|
|
22876
|
+
readyState === 0 /* DISABLED */,
|
|
22877
|
+
'Failed to call "configure()" on the network: cannot configure an already enabled network.'
|
|
22878
|
+
);
|
|
22859
22879
|
if (options2.handlers && !Object.is(options2.handlers, resolvedOptions.handlers)) {
|
|
22860
22880
|
handlersController = deriveHandlersController(options2.handlers);
|
|
22861
22881
|
}
|
|
@@ -22869,13 +22889,19 @@ Read more: https://mswjs.io/docs/http/intercepting-requests`;
|
|
|
22869
22889
|
readyState === 0 /* DISABLED */,
|
|
22870
22890
|
'Failed to call "enable" on the network: already enabled'
|
|
22871
22891
|
);
|
|
22872
|
-
listenersController = new AbortController();
|
|
22873
22892
|
readyState = 1 /* ENABLED */;
|
|
22893
|
+
const session = { active: true };
|
|
22894
|
+
disposable["subscriptions"].push(() => {
|
|
22895
|
+
session.active = false;
|
|
22896
|
+
});
|
|
22874
22897
|
const result = resolvedOptions.sources.map((source) => {
|
|
22875
22898
|
NetworkSource.prototype.disable.call(source);
|
|
22876
22899
|
source.on("frame", async ({ frame }) => {
|
|
22877
|
-
frame.events.on("*", (event) =>
|
|
22878
|
-
|
|
22900
|
+
frame.events.on("*", (event) => {
|
|
22901
|
+
if (!session.active) {
|
|
22902
|
+
return;
|
|
22903
|
+
}
|
|
22904
|
+
events.emit(event);
|
|
22879
22905
|
});
|
|
22880
22906
|
const handlers = frame.getHandlers(handlersController);
|
|
22881
22907
|
await frame.resolve(
|
|
@@ -22893,8 +22919,8 @@ Read more: https://mswjs.io/docs/http/intercepting-requests`;
|
|
|
22893
22919
|
readyState === 1 /* ENABLED */,
|
|
22894
22920
|
'Failed to call "disable" on the network: already disabled'
|
|
22895
22921
|
);
|
|
22896
|
-
listenersController.abort();
|
|
22897
22922
|
readyState = 0 /* DISABLED */;
|
|
22923
|
+
disposable.dispose();
|
|
22898
22924
|
return colorlessPromiseAll(
|
|
22899
22925
|
resolvedOptions.sources.map((source) => source.disable())
|
|
22900
22926
|
);
|
|
@@ -23116,6 +23142,15 @@ Read more: https://mswjs.io/docs/websocket`;
|
|
|
23116
23142
|
var InterceptorWebSocketNetworkFrame = class extends WebSocketNetworkFrame {
|
|
23117
23143
|
constructor(args) {
|
|
23118
23144
|
super({ connection: args.connection });
|
|
23145
|
+
args.connection.client.addEventListener(
|
|
23146
|
+
"close",
|
|
23147
|
+
() => {
|
|
23148
|
+
this.events.removeAllListeners();
|
|
23149
|
+
},
|
|
23150
|
+
{
|
|
23151
|
+
once: true
|
|
23152
|
+
}
|
|
23153
|
+
);
|
|
23119
23154
|
}
|
|
23120
23155
|
errorWith(reason) {
|
|
23121
23156
|
if (reason instanceof Error) {
|