msw 2.13.6 → 2.14.1
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/{HttpResponse-BMMzfpjG.d.mts → HttpResponse-CxHR1nNN.d.mts} +5 -1
- package/lib/core/{HttpResponse-DPDqE4Pb.d.ts → HttpResponse-aGiIzO91.d.ts} +5 -1
- package/lib/core/HttpResponse.d.mts +1 -1
- package/lib/core/HttpResponse.d.ts +1 -1
- package/lib/core/experimental/compat.d.mts +1 -1
- package/lib/core/experimental/compat.d.ts +1 -1
- package/lib/core/experimental/define-network.d.mts +1 -1
- package/lib/core/experimental/define-network.d.ts +1 -1
- package/lib/core/experimental/frames/http-frame.d.mts +1 -1
- package/lib/core/experimental/frames/http-frame.d.ts +1 -1
- package/lib/core/experimental/frames/http-frame.js +3 -2
- package/lib/core/experimental/frames/http-frame.js.map +1 -1
- package/lib/core/experimental/frames/http-frame.mjs +3 -2
- package/lib/core/experimental/frames/http-frame.mjs.map +1 -1
- package/lib/core/experimental/frames/network-frame.d.mts +1 -1
- package/lib/core/experimental/frames/network-frame.d.ts +1 -1
- package/lib/core/experimental/frames/websocket-frame.d.mts +1 -1
- package/lib/core/experimental/frames/websocket-frame.d.ts +1 -1
- package/lib/core/experimental/handlers-controller.d.mts +1 -1
- package/lib/core/experimental/handlers-controller.d.ts +1 -1
- package/lib/core/experimental/handlers-controller.js +16 -5
- package/lib/core/experimental/handlers-controller.js.map +1 -1
- package/lib/core/experimental/handlers-controller.mjs +16 -5
- package/lib/core/experimental/handlers-controller.mjs.map +1 -1
- package/lib/core/experimental/index.d.mts +3 -3
- package/lib/core/experimental/index.d.ts +3 -3
- package/lib/core/experimental/index.js +3 -0
- package/lib/core/experimental/index.js.map +1 -1
- package/lib/core/experimental/index.mjs +6 -0
- package/lib/core/experimental/index.mjs.map +1 -1
- package/lib/core/experimental/on-unhandled-frame.d.mts +1 -1
- package/lib/core/experimental/on-unhandled-frame.d.ts +1 -1
- package/lib/core/experimental/setup-api.d.mts +1 -1
- package/lib/core/experimental/setup-api.d.ts +1 -1
- package/lib/core/experimental/sources/interceptor-source.d.mts +1 -1
- package/lib/core/experimental/sources/interceptor-source.d.ts +1 -1
- package/lib/core/experimental/sources/network-source.d.mts +1 -1
- package/lib/core/experimental/sources/network-source.d.ts +1 -1
- package/lib/core/getResponse.d.mts +1 -1
- package/lib/core/getResponse.d.ts +1 -1
- package/lib/core/graphql.d.mts +1 -1
- package/lib/core/graphql.d.ts +1 -1
- package/lib/core/handlers/GraphQLHandler.d.mts +1 -1
- package/lib/core/handlers/GraphQLHandler.d.ts +1 -1
- package/lib/core/handlers/HttpHandler.d.mts +1 -1
- package/lib/core/handlers/HttpHandler.d.ts +1 -1
- package/lib/core/handlers/RequestHandler.d.mts +1 -1
- package/lib/core/handlers/RequestHandler.d.ts +1 -1
- package/lib/core/handlers/RequestHandler.js +22 -1
- package/lib/core/handlers/RequestHandler.js.map +1 -1
- package/lib/core/handlers/RequestHandler.mjs +22 -1
- package/lib/core/handlers/RequestHandler.mjs.map +1 -1
- package/lib/core/handlers/WebSocketHandler.js +1 -1
- package/lib/core/handlers/WebSocketHandler.js.map +1 -1
- package/lib/core/handlers/WebSocketHandler.mjs +1 -1
- package/lib/core/handlers/WebSocketHandler.mjs.map +1 -1
- package/lib/core/http.d.mts +1 -1
- package/lib/core/http.d.ts +1 -1
- package/lib/core/index.d.mts +1 -1
- package/lib/core/index.d.ts +1 -1
- package/lib/core/passthrough.d.mts +1 -1
- package/lib/core/passthrough.d.ts +1 -1
- package/lib/core/sse.d.mts +1 -1
- package/lib/core/sse.d.ts +1 -1
- package/lib/core/utils/HttpResponse/decorators.d.mts +3 -3
- package/lib/core/utils/HttpResponse/decorators.d.ts +3 -3
- package/lib/core/utils/HttpResponse/decorators.js +4 -10
- package/lib/core/utils/HttpResponse/decorators.js.map +1 -1
- package/lib/core/utils/HttpResponse/decorators.mjs +4 -10
- package/lib/core/utils/HttpResponse/decorators.mjs.map +1 -1
- package/lib/core/utils/executeHandlers.d.mts +1 -1
- package/lib/core/utils/executeHandlers.d.ts +1 -1
- package/lib/core/utils/handleRequest.d.mts +1 -1
- package/lib/core/utils/handleRequest.d.ts +1 -1
- package/lib/core/utils/internal/attachSiblingHandlers.d.mts +15 -0
- package/lib/core/utils/internal/attachSiblingHandlers.d.ts +15 -0
- package/lib/core/utils/internal/attachSiblingHandlers.js +44 -0
- package/lib/core/utils/internal/attachSiblingHandlers.js.map +1 -0
- package/lib/core/utils/internal/attachSiblingHandlers.mjs +24 -0
- package/lib/core/utils/internal/attachSiblingHandlers.mjs.map +1 -0
- package/lib/core/utils/internal/isHandlerKind.d.mts +1 -1
- package/lib/core/utils/internal/isHandlerKind.d.ts +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.mts +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.ts +1 -1
- package/lib/core/utils/internal/parseMultipartData.d.mts +1 -1
- package/lib/core/utils/internal/parseMultipartData.d.ts +1 -1
- package/lib/core/utils/request/storeResponseCookies.js +1 -1
- package/lib/core/utils/request/storeResponseCookies.js.map +1 -1
- package/lib/core/utils/request/storeResponseCookies.mjs +2 -2
- package/lib/core/utils/request/storeResponseCookies.mjs.map +1 -1
- package/lib/core/ws/handleWebSocketEvent.d.mts +1 -1
- package/lib/core/ws/handleWebSocketEvent.d.ts +1 -1
- package/lib/core/ws.d.mts +17 -4
- package/lib/core/ws.d.ts +17 -4
- package/lib/core/ws.js +30 -5
- package/lib/core/ws.js.map +1 -1
- package/lib/core/ws.mjs +34 -6
- package/lib/core/ws.mjs.map +1 -1
- package/lib/iife/index.js +1208 -1142
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +1 -1
- package/lib/node/index.d.mts +1 -1
- package/lib/node/index.d.ts +1 -1
- package/lib/node/index.js +2 -0
- package/lib/node/index.js.map +1 -1
- package/lib/node/index.mjs +1 -0
- package/package.json +2 -2
- package/src/core/experimental/frames/http-frame.test.ts +6 -1
- package/src/core/experimental/frames/http-frame.ts +6 -2
- package/src/core/experimental/handlers-controller.test.ts +139 -5
- package/src/core/experimental/handlers-controller.ts +24 -9
- package/src/core/experimental/index.ts +6 -0
- package/src/core/handlers/RequestHandler.ts +36 -1
- package/src/core/handlers/WebSocketHandler.ts +1 -1
- package/src/core/utils/HttpResponse/decorators.ts +6 -21
- package/src/core/utils/internal/attachSiblingHandlers.ts +28 -0
- package/src/core/utils/request/storeResponseCookies.ts +2 -4
- package/src/core/ws.ts +65 -6
- package/src/node/index.ts +1 -0
package/lib/mockServiceWorker.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - Please do NOT modify this file.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
const PACKAGE_VERSION = '2.
|
|
10
|
+
const PACKAGE_VERSION = '2.14.1'
|
|
11
11
|
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
|
|
12
12
|
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
|
13
13
|
const activeClientIds = new Set()
|
package/lib/node/index.d.mts
CHANGED
|
@@ -110,4 +110,4 @@ declare class SetupServerApi extends SetupServerCommonApi implements SetupServer
|
|
|
110
110
|
constructor(handlers: Array<AnyHandler>, interceptors: Array<Interceptor<any>>);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export { type SetupServer, SetupServerApi, SetupServerCommonApi, defaultNetworkOptions, setupServer };
|
|
113
|
+
export { AsyncHandlersController, type SetupServer, SetupServerApi, SetupServerCommonApi, defaultNetworkOptions, setupServer };
|
package/lib/node/index.d.ts
CHANGED
|
@@ -110,4 +110,4 @@ declare class SetupServerApi extends SetupServerCommonApi implements SetupServer
|
|
|
110
110
|
constructor(handlers: Array<AnyHandler>, interceptors: Array<Interceptor<any>>);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
export { type SetupServer, SetupServerApi, SetupServerCommonApi, defaultNetworkOptions, setupServer };
|
|
113
|
+
export { AsyncHandlersController, type SetupServer, SetupServerApi, SetupServerCommonApi, defaultNetworkOptions, setupServer };
|
package/lib/node/index.js
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/node/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AsyncHandlersController: () => AsyncHandlersController,
|
|
23
24
|
SetupServerApi: () => SetupServerApi,
|
|
24
25
|
SetupServerCommonApi: () => SetupServerCommonApi,
|
|
25
26
|
defaultNetworkOptions: () => defaultNetworkOptions,
|
|
@@ -199,6 +200,7 @@ var SetupServerApi = class extends SetupServerCommonApi {
|
|
|
199
200
|
};
|
|
200
201
|
// Annotate the CommonJS export names for ESM import in node:
|
|
201
202
|
0 && (module.exports = {
|
|
203
|
+
AsyncHandlersController,
|
|
202
204
|
SetupServerApi,
|
|
203
205
|
SetupServerCommonApi,
|
|
204
206
|
defaultNetworkOptions,
|
package/lib/node/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/node/index.ts","../../src/node/setup-server.ts","../../src/node/async-handlers-controller.ts","../../src/node/setup-server-common.ts"],"sourcesContent":["export type { SetupServer } from './glossary'\nexport {\n setupServer,\n SetupServerApi,\n defaultNetworkOptions,\n} from './setup-server'\nexport { SetupServerCommonApi } from './setup-server-common'\n","import type { Interceptor } from '@mswjs/interceptors'\nimport { ClientRequestInterceptor } from '@mswjs/interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '@mswjs/interceptors/XMLHttpRequest'\nimport { FetchInterceptor } from '@mswjs/interceptors/fetch'\nimport { WebSocketInterceptor } from '@mswjs/interceptors/WebSocket'\nimport {\n defineNetwork,\n type DefineNetworkOptions,\n} from '#core/experimental/define-network'\nimport type { AnyHandler } from '#core/experimental/handlers-controller'\nimport { InterceptorSource } from '#core/experimental/sources/interceptor-source'\nimport type { SetupServer } from './glossary'\nimport { AsyncHandlersController } from './async-handlers-controller'\nimport {\n defineSetupServerApi,\n SetupServerCommonApi,\n} from './setup-server-common'\n\nconst defaultInterceptors: Array<Interceptor<any>> = [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n new FetchInterceptor(),\n /**\n * @fixme WebSocketInterceptor is in a browser-only export of Interceptors\n * while the Interceptor class imported from the root module points to `lib/node`.\n * An absolute madness to solve as it requires to duplicate the build config we have\n * in MSW: shared core, CJS/ESM patching, .d.ts patching...\n */\n new WebSocketInterceptor() as any,\n]\n\nexport const defaultNetworkOptions: DefineNetworkOptions<[InterceptorSource]> =\n {\n sources: [\n new InterceptorSource({\n interceptors: defaultInterceptors,\n }),\n ],\n onUnhandledFrame: 'warn',\n context: {\n quiet: true,\n },\n }\n\n/**\n * Enables request interception in Node.js with the given request handlers.\n * @see {@link https://mswjs.io/docs/api/setup-server `setupServer()` API reference}\n */\nexport function setupServer(...handlers: Array<AnyHandler>): SetupServer {\n const handlersController = new AsyncHandlersController(handlers)\n const network = defineNetwork({\n ...defaultNetworkOptions,\n handlers: handlersController,\n })\n\n const commonApi = defineSetupServerApi(network)\n\n return {\n ...commonApi,\n boundary: handlersController.boundary.bind(handlersController),\n }\n}\n\n/**\n * @deprecated\n * Please use the `defineNetwork` API instead.\n */\nexport class SetupServerApi\n extends SetupServerCommonApi\n implements SetupServer\n{\n #handlersController: AsyncHandlersController\n\n public boundary: AsyncHandlersController['boundary']\n\n constructor(\n handlers: Array<AnyHandler>,\n interceptors: Array<Interceptor<any>>,\n ) {\n const controller = new AsyncHandlersController(handlers)\n super(interceptors, controller)\n\n const { sources: _, ...networkOptions } = defaultNetworkOptions\n this.network.configure(networkOptions)\n\n this.#handlersController = controller\n this.boundary = this.#handlersController.boundary.bind(\n this.#handlersController,\n )\n }\n}\n","import { AsyncLocalStorage } from 'node:async_hooks'\nimport {\n HandlersController,\n type AnyHandler,\n type HandlersMap,\n type HandlersControllerState,\n} from '#core/experimental/handlers-controller'\n\nexport interface AsyncHandlersControllerContext {\n initialHandlers: HandlersMap\n handlers: HandlersMap\n}\n\nexport class AsyncHandlersController extends HandlersController {\n #asyncContext: AsyncLocalStorage<AsyncHandlersControllerContext>\n #fallbackContext: AsyncHandlersControllerContext\n\n constructor(initialHandlers: Array<AnyHandler>) {\n super()\n\n const initialState = this.getInitialState(initialHandlers)\n\n this.#asyncContext = new AsyncLocalStorage()\n this.#fallbackContext = {\n initialHandlers: initialState.initialHandlers,\n handlers: initialState.handlers,\n }\n }\n\n protected getState() {\n const { initialHandlers, handlers } = this.#getContext()\n\n return {\n initialHandlers,\n handlers,\n }\n }\n\n protected setState(nextState: HandlersControllerState): void {\n const context = this.#getContext()\n\n if (nextState.initialHandlers) {\n context.initialHandlers = nextState.initialHandlers\n }\n\n if (nextState.handlers) {\n context.handlers = nextState.handlers\n }\n }\n\n public boundary<Args extends Array<any>, R>(callback: (...args: Args) => R) {\n return (...args: Args) => {\n const initialHandlers = { ...this.getState().handlers }\n\n return this.#asyncContext.run(\n {\n initialHandlers,\n handlers: { ...initialHandlers },\n },\n callback,\n ...args,\n )\n }\n }\n\n #getContext() {\n return this.#asyncContext.getStore() || this.#fallbackContext\n }\n}\n","import type { PartialDeep } from 'type-fest'\nimport type { Interceptor } from '@mswjs/interceptors'\nimport {\n NetworkReadyState,\n defineNetwork,\n type NetworkApi,\n} from '#core/experimental/define-network'\nimport type { AnyHandler } from '#core/experimental/handlers-controller'\nimport type { HandlersController } from '#core/experimental/handlers-controller'\nimport { InterceptorSource } from '#core/experimental/sources/interceptor-source'\nimport { fromLegacyOnUnhandledRequest } from '#core/experimental/compat'\nimport type { ListenOptions, SetupServerCommon } from './glossary'\n\n/**\n * Define the common `setupServer` API around the given network.\n * This is used by both `msw/node` and `msw/native` to implement the same\n * baseline setup methods, like `.use()`, `.resetHandlers()`, `.close()`, etc.\n */\nexport function defineSetupServerApi(\n network: NetworkApi<any>,\n): SetupServerCommon {\n return {\n events: network.events,\n listen(options) {\n network.configure({\n onUnhandledFrame: fromLegacyOnUnhandledRequest(() => {\n return options?.onUnhandledRequest || 'warn'\n }),\n })\n\n network.enable()\n },\n use: network.use.bind(network),\n resetHandlers: network.resetHandlers.bind(network),\n restoreHandlers: network.restoreHandlers.bind(network),\n listHandlers: network.listHandlers.bind(network),\n close() {\n /**\n * @note Ignore closing after closed for backwards compatibility.\n */\n if (network.readyState === NetworkReadyState.DISABLED) {\n return\n }\n\n network.disable()\n },\n }\n}\n\n/**\n * @deprecated\n * Please use the `defineNetwork` API instead.\n */\nexport class SetupServerCommonApi implements SetupServerCommon {\n protected network: NetworkApi<[InterceptorSource]>\n\n constructor(\n interceptors: Array<Interceptor<any>>,\n handlers: Array<AnyHandler> | HandlersController,\n ) {\n this.network = defineNetwork({\n sources: [new InterceptorSource({ interceptors })],\n handlers,\n })\n }\n\n get events() {\n return this.network.events\n }\n\n public listen(options?: PartialDeep<ListenOptions>): void {\n this.network.configure({\n onUnhandledFrame: fromLegacyOnUnhandledRequest(() => {\n return options?.onUnhandledRequest || 'warn'\n }),\n })\n\n this.network.enable()\n }\n\n public use(...handlers: Array<AnyHandler>): void {\n this.network.use(...handlers)\n }\n\n public resetHandlers(...nextHandlers: Array<AnyHandler>): void {\n return this.network.resetHandlers(...nextHandlers)\n }\n\n public restoreHandlers(): void {\n return this.network.restoreHandlers()\n }\n\n public listHandlers(): ReadonlyArray<AnyHandler> {\n return this.network.listHandlers()\n }\n\n public close(): void {\n this.network.disable()\n }\n}\n"],"mappings":"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","names":["import_define_network","import_interceptor_source"]}
|
|
1
|
+
{"version":3,"sources":["../../src/node/index.ts","../../src/node/setup-server.ts","../../src/node/async-handlers-controller.ts","../../src/node/setup-server-common.ts"],"sourcesContent":["export type { SetupServer } from './glossary'\nexport {\n setupServer,\n SetupServerApi,\n defaultNetworkOptions,\n} from './setup-server'\nexport { SetupServerCommonApi } from './setup-server-common'\nexport { AsyncHandlersController } from './async-handlers-controller'\n","import type { Interceptor } from '@mswjs/interceptors'\nimport { ClientRequestInterceptor } from '@mswjs/interceptors/ClientRequest'\nimport { XMLHttpRequestInterceptor } from '@mswjs/interceptors/XMLHttpRequest'\nimport { FetchInterceptor } from '@mswjs/interceptors/fetch'\nimport { WebSocketInterceptor } from '@mswjs/interceptors/WebSocket'\nimport {\n defineNetwork,\n type DefineNetworkOptions,\n} from '#core/experimental/define-network'\nimport type { AnyHandler } from '#core/experimental/handlers-controller'\nimport { InterceptorSource } from '#core/experimental/sources/interceptor-source'\nimport type { SetupServer } from './glossary'\nimport { AsyncHandlersController } from './async-handlers-controller'\nimport {\n defineSetupServerApi,\n SetupServerCommonApi,\n} from './setup-server-common'\n\nconst defaultInterceptors: Array<Interceptor<any>> = [\n new ClientRequestInterceptor(),\n new XMLHttpRequestInterceptor(),\n new FetchInterceptor(),\n /**\n * @fixme WebSocketInterceptor is in a browser-only export of Interceptors\n * while the Interceptor class imported from the root module points to `lib/node`.\n * An absolute madness to solve as it requires to duplicate the build config we have\n * in MSW: shared core, CJS/ESM patching, .d.ts patching...\n */\n new WebSocketInterceptor() as any,\n]\n\nexport const defaultNetworkOptions: DefineNetworkOptions<[InterceptorSource]> =\n {\n sources: [\n new InterceptorSource({\n interceptors: defaultInterceptors,\n }),\n ],\n onUnhandledFrame: 'warn',\n context: {\n quiet: true,\n },\n }\n\n/**\n * Enables request interception in Node.js with the given request handlers.\n * @see {@link https://mswjs.io/docs/api/setup-server `setupServer()` API reference}\n */\nexport function setupServer(...handlers: Array<AnyHandler>): SetupServer {\n const handlersController = new AsyncHandlersController(handlers)\n const network = defineNetwork({\n ...defaultNetworkOptions,\n handlers: handlersController,\n })\n\n const commonApi = defineSetupServerApi(network)\n\n return {\n ...commonApi,\n boundary: handlersController.boundary.bind(handlersController),\n }\n}\n\n/**\n * @deprecated\n * Please use the `defineNetwork` API instead.\n */\nexport class SetupServerApi\n extends SetupServerCommonApi\n implements SetupServer\n{\n #handlersController: AsyncHandlersController\n\n public boundary: AsyncHandlersController['boundary']\n\n constructor(\n handlers: Array<AnyHandler>,\n interceptors: Array<Interceptor<any>>,\n ) {\n const controller = new AsyncHandlersController(handlers)\n super(interceptors, controller)\n\n const { sources: _, ...networkOptions } = defaultNetworkOptions\n this.network.configure(networkOptions)\n\n this.#handlersController = controller\n this.boundary = this.#handlersController.boundary.bind(\n this.#handlersController,\n )\n }\n}\n","import { AsyncLocalStorage } from 'node:async_hooks'\nimport {\n HandlersController,\n type AnyHandler,\n type HandlersMap,\n type HandlersControllerState,\n} from '#core/experimental/handlers-controller'\n\nexport interface AsyncHandlersControllerContext {\n initialHandlers: HandlersMap\n handlers: HandlersMap\n}\n\nexport class AsyncHandlersController extends HandlersController {\n #asyncContext: AsyncLocalStorage<AsyncHandlersControllerContext>\n #fallbackContext: AsyncHandlersControllerContext\n\n constructor(initialHandlers: Array<AnyHandler>) {\n super()\n\n const initialState = this.getInitialState(initialHandlers)\n\n this.#asyncContext = new AsyncLocalStorage()\n this.#fallbackContext = {\n initialHandlers: initialState.initialHandlers,\n handlers: initialState.handlers,\n }\n }\n\n protected getState() {\n const { initialHandlers, handlers } = this.#getContext()\n\n return {\n initialHandlers,\n handlers,\n }\n }\n\n protected setState(nextState: HandlersControllerState): void {\n const context = this.#getContext()\n\n if (nextState.initialHandlers) {\n context.initialHandlers = nextState.initialHandlers\n }\n\n if (nextState.handlers) {\n context.handlers = nextState.handlers\n }\n }\n\n public boundary<Args extends Array<any>, R>(callback: (...args: Args) => R) {\n return (...args: Args) => {\n const initialHandlers = { ...this.getState().handlers }\n\n return this.#asyncContext.run(\n {\n initialHandlers,\n handlers: { ...initialHandlers },\n },\n callback,\n ...args,\n )\n }\n }\n\n #getContext() {\n return this.#asyncContext.getStore() || this.#fallbackContext\n }\n}\n","import type { PartialDeep } from 'type-fest'\nimport type { Interceptor } from '@mswjs/interceptors'\nimport {\n NetworkReadyState,\n defineNetwork,\n type NetworkApi,\n} from '#core/experimental/define-network'\nimport type { AnyHandler } from '#core/experimental/handlers-controller'\nimport type { HandlersController } from '#core/experimental/handlers-controller'\nimport { InterceptorSource } from '#core/experimental/sources/interceptor-source'\nimport { fromLegacyOnUnhandledRequest } from '#core/experimental/compat'\nimport type { ListenOptions, SetupServerCommon } from './glossary'\n\n/**\n * Define the common `setupServer` API around the given network.\n * This is used by both `msw/node` and `msw/native` to implement the same\n * baseline setup methods, like `.use()`, `.resetHandlers()`, `.close()`, etc.\n */\nexport function defineSetupServerApi(\n network: NetworkApi<any>,\n): SetupServerCommon {\n return {\n events: network.events,\n listen(options) {\n network.configure({\n onUnhandledFrame: fromLegacyOnUnhandledRequest(() => {\n return options?.onUnhandledRequest || 'warn'\n }),\n })\n\n network.enable()\n },\n use: network.use.bind(network),\n resetHandlers: network.resetHandlers.bind(network),\n restoreHandlers: network.restoreHandlers.bind(network),\n listHandlers: network.listHandlers.bind(network),\n close() {\n /**\n * @note Ignore closing after closed for backwards compatibility.\n */\n if (network.readyState === NetworkReadyState.DISABLED) {\n return\n }\n\n network.disable()\n },\n }\n}\n\n/**\n * @deprecated\n * Please use the `defineNetwork` API instead.\n */\nexport class SetupServerCommonApi implements SetupServerCommon {\n protected network: NetworkApi<[InterceptorSource]>\n\n constructor(\n interceptors: Array<Interceptor<any>>,\n handlers: Array<AnyHandler> | HandlersController,\n ) {\n this.network = defineNetwork({\n sources: [new InterceptorSource({ interceptors })],\n handlers,\n })\n }\n\n get events() {\n return this.network.events\n }\n\n public listen(options?: PartialDeep<ListenOptions>): void {\n this.network.configure({\n onUnhandledFrame: fromLegacyOnUnhandledRequest(() => {\n return options?.onUnhandledRequest || 'warn'\n }),\n })\n\n this.network.enable()\n }\n\n public use(...handlers: Array<AnyHandler>): void {\n this.network.use(...handlers)\n }\n\n public resetHandlers(...nextHandlers: Array<AnyHandler>): void {\n return this.network.resetHandlers(...nextHandlers)\n }\n\n public restoreHandlers(): void {\n return this.network.restoreHandlers()\n }\n\n public listHandlers(): ReadonlyArray<AnyHandler> {\n return this.network.listHandlers()\n }\n\n public close(): void {\n this.network.disable()\n }\n}\n"],"mappings":"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","names":["import_define_network","import_interceptor_source"]}
|
package/lib/node/index.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "msw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.14.1",
|
|
4
4
|
"description": "Seamless REST/GraphQL API mocking library for browser and Node.js.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./lib/core/index.js",
|
|
@@ -286,7 +286,7 @@
|
|
|
286
286
|
"vitest-environment-miniflare": "^2.14.4",
|
|
287
287
|
"webpack": "^5.106.2",
|
|
288
288
|
"webpack-http-server": "^0.5.0",
|
|
289
|
-
"msw": "^2.
|
|
289
|
+
"msw": "^2.14.1"
|
|
290
290
|
},
|
|
291
291
|
"peerDependencies": {
|
|
292
292
|
"typescript": ">= 4.8.x"
|
|
@@ -4,7 +4,8 @@ import { ws } from '../../ws'
|
|
|
4
4
|
import { bypass } from '../../bypass'
|
|
5
5
|
import type { HttpNetworkFrameEventMap } from './http-frame'
|
|
6
6
|
import { HttpNetworkFrame } from './http-frame'
|
|
7
|
-
import { InMemoryHandlersController } from '
|
|
7
|
+
import { InMemoryHandlersController } from '../../experimental/handlers-controller'
|
|
8
|
+
import { getSiblingHandlers } from '../../utils/internal/attachSiblingHandlers'
|
|
8
9
|
|
|
9
10
|
beforeAll(() => {
|
|
10
11
|
vi.spyOn(console, 'error').mockImplementation(() => {})
|
|
@@ -46,6 +47,9 @@ it('filters only request type handlers', async () => {
|
|
|
46
47
|
const webSocketHandlers = [
|
|
47
48
|
ws.link('ws://localhost').addEventListener('connection', () => {}),
|
|
48
49
|
]
|
|
50
|
+
const webSocketSiblingHandlers = webSocketHandlers.flatMap((handler) =>
|
|
51
|
+
getSiblingHandlers(handler),
|
|
52
|
+
)
|
|
49
53
|
|
|
50
54
|
const controller = new InMemoryHandlersController([
|
|
51
55
|
...httpHandlers,
|
|
@@ -55,6 +59,7 @@ it('filters only request type handlers', async () => {
|
|
|
55
59
|
|
|
56
60
|
expect(frame.getHandlers(controller)).toEqual([
|
|
57
61
|
...httpHandlers,
|
|
62
|
+
...webSocketSiblingHandlers,
|
|
58
63
|
...graphqlHandlers,
|
|
59
64
|
])
|
|
60
65
|
expect(frame.getHandlers(new InMemoryHandlersController([]))).toEqual([])
|
|
@@ -251,9 +251,13 @@ export abstract class HttpNetworkFrame extends NetworkFrame<
|
|
|
251
251
|
return null
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
const responseCloneForLogs = resolutionContext?.quiet
|
|
255
|
+
? null
|
|
256
|
+
: response.clone()
|
|
257
|
+
|
|
254
258
|
await storeResponseCookies(request, response)
|
|
255
259
|
|
|
256
|
-
this.respondWith(response
|
|
260
|
+
this.respondWith(response)
|
|
257
261
|
|
|
258
262
|
this.events.emit(
|
|
259
263
|
new RequestEvent('request:end', {
|
|
@@ -265,7 +269,7 @@ export abstract class HttpNetworkFrame extends NetworkFrame<
|
|
|
265
269
|
if (!resolutionContext?.quiet) {
|
|
266
270
|
handler.log({
|
|
267
271
|
request: requestCloneForLogs!,
|
|
268
|
-
response
|
|
272
|
+
response: responseCloneForLogs!,
|
|
269
273
|
parsedResult,
|
|
270
274
|
})
|
|
271
275
|
}
|
|
@@ -1,8 +1,68 @@
|
|
|
1
1
|
import { http } from '../http'
|
|
2
2
|
import { graphql } from '../graphql'
|
|
3
3
|
import { ws } from '../ws'
|
|
4
|
+
import { getSiblingHandlers } from '../utils/internal/attachSiblingHandlers'
|
|
4
5
|
import { InMemoryHandlersController } from './handlers-controller'
|
|
5
6
|
|
|
7
|
+
describe('constructor', () => {
|
|
8
|
+
it('places the sibling in its own kind bucket', () => {
|
|
9
|
+
const wsHandler = ws.link('*').addEventListener('connection', () => {})
|
|
10
|
+
const [upgradeHandler] = getSiblingHandlers(wsHandler)
|
|
11
|
+
|
|
12
|
+
const controller = new InMemoryHandlersController([wsHandler])
|
|
13
|
+
|
|
14
|
+
expect(controller.getHandlersByKind('websocket')).toEqual([wsHandler])
|
|
15
|
+
expect(controller.getHandlersByKind('request')).toEqual([upgradeHandler])
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it('interleaves the sibling at the owner position when grouping by kind', () => {
|
|
19
|
+
const httpOne = http.get('/', () => {})
|
|
20
|
+
const wsHandler = ws.link('*').addEventListener('connection', () => {})
|
|
21
|
+
const [upgradeHandler] = getSiblingHandlers(wsHandler)
|
|
22
|
+
const httpTwo = http.get('/', () => {})
|
|
23
|
+
|
|
24
|
+
const controller = new InMemoryHandlersController([
|
|
25
|
+
httpOne,
|
|
26
|
+
wsHandler,
|
|
27
|
+
httpTwo,
|
|
28
|
+
])
|
|
29
|
+
|
|
30
|
+
expect(controller.getHandlersByKind('request')).toEqual([
|
|
31
|
+
httpOne,
|
|
32
|
+
upgradeHandler,
|
|
33
|
+
httpTwo,
|
|
34
|
+
])
|
|
35
|
+
expect(controller.getHandlersByKind('websocket')).toEqual([wsHandler])
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it('extracts siblings from every owner in the input list', () => {
|
|
39
|
+
const wsOne = ws.link('*').addEventListener('connection', () => {})
|
|
40
|
+
const wsTwo = ws.link('*').addEventListener('connection', () => {})
|
|
41
|
+
const [upgradeOne] = getSiblingHandlers(wsOne)
|
|
42
|
+
const [upgradeTwo] = getSiblingHandlers(wsTwo)
|
|
43
|
+
|
|
44
|
+
const controller = new InMemoryHandlersController([wsOne, wsTwo])
|
|
45
|
+
|
|
46
|
+
expect(controller.getHandlersByKind('websocket')).toEqual([wsOne, wsTwo])
|
|
47
|
+
expect(controller.getHandlersByKind('request')).toEqual([
|
|
48
|
+
upgradeOne,
|
|
49
|
+
upgradeTwo,
|
|
50
|
+
])
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
it('dedupes the shared upgrade sibling across multiple handlers from the same link', () => {
|
|
54
|
+
const chat = ws.link('*')
|
|
55
|
+
const wsOne = chat.addEventListener('connection', () => {})
|
|
56
|
+
const wsTwo = chat.addEventListener('connection', () => {})
|
|
57
|
+
const [upgradeHandler] = getSiblingHandlers(wsOne)
|
|
58
|
+
|
|
59
|
+
const controller = new InMemoryHandlersController([wsOne, wsTwo])
|
|
60
|
+
|
|
61
|
+
expect(controller.getHandlersByKind('websocket')).toEqual([wsOne, wsTwo])
|
|
62
|
+
expect(controller.getHandlersByKind('request')).toEqual([upgradeHandler])
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
6
66
|
describe(InMemoryHandlersController.prototype.use, () => {
|
|
7
67
|
it('prepends a handler to an empty controller', () => {
|
|
8
68
|
const controller = new InMemoryHandlersController([])
|
|
@@ -51,6 +111,44 @@ describe(InMemoryHandlersController.prototype.use, () => {
|
|
|
51
111
|
|
|
52
112
|
expect(controller.currentHandlers()).toEqual([graphqlOne, httpTwo, httpOne])
|
|
53
113
|
})
|
|
114
|
+
|
|
115
|
+
it('propagates siblings to their kind buckets at runtime', () => {
|
|
116
|
+
const controller = new InMemoryHandlersController([])
|
|
117
|
+
const wsHandler = ws.link('*').addEventListener('connection', () => {})
|
|
118
|
+
const [upgradeHandler] = getSiblingHandlers(wsHandler)
|
|
119
|
+
|
|
120
|
+
controller.use([wsHandler])
|
|
121
|
+
|
|
122
|
+
expect(controller.getHandlersByKind('websocket')).toEqual([wsHandler])
|
|
123
|
+
expect(controller.getHandlersByKind('request')).toEqual([upgradeHandler])
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
it('prepends incoming siblings before existing handlers of the same kind', () => {
|
|
127
|
+
const existingHttp = http.get('/existing', () => {})
|
|
128
|
+
const controller = new InMemoryHandlersController([existingHttp])
|
|
129
|
+
const wsHandler = ws.link('*').addEventListener('connection', () => {})
|
|
130
|
+
const [upgradeHandler] = getSiblingHandlers(wsHandler)
|
|
131
|
+
|
|
132
|
+
controller.use([wsHandler])
|
|
133
|
+
|
|
134
|
+
expect(controller.getHandlersByKind('request')).toEqual([
|
|
135
|
+
upgradeHandler,
|
|
136
|
+
existingHttp,
|
|
137
|
+
])
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
it('dedupes the shared upgrade sibling when called with multiple handlers from the same link', () => {
|
|
141
|
+
const chat = ws.link('*')
|
|
142
|
+
const wsOne = chat.addEventListener('connection', () => {})
|
|
143
|
+
const wsTwo = chat.addEventListener('connection', () => {})
|
|
144
|
+
const [upgradeHandler] = getSiblingHandlers(wsOne)
|
|
145
|
+
|
|
146
|
+
const controller = new InMemoryHandlersController([])
|
|
147
|
+
controller.use([wsOne, wsTwo])
|
|
148
|
+
|
|
149
|
+
expect(controller.getHandlersByKind('websocket')).toEqual([wsOne, wsTwo])
|
|
150
|
+
expect(controller.getHandlersByKind('request')).toEqual([upgradeHandler])
|
|
151
|
+
})
|
|
54
152
|
})
|
|
55
153
|
|
|
56
154
|
describe(InMemoryHandlersController.prototype.reset, () => {
|
|
@@ -96,6 +194,42 @@ describe(InMemoryHandlersController.prototype.reset, () => {
|
|
|
96
194
|
*/
|
|
97
195
|
expect(controller.currentHandlers()).toEqual([httpTwo])
|
|
98
196
|
})
|
|
197
|
+
|
|
198
|
+
it('places siblings into their kind buckets when resetting to next handlers', () => {
|
|
199
|
+
const controller = new InMemoryHandlersController([])
|
|
200
|
+
const wsHandler = ws.link('*').addEventListener('connection', () => {})
|
|
201
|
+
const [upgradeHandler] = getSiblingHandlers(wsHandler)
|
|
202
|
+
|
|
203
|
+
controller.reset([wsHandler])
|
|
204
|
+
|
|
205
|
+
expect(controller.getHandlersByKind('websocket')).toEqual([wsHandler])
|
|
206
|
+
expect(controller.getHandlersByKind('request')).toEqual([upgradeHandler])
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('restores siblings when resetting to the initial handlers', () => {
|
|
210
|
+
const wsHandler = ws.link('*').addEventListener('connection', () => {})
|
|
211
|
+
const [upgradeHandler] = getSiblingHandlers(wsHandler)
|
|
212
|
+
const controller = new InMemoryHandlersController([wsHandler])
|
|
213
|
+
|
|
214
|
+
controller.use([http.get('/runtime', () => {})])
|
|
215
|
+
controller.reset([])
|
|
216
|
+
|
|
217
|
+
expect(controller.getHandlersByKind('websocket')).toEqual([wsHandler])
|
|
218
|
+
expect(controller.getHandlersByKind('request')).toEqual([upgradeHandler])
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
it('dedupes the shared upgrade sibling when reset with multiple handlers from the same link', () => {
|
|
222
|
+
const chat = ws.link('*')
|
|
223
|
+
const wsOne = chat.addEventListener('connection', () => {})
|
|
224
|
+
const wsTwo = chat.addEventListener('connection', () => {})
|
|
225
|
+
const [upgradeHandler] = getSiblingHandlers(wsOne)
|
|
226
|
+
|
|
227
|
+
const controller = new InMemoryHandlersController([])
|
|
228
|
+
controller.reset([wsOne, wsTwo])
|
|
229
|
+
|
|
230
|
+
expect(controller.getHandlersByKind('websocket')).toEqual([wsOne, wsTwo])
|
|
231
|
+
expect(controller.getHandlersByKind('request')).toEqual([upgradeHandler])
|
|
232
|
+
})
|
|
99
233
|
})
|
|
100
234
|
|
|
101
235
|
describe(InMemoryHandlersController.prototype.getHandlersByKind, () => {
|
|
@@ -112,11 +246,10 @@ describe(InMemoryHandlersController.prototype.getHandlersByKind, () => {
|
|
|
112
246
|
]).getHandlersByKind('websocket'),
|
|
113
247
|
).toEqual([])
|
|
114
248
|
|
|
249
|
+
const wsHandler = ws.link('*').addEventListener('connection', () => {})
|
|
115
250
|
expect(
|
|
116
|
-
new InMemoryHandlersController([
|
|
117
|
-
|
|
118
|
-
]).getHandlersByKind('request'),
|
|
119
|
-
).toEqual([])
|
|
251
|
+
new InMemoryHandlersController([wsHandler]).getHandlersByKind('request'),
|
|
252
|
+
).toEqual(getSiblingHandlers(wsHandler))
|
|
120
253
|
})
|
|
121
254
|
|
|
122
255
|
it('returns all handlers if they all match', () => {
|
|
@@ -142,6 +275,7 @@ describe(InMemoryHandlersController.prototype.getHandlersByKind, () => {
|
|
|
142
275
|
const httpHandler = http.get('/', () => {})
|
|
143
276
|
const graphqlHandler = graphql.query('', () => {})
|
|
144
277
|
const wsHandler = ws.link('*').addEventListener('connection', () => {})
|
|
278
|
+
const wsHandlerSiblings = getSiblingHandlers(wsHandler)
|
|
145
279
|
|
|
146
280
|
expect(
|
|
147
281
|
new InMemoryHandlersController([
|
|
@@ -149,7 +283,7 @@ describe(InMemoryHandlersController.prototype.getHandlersByKind, () => {
|
|
|
149
283
|
graphqlHandler,
|
|
150
284
|
wsHandler,
|
|
151
285
|
]).getHandlersByKind('request'),
|
|
152
|
-
).toEqual([httpHandler, graphqlHandler])
|
|
286
|
+
).toEqual([httpHandler, graphqlHandler, ...wsHandlerSiblings])
|
|
153
287
|
|
|
154
288
|
expect(
|
|
155
289
|
new InMemoryHandlersController([
|
|
@@ -2,6 +2,7 @@ import { invariant } from 'outvariant'
|
|
|
2
2
|
import { type RequestHandler } from '../handlers/RequestHandler'
|
|
3
3
|
import { type WebSocketHandler } from '../handlers/WebSocketHandler'
|
|
4
4
|
import { devUtils } from '../utils/internal/devUtils'
|
|
5
|
+
import { getSiblingHandlers } from '../utils/internal/attachSiblingHandlers'
|
|
5
6
|
|
|
6
7
|
export type AnyHandler = RequestHandler | WebSocketHandler
|
|
7
8
|
export type HandlersMap = Partial<Record<AnyHandler['kind'], Array<AnyHandler>>>
|
|
@@ -9,11 +10,23 @@ export type HandlersMap = Partial<Record<AnyHandler['kind'], Array<AnyHandler>>>
|
|
|
9
10
|
export function groupHandlersByKind(handlers: Array<AnyHandler>): HandlersMap {
|
|
10
11
|
const groups: HandlersMap = {}
|
|
11
12
|
|
|
13
|
+
const pushUnique = (kind: AnyHandler['kind'], handler: AnyHandler) => {
|
|
14
|
+
const bucket = (groups[kind] ||= [])
|
|
15
|
+
|
|
16
|
+
if (!bucket.includes(handler)) {
|
|
17
|
+
bucket.push(handler)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
12
21
|
/**
|
|
13
22
|
* @note `Object.groupBy` is not implemented in Node.js v20.
|
|
14
23
|
*/
|
|
15
24
|
for (const handler of handlers) {
|
|
16
|
-
|
|
25
|
+
pushUnique(handler.kind, handler)
|
|
26
|
+
|
|
27
|
+
for (const sibling of getSiblingHandlers(handler)) {
|
|
28
|
+
pushUnique(sibling.kind, sibling)
|
|
29
|
+
}
|
|
17
30
|
}
|
|
18
31
|
|
|
19
32
|
return groups
|
|
@@ -69,14 +82,16 @@ export abstract class HandlersController {
|
|
|
69
82
|
}
|
|
70
83
|
|
|
71
84
|
const { handlers } = this.getState()
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
85
|
+
const overrides = groupHandlersByKind(nextHandlers)
|
|
86
|
+
|
|
87
|
+
// Prepend overrides to their respective kind buckets so they take
|
|
88
|
+
// priority over existing handlers while preserving input order.
|
|
89
|
+
for (const kind in overrides) {
|
|
90
|
+
const overridesForKind = overrides[kind as AnyHandler['kind']]!
|
|
91
|
+
const existingForKind = handlers[kind as AnyHandler['kind']]
|
|
92
|
+
handlers[kind as AnyHandler['kind']] = existingForKind
|
|
93
|
+
? [...overridesForKind, ...existingForKind]
|
|
94
|
+
: overridesForKind
|
|
80
95
|
}
|
|
81
96
|
|
|
82
97
|
this.setState({ handlers })
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Headers as HeadersPolyfill } from 'headers-polyfill'
|
|
1
2
|
import { getCallFrame } from '../utils/internal/getCallFrame'
|
|
2
3
|
import {
|
|
3
4
|
isIterable,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
type DefaultUnsafeFetchResponse,
|
|
13
14
|
} from '../HttpResponse'
|
|
14
15
|
import type { GraphQLRequestBody } from './GraphQLHandler'
|
|
16
|
+
import { getRawSetCookie } from '../utils/HttpResponse/decorators'
|
|
15
17
|
|
|
16
18
|
export type DefaultRequestMultipartBody = Record<
|
|
17
19
|
string,
|
|
@@ -335,7 +337,7 @@ export abstract class RequestHandler<
|
|
|
335
337
|
...resolverExtras,
|
|
336
338
|
requestId: args.requestId,
|
|
337
339
|
request: args.request,
|
|
338
|
-
}) as Promise<Response>
|
|
340
|
+
}) as Promise<Response | undefined>
|
|
339
341
|
).catch((errorOrResponse) => {
|
|
340
342
|
// Allow throwing a Response instance in a response resolver.
|
|
341
343
|
if (errorOrResponse instanceof Response) {
|
|
@@ -348,6 +350,10 @@ export abstract class RequestHandler<
|
|
|
348
350
|
|
|
349
351
|
const mockedResponse = await mockedResponsePromise
|
|
350
352
|
|
|
353
|
+
if (mockedResponse) {
|
|
354
|
+
forwardResponseCookies(mockedResponse)
|
|
355
|
+
}
|
|
356
|
+
|
|
351
357
|
const executionResult = this.createExecutionResult({
|
|
352
358
|
// Pass the cloned request to the result so that logging
|
|
353
359
|
// and other consumers could read its body once more.
|
|
@@ -416,3 +422,32 @@ export abstract class RequestHandler<
|
|
|
416
422
|
}
|
|
417
423
|
}
|
|
418
424
|
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Forwards the cookies from the given response to `document.cookie`.
|
|
428
|
+
*/
|
|
429
|
+
export function forwardResponseCookies(response: Response): void {
|
|
430
|
+
// Cookie forwarding is only relevant in the browser.
|
|
431
|
+
if (typeof document === 'undefined') {
|
|
432
|
+
return
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const responseCookies = getRawSetCookie(response)
|
|
436
|
+
|
|
437
|
+
if (!responseCookies) {
|
|
438
|
+
return
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// Write the mocked response cookies to the document.
|
|
442
|
+
// Use `headers-polyfill` to get the Set-Cookie header value correctly.
|
|
443
|
+
// This is an alternative until TypeScript 5.2
|
|
444
|
+
// and Node.js v20 become the minimum supported versions
|
|
445
|
+
// and "Headers.prototype.getSetCookie" can be used directly.
|
|
446
|
+
const allResponseCookies = HeadersPolyfill.prototype.getSetCookie.call(
|
|
447
|
+
new Headers([['set-cookie', responseCookies]]),
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
for (const cookieString of allResponseCookies) {
|
|
451
|
+
document.cookie = cookieString
|
|
452
|
+
}
|
|
453
|
+
}
|
|
@@ -118,7 +118,7 @@ export class WebSocketHandler {
|
|
|
118
118
|
params: parsedResult.match.params || {},
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
if (resolutionContext?.[kAutoConnect]) {
|
|
121
|
+
if (resolutionContext?.[kAutoConnect] ?? true) {
|
|
122
122
|
if (this[kConnect](resolvedConnection)) {
|
|
123
123
|
return resolvedConnection
|
|
124
124
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import statuses from '../../../shims/statuses'
|
|
2
|
-
import { Headers as HeadersPolyfill } from 'headers-polyfill'
|
|
3
2
|
import type { HttpResponseInit } from '../../HttpResponse'
|
|
4
3
|
|
|
5
4
|
const { message } = statuses
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
const kSetCookie = Symbol('kSetCookie')
|
|
8
7
|
|
|
9
8
|
export interface HttpResponseDecoratedInit extends HttpResponseInit {
|
|
10
9
|
status: number
|
|
@@ -31,7 +30,7 @@ export function decorateResponse(
|
|
|
31
30
|
response: Response,
|
|
32
31
|
init: HttpResponseDecoratedInit,
|
|
33
32
|
): Response {
|
|
34
|
-
// Allow
|
|
33
|
+
// Allow mocking the response type.
|
|
35
34
|
if (init.type) {
|
|
36
35
|
Object.defineProperty(response, 'type', {
|
|
37
36
|
value: init.type,
|
|
@@ -52,25 +51,11 @@ export function decorateResponse(
|
|
|
52
51
|
enumerable: false,
|
|
53
52
|
writable: false,
|
|
54
53
|
})
|
|
55
|
-
|
|
56
|
-
// Cookie forwarding is only relevant in the browser.
|
|
57
|
-
if (typeof document !== 'undefined') {
|
|
58
|
-
// Write the mocked response cookies to the document.
|
|
59
|
-
// Use `headers-polyfill` to get the Set-Cookie header value correctly.
|
|
60
|
-
// This is an alternative until TypeScript 5.2
|
|
61
|
-
// and Node.js v20 become the minimum supported version
|
|
62
|
-
// and getSetCookie in Headers can be used directly.
|
|
63
|
-
const responseCookiePairs = HeadersPolyfill.prototype.getSetCookie.call(
|
|
64
|
-
init.headers,
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
for (const cookieString of responseCookiePairs) {
|
|
68
|
-
// No need to parse the cookie headers because it's defined
|
|
69
|
-
// as the valid cookie string to begin with.
|
|
70
|
-
document.cookie = cookieString
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
54
|
}
|
|
74
55
|
|
|
75
56
|
return response
|
|
76
57
|
}
|
|
58
|
+
|
|
59
|
+
export function getRawSetCookie(response: Response): string | undefined {
|
|
60
|
+
return Reflect.get(response, kSetCookie)
|
|
61
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { invariant } from 'outvariant'
|
|
2
|
+
import type { AnyHandler } from '../../experimental/handlers-controller'
|
|
3
|
+
|
|
4
|
+
const kSiblingHandlers = Symbol('kSiblingHandlers')
|
|
5
|
+
|
|
6
|
+
export function attachSiblingHandlers<T extends AnyHandler>(
|
|
7
|
+
owner: T,
|
|
8
|
+
siblings: Array<AnyHandler>,
|
|
9
|
+
): T {
|
|
10
|
+
invariant(
|
|
11
|
+
getSiblingHandlers(owner).length === 0,
|
|
12
|
+
'Failed to merge handlers: the owner "%s" handler is already merged',
|
|
13
|
+
owner.kind,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
Object.defineProperty(owner, kSiblingHandlers, {
|
|
17
|
+
value: siblings,
|
|
18
|
+
enumerable: false,
|
|
19
|
+
writable: false,
|
|
20
|
+
configurable: false,
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
return owner
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function getSiblingHandlers(owner: AnyHandler): Array<AnyHandler> {
|
|
27
|
+
return Reflect.get(owner, kSiblingHandlers) || []
|
|
28
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cookieStore } from '../cookieStore'
|
|
2
|
-
import {
|
|
2
|
+
import { getRawSetCookie } from '../HttpResponse/decorators'
|
|
3
3
|
|
|
4
4
|
export async function storeResponseCookies(
|
|
5
5
|
request: Request,
|
|
@@ -7,9 +7,7 @@ export async function storeResponseCookies(
|
|
|
7
7
|
): Promise<void> {
|
|
8
8
|
// Grab the raw "Set-Cookie" response header provided
|
|
9
9
|
// in the HeadersInit for this mocked response.
|
|
10
|
-
const responseCookies =
|
|
11
|
-
| string
|
|
12
|
-
| undefined
|
|
10
|
+
const responseCookies = getRawSetCookie(response)
|
|
13
11
|
|
|
14
12
|
if (responseCookies) {
|
|
15
13
|
await cookieStore.setCookie(responseCookies, request.url)
|