msw 2.3.0-ws.rc-6 → 2.3.0-ws.rc-7

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 (66) hide show
  1. package/README.md +3 -9
  2. package/lib/browser/index.js +160 -64
  3. package/lib/browser/index.js.map +1 -1
  4. package/lib/browser/index.mjs +160 -64
  5. package/lib/browser/index.mjs.map +1 -1
  6. package/lib/core/handlers/WebSocketHandler.js +1 -2
  7. package/lib/core/handlers/WebSocketHandler.js.map +1 -1
  8. package/lib/core/handlers/WebSocketHandler.mjs +1 -2
  9. package/lib/core/handlers/WebSocketHandler.mjs.map +1 -1
  10. package/lib/core/utils/internal/Disposable.d.mts +2 -2
  11. package/lib/core/utils/internal/Disposable.d.ts +2 -2
  12. package/lib/core/utils/internal/Disposable.js +5 -2
  13. package/lib/core/utils/internal/Disposable.js.map +1 -1
  14. package/lib/core/utils/internal/Disposable.mjs +5 -2
  15. package/lib/core/utils/internal/Disposable.mjs.map +1 -1
  16. package/lib/core/utils/internal/devUtils.d.mts +10 -1
  17. package/lib/core/utils/internal/devUtils.d.ts +10 -1
  18. package/lib/core/utils/internal/devUtils.js +7 -0
  19. package/lib/core/utils/internal/devUtils.js.map +1 -1
  20. package/lib/core/utils/internal/devUtils.mjs +7 -0
  21. package/lib/core/utils/internal/devUtils.mjs.map +1 -1
  22. package/lib/core/utils/matching/normalizePath.d.mts +1 -0
  23. package/lib/core/utils/matching/normalizePath.d.ts +1 -0
  24. package/lib/core/utils/matching/normalizePath.js.map +1 -1
  25. package/lib/core/utils/matching/normalizePath.mjs.map +1 -1
  26. package/lib/core/utils/request/onUnhandledRequest.js +3 -3
  27. package/lib/core/utils/request/onUnhandledRequest.js.map +1 -1
  28. package/lib/core/utils/request/onUnhandledRequest.mjs +4 -4
  29. package/lib/core/utils/request/onUnhandledRequest.mjs.map +1 -1
  30. package/lib/core/utils/url/cleanUrl.d.mts +2 -1
  31. package/lib/core/utils/url/cleanUrl.d.ts +2 -1
  32. package/lib/core/utils/url/cleanUrl.js +3 -0
  33. package/lib/core/utils/url/cleanUrl.js.map +1 -1
  34. package/lib/core/utils/url/cleanUrl.mjs +3 -0
  35. package/lib/core/utils/url/cleanUrl.mjs.map +1 -1
  36. package/lib/core/ws/WebSocketClientManager.js.map +1 -1
  37. package/lib/core/ws/WebSocketClientManager.mjs.map +1 -1
  38. package/lib/iife/index.js +204 -79
  39. package/lib/iife/index.js.map +1 -1
  40. package/lib/mockServiceWorker.js +1 -1
  41. package/lib/native/index.js +5 -0
  42. package/lib/native/index.js.map +1 -1
  43. package/lib/native/index.mjs +6 -1
  44. package/lib/native/index.mjs.map +1 -1
  45. package/lib/node/index.js +5 -0
  46. package/lib/node/index.js.map +1 -1
  47. package/lib/node/index.mjs +6 -1
  48. package/lib/node/index.mjs.map +1 -1
  49. package/package.json +17 -5
  50. package/src/browser/setupWorker/start/createStartHandler.ts +6 -0
  51. package/src/core/handlers/WebSocketHandler.ts +1 -2
  52. package/src/core/utils/internal/Disposable.ts +6 -3
  53. package/src/core/utils/internal/devUtils.test.ts +21 -0
  54. package/src/core/utils/internal/devUtils.ts +13 -0
  55. package/src/core/utils/matching/matchRequestUrl.test.ts +11 -0
  56. package/src/core/utils/matching/normalizePath.test.ts +7 -1
  57. package/src/core/utils/matching/normalizePath.ts +1 -0
  58. package/src/core/utils/request/onUnhandledRequest.test.ts +30 -4
  59. package/src/core/utils/request/onUnhandledRequest.ts +4 -4
  60. package/src/core/utils/url/cleanUrl.test.ts +8 -3
  61. package/src/core/utils/url/cleanUrl.ts +9 -1
  62. package/src/core/utils/url/getAbsoluteUrl.node.test.ts +3 -3
  63. package/src/core/utils/url/getAbsoluteUrl.test.ts +5 -5
  64. package/src/core/utils/url/isAbsoluteUrl.test.ts +7 -7
  65. package/src/core/ws/WebSocketClientManager.ts +1 -2
  66. package/src/node/SetupServerCommonApi.ts +7 -1
