msw 2.11.1 → 2.11.2
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/browser/index.d.mts +0 -3
- package/lib/browser/index.d.ts +0 -3
- package/lib/browser/index.js +503 -294
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/index.mjs +503 -294
- package/lib/browser/index.mjs.map +1 -1
- package/lib/core/handlers/GraphQLHandler.js.map +1 -1
- package/lib/core/handlers/GraphQLHandler.mjs.map +1 -1
- package/lib/core/handlers/HttpHandler.js.map +1 -1
- package/lib/core/handlers/HttpHandler.mjs.map +1 -1
- package/lib/core/utils/internal/devUtils.js.map +1 -1
- package/lib/core/utils/internal/devUtils.mjs.map +1 -1
- package/lib/core/utils/internal/getCallFrame.js +2 -2
- package/lib/core/utils/internal/getCallFrame.js.map +1 -1
- package/lib/core/utils/internal/getCallFrame.mjs +2 -2
- package/lib/core/utils/internal/getCallFrame.mjs.map +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.js +1 -0
- package/lib/core/utils/internal/parseGraphQLRequest.js.map +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.mjs +1 -0
- package/lib/core/utils/internal/parseGraphQLRequest.mjs.map +1 -1
- package/lib/core/utils/matching/matchRequestUrl.js +1 -1
- package/lib/core/utils/matching/matchRequestUrl.js.map +1 -1
- package/lib/core/utils/matching/matchRequestUrl.mjs +1 -1
- package/lib/core/utils/matching/matchRequestUrl.mjs.map +1 -1
- package/lib/core/utils/url/cleanUrl.js +1 -1
- package/lib/core/utils/url/cleanUrl.js.map +1 -1
- package/lib/core/utils/url/cleanUrl.mjs +1 -1
- package/lib/core/utils/url/cleanUrl.mjs.map +1 -1
- package/lib/core/utils/url/isAbsoluteUrl.js +1 -1
- package/lib/core/utils/url/isAbsoluteUrl.js.map +1 -1
- package/lib/core/utils/url/isAbsoluteUrl.mjs +1 -1
- package/lib/core/utils/url/isAbsoluteUrl.mjs.map +1 -1
- package/lib/core/ws/WebSocketIndexedDBClientStore.js.map +1 -1
- package/lib/core/ws/WebSocketIndexedDBClientStore.mjs.map +1 -1
- package/lib/core/ws/utils/attachWebSocketLogger.js.map +1 -1
- package/lib/core/ws/utils/attachWebSocketLogger.mjs.map +1 -1
- package/lib/iife/index.js +2494 -2281
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +16 -12
- package/package.json +20 -13
- package/src/browser/setupWorker/glossary.ts +9 -114
- package/src/browser/setupWorker/setupWorker.ts +82 -119
- package/src/browser/setupWorker/start/createRequestListener.ts +20 -24
- package/src/browser/setupWorker/start/createResponseListener.ts +15 -22
- package/src/browser/setupWorker/start/createStartHandler.ts +24 -18
- package/src/browser/setupWorker/start/utils/enableMocking.ts +18 -21
- package/src/browser/setupWorker/start/utils/printStartMessage.ts +0 -2
- package/src/browser/utils/checkWorkerIntegrity.ts +22 -14
- package/src/browser/utils/workerChannel.ts +146 -0
- package/src/core/handlers/GraphQLHandler.ts +0 -3
- package/src/core/handlers/HttpHandler.ts +0 -2
- package/src/core/utils/internal/devUtils.ts +0 -2
- package/src/core/utils/internal/getCallFrame.ts +2 -2
- package/src/core/utils/internal/parseGraphQLRequest.ts +1 -0
- package/src/core/utils/matching/matchRequestUrl.ts +2 -2
- package/src/core/utils/request/onUnhandledRequest.test.ts +1 -1
- package/src/core/utils/url/cleanUrl.ts +1 -1
- package/src/core/utils/url/isAbsoluteUrl.ts +1 -1
- package/src/core/ws/WebSocketIndexedDBClientStore.ts +0 -4
- package/src/core/ws/utils/attachWebSocketLogger.ts +0 -14
- package/src/mockServiceWorker.js +14 -10
- package/src/browser/setupWorker/start/createFallbackStart.ts +0 -21
- package/src/browser/setupWorker/start/utils/createMessageChannel.ts +0 -32
- package/src/browser/setupWorker/stop/createFallbackStop.ts +0 -11
- package/src/browser/setupWorker/stop/createStop.ts +0 -35
package/lib/mockServiceWorker.js
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* - Please do NOT modify this file.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
const PACKAGE_VERSION = '2.11.
|
|
11
|
-
const INTEGRITY_CHECKSUM = '
|
|
10
|
+
const PACKAGE_VERSION = '2.11.2'
|
|
11
|
+
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'
|
|
12
12
|
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
|
13
13
|
const activeClientIds = new Set()
|
|
14
14
|
|
|
@@ -71,11 +71,6 @@ addEventListener('message', async function (event) {
|
|
|
71
71
|
break
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
case 'MOCK_DEACTIVATE': {
|
|
75
|
-
activeClientIds.delete(clientId)
|
|
76
|
-
break
|
|
77
|
-
}
|
|
78
|
-
|
|
79
74
|
case 'CLIENT_CLOSED': {
|
|
80
75
|
activeClientIds.delete(clientId)
|
|
81
76
|
|
|
@@ -94,6 +89,8 @@ addEventListener('message', async function (event) {
|
|
|
94
89
|
})
|
|
95
90
|
|
|
96
91
|
addEventListener('fetch', function (event) {
|
|
92
|
+
const requestInterceptedAt = Date.now()
|
|
93
|
+
|
|
97
94
|
// Bypass navigation requests.
|
|
98
95
|
if (event.request.mode === 'navigate') {
|
|
99
96
|
return
|
|
@@ -110,23 +107,29 @@ addEventListener('fetch', function (event) {
|
|
|
110
107
|
|
|
111
108
|
// Bypass all requests when there are no active clients.
|
|
112
109
|
// Prevents the self-unregistered worked from handling requests
|
|
113
|
-
// after it's been
|
|
110
|
+
// after it's been terminated (still remains active until the next reload).
|
|
114
111
|
if (activeClientIds.size === 0) {
|
|
115
112
|
return
|
|
116
113
|
}
|
|
117
114
|
|
|
118
115
|
const requestId = crypto.randomUUID()
|
|
119
|
-
event.respondWith(handleRequest(event, requestId))
|
|
116
|
+
event.respondWith(handleRequest(event, requestId, requestInterceptedAt))
|
|
120
117
|
})
|
|
121
118
|
|
|
122
119
|
/**
|
|
123
120
|
* @param {FetchEvent} event
|
|
124
121
|
* @param {string} requestId
|
|
122
|
+
* @param {number} requestInterceptedAt
|
|
125
123
|
*/
|
|
126
|
-
async function handleRequest(event, requestId) {
|
|
124
|
+
async function handleRequest(event, requestId, requestInterceptedAt) {
|
|
127
125
|
const client = await resolveMainClient(event)
|
|
128
126
|
const requestCloneForEvents = event.request.clone()
|
|
129
|
-
const response = await getResponse(
|
|
127
|
+
const response = await getResponse(
|
|
128
|
+
event,
|
|
129
|
+
client,
|
|
130
|
+
requestId,
|
|
131
|
+
requestInterceptedAt,
|
|
132
|
+
)
|
|
130
133
|
|
|
131
134
|
// Send back the response clone for the "response:*" life-cycle events.
|
|
132
135
|
// Ensure MSW is active and ready to handle the message, otherwise
|
|
@@ -204,7 +207,7 @@ async function resolveMainClient(event) {
|
|
|
204
207
|
* @param {string} requestId
|
|
205
208
|
* @returns {Promise<Response>}
|
|
206
209
|
*/
|
|
207
|
-
async function getResponse(event, client, requestId) {
|
|
210
|
+
async function getResponse(event, client, requestId, requestInterceptedAt) {
|
|
208
211
|
// Clone the request because it might've been already used
|
|
209
212
|
// (i.e. its body has been read and sent to the client).
|
|
210
213
|
const requestClone = event.request.clone()
|
|
@@ -255,6 +258,7 @@ async function getResponse(event, client, requestId) {
|
|
|
255
258
|
type: 'REQUEST',
|
|
256
259
|
payload: {
|
|
257
260
|
id: requestId,
|
|
261
|
+
interceptedAt: requestInterceptedAt,
|
|
258
262
|
...serializedRequest,
|
|
259
263
|
},
|
|
260
264
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "msw",
|
|
3
|
-
"version": "2.11.
|
|
3
|
+
"version": "2.11.2",
|
|
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",
|
|
@@ -228,6 +228,7 @@
|
|
|
228
228
|
"outvariant": "^1.4.3",
|
|
229
229
|
"path-to-regexp": "^6.3.0",
|
|
230
230
|
"picocolors": "^1.1.1",
|
|
231
|
+
"rettime": "^0.7.0",
|
|
231
232
|
"strict-event-emitter": "^0.5.1",
|
|
232
233
|
"tough-cookie": "^6.0.0",
|
|
233
234
|
"type-fest": "^4.26.1",
|
|
@@ -236,18 +237,22 @@
|
|
|
236
237
|
"devDependencies": {
|
|
237
238
|
"@commitlint/cli": "^18.4.4",
|
|
238
239
|
"@commitlint/config-conventional": "^18.4.4",
|
|
240
|
+
"@eslint/eslintrc": "^3.3.1",
|
|
241
|
+
"@eslint/js": "^9.34.0",
|
|
239
242
|
"@fastify/websocket": "^8.3.1",
|
|
243
|
+
"@graphql-typed-document-node/core": "^3.2.0",
|
|
240
244
|
"@open-draft/test-server": "^0.4.2",
|
|
241
245
|
"@ossjs/release": "^0.8.1",
|
|
242
246
|
"@playwright/test": "^1.48.0",
|
|
247
|
+
"@swc/core": "^1.13.5",
|
|
248
|
+
"@types/eslint__js": "^8.42.3",
|
|
243
249
|
"@types/express": "^4.17.21",
|
|
244
250
|
"@types/json-bigint": "^1.0.4",
|
|
245
|
-
"@types/node": "
|
|
246
|
-
"@
|
|
247
|
-
"@typescript-eslint/
|
|
248
|
-
"@
|
|
249
|
-
"
|
|
250
|
-
"axios": "^1.7.7",
|
|
251
|
+
"@types/node": "18.x",
|
|
252
|
+
"@typescript-eslint/eslint-plugin": "^8.42.0",
|
|
253
|
+
"@typescript-eslint/parser": "^8.42.0",
|
|
254
|
+
"@web/dev-server": "^0.1.38",
|
|
255
|
+
"axios": "^1.6.5",
|
|
251
256
|
"babel-minify": "^0.5.1",
|
|
252
257
|
"commitizen": "^4.3.1",
|
|
253
258
|
"cross-env": "^7.0.3",
|
|
@@ -255,11 +260,12 @@
|
|
|
255
260
|
"cz-conventional-changelog": "3.3.0",
|
|
256
261
|
"esbuild": "^0.25.3",
|
|
257
262
|
"esbuild-loader": "^4.2.2",
|
|
258
|
-
"eslint": "^
|
|
259
|
-
"eslint-config-prettier": "^
|
|
260
|
-
"eslint-plugin-prettier": "^5.
|
|
263
|
+
"eslint": "^9.34.0",
|
|
264
|
+
"eslint-config-prettier": "^10.1.8",
|
|
265
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
261
266
|
"express": "^5.0.0",
|
|
262
267
|
"fastify": "^4.26.0",
|
|
268
|
+
"fs-extra": "^11.2.0",
|
|
263
269
|
"fs-teardown": "^0.3.0",
|
|
264
270
|
"glob": "^11.0.0",
|
|
265
271
|
"jsdom": "^25.0.1",
|
|
@@ -267,20 +273,21 @@
|
|
|
267
273
|
"knip": "^5.51.1",
|
|
268
274
|
"lint-staged": "^15.2.10",
|
|
269
275
|
"page-with": "^0.6.1",
|
|
270
|
-
"prettier": "^3.
|
|
276
|
+
"prettier": "^3.6.2",
|
|
271
277
|
"publint": "^0.3.12",
|
|
272
278
|
"regenerator-runtime": "^0.14.1",
|
|
273
279
|
"rimraf": "^6.0.1",
|
|
274
280
|
"simple-git-hooks": "^2.9.0",
|
|
275
281
|
"tsup": "^8.4.0",
|
|
276
282
|
"typescript": "^5.9.2",
|
|
283
|
+
"typescript-eslint": "^8.42.0",
|
|
277
284
|
"undici": "^6.20.0",
|
|
278
285
|
"url-loader": "^4.1.1",
|
|
279
286
|
"vitest": "^3.1.4",
|
|
280
287
|
"vitest-environment-miniflare": "^2.14.4",
|
|
281
288
|
"webpack": "^5.95.0",
|
|
282
289
|
"webpack-http-server": "^0.5.0",
|
|
283
|
-
"msw": "2.11.
|
|
290
|
+
"msw": "2.11.2"
|
|
284
291
|
},
|
|
285
292
|
"peerDependencies": {
|
|
286
293
|
"typescript": ">= 4.8.x"
|
|
@@ -303,7 +310,7 @@
|
|
|
303
310
|
"scripts": {
|
|
304
311
|
"start": "tsup --watch",
|
|
305
312
|
"clean": "rimraf ./lib",
|
|
306
|
-
"lint": "eslint \"{cli,src}/**/*.ts\"",
|
|
313
|
+
"lint": "eslint \"{cli,src,test}/**/*.ts\"",
|
|
307
314
|
"build": "pnpm clean && cross-env NODE_ENV=production tsup && pnpm patch:dts",
|
|
308
315
|
"patch:dts": "node \"./config/scripts/patch-ts.js\"",
|
|
309
316
|
"publint": "publint",
|
|
@@ -1,137 +1,30 @@
|
|
|
1
1
|
import { Emitter } from 'strict-event-emitter'
|
|
2
|
+
import type { DeferredPromise } from '@open-draft/deferred-promise'
|
|
2
3
|
import {
|
|
3
4
|
LifeCycleEventEmitter,
|
|
4
5
|
LifeCycleEventsMap,
|
|
5
6
|
SharedOptions,
|
|
6
7
|
} from '~/core/sharedOptions'
|
|
7
|
-
import { ServiceWorkerMessage } from './start/utils/createMessageChannel'
|
|
8
8
|
import { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
9
9
|
import type { HttpRequestEventMap, Interceptor } from '@mswjs/interceptors'
|
|
10
10
|
import type { RequiredDeep } from '~/core/typeUtils'
|
|
11
11
|
import type { WebSocketHandler } from '~/core/handlers/WebSocketHandler'
|
|
12
|
-
|
|
13
|
-
type RequestWithoutMethods = Omit<
|
|
14
|
-
Request,
|
|
15
|
-
| 'text'
|
|
16
|
-
| 'body'
|
|
17
|
-
| 'json'
|
|
18
|
-
| 'blob'
|
|
19
|
-
| 'arrayBuffer'
|
|
20
|
-
| 'formData'
|
|
21
|
-
| 'clone'
|
|
22
|
-
| 'signal'
|
|
23
|
-
| 'isHistoryNavigation'
|
|
24
|
-
| 'isReloadNavigation'
|
|
25
|
-
>
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Request representation received from the worker message event.
|
|
29
|
-
*/
|
|
30
|
-
export interface ServiceWorkerIncomingRequest extends RequestWithoutMethods {
|
|
31
|
-
/**
|
|
32
|
-
* Unique ID of the request generated once the request is
|
|
33
|
-
* intercepted by the "fetch" event in the Service Worker.
|
|
34
|
-
*/
|
|
35
|
-
id: string
|
|
36
|
-
body?: ArrayBuffer | null
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
type ServiceWorkerIncomingResponse = {
|
|
40
|
-
isMockedResponse: boolean
|
|
41
|
-
request: ServiceWorkerIncomingRequest
|
|
42
|
-
response: Pick<
|
|
43
|
-
Response,
|
|
44
|
-
'type' | 'ok' | 'status' | 'statusText' | 'body' | 'headers' | 'redirected'
|
|
45
|
-
>
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Map of the events that can be received from the Service Worker.
|
|
50
|
-
*/
|
|
51
|
-
export interface ServiceWorkerIncomingEventsMap {
|
|
52
|
-
MOCKING_ENABLED: {
|
|
53
|
-
client: {
|
|
54
|
-
id: string
|
|
55
|
-
frameType: string
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
INTEGRITY_CHECK_RESPONSE: {
|
|
59
|
-
packageVersion: string
|
|
60
|
-
checksum: string
|
|
61
|
-
}
|
|
62
|
-
KEEPALIVE_RESPONSE: never
|
|
63
|
-
REQUEST: ServiceWorkerIncomingRequest
|
|
64
|
-
RESPONSE: ServiceWorkerIncomingResponse
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Map of the events that can be sent to the Service Worker
|
|
69
|
-
* from any execution context.
|
|
70
|
-
*/
|
|
71
|
-
type ServiceWorkerOutgoingEventTypes =
|
|
72
|
-
| 'MOCK_ACTIVATE'
|
|
73
|
-
| 'MOCK_DEACTIVATE'
|
|
74
|
-
| 'INTEGRITY_CHECK_REQUEST'
|
|
75
|
-
| 'KEEPALIVE_REQUEST'
|
|
76
|
-
| 'CLIENT_CLOSED'
|
|
12
|
+
import type { WorkerChannel } from '../utils/workerChannel'
|
|
77
13
|
|
|
78
14
|
export interface StringifiedResponse extends ResponseInit {
|
|
79
15
|
body: string | ArrayBuffer | ReadableStream<Uint8Array> | null
|
|
80
16
|
}
|
|
81
17
|
|
|
82
|
-
|
|
83
|
-
(event: EventType): void
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
export interface SetupWorkerInternalContext {
|
|
18
|
+
export type SetupWorkerInternalContext = {
|
|
87
19
|
isMockingEnabled: boolean
|
|
20
|
+
workerStoppedAt?: number
|
|
88
21
|
startOptions: RequiredDeep<StartOptions>
|
|
89
|
-
|
|
90
|
-
registration: ServiceWorkerRegistration |
|
|
22
|
+
workerPromise: DeferredPromise<ServiceWorker>
|
|
23
|
+
registration: ServiceWorkerRegistration | undefined
|
|
91
24
|
getRequestHandlers: () => Array<RequestHandler | WebSocketHandler>
|
|
92
25
|
emitter: Emitter<LifeCycleEventsMap>
|
|
93
26
|
keepAliveInterval?: number
|
|
94
|
-
workerChannel:
|
|
95
|
-
/**
|
|
96
|
-
* Adds a Service Worker event listener.
|
|
97
|
-
*/
|
|
98
|
-
on<EventType extends keyof ServiceWorkerIncomingEventsMap>(
|
|
99
|
-
eventType: EventType,
|
|
100
|
-
callback: (
|
|
101
|
-
event: MessageEvent,
|
|
102
|
-
message: ServiceWorkerMessage<
|
|
103
|
-
EventType,
|
|
104
|
-
ServiceWorkerIncomingEventsMap[EventType]
|
|
105
|
-
>,
|
|
106
|
-
) => void,
|
|
107
|
-
): void
|
|
108
|
-
send<EventType extends ServiceWorkerOutgoingEventTypes>(
|
|
109
|
-
eventType: EventType,
|
|
110
|
-
): void
|
|
111
|
-
}
|
|
112
|
-
events: {
|
|
113
|
-
/**
|
|
114
|
-
* Adds an event listener on the given target.
|
|
115
|
-
* Returns a clean-up function that removes that listener.
|
|
116
|
-
*/
|
|
117
|
-
addListener<EventType extends Event>(
|
|
118
|
-
target: EventTarget,
|
|
119
|
-
eventType: string,
|
|
120
|
-
callback: StrictEventListener<EventType>,
|
|
121
|
-
): () => void
|
|
122
|
-
/**
|
|
123
|
-
* Removes all currently attached listeners.
|
|
124
|
-
*/
|
|
125
|
-
removeAllListeners(): void
|
|
126
|
-
/**
|
|
127
|
-
* Awaits a given message type from the Service Worker.
|
|
128
|
-
*/
|
|
129
|
-
once<EventType extends keyof ServiceWorkerIncomingEventsMap>(
|
|
130
|
-
eventType: EventType,
|
|
131
|
-
): Promise<
|
|
132
|
-
ServiceWorkerMessage<EventType, ServiceWorkerIncomingEventsMap[EventType]>
|
|
133
|
-
>
|
|
134
|
-
}
|
|
27
|
+
workerChannel: WorkerChannel
|
|
135
28
|
supports: {
|
|
136
29
|
serviceWorkerApi: boolean
|
|
137
30
|
readableStreamTransfer: boolean
|
|
@@ -184,10 +77,12 @@ export interface StartOptions extends SharedOptions {
|
|
|
184
77
|
}
|
|
185
78
|
|
|
186
79
|
export type StartReturnType = Promise<ServiceWorkerRegistration | undefined>
|
|
80
|
+
|
|
187
81
|
export type StartHandler = (
|
|
188
82
|
options: RequiredDeep<StartOptions>,
|
|
189
83
|
initialOptions: StartOptions,
|
|
190
84
|
) => StartReturnType
|
|
85
|
+
|
|
191
86
|
export type StopHandler = () => void
|
|
192
87
|
|
|
193
88
|
export interface SetupWorker {
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import { invariant } from 'outvariant'
|
|
2
2
|
import { isNodeProcess } from 'is-node-process'
|
|
3
|
-
import {
|
|
3
|
+
import type {
|
|
4
4
|
SetupWorkerInternalContext,
|
|
5
|
-
ServiceWorkerIncomingEventsMap,
|
|
6
5
|
StartReturnType,
|
|
7
|
-
StopHandler,
|
|
8
|
-
StartHandler,
|
|
9
6
|
StartOptions,
|
|
10
7
|
SetupWorker,
|
|
11
8
|
} from './glossary'
|
|
12
|
-
import { createStartHandler } from './start/createStartHandler'
|
|
13
|
-
import { createStop } from './stop/createStop'
|
|
14
|
-
import { ServiceWorkerMessage } from './start/utils/createMessageChannel'
|
|
15
9
|
import { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
16
10
|
import { DEFAULT_START_OPTIONS } from './start/utils/prepareStartHandler'
|
|
17
|
-
import {
|
|
18
|
-
import { createFallbackStop } from './stop/createFallbackStop'
|
|
11
|
+
import { createStartHandler } from './start/createStartHandler'
|
|
19
12
|
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
20
13
|
import { SetupApi } from '~/core/SetupApi'
|
|
21
14
|
import { mergeRight } from '~/core/utils/internal/mergeRight'
|
|
@@ -25,21 +18,17 @@ import { supportsReadableStreamTransfer } from '../utils/supportsReadableStreamT
|
|
|
25
18
|
import { webSocketInterceptor } from '~/core/ws/webSocketInterceptor'
|
|
26
19
|
import { handleWebSocketEvent } from '~/core/ws/handleWebSocketEvent'
|
|
27
20
|
import { attachWebSocketLogger } from '~/core/ws/utils/attachWebSocketLogger'
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
21
|
+
import { WorkerChannel } from '../utils/workerChannel'
|
|
22
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
23
|
+
import { createFallbackRequestListener } from './start/createFallbackRequestListener'
|
|
24
|
+
import { printStartMessage } from './start/utils/printStartMessage'
|
|
25
|
+
import { printStopMessage } from './stop/utils/printStopMessage'
|
|
34
26
|
|
|
35
27
|
export class SetupWorkerApi
|
|
36
28
|
extends SetupApi<LifeCycleEventsMap>
|
|
37
29
|
implements SetupWorker
|
|
38
30
|
{
|
|
39
31
|
private context: SetupWorkerInternalContext
|
|
40
|
-
private startHandler: StartHandler = null as any
|
|
41
|
-
private stopHandler: StopHandler = null as any
|
|
42
|
-
private listeners: Array<Listener>
|
|
43
32
|
|
|
44
33
|
constructor(...handlers: Array<RequestHandler | WebSocketHandler>) {
|
|
45
34
|
super(...handlers)
|
|
@@ -51,129 +40,53 @@ export class SetupWorkerApi
|
|
|
51
40
|
),
|
|
52
41
|
)
|
|
53
42
|
|
|
54
|
-
this.listeners = []
|
|
55
43
|
this.context = this.createWorkerContext()
|
|
56
44
|
}
|
|
57
45
|
|
|
58
46
|
private createWorkerContext(): SetupWorkerInternalContext {
|
|
59
|
-
const
|
|
47
|
+
const workerPromise = new DeferredPromise<ServiceWorker>()
|
|
48
|
+
|
|
49
|
+
return {
|
|
60
50
|
// Mocking is not considered enabled until the worker
|
|
61
51
|
// signals back the successful activation event.
|
|
62
52
|
isMockingEnabled: false,
|
|
63
53
|
startOptions: null as any,
|
|
64
|
-
|
|
54
|
+
workerPromise,
|
|
55
|
+
registration: undefined,
|
|
65
56
|
getRequestHandlers: () => {
|
|
66
57
|
return this.handlersController.currentHandlers()
|
|
67
58
|
},
|
|
68
|
-
registration: null,
|
|
69
59
|
emitter: this.emitter,
|
|
70
|
-
workerChannel: {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
MessageEvent<ServiceWorkerMessage<typeof eventType, any>>
|
|
74
|
-
>(navigator.serviceWorker, 'message', (event) => {
|
|
75
|
-
// Avoid messages broadcasted from unrelated workers.
|
|
76
|
-
if (event.source !== this.context.worker) {
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const message = event.data
|
|
81
|
-
|
|
82
|
-
if (!message) {
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (message.type === eventType) {
|
|
87
|
-
callback(event, message)
|
|
88
|
-
}
|
|
89
|
-
})
|
|
90
|
-
},
|
|
91
|
-
send: (type) => {
|
|
92
|
-
this.context.worker?.postMessage(type)
|
|
93
|
-
},
|
|
94
|
-
},
|
|
95
|
-
events: {
|
|
96
|
-
addListener: (target, eventType, callback) => {
|
|
97
|
-
target.addEventListener(eventType, callback as EventListener)
|
|
98
|
-
this.listeners.push({
|
|
99
|
-
eventType,
|
|
100
|
-
target,
|
|
101
|
-
callback: callback as EventListener,
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
return () => {
|
|
105
|
-
target.removeEventListener(eventType, callback as EventListener)
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
removeAllListeners: () => {
|
|
109
|
-
for (const { target, eventType, callback } of this.listeners) {
|
|
110
|
-
target.removeEventListener(eventType, callback)
|
|
111
|
-
}
|
|
112
|
-
this.listeners = []
|
|
113
|
-
},
|
|
114
|
-
once: (eventType) => {
|
|
115
|
-
const bindings: Array<() => void> = []
|
|
116
|
-
|
|
117
|
-
return new Promise<
|
|
118
|
-
ServiceWorkerMessage<
|
|
119
|
-
typeof eventType,
|
|
120
|
-
ServiceWorkerIncomingEventsMap[typeof eventType]
|
|
121
|
-
>
|
|
122
|
-
>((resolve, reject) => {
|
|
123
|
-
const handleIncomingMessage = (event: MessageEvent) => {
|
|
124
|
-
try {
|
|
125
|
-
const message = event.data
|
|
126
|
-
|
|
127
|
-
if (message.type === eventType) {
|
|
128
|
-
resolve(message)
|
|
129
|
-
}
|
|
130
|
-
} catch (error) {
|
|
131
|
-
reject(error)
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
bindings.push(
|
|
136
|
-
this.context.events.addListener(
|
|
137
|
-
navigator.serviceWorker,
|
|
138
|
-
'message',
|
|
139
|
-
handleIncomingMessage,
|
|
140
|
-
),
|
|
141
|
-
this.context.events.addListener(
|
|
142
|
-
navigator.serviceWorker,
|
|
143
|
-
'messageerror',
|
|
144
|
-
reject,
|
|
145
|
-
),
|
|
146
|
-
)
|
|
147
|
-
}).finally(() => {
|
|
148
|
-
bindings.forEach((unbind) => unbind())
|
|
149
|
-
})
|
|
150
|
-
},
|
|
151
|
-
},
|
|
60
|
+
workerChannel: new WorkerChannel({
|
|
61
|
+
worker: workerPromise,
|
|
62
|
+
}),
|
|
152
63
|
supports: {
|
|
153
64
|
serviceWorkerApi:
|
|
154
|
-
|
|
65
|
+
'serviceWorker' in navigator && location.protocol !== 'file:',
|
|
155
66
|
readableStreamTransfer: supportsReadableStreamTransfer(),
|
|
156
67
|
},
|
|
157
68
|
}
|
|
158
|
-
|
|
159
|
-
this.startHandler = context.supports.serviceWorkerApi
|
|
160
|
-
? createFallbackStart(context)
|
|
161
|
-
: createStartHandler(context)
|
|
162
|
-
|
|
163
|
-
this.stopHandler = context.supports.serviceWorkerApi
|
|
164
|
-
? createFallbackStop(context)
|
|
165
|
-
: createStop(context)
|
|
166
|
-
|
|
167
|
-
return context
|
|
168
69
|
}
|
|
169
70
|
|
|
170
71
|
public async start(options: StartOptions = {}): StartReturnType {
|
|
171
|
-
if (
|
|
72
|
+
if ('waitUntilReady' in options) {
|
|
172
73
|
devUtils.warn(
|
|
173
74
|
'The "waitUntilReady" option has been deprecated. Please remove it from this "worker.start()" call. Follow the recommended Browser integration (https://mswjs.io/docs/integrations/browser) to eliminate any race conditions between the Service Worker registration and any requests made by your application on initial render.',
|
|
174
75
|
)
|
|
175
76
|
}
|
|
176
77
|
|
|
78
|
+
// Warn the developer on multiple "worker.start()" calls.
|
|
79
|
+
// While this will not affect the worker in any way,
|
|
80
|
+
// it likely indicates an issue with the developer's code.
|
|
81
|
+
if (this.context.isMockingEnabled) {
|
|
82
|
+
devUtils.warn(
|
|
83
|
+
`Found a redundant "worker.start()" call. Note that starting the worker while mocking is already enabled will have no effect. Consider removing this "worker.start()" call.`,
|
|
84
|
+
)
|
|
85
|
+
return this.context.registration
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this.context.workerStoppedAt = undefined
|
|
89
|
+
|
|
177
90
|
this.context.startOptions = mergeRight(
|
|
178
91
|
DEFAULT_START_OPTIONS,
|
|
179
92
|
options,
|
|
@@ -202,14 +115,64 @@ export class SetupWorkerApi
|
|
|
202
115
|
webSocketInterceptor.dispose()
|
|
203
116
|
})
|
|
204
117
|
|
|
205
|
-
|
|
118
|
+
// Use a fallback interception algorithm in the environments
|
|
119
|
+
// where the Service Worker API isn't supported.
|
|
120
|
+
if (!this.context.supports.serviceWorkerApi) {
|
|
121
|
+
const fallbackInterceptor = createFallbackRequestListener(
|
|
122
|
+
this.context,
|
|
123
|
+
this.context.startOptions,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
this.subscriptions.push(() => {
|
|
127
|
+
fallbackInterceptor.dispose()
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
this.context.isMockingEnabled = true
|
|
131
|
+
|
|
132
|
+
printStartMessage({
|
|
133
|
+
message: 'Mocking enabled (fallback mode).',
|
|
134
|
+
quiet: this.context.startOptions.quiet,
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
return undefined
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const startHandler = createStartHandler(this.context)
|
|
141
|
+
const registration = await startHandler(this.context.startOptions, options)
|
|
142
|
+
|
|
143
|
+
this.context.isMockingEnabled = true
|
|
144
|
+
|
|
145
|
+
return registration
|
|
206
146
|
}
|
|
207
147
|
|
|
208
148
|
public stop(): void {
|
|
209
149
|
super.dispose()
|
|
210
|
-
|
|
150
|
+
|
|
151
|
+
if (!this.context.isMockingEnabled) {
|
|
152
|
+
devUtils.warn(
|
|
153
|
+
'Found a redundant "worker.stop()" call. Notice that stopping the worker after it has already been stopped has no effect. Consider removing this "worker.stop()" call.',
|
|
154
|
+
)
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
this.context.isMockingEnabled = false
|
|
159
|
+
this.context.workerStoppedAt = Date.now()
|
|
211
160
|
this.context.emitter.removeAllListeners()
|
|
212
|
-
|
|
161
|
+
|
|
162
|
+
if (this.context.supports.serviceWorkerApi) {
|
|
163
|
+
this.context.workerChannel.removeAllListeners('RESPONSE')
|
|
164
|
+
window.clearInterval(this.context.keepAliveInterval)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Post the internal stop message on the window
|
|
168
|
+
// to let any logic know when the worker has stopped.
|
|
169
|
+
// E.g. the WebSocket client manager needs this to know
|
|
170
|
+
// when to clear its in-memory clients list.
|
|
171
|
+
window.postMessage({ type: 'msw/worker:stop' })
|
|
172
|
+
|
|
173
|
+
printStopMessage({
|
|
174
|
+
quiet: this.context.startOptions?.quiet,
|
|
175
|
+
})
|
|
213
176
|
}
|
|
214
177
|
}
|
|
215
178
|
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
SetupWorkerInternalContext,
|
|
4
|
-
ServiceWorkerIncomingEventsMap,
|
|
5
|
-
} from '../glossary'
|
|
6
|
-
import {
|
|
7
|
-
ServiceWorkerMessage,
|
|
8
|
-
WorkerChannel,
|
|
9
|
-
} from './utils/createMessageChannel'
|
|
1
|
+
import { Emitter } from 'rettime'
|
|
2
|
+
import { StartOptions, SetupWorkerInternalContext } from '../glossary'
|
|
10
3
|
import { deserializeRequest } from '../../utils/deserializeRequest'
|
|
11
4
|
import { RequestHandler } from '~/core/handlers/RequestHandler'
|
|
12
5
|
import { handleRequest } from '~/core/utils/handleRequest'
|
|
@@ -18,18 +11,21 @@ import { isHandlerKind } from '~/core/utils/internal/isHandlerKind'
|
|
|
18
11
|
export const createRequestListener = (
|
|
19
12
|
context: SetupWorkerInternalContext,
|
|
20
13
|
options: RequiredDeep<StartOptions>,
|
|
21
|
-
) => {
|
|
22
|
-
return async (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
): Emitter.ListenerType<typeof context.workerChannel, 'REQUEST'> => {
|
|
15
|
+
return async (event) => {
|
|
16
|
+
// Treat any incoming requests from the worker as passthrough
|
|
17
|
+
// if `worker.stop()` has been called for this client.
|
|
18
|
+
if (
|
|
19
|
+
!context.isMockingEnabled &&
|
|
20
|
+
context.workerStoppedAt &&
|
|
21
|
+
event.data.interceptedAt > context.workerStoppedAt
|
|
22
|
+
) {
|
|
23
|
+
event.postMessage('PASSTHROUGH')
|
|
24
|
+
return
|
|
25
|
+
}
|
|
30
26
|
|
|
31
|
-
const requestId =
|
|
32
|
-
const request = deserializeRequest(
|
|
27
|
+
const requestId = event.data.id
|
|
28
|
+
const request = deserializeRequest(event.data)
|
|
33
29
|
const requestCloneForLogs = request.clone()
|
|
34
30
|
|
|
35
31
|
// Make this the first request clone before the
|
|
@@ -48,7 +44,7 @@ export const createRequestListener = (
|
|
|
48
44
|
context.emitter,
|
|
49
45
|
{
|
|
50
46
|
onPassthroughResponse() {
|
|
51
|
-
|
|
47
|
+
event.postMessage('PASSTHROUGH')
|
|
52
48
|
},
|
|
53
49
|
async onMockedResponse(response, { handler, parsedResult }) {
|
|
54
50
|
// Clone the mocked response so its body could be read
|
|
@@ -65,7 +61,7 @@ export const createRequestListener = (
|
|
|
65
61
|
if (context.supports.readableStreamTransfer) {
|
|
66
62
|
const responseStreamOrNull = response.body
|
|
67
63
|
|
|
68
|
-
|
|
64
|
+
event.postMessage(
|
|
69
65
|
'MOCK_RESPONSE',
|
|
70
66
|
{
|
|
71
67
|
...responseInit,
|
|
@@ -85,7 +81,7 @@ export const createRequestListener = (
|
|
|
85
81
|
? null
|
|
86
82
|
: await responseClone.arrayBuffer()
|
|
87
83
|
|
|
88
|
-
|
|
84
|
+
event.postMessage('MOCK_RESPONSE', {
|
|
89
85
|
...responseInit,
|
|
90
86
|
body: responseBufferOrNull,
|
|
91
87
|
})
|
|
@@ -118,7 +114,7 @@ This exception has been gracefully handled as a 500 response, however, it's stro
|
|
|
118
114
|
|
|
119
115
|
// Treat all other exceptions in a request handler as unintended,
|
|
120
116
|
// alerting that there is a problem that needs fixing.
|
|
121
|
-
|
|
117
|
+
event.postMessage('MOCK_RESPONSE', {
|
|
122
118
|
status: 500,
|
|
123
119
|
statusText: 'Request Handler Error',
|
|
124
120
|
headers: {
|