@@ -52,8 +52,7 @@ class WebSocketHandler {
52
52
  const parsedResult = this.parse({ event });
53
53
  const connection = event.data;
54
54
  const resolvedConnection = {
55
- client: connection.client,
56
- server: connection.server,
55
+ ...connection,
57
56
  params: parsedResult.match.params || {}
58
57
  };
59
58
  this[kEmitter].emit("connection", resolvedConnection);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/handlers/WebSocketHandler.ts"],"sourcesContent":["import { Emitter } from 'strict-event-emitter'\nimport type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'\nimport {\n type Match,\n type Path,\n type PathParams,\n matchRequestUrl,\n} from '../utils/matching/matchRequestUrl'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\n\ntype WebSocketHandlerParsedResult = {\n match: Match\n}\n\nexport type WebSocketHandlerEventMap = {\n connection: [args: WebSocketHandlerConnection]\n}\n\ninterface WebSocketHandlerConnection extends WebSocketConnectionData {\n params: PathParams\n}\n\nexport const kEmitter = Symbol('kEmitter')\nexport const kDispatchEvent = Symbol('kDispatchEvent')\nexport const kSender = Symbol('kSender')\n\nexport class WebSocketHandler {\n public callFrame?: string\n\n protected [kEmitter]: Emitter<WebSocketHandlerEventMap>\n\n constructor(private readonly url: Path) {\n this[kEmitter] = new Emitter()\n this.callFrame = getCallFrame(new Error())\n }\n\n public parse(args: {\n event: MessageEvent<WebSocketConnectionData>\n }): WebSocketHandlerParsedResult {\n const connection = args.event.data\n const match = matchRequestUrl(connection.client.url, this.url)\n\n return {\n match,\n }\n }\n\n public predicate(args: {\n event: MessageEvent<WebSocketConnectionData>\n parsedResult: WebSocketHandlerParsedResult\n }): boolean {\n return args.parsedResult.match.matches\n }\n\n async [kDispatchEvent](\n event: MessageEvent<WebSocketConnectionData>,\n ): Promise<void> {\n const parsedResult = this.parse({ event })\n const connection = event.data\n\n const resolvedConnection: WebSocketHandlerConnection = {\n client: connection.client,\n server: connection.server,\n params: parsedResult.match.params || {},\n }\n\n // Emit the connection event on the handler.\n // This is what the developer adds listeners for.\n this[kEmitter].emit('connection', resolvedConnection)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAAwB;AAExB,6BAKO;AACP,0BAA6B;AActB,MAAM,WAAW,OAAO,UAAU;AAClC,MAAM,iBAAiB,OAAO,gBAAgB;AAC9C,MAAM,UAAU,OAAO,SAAS;AAEhC,MAAM,iBAAiB;AAAA,EAK5B,YAA6B,KAAW;AAAX;AAC3B,SAAK,QAAQ,IAAI,IAAI,oCAAQ;AAC7B,SAAK,gBAAY,kCAAa,IAAI,MAAM,CAAC;AAAA,EAC3C;AAAA,EAPO;AAAA,EAEP,CAAW,QAAQ;AAAA,EAOZ,MAAM,MAEoB;AAC/B,UAAM,aAAa,KAAK,MAAM;AAC9B,UAAM,YAAQ,wCAAgB,WAAW,OAAO,KAAK,KAAK,GAAG;AAE7D,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAAA,EAEO,UAAU,MAGL;AACV,WAAO,KAAK,aAAa,MAAM;AAAA,EACjC;AAAA,EAEA,OAAO,cAAc,EACnB,OACe;AACf,UAAM,eAAe,KAAK,MAAM,EAAE,MAAM,CAAC;AACzC,UAAM,aAAa,MAAM;AAEzB,UAAM,qBAAiD;AAAA,MACrD,QAAQ,WAAW;AAAA,MACnB,QAAQ,WAAW;AAAA,MACnB,QAAQ,aAAa,MAAM,UAAU,CAAC;AAAA,IACxC;AAIA,SAAK,QAAQ,EAAE,KAAK,cAAc,kBAAkB;AAAA,EACtD;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/core/handlers/WebSocketHandler.ts"],"sourcesContent":["import { Emitter } from 'strict-event-emitter'\nimport type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'\nimport {\n type Match,\n type Path,\n type PathParams,\n matchRequestUrl,\n} from '../utils/matching/matchRequestUrl'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\n\ntype WebSocketHandlerParsedResult = {\n match: Match\n}\n\nexport type WebSocketHandlerEventMap = {\n connection: [args: WebSocketHandlerConnection]\n}\n\ninterface WebSocketHandlerConnection extends WebSocketConnectionData {\n params: PathParams\n}\n\nexport const kEmitter = Symbol('kEmitter')\nexport const kDispatchEvent = Symbol('kDispatchEvent')\nexport const kSender = Symbol('kSender')\n\nexport class WebSocketHandler {\n public callFrame?: string\n\n protected [kEmitter]: Emitter<WebSocketHandlerEventMap>\n\n constructor(private readonly url: Path) {\n this[kEmitter] = new Emitter()\n this.callFrame = getCallFrame(new Error())\n }\n\n public parse(args: {\n event: MessageEvent<WebSocketConnectionData>\n }): WebSocketHandlerParsedResult {\n const connection = args.event.data\n const match = matchRequestUrl(connection.client.url, this.url)\n\n return {\n match,\n }\n }\n\n public predicate(args: {\n event: MessageEvent<WebSocketConnectionData>\n parsedResult: WebSocketHandlerParsedResult\n }): boolean {\n return args.parsedResult.match.matches\n }\n\n async [kDispatchEvent](\n event: MessageEvent<WebSocketConnectionData>,\n ): Promise<void> {\n const parsedResult = this.parse({ event })\n const connection = event.data\n\n const resolvedConnection: WebSocketHandlerConnection = {\n ...connection,\n params: parsedResult.match.params || {},\n }\n\n // Emit the connection event on the handler.\n // This is what the developer adds listeners for.\n this[kEmitter].emit('connection', resolvedConnection)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAAwB;AAExB,6BAKO;AACP,0BAA6B;AActB,MAAM,WAAW,OAAO,UAAU;AAClC,MAAM,iBAAiB,OAAO,gBAAgB;AAC9C,MAAM,UAAU,OAAO,SAAS;AAEhC,MAAM,iBAAiB;AAAA,EAK5B,YAA6B,KAAW;AAAX;AAC3B,SAAK,QAAQ,IAAI,IAAI,oCAAQ;AAC7B,SAAK,gBAAY,kCAAa,IAAI,MAAM,CAAC;AAAA,EAC3C;AAAA,EAPO;AAAA,EAEP,CAAW,QAAQ;AAAA,EAOZ,MAAM,MAEoB;AAC/B,UAAM,aAAa,KAAK,MAAM;AAC9B,UAAM,YAAQ,wCAAgB,WAAW,OAAO,KAAK,KAAK,GAAG;AAE7D,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAAA,EAEO,UAAU,MAGL;AACV,WAAO,KAAK,aAAa,MAAM;AAAA,EACjC;AAAA,EAEA,OAAO,cAAc,EACnB,OACe;AACf,UAAM,eAAe,KAAK,MAAM,EAAE,MAAM,CAAC;AACzC,UAAM,aAAa,MAAM;AAEzB,UAAM,qBAAiD;AAAA,MACrD,GAAG;AAAA,MACH,QAAQ,aAAa,MAAM,UAAU,CAAC;AAAA,IACxC;AAIA,SAAK,QAAQ,EAAE,KAAK,cAAc,kBAAkB;AAAA,EACtD;AACF;","names":[]}
@@ -28,8 +28,7 @@ class WebSocketHandler {
28
28
  const parsedResult = this.parse({ event });
29
29
  const connection = event.data;
30
30
  const resolvedConnection = {
31
- client: connection.client,
32
- server: connection.server,
31
+ ...connection,
33
32
  params: parsedResult.match.params || {}
34
33
  };
35
34
  this[kEmitter].emit("connection", resolvedConnection);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/handlers/WebSocketHandler.ts"],"sourcesContent":["import { Emitter } from 'strict-event-emitter'\nimport type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'\nimport {\n type Match,\n type Path,\n type PathParams,\n matchRequestUrl,\n} from '../utils/matching/matchRequestUrl'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\n\ntype WebSocketHandlerParsedResult = {\n match: Match\n}\n\nexport type WebSocketHandlerEventMap = {\n connection: [args: WebSocketHandlerConnection]\n}\n\ninterface WebSocketHandlerConnection extends WebSocketConnectionData {\n params: PathParams\n}\n\nexport const kEmitter = Symbol('kEmitter')\nexport const kDispatchEvent = Symbol('kDispatchEvent')\nexport const kSender = Symbol('kSender')\n\nexport class WebSocketHandler {\n public callFrame?: string\n\n protected [kEmitter]: Emitter<WebSocketHandlerEventMap>\n\n constructor(private readonly url: Path) {\n this[kEmitter] = new Emitter()\n this.callFrame = getCallFrame(new Error())\n }\n\n public parse(args: {\n event: MessageEvent<WebSocketConnectionData>\n }): WebSocketHandlerParsedResult {\n const connection = args.event.data\n const match = matchRequestUrl(connection.client.url, this.url)\n\n return {\n match,\n }\n }\n\n public predicate(args: {\n event: MessageEvent<WebSocketConnectionData>\n parsedResult: WebSocketHandlerParsedResult\n }): boolean {\n return args.parsedResult.match.matches\n }\n\n async [kDispatchEvent](\n event: MessageEvent<WebSocketConnectionData>,\n ): Promise<void> {\n const parsedResult = this.parse({ event })\n const connection = event.data\n\n const resolvedConnection: WebSocketHandlerConnection = {\n client: connection.client,\n server: connection.server,\n params: parsedResult.match.params || {},\n }\n\n // Emit the connection event on the handler.\n // This is what the developer adds listeners for.\n this[kEmitter].emit('connection', resolvedConnection)\n }\n}\n"],"mappings":"AAAA,SAAS,eAAe;AAExB;AAAA,EAIE;AAAA,OACK;AACP,SAAS,oBAAoB;AActB,MAAM,WAAW,OAAO,UAAU;AAClC,MAAM,iBAAiB,OAAO,gBAAgB;AAC9C,MAAM,UAAU,OAAO,SAAS;AAEhC,MAAM,iBAAiB;AAAA,EAK5B,YAA6B,KAAW;AAAX;AAC3B,SAAK,QAAQ,IAAI,IAAI,QAAQ;AAC7B,SAAK,YAAY,aAAa,IAAI,MAAM,CAAC;AAAA,EAC3C;AAAA,EAPO;AAAA,EAEP,CAAW,QAAQ;AAAA,EAOZ,MAAM,MAEoB;AAC/B,UAAM,aAAa,KAAK,MAAM;AAC9B,UAAM,QAAQ,gBAAgB,WAAW,OAAO,KAAK,KAAK,GAAG;AAE7D,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAAA,EAEO,UAAU,MAGL;AACV,WAAO,KAAK,aAAa,MAAM;AAAA,EACjC;AAAA,EAEA,OAAO,cAAc,EACnB,OACe;AACf,UAAM,eAAe,KAAK,MAAM,EAAE,MAAM,CAAC;AACzC,UAAM,aAAa,MAAM;AAEzB,UAAM,qBAAiD;AAAA,MACrD,QAAQ,WAAW;AAAA,MACnB,QAAQ,WAAW;AAAA,MACnB,QAAQ,aAAa,MAAM,UAAU,CAAC;AAAA,IACxC;AAIA,SAAK,QAAQ,EAAE,KAAK,cAAc,kBAAkB;AAAA,EACtD;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/core/handlers/WebSocketHandler.ts"],"sourcesContent":["import { Emitter } from 'strict-event-emitter'\nimport type { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket'\nimport {\n type Match,\n type Path,\n type PathParams,\n matchRequestUrl,\n} from '../utils/matching/matchRequestUrl'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\n\ntype WebSocketHandlerParsedResult = {\n match: Match\n}\n\nexport type WebSocketHandlerEventMap = {\n connection: [args: WebSocketHandlerConnection]\n}\n\ninterface WebSocketHandlerConnection extends WebSocketConnectionData {\n params: PathParams\n}\n\nexport const kEmitter = Symbol('kEmitter')\nexport const kDispatchEvent = Symbol('kDispatchEvent')\nexport const kSender = Symbol('kSender')\n\nexport class WebSocketHandler {\n public callFrame?: string\n\n protected [kEmitter]: Emitter<WebSocketHandlerEventMap>\n\n constructor(private readonly url: Path) {\n this[kEmitter] = new Emitter()\n this.callFrame = getCallFrame(new Error())\n }\n\n public parse(args: {\n event: MessageEvent<WebSocketConnectionData>\n }): WebSocketHandlerParsedResult {\n const connection = args.event.data\n const match = matchRequestUrl(connection.client.url, this.url)\n\n return {\n match,\n }\n }\n\n public predicate(args: {\n event: MessageEvent<WebSocketConnectionData>\n parsedResult: WebSocketHandlerParsedResult\n }): boolean {\n return args.parsedResult.match.matches\n }\n\n async [kDispatchEvent](\n event: MessageEvent<WebSocketConnectionData>,\n ): Promise<void> {\n const parsedResult = this.parse({ event })\n const connection = event.data\n\n const resolvedConnection: WebSocketHandlerConnection = {\n ...connection,\n params: parsedResult.match.params || {},\n }\n\n // Emit the connection event on the handler.\n // This is what the developer adds listeners for.\n this[kEmitter].emit('connection', resolvedConnection)\n }\n}\n"],"mappings":"AAAA,SAAS,eAAe;AAExB;AAAA,EAIE;AAAA,OACK;AACP,SAAS,oBAAoB;AActB,MAAM,WAAW,OAAO,UAAU;AAClC,MAAM,iBAAiB,OAAO,gBAAgB;AAC9C,MAAM,UAAU,OAAO,SAAS;AAEhC,MAAM,iBAAiB;AAAA,EAK5B,YAA6B,KAAW;AAAX;AAC3B,SAAK,QAAQ,IAAI,IAAI,QAAQ;AAC7B,SAAK,YAAY,aAAa,IAAI,MAAM,CAAC;AAAA,EAC3C;AAAA,EAPO;AAAA,EAEP,CAAW,QAAQ;AAAA,EAOZ,MAAM,MAEoB;AAC/B,UAAM,aAAa,KAAK,MAAM;AAC9B,UAAM,QAAQ,gBAAgB,WAAW,OAAO,KAAK,KAAK,GAAG;AAE7D,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF;AAAA,EAEO,UAAU,MAGL;AACV,WAAO,KAAK,aAAa,MAAM;AAAA,EACjC;AAAA,EAEA,OAAO,cAAc,EACnB,OACe;AACf,UAAM,eAAe,KAAK,MAAM,EAAE,MAAM,CAAC;AACzC,UAAM,aAAa,MAAM;AAEzB,UAAM,qBAAiD;AAAA,MACrD,GAAG;AAAA,MACH,QAAQ,aAAa,MAAM,UAAU,CAAC;AAAA,IACxC;AAIA,SAAK,QAAQ,EAAE,KAAK,cAAc,kBAAkB;AAAA,EACtD;AACF;","names":[]}
@@ -1,7 +1,7 @@
1
- type DisposableSubscription = () => Promise<void> | void;
1
+ type DisposableSubscription = () => void;
2
2
  declare class Disposable {
3
3
  protected subscriptions: Array<DisposableSubscription>;
4
- dispose(): Promise<void>;
4
+ dispose(): void;
5
5
  }
6
6
 
7
7
  export { Disposable, type DisposableSubscription };
@@ -1,7 +1,7 @@
1
- type DisposableSubscription = () => Promise<void> | void;
1
+ type DisposableSubscription = () => void;
2
2
  declare class Disposable {
3
3
  protected subscriptions: Array<DisposableSubscription>;
4
- dispose(): Promise<void>;
4
+ dispose(): void;
5
5
  }
6
6
 
7
7
  export { Disposable, type DisposableSubscription };
@@ -23,8 +23,11 @@ __export(Disposable_exports, {
23
23
  module.exports = __toCommonJS(Disposable_exports);
24
24
  class Disposable {
25
25
  subscriptions = [];
26
- async dispose() {
27
- await Promise.all(this.subscriptions.map((subscription) => subscription()));
26
+ dispose() {
27
+ let subscription;
28
+ while (subscription = this.subscriptions.shift()) {
29
+ subscription();
30
+ }
28
31
  }
29
32
  }
30
33
  //# sourceMappingURL=Disposable.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/internal/Disposable.ts"],"sourcesContent":["export type DisposableSubscription = () => Promise<void> | void\n\nexport class Disposable {\n protected subscriptions: Array<DisposableSubscription> = []\n\n public async dispose() {\n await Promise.all(this.subscriptions.map((subscription) => subscription()))\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,MAAM,WAAW;AAAA,EACZ,gBAA+C,CAAC;AAAA,EAE1D,MAAa,UAAU;AACrB,UAAM,QAAQ,IAAI,KAAK,cAAc,IAAI,CAAC,iBAAiB,aAAa,CAAC,CAAC;AAAA,EAC5E;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/utils/internal/Disposable.ts"],"sourcesContent":["export type DisposableSubscription = () => void\n\nexport class Disposable {\n protected subscriptions: Array<DisposableSubscription> = []\n\n public dispose() {\n let subscription: DisposableSubscription | undefined\n while ((subscription = this.subscriptions.shift())) {\n subscription()\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEO,MAAM,WAAW;AAAA,EACZ,gBAA+C,CAAC;AAAA,EAEnD,UAAU;AACf,QAAI;AACJ,WAAQ,eAAe,KAAK,cAAc,MAAM,GAAI;AAClD,mBAAa;AAAA,IACf;AAAA,EACF;AACF;","names":[]}
@@ -1,7 +1,10 @@
1
1
  class Disposable {
2
2
  subscriptions = [];
3
- async dispose() {
4
- await Promise.all(this.subscriptions.map((subscription) => subscription()));
3
+ dispose() {
4
+ let subscription;
5
+ while (subscription = this.subscriptions.shift()) {
6
+ subscription();
7
+ }
5
8
  }
6
9
  }
7
10
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/internal/Disposable.ts"],"sourcesContent":["export type DisposableSubscription = () => Promise<void> | void\n\nexport class Disposable {\n protected subscriptions: Array<DisposableSubscription> = []\n\n public async dispose() {\n await Promise.all(this.subscriptions.map((subscription) => subscription()))\n }\n}\n"],"mappings":"AAEO,MAAM,WAAW;AAAA,EACZ,gBAA+C,CAAC;AAAA,EAE1D,MAAa,UAAU;AACrB,UAAM,QAAQ,IAAI,KAAK,cAAc,IAAI,CAAC,iBAAiB,aAAa,CAAC,CAAC;AAAA,EAC5E;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/utils/internal/Disposable.ts"],"sourcesContent":["export type DisposableSubscription = () => void\n\nexport class Disposable {\n protected subscriptions: Array<DisposableSubscription> = []\n\n public dispose() {\n let subscription: DisposableSubscription | undefined\n while ((subscription = this.subscriptions.shift())) {\n subscription()\n }\n }\n}\n"],"mappings":"AAEO,MAAM,WAAW;AAAA,EACZ,gBAA+C,CAAC;AAAA,EAEnD,UAAU;AACf,QAAI;AACJ,WAAQ,eAAe,KAAK,cAAc,MAAM,GAAI;AAClD,mBAAa;AAAA,IACf;AAAA,EACF;AACF;","names":[]}
@@ -15,5 +15,14 @@ declare const devUtils: {
15
15
  warn: typeof warn;
16
16
  error: typeof error;
17
17
  };
18
+ /**
19
+ * Internal error instance.
20
+ * Used to differentiate the library errors that must be forwarded
21
+ * to the user from the unhandled exceptions. Use this if you don't
22
+ * wish for the error to be coerced to a 500 fallback response.
23
+ */
24
+ declare class InternalError extends Error {
25
+ constructor(message: string);
26
+ }
18
27
 
19
- export { devUtils };
28
+ export { InternalError, devUtils };
@@ -15,5 +15,14 @@ declare const devUtils: {
15
15
  warn: typeof warn;
16
16
  error: typeof error;
17
17
  };
18
+ /**
19
+ * Internal error instance.
20
+ * Used to differentiate the library errors that must be forwarded
21
+ * to the user from the unhandled exceptions. Use this if you don't
22
+ * wish for the error to be coerced to a 500 fallback response.
23
+ */
24
+ declare class InternalError extends Error {
25
+ constructor(message: string);
26
+ }
18
27
 
19
- export { devUtils };
28
+ export { InternalError, devUtils };
@@ -18,6 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var devUtils_exports = {};
20
20
  __export(devUtils_exports, {
21
+ InternalError: () => InternalError,
21
22
  devUtils: () => devUtils
22
23
  });
23
24
  module.exports = __toCommonJS(devUtils_exports);
@@ -38,4 +39,10 @@ const devUtils = {
38
39
  warn,
39
40
  error
40
41
  };
42
+ class InternalError extends Error {
43
+ constructor(message) {
44
+ super(message);
45
+ this.name = "InternalError";
46
+ }
47
+ }
41
48
  //# sourceMappingURL=devUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/internal/devUtils.ts"],"sourcesContent":["import { format } from 'outvariant'\n\nconst LIBRARY_PREFIX = '[MSW]'\n\n/**\n * Formats a given message by appending the library's prefix string.\n */\nfunction formatMessage(message: string, ...positionals: any[]): string {\n const interpolatedMessage = format(message, ...positionals)\n return `${LIBRARY_PREFIX} ${interpolatedMessage}`\n}\n\n/**\n * Prints a library-specific warning.\n */\nfunction warn(message: string, ...positionals: any[]): void {\n console.warn(formatMessage(message, ...positionals))\n}\n\n/**\n * Prints a library-specific error.\n */\nfunction error(message: string, ...positionals: any[]): void {\n console.error(formatMessage(message, ...positionals))\n}\n\nexport const devUtils = {\n formatMessage,\n warn,\n error,\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAuB;AAEvB,MAAM,iBAAiB;AAKvB,SAAS,cAAc,YAAoB,aAA4B;AACrE,QAAM,0BAAsB,0BAAO,SAAS,GAAG,WAAW;AAC1D,SAAO,GAAG,cAAc,IAAI,mBAAmB;AACjD;AAKA,SAAS,KAAK,YAAoB,aAA0B;AAC1D,UAAQ,KAAK,cAAc,SAAS,GAAG,WAAW,CAAC;AACrD;AAKA,SAAS,MAAM,YAAoB,aAA0B;AAC3D,UAAQ,MAAM,cAAc,SAAS,GAAG,WAAW,CAAC;AACtD;AAEO,MAAM,WAAW;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/utils/internal/devUtils.ts"],"sourcesContent":["import { format } from 'outvariant'\n\nconst LIBRARY_PREFIX = '[MSW]'\n\n/**\n * Formats a given message by appending the library's prefix string.\n */\nfunction formatMessage(message: string, ...positionals: any[]): string {\n const interpolatedMessage = format(message, ...positionals)\n return `${LIBRARY_PREFIX} ${interpolatedMessage}`\n}\n\n/**\n * Prints a library-specific warning.\n */\nfunction warn(message: string, ...positionals: any[]): void {\n console.warn(formatMessage(message, ...positionals))\n}\n\n/**\n * Prints a library-specific error.\n */\nfunction error(message: string, ...positionals: any[]): void {\n console.error(formatMessage(message, ...positionals))\n}\n\nexport const devUtils = {\n formatMessage,\n warn,\n error,\n}\n\n/**\n * Internal error instance.\n * Used to differentiate the library errors that must be forwarded\n * to the user from the unhandled exceptions. Use this if you don't\n * wish for the error to be coerced to a 500 fallback response.\n */\nexport class InternalError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InternalError'\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAuB;AAEvB,MAAM,iBAAiB;AAKvB,SAAS,cAAc,YAAoB,aAA4B;AACrE,QAAM,0BAAsB,0BAAO,SAAS,GAAG,WAAW;AAC1D,SAAO,GAAG,cAAc,IAAI,mBAAmB;AACjD;AAKA,SAAS,KAAK,YAAoB,aAA0B;AAC1D,UAAQ,KAAK,cAAc,SAAS,GAAG,WAAW,CAAC;AACrD;AAKA,SAAS,MAAM,YAAoB,aAA0B;AAC3D,UAAQ,MAAM,cAAc,SAAS,GAAG,WAAW,CAAC;AACtD;AAEO,MAAM,WAAW;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF;AAQO,MAAM,sBAAsB,MAAM;AAAA,EACvC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
@@ -15,7 +15,14 @@ const devUtils = {
15
15
  warn,
16
16
  error
17
17
  };
18
+ class InternalError extends Error {
19
+ constructor(message) {
20
+ super(message);
21
+ this.name = "InternalError";
22
+ }
23
+ }
18
24
  export {
25
+ InternalError,
19
26
  devUtils
20
27
  };
21
28
  //# sourceMappingURL=devUtils.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/internal/devUtils.ts"],"sourcesContent":["import { format } from 'outvariant'\n\nconst LIBRARY_PREFIX = '[MSW]'\n\n/**\n * Formats a given message by appending the library's prefix string.\n */\nfunction formatMessage(message: string, ...positionals: any[]): string {\n const interpolatedMessage = format(message, ...positionals)\n return `${LIBRARY_PREFIX} ${interpolatedMessage}`\n}\n\n/**\n * Prints a library-specific warning.\n */\nfunction warn(message: string, ...positionals: any[]): void {\n console.warn(formatMessage(message, ...positionals))\n}\n\n/**\n * Prints a library-specific error.\n */\nfunction error(message: string, ...positionals: any[]): void {\n console.error(formatMessage(message, ...positionals))\n}\n\nexport const devUtils = {\n formatMessage,\n warn,\n error,\n}\n"],"mappings":"AAAA,SAAS,cAAc;AAEvB,MAAM,iBAAiB;AAKvB,SAAS,cAAc,YAAoB,aAA4B;AACrE,QAAM,sBAAsB,OAAO,SAAS,GAAG,WAAW;AAC1D,SAAO,GAAG,cAAc,IAAI,mBAAmB;AACjD;AAKA,SAAS,KAAK,YAAoB,aAA0B;AAC1D,UAAQ,KAAK,cAAc,SAAS,GAAG,WAAW,CAAC;AACrD;AAKA,SAAS,MAAM,YAAoB,aAA0B;AAC3D,UAAQ,MAAM,cAAc,SAAS,GAAG,WAAW,CAAC;AACtD;AAEO,MAAM,WAAW;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/utils/internal/devUtils.ts"],"sourcesContent":["import { format } from 'outvariant'\n\nconst LIBRARY_PREFIX = '[MSW]'\n\n/**\n * Formats a given message by appending the library's prefix string.\n */\nfunction formatMessage(message: string, ...positionals: any[]): string {\n const interpolatedMessage = format(message, ...positionals)\n return `${LIBRARY_PREFIX} ${interpolatedMessage}`\n}\n\n/**\n * Prints a library-specific warning.\n */\nfunction warn(message: string, ...positionals: any[]): void {\n console.warn(formatMessage(message, ...positionals))\n}\n\n/**\n * Prints a library-specific error.\n */\nfunction error(message: string, ...positionals: any[]): void {\n console.error(formatMessage(message, ...positionals))\n}\n\nexport const devUtils = {\n formatMessage,\n warn,\n error,\n}\n\n/**\n * Internal error instance.\n * Used to differentiate the library errors that must be forwarded\n * to the user from the unhandled exceptions. Use this if you don't\n * wish for the error to be coerced to a 500 fallback response.\n */\nexport class InternalError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InternalError'\n }\n}\n"],"mappings":"AAAA,SAAS,cAAc;AAEvB,MAAM,iBAAiB;AAKvB,SAAS,cAAc,YAAoB,aAA4B;AACrE,QAAM,sBAAsB,OAAO,SAAS,GAAG,WAAW;AAC1D,SAAO,GAAG,cAAc,IAAI,mBAAmB;AACjD;AAKA,SAAS,KAAK,YAAoB,aAA0B;AAC1D,UAAQ,KAAK,cAAc,SAAS,GAAG,WAAW,CAAC;AACrD;AAKA,SAAS,MAAM,YAAoB,aAA0B;AAC3D,UAAQ,MAAM,cAAc,SAAS,GAAG,WAAW,CAAC;AACtD;AAEO,MAAM,WAAW;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF;AAQO,MAAM,sBAAsB,MAAM;AAAA,EACvC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
@@ -6,6 +6,7 @@ import { Path } from './matchRequestUrl.mjs';
6
6
  * - Removes query parameters and hashes.
7
7
  * - Rebases relative URLs against the "baseUrl" or the current location.
8
8
  * - Preserves relative URLs in Node.js, unless specified otherwise.
9
+ * - Preserves optional path parameters.
9
10
  */
10
11
  declare function normalizePath(path: Path, baseUrl?: string): Path;
11
12
 
@@ -6,6 +6,7 @@ import { Path } from './matchRequestUrl.js';
6
6
  * - Removes query parameters and hashes.
7
7
  * - Rebases relative URLs against the "baseUrl" or the current location.
8
8
  * - Preserves relative URLs in Node.js, unless specified otherwise.
9
+ * - Preserves optional path parameters.
9
10
  */
10
11
  declare function normalizePath(path: Path, baseUrl?: string): Path;
11
12
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/matching/normalizePath.ts"],"sourcesContent":["import type { Path } from './matchRequestUrl'\nimport { cleanUrl } from '../url/cleanUrl'\nimport { getAbsoluteUrl } from '../url/getAbsoluteUrl'\n\n/**\n * Normalizes a given request handler path:\n * - Preserves RegExp.\n * - Removes query parameters and hashes.\n * - Rebases relative URLs against the \"baseUrl\" or the current location.\n * - Preserves relative URLs in Node.js, unless specified otherwise.\n */\nexport function normalizePath(path: Path, baseUrl?: string): Path {\n // RegExp paths do not need normalization.\n if (path instanceof RegExp) {\n return path\n }\n\n const maybeAbsoluteUrl = getAbsoluteUrl(path, baseUrl)\n\n return cleanUrl(maybeAbsoluteUrl)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,sBAAyB;AACzB,4BAA+B;AASxB,SAAS,cAAc,MAAY,SAAwB;AAEhE,MAAI,gBAAgB,QAAQ;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,uBAAmB,sCAAe,MAAM,OAAO;AAErD,aAAO,0BAAS,gBAAgB;AAClC;","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/utils/matching/normalizePath.ts"],"sourcesContent":["import type { Path } from './matchRequestUrl'\nimport { cleanUrl } from '../url/cleanUrl'\nimport { getAbsoluteUrl } from '../url/getAbsoluteUrl'\n\n/**\n * Normalizes a given request handler path:\n * - Preserves RegExp.\n * - Removes query parameters and hashes.\n * - Rebases relative URLs against the \"baseUrl\" or the current location.\n * - Preserves relative URLs in Node.js, unless specified otherwise.\n * - Preserves optional path parameters.\n */\nexport function normalizePath(path: Path, baseUrl?: string): Path {\n // RegExp paths do not need normalization.\n if (path instanceof RegExp) {\n return path\n }\n\n const maybeAbsoluteUrl = getAbsoluteUrl(path, baseUrl)\n\n return cleanUrl(maybeAbsoluteUrl)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,sBAAyB;AACzB,4BAA+B;AAUxB,SAAS,cAAc,MAAY,SAAwB;AAEhE,MAAI,gBAAgB,QAAQ;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,uBAAmB,sCAAe,MAAM,OAAO;AAErD,aAAO,0BAAS,gBAAgB;AAClC;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/matching/normalizePath.ts"],"sourcesContent":["import type { Path } from './matchRequestUrl'\nimport { cleanUrl } from '../url/cleanUrl'\nimport { getAbsoluteUrl } from '../url/getAbsoluteUrl'\n\n/**\n * Normalizes a given request handler path:\n * - Preserves RegExp.\n * - Removes query parameters and hashes.\n * - Rebases relative URLs against the \"baseUrl\" or the current location.\n * - Preserves relative URLs in Node.js, unless specified otherwise.\n */\nexport function normalizePath(path: Path, baseUrl?: string): Path {\n // RegExp paths do not need normalization.\n if (path instanceof RegExp) {\n return path\n }\n\n const maybeAbsoluteUrl = getAbsoluteUrl(path, baseUrl)\n\n return cleanUrl(maybeAbsoluteUrl)\n}\n"],"mappings":"AACA,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AASxB,SAAS,cAAc,MAAY,SAAwB;AAEhE,MAAI,gBAAgB,QAAQ;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,mBAAmB,eAAe,MAAM,OAAO;AAErD,SAAO,SAAS,gBAAgB;AAClC;","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/utils/matching/normalizePath.ts"],"sourcesContent":["import type { Path } from './matchRequestUrl'\nimport { cleanUrl } from '../url/cleanUrl'\nimport { getAbsoluteUrl } from '../url/getAbsoluteUrl'\n\n/**\n * Normalizes a given request handler path:\n * - Preserves RegExp.\n * - Removes query parameters and hashes.\n * - Rebases relative URLs against the \"baseUrl\" or the current location.\n * - Preserves relative URLs in Node.js, unless specified otherwise.\n * - Preserves optional path parameters.\n */\nexport function normalizePath(path: Path, baseUrl?: string): Path {\n // RegExp paths do not need normalization.\n if (path instanceof RegExp) {\n return path\n }\n\n const maybeAbsoluteUrl = getAbsoluteUrl(path, baseUrl)\n\n return cleanUrl(maybeAbsoluteUrl)\n}\n"],"mappings":"AACA,SAAS,gBAAgB;AACzB,SAAS,sBAAsB;AAUxB,SAAS,cAAc,MAAY,SAAwB;AAEhE,MAAI,gBAAgB,QAAQ;AAC1B,WAAO;AAAA,EACT;AAEA,QAAM,mBAAmB,eAAe,MAAM,OAAO;AAErD,SAAO,SAAS,gBAAgB;AAClC;","names":[]}
@@ -25,7 +25,7 @@ var import_toPublicUrl = require("./toPublicUrl.js");
25
25
  var import_devUtils = require("../internal/devUtils.js");
26
26
  async function onUnhandledRequest(request, strategy = "warn") {
27
27
  const url = new URL(request.url);
28
- const publicUrl = (0, import_toPublicUrl.toPublicUrl)(url);
28
+ const publicUrl = (0, import_toPublicUrl.toPublicUrl)(url) + url.search;
29
29
  const unhandledRequestMessage = `intercepted a request without a matching request handler:
30
30
 
31
31
  \u2022 ${request.method} ${publicUrl}
@@ -36,7 +36,7 @@ Read more: https://mswjs.io/docs/getting-started/mocks`;
36
36
  switch (strategy2) {
37
37
  case "error": {
38
38
  import_devUtils.devUtils.error("Error: %s", unhandledRequestMessage);
39
- throw new Error(
39
+ throw new import_devUtils.InternalError(
40
40
  import_devUtils.devUtils.formatMessage(
41
41
  'Cannot bypass a request when using the "error" strategy for the "onUnhandledRequest" option.'
42
42
  )
@@ -49,7 +49,7 @@ Read more: https://mswjs.io/docs/getting-started/mocks`;
49
49
  case "bypass":
50
50
  break;
51
51
  default:
52
- throw new Error(
52
+ throw new import_devUtils.InternalError(
53
53
  import_devUtils.devUtils.formatMessage(
54
54
  'Failed to react to an unhandled request: unknown strategy "%s". Please provide one of the supported strategies ("bypass", "warn", "error") or a custom callback function as the value of the "onUnhandledRequest" option.',
55
55
  strategy2
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/request/onUnhandledRequest.ts"],"sourcesContent":["import { toPublicUrl } from './toPublicUrl'\nimport { devUtils } from '../internal/devUtils'\n\nexport interface UnhandledRequestPrint {\n warning(): void\n error(): void\n}\n\nexport type UnhandledRequestCallback = (\n request: Request,\n print: UnhandledRequestPrint,\n) => void\n\nexport type UnhandledRequestStrategy =\n | 'bypass'\n | 'warn'\n | 'error'\n | UnhandledRequestCallback\n\nexport async function onUnhandledRequest(\n request: Request,\n strategy: UnhandledRequestStrategy = 'warn',\n): Promise<void> {\n const url = new URL(request.url)\n const publicUrl = toPublicUrl(url)\n\n const unhandledRequestMessage = `intercepted a request without a matching request handler:\\n\\n \\u2022 ${request.method} ${publicUrl}\\n\\nIf you still wish to intercept this unhandled request, please create a request handler for it.\\nRead more: https://mswjs.io/docs/getting-started/mocks`\n\n function applyStrategy(strategy: UnhandledRequestStrategy) {\n switch (strategy) {\n case 'error': {\n // Print a developer-friendly error.\n devUtils.error('Error: %s', unhandledRequestMessage)\n\n // Throw an exception to halt request processing and not perform the original request.\n throw new Error(\n devUtils.formatMessage(\n 'Cannot bypass a request when using the \"error\" strategy for the \"onUnhandledRequest\" option.',\n ),\n )\n }\n\n case 'warn': {\n devUtils.warn('Warning: %s', unhandledRequestMessage)\n break\n }\n\n case 'bypass':\n break\n\n default:\n throw new Error(\n devUtils.formatMessage(\n 'Failed to react to an unhandled request: unknown strategy \"%s\". Please provide one of the supported strategies (\"bypass\", \"warn\", \"error\") or a custom callback function as the value of the \"onUnhandledRequest\" option.',\n strategy,\n ),\n )\n }\n }\n\n if (typeof strategy === 'function') {\n strategy(request, {\n warning: applyStrategy.bind(null, 'warn'),\n error: applyStrategy.bind(null, 'error'),\n })\n return\n }\n\n /**\n * @note Ignore \"file://\" requests.\n * Those often are an implementation detail of modern tooling\n * that fetches modules via HTTP. Developers don't issue those\n * requests and so they mustn't be warned about them.\n */\n if (url.protocol === 'file:') {\n return\n }\n\n applyStrategy(strategy)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAA4B;AAC5B,sBAAyB;AAkBzB,eAAsB,mBACpB,SACA,WAAqC,QACtB;AACf,QAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,QAAM,gBAAY,gCAAY,GAAG;AAEjC,QAAM,0BAA0B;AAAA;AAAA,WAAyE,QAAQ,MAAM,IAAI,SAAS;AAAA;AAAA;AAAA;AAEpI,WAAS,cAAcA,WAAoC;AACzD,YAAQA,WAAU;AAAA,MAChB,KAAK,SAAS;AAEZ,iCAAS,MAAM,aAAa,uBAAuB;AAGnD,cAAM,IAAI;AAAA,UACR,yBAAS;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,iCAAS,KAAK,eAAe,uBAAuB;AACpD;AAAA,MACF;AAAA,MAEA,KAAK;AACH;AAAA,MAEF;AACE,cAAM,IAAI;AAAA,UACR,yBAAS;AAAA,YACP;AAAA,YACAA;AAAA,UACF;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,OAAO,aAAa,YAAY;AAClC,aAAS,SAAS;AAAA,MAChB,SAAS,cAAc,KAAK,MAAM,MAAM;AAAA,MACxC,OAAO,cAAc,KAAK,MAAM,OAAO;AAAA,IACzC,CAAC;AACD;AAAA,EACF;AAQA,MAAI,IAAI,aAAa,SAAS;AAC5B;AAAA,EACF;AAEA,gBAAc,QAAQ;AACxB;","names":["strategy"]}
1
+ {"version":3,"sources":["../../../../src/core/utils/request/onUnhandledRequest.ts"],"sourcesContent":["import { toPublicUrl } from './toPublicUrl'\nimport { InternalError, devUtils } from '../internal/devUtils'\n\nexport interface UnhandledRequestPrint {\n warning(): void\n error(): void\n}\n\nexport type UnhandledRequestCallback = (\n request: Request,\n print: UnhandledRequestPrint,\n) => void\n\nexport type UnhandledRequestStrategy =\n | 'bypass'\n | 'warn'\n | 'error'\n | UnhandledRequestCallback\n\nexport async function onUnhandledRequest(\n request: Request,\n strategy: UnhandledRequestStrategy = 'warn',\n): Promise<void> {\n const url = new URL(request.url)\n const publicUrl = toPublicUrl(url) + url.search\n\n const unhandledRequestMessage = `intercepted a request without a matching request handler:\\n\\n \\u2022 ${request.method} ${publicUrl}\\n\\nIf you still wish to intercept this unhandled request, please create a request handler for it.\\nRead more: https://mswjs.io/docs/getting-started/mocks`\n\n function applyStrategy(strategy: UnhandledRequestStrategy) {\n switch (strategy) {\n case 'error': {\n // Print a developer-friendly error.\n devUtils.error('Error: %s', unhandledRequestMessage)\n\n // Throw an exception to halt request processing and not perform the original request.\n throw new InternalError(\n devUtils.formatMessage(\n 'Cannot bypass a request when using the \"error\" strategy for the \"onUnhandledRequest\" option.',\n ),\n )\n }\n\n case 'warn': {\n devUtils.warn('Warning: %s', unhandledRequestMessage)\n break\n }\n\n case 'bypass':\n break\n\n default:\n throw new InternalError(\n devUtils.formatMessage(\n 'Failed to react to an unhandled request: unknown strategy \"%s\". Please provide one of the supported strategies (\"bypass\", \"warn\", \"error\") or a custom callback function as the value of the \"onUnhandledRequest\" option.',\n strategy,\n ),\n )\n }\n }\n\n if (typeof strategy === 'function') {\n strategy(request, {\n warning: applyStrategy.bind(null, 'warn'),\n error: applyStrategy.bind(null, 'error'),\n })\n return\n }\n\n /**\n * @note Ignore \"file://\" requests.\n * Those often are an implementation detail of modern tooling\n * that fetches modules via HTTP. Developers don't issue those\n * requests and so they mustn't be warned about them.\n */\n if (url.protocol === 'file:') {\n return\n }\n\n applyStrategy(strategy)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAA4B;AAC5B,sBAAwC;AAkBxC,eAAsB,mBACpB,SACA,WAAqC,QACtB;AACf,QAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,QAAM,gBAAY,gCAAY,GAAG,IAAI,IAAI;AAEzC,QAAM,0BAA0B;AAAA;AAAA,WAAyE,QAAQ,MAAM,IAAI,SAAS;AAAA;AAAA;AAAA;AAEpI,WAAS,cAAcA,WAAoC;AACzD,YAAQA,WAAU;AAAA,MAChB,KAAK,SAAS;AAEZ,iCAAS,MAAM,aAAa,uBAAuB;AAGnD,cAAM,IAAI;AAAA,UACR,yBAAS;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,iCAAS,KAAK,eAAe,uBAAuB;AACpD;AAAA,MACF;AAAA,MAEA,KAAK;AACH;AAAA,MAEF;AACE,cAAM,IAAI;AAAA,UACR,yBAAS;AAAA,YACP;AAAA,YACAA;AAAA,UACF;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,OAAO,aAAa,YAAY;AAClC,aAAS,SAAS;AAAA,MAChB,SAAS,cAAc,KAAK,MAAM,MAAM;AAAA,MACxC,OAAO,cAAc,KAAK,MAAM,OAAO;AAAA,IACzC,CAAC;AACD;AAAA,EACF;AAQA,MAAI,IAAI,aAAa,SAAS;AAC5B;AAAA,EACF;AAEA,gBAAc,QAAQ;AACxB;","names":["strategy"]}
@@ -1,8 +1,8 @@
1
1
  import { toPublicUrl } from './toPublicUrl.mjs';
2
- import { devUtils } from '../internal/devUtils.mjs';
2
+ import { InternalError, devUtils } from '../internal/devUtils.mjs';
3
3
  async function onUnhandledRequest(request, strategy = "warn") {
4
4
  const url = new URL(request.url);
5
- const publicUrl = toPublicUrl(url);
5
+ const publicUrl = toPublicUrl(url) + url.search;
6
6
  const unhandledRequestMessage = `intercepted a request without a matching request handler:
7
7
 
8
8
  \u2022 ${request.method} ${publicUrl}
@@ -13,7 +13,7 @@ Read more: https://mswjs.io/docs/getting-started/mocks`;
13
13
  switch (strategy2) {
14
14
  case "error": {
15
15
  devUtils.error("Error: %s", unhandledRequestMessage);
16
- throw new Error(
16
+ throw new InternalError(
17
17
  devUtils.formatMessage(
18
18
  'Cannot bypass a request when using the "error" strategy for the "onUnhandledRequest" option.'
19
19
  )
@@ -26,7 +26,7 @@ Read more: https://mswjs.io/docs/getting-started/mocks`;
26
26
  case "bypass":
27
27
  break;
28
28
  default:
29
- throw new Error(
29
+ throw new InternalError(
30
30
  devUtils.formatMessage(
31
31
  'Failed to react to an unhandled request: unknown strategy "%s". Please provide one of the supported strategies ("bypass", "warn", "error") or a custom callback function as the value of the "onUnhandledRequest" option.',
32
32
  strategy2
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/request/onUnhandledRequest.ts"],"sourcesContent":["import { toPublicUrl } from './toPublicUrl'\nimport { devUtils } from '../internal/devUtils'\n\nexport interface UnhandledRequestPrint {\n warning(): void\n error(): void\n}\n\nexport type UnhandledRequestCallback = (\n request: Request,\n print: UnhandledRequestPrint,\n) => void\n\nexport type UnhandledRequestStrategy =\n | 'bypass'\n | 'warn'\n | 'error'\n | UnhandledRequestCallback\n\nexport async function onUnhandledRequest(\n request: Request,\n strategy: UnhandledRequestStrategy = 'warn',\n): Promise<void> {\n const url = new URL(request.url)\n const publicUrl = toPublicUrl(url)\n\n const unhandledRequestMessage = `intercepted a request without a matching request handler:\\n\\n \\u2022 ${request.method} ${publicUrl}\\n\\nIf you still wish to intercept this unhandled request, please create a request handler for it.\\nRead more: https://mswjs.io/docs/getting-started/mocks`\n\n function applyStrategy(strategy: UnhandledRequestStrategy) {\n switch (strategy) {\n case 'error': {\n // Print a developer-friendly error.\n devUtils.error('Error: %s', unhandledRequestMessage)\n\n // Throw an exception to halt request processing and not perform the original request.\n throw new Error(\n devUtils.formatMessage(\n 'Cannot bypass a request when using the \"error\" strategy for the \"onUnhandledRequest\" option.',\n ),\n )\n }\n\n case 'warn': {\n devUtils.warn('Warning: %s', unhandledRequestMessage)\n break\n }\n\n case 'bypass':\n break\n\n default:\n throw new Error(\n devUtils.formatMessage(\n 'Failed to react to an unhandled request: unknown strategy \"%s\". Please provide one of the supported strategies (\"bypass\", \"warn\", \"error\") or a custom callback function as the value of the \"onUnhandledRequest\" option.',\n strategy,\n ),\n )\n }\n }\n\n if (typeof strategy === 'function') {\n strategy(request, {\n warning: applyStrategy.bind(null, 'warn'),\n error: applyStrategy.bind(null, 'error'),\n })\n return\n }\n\n /**\n * @note Ignore \"file://\" requests.\n * Those often are an implementation detail of modern tooling\n * that fetches modules via HTTP. Developers don't issue those\n * requests and so they mustn't be warned about them.\n */\n if (url.protocol === 'file:') {\n return\n }\n\n applyStrategy(strategy)\n}\n"],"mappings":"AAAA,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AAkBzB,eAAsB,mBACpB,SACA,WAAqC,QACtB;AACf,QAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,QAAM,YAAY,YAAY,GAAG;AAEjC,QAAM,0BAA0B;AAAA;AAAA,WAAyE,QAAQ,MAAM,IAAI,SAAS;AAAA;AAAA;AAAA;AAEpI,WAAS,cAAcA,WAAoC;AACzD,YAAQA,WAAU;AAAA,MAChB,KAAK,SAAS;AAEZ,iBAAS,MAAM,aAAa,uBAAuB;AAGnD,cAAM,IAAI;AAAA,UACR,SAAS;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,iBAAS,KAAK,eAAe,uBAAuB;AACpD;AAAA,MACF;AAAA,MAEA,KAAK;AACH;AAAA,MAEF;AACE,cAAM,IAAI;AAAA,UACR,SAAS;AAAA,YACP;AAAA,YACAA;AAAA,UACF;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,OAAO,aAAa,YAAY;AAClC,aAAS,SAAS;AAAA,MAChB,SAAS,cAAc,KAAK,MAAM,MAAM;AAAA,MACxC,OAAO,cAAc,KAAK,MAAM,OAAO;AAAA,IACzC,CAAC;AACD;AAAA,EACF;AAQA,MAAI,IAAI,aAAa,SAAS;AAC5B;AAAA,EACF;AAEA,gBAAc,QAAQ;AACxB;","names":["strategy"]}
1
+ {"version":3,"sources":["../../../../src/core/utils/request/onUnhandledRequest.ts"],"sourcesContent":["import { toPublicUrl } from './toPublicUrl'\nimport { InternalError, devUtils } from '../internal/devUtils'\n\nexport interface UnhandledRequestPrint {\n warning(): void\n error(): void\n}\n\nexport type UnhandledRequestCallback = (\n request: Request,\n print: UnhandledRequestPrint,\n) => void\n\nexport type UnhandledRequestStrategy =\n | 'bypass'\n | 'warn'\n | 'error'\n | UnhandledRequestCallback\n\nexport async function onUnhandledRequest(\n request: Request,\n strategy: UnhandledRequestStrategy = 'warn',\n): Promise<void> {\n const url = new URL(request.url)\n const publicUrl = toPublicUrl(url) + url.search\n\n const unhandledRequestMessage = `intercepted a request without a matching request handler:\\n\\n \\u2022 ${request.method} ${publicUrl}\\n\\nIf you still wish to intercept this unhandled request, please create a request handler for it.\\nRead more: https://mswjs.io/docs/getting-started/mocks`\n\n function applyStrategy(strategy: UnhandledRequestStrategy) {\n switch (strategy) {\n case 'error': {\n // Print a developer-friendly error.\n devUtils.error('Error: %s', unhandledRequestMessage)\n\n // Throw an exception to halt request processing and not perform the original request.\n throw new InternalError(\n devUtils.formatMessage(\n 'Cannot bypass a request when using the \"error\" strategy for the \"onUnhandledRequest\" option.',\n ),\n )\n }\n\n case 'warn': {\n devUtils.warn('Warning: %s', unhandledRequestMessage)\n break\n }\n\n case 'bypass':\n break\n\n default:\n throw new InternalError(\n devUtils.formatMessage(\n 'Failed to react to an unhandled request: unknown strategy \"%s\". Please provide one of the supported strategies (\"bypass\", \"warn\", \"error\") or a custom callback function as the value of the \"onUnhandledRequest\" option.',\n strategy,\n ),\n )\n }\n }\n\n if (typeof strategy === 'function') {\n strategy(request, {\n warning: applyStrategy.bind(null, 'warn'),\n error: applyStrategy.bind(null, 'error'),\n })\n return\n }\n\n /**\n * @note Ignore \"file://\" requests.\n * Those often are an implementation detail of modern tooling\n * that fetches modules via HTTP. Developers don't issue those\n * requests and so they mustn't be warned about them.\n */\n if (url.protocol === 'file:') {\n return\n }\n\n applyStrategy(strategy)\n}\n"],"mappings":"AAAA,SAAS,mBAAmB;AAC5B,SAAS,eAAe,gBAAgB;AAkBxC,eAAsB,mBACpB,SACA,WAAqC,QACtB;AACf,QAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,QAAM,YAAY,YAAY,GAAG,IAAI,IAAI;AAEzC,QAAM,0BAA0B;AAAA;AAAA,WAAyE,QAAQ,MAAM,IAAI,SAAS;AAAA;AAAA;AAAA;AAEpI,WAAS,cAAcA,WAAoC;AACzD,YAAQA,WAAU;AAAA,MAChB,KAAK,SAAS;AAEZ,iBAAS,MAAM,aAAa,uBAAuB;AAGnD,cAAM,IAAI;AAAA,UACR,SAAS;AAAA,YACP;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,KAAK,QAAQ;AACX,iBAAS,KAAK,eAAe,uBAAuB;AACpD;AAAA,MACF;AAAA,MAEA,KAAK;AACH;AAAA,MAEF;AACE,cAAM,IAAI;AAAA,UACR,SAAS;AAAA,YACP;AAAA,YACAA;AAAA,UACF;AAAA,QACF;AAAA,IACJ;AAAA,EACF;AAEA,MAAI,OAAO,aAAa,YAAY;AAClC,aAAS,SAAS;AAAA,MAChB,SAAS,cAAc,KAAK,MAAM,MAAM;AAAA,MACxC,OAAO,cAAc,KAAK,MAAM,OAAO;AAAA,IACzC,CAAC;AACD;AAAA,EACF;AAQA,MAAI,IAAI,aAAa,SAAS;AAC5B;AAAA,EACF;AAEA,gBAAc,QAAQ;AACxB;","names":["strategy"]}
@@ -1,6 +1,7 @@
1
1
  declare function getSearchParams(path: string): URLSearchParams;
2
2
  /**
3
- * Removes query parameters and hashes from a given URL string.
3
+ * Removes search parameters and the fragment
4
+ * from a given URL string.
4
5
  */
5
6
  declare function cleanUrl(path: string): string;
6
7
 
@@ -1,6 +1,7 @@
1
1
  declare function getSearchParams(path: string): URLSearchParams;
2
2
  /**
3
- * Removes query parameters and hashes from a given URL string.
3
+ * Removes search parameters and the fragment
4
+ * from a given URL string.
4
5
  */
5
6
  declare function cleanUrl(path: string): string;
6
7
 
@@ -27,6 +27,9 @@ function getSearchParams(path) {
27
27
  return new URL(`/${path}`, "http://localhost").searchParams;
28
28
  }
29
29
  function cleanUrl(path) {
30
+ if (path.endsWith("?")) {
31
+ return path;
32
+ }
30
33
  return path.replace(REDUNDANT_CHARACTERS_EXP, "");
31
34
  }
32
35
  //# sourceMappingURL=cleanUrl.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/url/cleanUrl.ts"],"sourcesContent":["const REDUNDANT_CHARACTERS_EXP = /[\\?|#].*$/g\n\nexport function getSearchParams(path: string) {\n return new URL(`/${path}`, 'http://localhost').searchParams\n}\n\n/**\n * Removes query parameters and hashes from a given URL string.\n */\nexport function cleanUrl(path: string): string {\n return path.replace(REDUNDANT_CHARACTERS_EXP, '')\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAM,2BAA2B;AAE1B,SAAS,gBAAgB,MAAc;AAC5C,SAAO,IAAI,IAAI,IAAI,IAAI,IAAI,kBAAkB,EAAE;AACjD;AAKO,SAAS,SAAS,MAAsB;AAC7C,SAAO,KAAK,QAAQ,0BAA0B,EAAE;AAClD;","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/utils/url/cleanUrl.ts"],"sourcesContent":["const REDUNDANT_CHARACTERS_EXP = /[\\?|#].*$/g\n\nexport function getSearchParams(path: string) {\n return new URL(`/${path}`, 'http://localhost').searchParams\n}\n\n/**\n * Removes search parameters and the fragment\n * from a given URL string.\n */\nexport function cleanUrl(path: string): string {\n // If the path ends with an optional path parameter,\n // return it as-is.\n if (path.endsWith('?')) {\n return path\n }\n\n // Otherwise, remove the search and fragment from it.\n return path.replace(REDUNDANT_CHARACTERS_EXP, '')\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAM,2BAA2B;AAE1B,SAAS,gBAAgB,MAAc;AAC5C,SAAO,IAAI,IAAI,IAAI,IAAI,IAAI,kBAAkB,EAAE;AACjD;AAMO,SAAS,SAAS,MAAsB;AAG7C,MAAI,KAAK,SAAS,GAAG,GAAG;AACtB,WAAO;AAAA,EACT;AAGA,SAAO,KAAK,QAAQ,0BAA0B,EAAE;AAClD;","names":[]}
@@ -3,6 +3,9 @@ function getSearchParams(path) {
3
3
  return new URL(`/${path}`, "http://localhost").searchParams;
4
4
  }
5
5
  function cleanUrl(path) {
6
+ if (path.endsWith("?")) {
7
+ return path;
8
+ }
6
9
  return path.replace(REDUNDANT_CHARACTERS_EXP, "");
7
10
  }
8
11
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/utils/url/cleanUrl.ts"],"sourcesContent":["const REDUNDANT_CHARACTERS_EXP = /[\\?|#].*$/g\n\nexport function getSearchParams(path: string) {\n return new URL(`/${path}`, 'http://localhost').searchParams\n}\n\n/**\n * Removes query parameters and hashes from a given URL string.\n */\nexport function cleanUrl(path: string): string {\n return path.replace(REDUNDANT_CHARACTERS_EXP, '')\n}\n"],"mappings":"AAAA,MAAM,2BAA2B;AAE1B,SAAS,gBAAgB,MAAc;AAC5C,SAAO,IAAI,IAAI,IAAI,IAAI,IAAI,kBAAkB,EAAE;AACjD;AAKO,SAAS,SAAS,MAAsB;AAC7C,SAAO,KAAK,QAAQ,0BAA0B,EAAE;AAClD;","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/utils/url/cleanUrl.ts"],"sourcesContent":["const REDUNDANT_CHARACTERS_EXP = /[\\?|#].*$/g\n\nexport function getSearchParams(path: string) {\n return new URL(`/${path}`, 'http://localhost').searchParams\n}\n\n/**\n * Removes search parameters and the fragment\n * from a given URL string.\n */\nexport function cleanUrl(path: string): string {\n // If the path ends with an optional path parameter,\n // return it as-is.\n if (path.endsWith('?')) {\n return path\n }\n\n // Otherwise, remove the search and fragment from it.\n return path.replace(REDUNDANT_CHARACTERS_EXP, '')\n}\n"],"mappings":"AAAA,MAAM,2BAA2B;AAE1B,SAAS,gBAAgB,MAAc;AAC5C,SAAO,IAAI,IAAI,IAAI,IAAI,IAAI,kBAAkB,EAAE;AACjD;AAMO,SAAS,SAAS,MAAsB;AAG7C,MAAI,KAAK,SAAS,GAAG,GAAG;AACtB,WAAO;AAAA,EACT;AAGA,SAAO,KAAK,QAAQ,0BAA0B,EAAE;AAClD;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/ws/WebSocketClientManager.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport type {\n WebSocketData,\n WebSocketClientConnection,\n WebSocketClientConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport { matchRequestUrl, type Path } from '../utils/matching/matchRequestUrl'\n\nexport const MSW_WEBSOCKET_CLIENTS_KEY = 'msw:ws:clients'\n\nexport type WebSocketBroadcastChannelMessage =\n | {\n type: 'extraneous:send'\n payload: {\n clientId: string\n data: WebSocketData\n }\n }\n | {\n type: 'extraneous:close'\n payload: {\n clientId: string\n code?: number\n reason?: string\n }\n }\n\ntype SerializedClient = {\n clientId: string\n url: string\n}\n\n/**\n * A manager responsible for accumulating WebSocket client\n * connections across different browser runtimes.\n */\nexport class WebSocketClientManager {\n private inMemoryClients: Set<WebSocketClientConnectionProtocol>\n\n constructor(\n private channel: BroadcastChannel,\n private url: Path,\n ) {\n this.inMemoryClients = new Set()\n\n if (typeof localStorage !== 'undefined') {\n // When the worker clears the local storage key in \"worker.stop()\",\n // also clear the in-memory clients map.\n localStorage.removeItem = new Proxy(localStorage.removeItem, {\n apply: (target, thisArg, args) => {\n const [key] = args\n\n if (key === MSW_WEBSOCKET_CLIENTS_KEY) {\n this.inMemoryClients.clear()\n }\n\n return Reflect.apply(target, thisArg, args)\n },\n })\n }\n }\n\n /**\n * All active WebSocket client connections.\n */\n get clients(): Set<WebSocketClientConnectionProtocol> {\n // In the browser, different runtimes use \"localStorage\"\n // as the shared source of all the clients.\n if (typeof localStorage !== 'undefined') {\n const inMemoryClients = Array.from(this.inMemoryClients)\n\n console.log('get clients()', inMemoryClients, this.getSerializedClients())\n\n return new Set(\n inMemoryClients.concat(\n this.getSerializedClients()\n // Filter out the serialized clients that are already present\n // in this runtime in-memory. This is crucial because a remote client\n // wrapper CANNOT send a message to the client in THIS runtime\n // (the \"message\" event on broadcast channel won't trigger).\n .filter((serializedClient) => {\n if (\n inMemoryClients.every(\n (client) => client.id !== serializedClient.clientId,\n )\n ) {\n return serializedClient\n }\n })\n .map((serializedClient) => {\n return new WebSocketRemoteClientConnection(\n serializedClient.clientId,\n new URL(serializedClient.url),\n this.channel,\n )\n }),\n ),\n )\n }\n\n // In Node.js, the manager acts as a singleton, and all clients\n // are kept in-memory.\n return this.inMemoryClients\n }\n\n private getSerializedClients(): Array<SerializedClient> {\n invariant(\n typeof localStorage !== 'undefined',\n 'Failed to call WebSocketClientManager#getSerializedClients() in a non-browser environment. This is likely a bug in MSW. Please, report it on GitHub: https://github.com/mswjs/msw',\n )\n\n const clientsJson = localStorage.getItem(MSW_WEBSOCKET_CLIENTS_KEY)\n\n if (!clientsJson) {\n return []\n }\n\n const allClients = JSON.parse(clientsJson) as Array<SerializedClient>\n const matchingClients = allClients.filter((client) => {\n return matchRequestUrl(new URL(client.url), this.url).matches\n })\n\n return matchingClients\n }\n\n private addClient(client: WebSocketClientConnection): void {\n this.inMemoryClients.add(client)\n\n if (typeof localStorage !== 'undefined') {\n const serializedClients = this.getSerializedClients()\n\n // Serialize the current client for other runtimes to create\n // a remote wrapper over it. This has no effect on the current runtime.\n const nextSerializedClients = serializedClients.concat({\n clientId: client.id,\n url: client.url.href,\n } as SerializedClient)\n\n localStorage.setItem(\n MSW_WEBSOCKET_CLIENTS_KEY,\n JSON.stringify(nextSerializedClients),\n )\n }\n }\n\n /**\n * Adds the given `WebSocket` client connection to the set\n * of all connections. The given connection is always the complete\n * connection object because `addConnection()` is called only\n * for the opened connections in the same runtime.\n */\n public addConnection(client: WebSocketClientConnection): void {\n this.addClient(client)\n\n // Instruct the current client how to handle events\n // coming from other runtimes (e.g. when calling `.broadcast()`).\n const handleExtraneousMessage = (\n message: MessageEvent<WebSocketBroadcastChannelMessage>,\n ) => {\n const { type, payload } = message.data\n\n // Ignore broadcasted messages for other clients.\n if (\n typeof payload === 'object' &&\n 'clientId' in payload &&\n payload.clientId !== client.id\n ) {\n return\n }\n\n switch (type) {\n case 'extraneous:send': {\n client.send(payload.data)\n break\n }\n\n case 'extraneous:close': {\n client.close(payload.code, payload.reason)\n break\n }\n }\n }\n\n const abortController = new AbortController()\n\n this.channel.addEventListener('message', handleExtraneousMessage, {\n signal: abortController.signal,\n })\n\n // Once closed, this connection cannot be operated on.\n // This must include the extraneous runtimes as well.\n client.addEventListener('close', () => abortController.abort(), {\n once: true,\n })\n }\n}\n\n/**\n * A wrapper class to operate with WebSocket client connections\n * from other runtimes. This class maintains 1-1 public API\n * compatibility to the `WebSocketClientConnection` but relies\n * on the given `BroadcastChannel` to communicate instructions\n * with the client connections from other runtimes.\n */\nexport class WebSocketRemoteClientConnection\n implements WebSocketClientConnectionProtocol\n{\n constructor(\n public readonly id: string,\n public readonly url: URL,\n private channel: BroadcastChannel,\n ) {}\n\n send(data: WebSocketData): void {\n this.channel.postMessage({\n type: 'extraneous:send',\n payload: {\n clientId: this.id,\n data,\n },\n } as WebSocketBroadcastChannelMessage)\n }\n\n close(code?: number | undefined, reason?: string | undefined): void {\n this.channel.postMessage({\n type: 'extraneous:close',\n payload: {\n clientId: this.id,\n code,\n reason,\n },\n } as WebSocketBroadcastChannelMessage)\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/core/ws/WebSocketClientManager.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport type {\n WebSocketData,\n WebSocketClientConnection,\n WebSocketClientConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport { matchRequestUrl, type Path } from '../utils/matching/matchRequestUrl'\n\nexport const MSW_WEBSOCKET_CLIENTS_KEY = 'msw:ws:clients'\n\nexport type WebSocketBroadcastChannelMessage =\n | {\n type: 'extraneous:send'\n payload: {\n clientId: string\n data: WebSocketData\n }\n }\n | {\n type: 'extraneous:close'\n payload: {\n clientId: string\n code?: number\n reason?: string\n }\n }\n\ntype SerializedClient = {\n clientId: string\n url: string\n}\n\n/**\n * A manager responsible for accumulating WebSocket client\n * connections across different browser runtimes.\n */\nexport class WebSocketClientManager {\n private inMemoryClients: Set<WebSocketClientConnectionProtocol>\n\n constructor(\n private channel: BroadcastChannel,\n private url: Path,\n ) {\n this.inMemoryClients = new Set()\n\n // Purge in-memory clients when the worker stops.\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem = new Proxy(localStorage.removeItem, {\n apply: (target, thisArg, args) => {\n const [key] = args\n\n if (key === MSW_WEBSOCKET_CLIENTS_KEY) {\n this.inMemoryClients.clear()\n }\n\n return Reflect.apply(target, thisArg, args)\n },\n })\n }\n }\n\n /**\n * All active WebSocket client connections.\n */\n get clients(): Set<WebSocketClientConnectionProtocol> {\n // In the browser, different runtimes use \"localStorage\"\n // as the shared source of all the clients.\n if (typeof localStorage !== 'undefined') {\n const inMemoryClients = Array.from(this.inMemoryClients)\n\n console.log('get clients()', inMemoryClients, this.getSerializedClients())\n\n return new Set(\n inMemoryClients.concat(\n this.getSerializedClients()\n // Filter out the serialized clients that are already present\n // in this runtime in-memory. This is crucial because a remote client\n // wrapper CANNOT send a message to the client in THIS runtime\n // (the \"message\" event on broadcast channel won't trigger).\n .filter((serializedClient) => {\n if (\n inMemoryClients.every(\n (client) => client.id !== serializedClient.clientId,\n )\n ) {\n return serializedClient\n }\n })\n .map((serializedClient) => {\n return new WebSocketRemoteClientConnection(\n serializedClient.clientId,\n new URL(serializedClient.url),\n this.channel,\n )\n }),\n ),\n )\n }\n\n // In Node.js, the manager acts as a singleton, and all clients\n // are kept in-memory.\n return this.inMemoryClients\n }\n\n private getSerializedClients(): Array<SerializedClient> {\n invariant(\n typeof localStorage !== 'undefined',\n 'Failed to call WebSocketClientManager#getSerializedClients() in a non-browser environment. This is likely a bug in MSW. Please, report it on GitHub: https://github.com/mswjs/msw',\n )\n\n const clientsJson = localStorage.getItem(MSW_WEBSOCKET_CLIENTS_KEY)\n\n if (!clientsJson) {\n return []\n }\n\n const allClients = JSON.parse(clientsJson) as Array<SerializedClient>\n const matchingClients = allClients.filter((client) => {\n return matchRequestUrl(new URL(client.url), this.url).matches\n })\n\n return matchingClients\n }\n\n private addClient(client: WebSocketClientConnection): void {\n this.inMemoryClients.add(client)\n\n if (typeof localStorage !== 'undefined') {\n const serializedClients = this.getSerializedClients()\n\n // Serialize the current client for other runtimes to create\n // a remote wrapper over it. This has no effect on the current runtime.\n const nextSerializedClients = serializedClients.concat({\n clientId: client.id,\n url: client.url.href,\n } as SerializedClient)\n\n localStorage.setItem(\n MSW_WEBSOCKET_CLIENTS_KEY,\n JSON.stringify(nextSerializedClients),\n )\n }\n }\n\n /**\n * Adds the given `WebSocket` client connection to the set\n * of all connections. The given connection is always the complete\n * connection object because `addConnection()` is called only\n * for the opened connections in the same runtime.\n */\n public addConnection(client: WebSocketClientConnection): void {\n this.addClient(client)\n\n // Instruct the current client how to handle events\n // coming from other runtimes (e.g. when calling `.broadcast()`).\n const handleExtraneousMessage = (\n message: MessageEvent<WebSocketBroadcastChannelMessage>,\n ) => {\n const { type, payload } = message.data\n\n // Ignore broadcasted messages for other clients.\n if (\n typeof payload === 'object' &&\n 'clientId' in payload &&\n payload.clientId !== client.id\n ) {\n return\n }\n\n switch (type) {\n case 'extraneous:send': {\n client.send(payload.data)\n break\n }\n\n case 'extraneous:close': {\n client.close(payload.code, payload.reason)\n break\n }\n }\n }\n\n const abortController = new AbortController()\n\n this.channel.addEventListener('message', handleExtraneousMessage, {\n signal: abortController.signal,\n })\n\n // Once closed, this connection cannot be operated on.\n // This must include the extraneous runtimes as well.\n client.addEventListener('close', () => abortController.abort(), {\n once: true,\n })\n }\n}\n\n/**\n * A wrapper class to operate with WebSocket client connections\n * from other runtimes. This class maintains 1-1 public API\n * compatibility to the `WebSocketClientConnection` but relies\n * on the given `BroadcastChannel` to communicate instructions\n * with the client connections from other runtimes.\n */\nexport class WebSocketRemoteClientConnection\n implements WebSocketClientConnectionProtocol\n{\n constructor(\n public readonly id: string,\n public readonly url: URL,\n private channel: BroadcastChannel,\n ) {}\n\n send(data: WebSocketData): void {\n this.channel.postMessage({\n type: 'extraneous:send',\n payload: {\n clientId: this.id,\n data,\n },\n } as WebSocketBroadcastChannelMessage)\n }\n\n close(code?: number | undefined, reason?: string | undefined): void {\n this.channel.postMessage({\n type: 'extraneous:close',\n payload: {\n clientId: this.id,\n code,\n reason,\n },\n } as WebSocketBroadcastChannelMessage)\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/core/ws/WebSocketClientManager.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport type {\n WebSocketData,\n WebSocketClientConnection,\n WebSocketClientConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport { matchRequestUrl, type Path } from '../utils/matching/matchRequestUrl'\n\nexport const MSW_WEBSOCKET_CLIENTS_KEY = 'msw:ws:clients'\n\nexport type WebSocketBroadcastChannelMessage =\n | {\n type: 'extraneous:send'\n payload: {\n clientId: string\n data: WebSocketData\n }\n }\n | {\n type: 'extraneous:close'\n payload: {\n clientId: string\n code?: number\n reason?: string\n }\n }\n\ntype SerializedClient = {\n clientId: string\n url: string\n}\n\n/**\n * A manager responsible for accumulating WebSocket client\n * connections across different browser runtimes.\n */\nexport class WebSocketClientManager {\n private inMemoryClients: Set<WebSocketClientConnectionProtocol>\n\n constructor(\n private channel: BroadcastChannel,\n private url: Path,\n ) {\n this.inMemoryClients = new Set()\n\n if (typeof localStorage !== 'undefined') {\n // When the worker clears the local storage key in \"worker.stop()\",\n // also clear the in-memory clients map.\n localStorage.removeItem = new Proxy(localStorage.removeItem, {\n apply: (target, thisArg, args) => {\n const [key] = args\n\n if (key === MSW_WEBSOCKET_CLIENTS_KEY) {\n this.inMemoryClients.clear()\n }\n\n return Reflect.apply(target, thisArg, args)\n },\n })\n }\n }\n\n /**\n * All active WebSocket client connections.\n */\n get clients(): Set<WebSocketClientConnectionProtocol> {\n // In the browser, different runtimes use \"localStorage\"\n // as the shared source of all the clients.\n if (typeof localStorage !== 'undefined') {\n const inMemoryClients = Array.from(this.inMemoryClients)\n\n console.log('get clients()', inMemoryClients, this.getSerializedClients())\n\n return new Set(\n inMemoryClients.concat(\n this.getSerializedClients()\n // Filter out the serialized clients that are already present\n // in this runtime in-memory. This is crucial because a remote client\n // wrapper CANNOT send a message to the client in THIS runtime\n // (the \"message\" event on broadcast channel won't trigger).\n .filter((serializedClient) => {\n if (\n inMemoryClients.every(\n (client) => client.id !== serializedClient.clientId,\n )\n ) {\n return serializedClient\n }\n })\n .map((serializedClient) => {\n return new WebSocketRemoteClientConnection(\n serializedClient.clientId,\n new URL(serializedClient.url),\n this.channel,\n )\n }),\n ),\n )\n }\n\n // In Node.js, the manager acts as a singleton, and all clients\n // are kept in-memory.\n return this.inMemoryClients\n }\n\n private getSerializedClients(): Array<SerializedClient> {\n invariant(\n typeof localStorage !== 'undefined',\n 'Failed to call WebSocketClientManager#getSerializedClients() in a non-browser environment. This is likely a bug in MSW. Please, report it on GitHub: https://github.com/mswjs/msw',\n )\n\n const clientsJson = localStorage.getItem(MSW_WEBSOCKET_CLIENTS_KEY)\n\n if (!clientsJson) {\n return []\n }\n\n const allClients = JSON.parse(clientsJson) as Array<SerializedClient>\n const matchingClients = allClients.filter((client) => {\n return matchRequestUrl(new URL(client.url), this.url).matches\n })\n\n return matchingClients\n }\n\n private addClient(client: WebSocketClientConnection): void {\n this.inMemoryClients.add(client)\n\n if (typeof localStorage !== 'undefined') {\n const serializedClients = this.getSerializedClients()\n\n // Serialize the current client for other runtimes to create\n // a remote wrapper over it. This has no effect on the current runtime.\n const nextSerializedClients = serializedClients.concat({\n clientId: client.id,\n url: client.url.href,\n } as SerializedClient)\n\n localStorage.setItem(\n MSW_WEBSOCKET_CLIENTS_KEY,\n JSON.stringify(nextSerializedClients),\n )\n }\n }\n\n /**\n * Adds the given `WebSocket` client connection to the set\n * of all connections. The given connection is always the complete\n * connection object because `addConnection()` is called only\n * for the opened connections in the same runtime.\n */\n public addConnection(client: WebSocketClientConnection): void {\n this.addClient(client)\n\n // Instruct the current client how to handle events\n // coming from other runtimes (e.g. when calling `.broadcast()`).\n const handleExtraneousMessage = (\n message: MessageEvent<WebSocketBroadcastChannelMessage>,\n ) => {\n const { type, payload } = message.data\n\n // Ignore broadcasted messages for other clients.\n if (\n typeof payload === 'object' &&\n 'clientId' in payload &&\n payload.clientId !== client.id\n ) {\n return\n }\n\n switch (type) {\n case 'extraneous:send': {\n client.send(payload.data)\n break\n }\n\n case 'extraneous:close': {\n client.close(payload.code, payload.reason)\n break\n }\n }\n }\n\n const abortController = new AbortController()\n\n this.channel.addEventListener('message', handleExtraneousMessage, {\n signal: abortController.signal,\n })\n\n // Once closed, this connection cannot be operated on.\n // This must include the extraneous runtimes as well.\n client.addEventListener('close', () => abortController.abort(), {\n once: true,\n })\n }\n}\n\n/**\n * A wrapper class to operate with WebSocket client connections\n * from other runtimes. This class maintains 1-1 public API\n * compatibility to the `WebSocketClientConnection` but relies\n * on the given `BroadcastChannel` to communicate instructions\n * with the client connections from other runtimes.\n */\nexport class WebSocketRemoteClientConnection\n implements WebSocketClientConnectionProtocol\n{\n constructor(\n public readonly id: string,\n public readonly url: URL,\n private channel: BroadcastChannel,\n ) {}\n\n send(data: WebSocketData): void {\n this.channel.postMessage({\n type: 'extraneous:send',\n payload: {\n clientId: this.id,\n data,\n },\n } as WebSocketBroadcastChannelMessage)\n }\n\n close(code?: number | undefined, reason?: string | undefined): void {\n this.channel.postMessage({\n type: 'extraneous:close',\n payload: {\n clientId: this.id,\n code,\n reason,\n },\n } as WebSocketBroadcastChannelMessage)\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/core/ws/WebSocketClientManager.ts"],"sourcesContent":["import { invariant } from 'outvariant'\nimport type {\n WebSocketData,\n WebSocketClientConnection,\n WebSocketClientConnectionProtocol,\n} from '@mswjs/interceptors/WebSocket'\nimport { matchRequestUrl, type Path } from '../utils/matching/matchRequestUrl'\n\nexport const MSW_WEBSOCKET_CLIENTS_KEY = 'msw:ws:clients'\n\nexport type WebSocketBroadcastChannelMessage =\n | {\n type: 'extraneous:send'\n payload: {\n clientId: string\n data: WebSocketData\n }\n }\n | {\n type: 'extraneous:close'\n payload: {\n clientId: string\n code?: number\n reason?: string\n }\n }\n\ntype SerializedClient = {\n clientId: string\n url: string\n}\n\n/**\n * A manager responsible for accumulating WebSocket client\n * connections across different browser runtimes.\n */\nexport class WebSocketClientManager {\n private inMemoryClients: Set<WebSocketClientConnectionProtocol>\n\n constructor(\n private channel: BroadcastChannel,\n private url: Path,\n ) {\n this.inMemoryClients = new Set()\n\n // Purge in-memory clients when the worker stops.\n if (typeof localStorage !== 'undefined') {\n localStorage.removeItem = new Proxy(localStorage.removeItem, {\n apply: (target, thisArg, args) => {\n const [key] = args\n\n if (key === MSW_WEBSOCKET_CLIENTS_KEY) {\n this.inMemoryClients.clear()\n }\n\n return Reflect.apply(target, thisArg, args)\n },\n })\n }\n }\n\n /**\n * All active WebSocket client connections.\n */\n get clients(): Set<WebSocketClientConnectionProtocol> {\n // In the browser, different runtimes use \"localStorage\"\n // as the shared source of all the clients.\n if (typeof localStorage !== 'undefined') {\n const inMemoryClients = Array.from(this.inMemoryClients)\n\n console.log('get clients()', inMemoryClients, this.getSerializedClients())\n\n return new Set(\n inMemoryClients.concat(\n this.getSerializedClients()\n // Filter out the serialized clients that are already present\n // in this runtime in-memory. This is crucial because a remote client\n // wrapper CANNOT send a message to the client in THIS runtime\n // (the \"message\" event on broadcast channel won't trigger).\n .filter((serializedClient) => {\n if (\n inMemoryClients.every(\n (client) => client.id !== serializedClient.clientId,\n )\n ) {\n return serializedClient\n }\n })\n .map((serializedClient) => {\n return new WebSocketRemoteClientConnection(\n serializedClient.clientId,\n new URL(serializedClient.url),\n this.channel,\n )\n }),\n ),\n )\n }\n\n // In Node.js, the manager acts as a singleton, and all clients\n // are kept in-memory.\n return this.inMemoryClients\n }\n\n private getSerializedClients(): Array<SerializedClient> {\n invariant(\n typeof localStorage !== 'undefined',\n 'Failed to call WebSocketClientManager#getSerializedClients() in a non-browser environment. This is likely a bug in MSW. Please, report it on GitHub: https://github.com/mswjs/msw',\n )\n\n const clientsJson = localStorage.getItem(MSW_WEBSOCKET_CLIENTS_KEY)\n\n if (!clientsJson) {\n return []\n }\n\n const allClients = JSON.parse(clientsJson) as Array<SerializedClient>\n const matchingClients = allClients.filter((client) => {\n return matchRequestUrl(new URL(client.url), this.url).matches\n })\n\n return matchingClients\n }\n\n private addClient(client: WebSocketClientConnection): void {\n this.inMemoryClients.add(client)\n\n if (typeof localStorage !== 'undefined') {\n const serializedClients = this.getSerializedClients()\n\n // Serialize the current client for other runtimes to create\n // a remote wrapper over it. This has no effect on the current runtime.\n const nextSerializedClients = serializedClients.concat({\n clientId: client.id,\n url: client.url.href,\n } as SerializedClient)\n\n localStorage.setItem(\n MSW_WEBSOCKET_CLIENTS_KEY,\n JSON.stringify(nextSerializedClients),\n )\n }\n }\n\n /**\n * Adds the given `WebSocket` client connection to the set\n * of all connections. The given connection is always the complete\n * connection object because `addConnection()` is called only\n * for the opened connections in the same runtime.\n */\n public addConnection(client: WebSocketClientConnection): void {\n this.addClient(client)\n\n // Instruct the current client how to handle events\n // coming from other runtimes (e.g. when calling `.broadcast()`).\n const handleExtraneousMessage = (\n message: MessageEvent<WebSocketBroadcastChannelMessage>,\n ) => {\n const { type, payload } = message.data\n\n // Ignore broadcasted messages for other clients.\n if (\n typeof payload === 'object' &&\n 'clientId' in payload &&\n payload.clientId !== client.id\n ) {\n return\n }\n\n switch (type) {\n case 'extraneous:send': {\n client.send(payload.data)\n break\n }\n\n case 'extraneous:close': {\n client.close(payload.code, payload.reason)\n break\n }\n }\n }\n\n const abortController = new AbortController()\n\n this.channel.addEventListener('message', handleExtraneousMessage, {\n signal: abortController.signal,\n })\n\n // Once closed, this connection cannot be operated on.\n // This must include the extraneous runtimes as well.\n client.addEventListener('close', () => abortController.abort(), {\n once: true,\n })\n }\n}\n\n/**\n * A wrapper class to operate with WebSocket client connections\n * from other runtimes. This class maintains 1-1 public API\n * compatibility to the `WebSocketClientConnection` but relies\n * on the given `BroadcastChannel` to communicate instructions\n * with the client connections from other runtimes.\n */\nexport class WebSocketRemoteClientConnection\n implements WebSocketClientConnectionProtocol\n{\n constructor(\n public readonly id: string,\n public readonly url: URL,\n private channel: BroadcastChannel,\n ) {}\n\n send(data: WebSocketData): void {\n this.channel.postMessage({\n type: 'extraneous:send',\n payload: {\n clientId: this.id,\n data,\n },\n } as WebSocketBroadcastChannelMessage)\n }\n\n close(code?: number | undefined, reason?: string | undefined): void {\n this.channel.postMessage({\n type: 'extraneous:close',\n payload: {\n clientId: this.id,\n code,\n reason,\n },\n } as WebSocketBroadcastChannelMessage)\n }\n}\n"],"mappings":"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","names":[]}