msw 2.11.1 → 2.11.3
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 +536 -318
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/index.mjs +536 -318
- 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/handleRequest.js +8 -8
- package/lib/core/utils/handleRequest.js.map +1 -1
- package/lib/core/utils/handleRequest.mjs +8 -8
- package/lib/core/utils/handleRequest.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 +2536 -2314
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +16 -12
- package/package.json +22 -15
- 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/getWorkerInstance.ts +17 -16
- package/src/browser/setupWorker/start/utils/printStartMessage.ts +0 -2
- package/src/browser/utils/checkWorkerIntegrity.ts +22 -14
- package/src/browser/utils/deferNetworkRequestsUntil.ts +1 -1
- 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/handleRequest.ts +8 -8
- 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
|
@@ -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: {
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import { FetchResponse } from '@mswjs/interceptors'
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
SetupWorkerInternalContext,
|
|
5
|
-
} from '../glossary'
|
|
6
|
-
import type { ServiceWorkerMessage } from './utils/createMessageChannel'
|
|
2
|
+
import type { Emitter } from 'rettime'
|
|
3
|
+
import type { SetupWorkerInternalContext } from '../glossary'
|
|
7
4
|
import { deserializeRequest } from '../../utils/deserializeRequest'
|
|
8
5
|
|
|
9
|
-
export function createResponseListener(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
>,
|
|
16
|
-
) => {
|
|
17
|
-
const { payload: responseJson } = message
|
|
18
|
-
const request = deserializeRequest(responseJson.request)
|
|
6
|
+
export function createResponseListener(
|
|
7
|
+
context: SetupWorkerInternalContext,
|
|
8
|
+
): Emitter.ListenerType<typeof context.workerChannel, 'RESPONSE'> {
|
|
9
|
+
return (event) => {
|
|
10
|
+
const responseMessage = event.data
|
|
11
|
+
const request = deserializeRequest(responseMessage.request)
|
|
19
12
|
|
|
20
13
|
/**
|
|
21
14
|
* CORS requests with `mode: "no-cors"` result in "opaque" responses.
|
|
@@ -24,12 +17,12 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
|
|
|
24
17
|
* @see https://fetch.spec.whatwg.org/#concept-filtered-response-opaque
|
|
25
18
|
* @see https://github.com/mswjs/msw/issues/529
|
|
26
19
|
*/
|
|
27
|
-
if (
|
|
20
|
+
if (responseMessage.response.type?.includes('opaque')) {
|
|
28
21
|
return
|
|
29
22
|
}
|
|
30
23
|
|
|
31
24
|
const response =
|
|
32
|
-
|
|
25
|
+
responseMessage.response.status === 0
|
|
33
26
|
? Response.error()
|
|
34
27
|
: new FetchResponse(
|
|
35
28
|
/**
|
|
@@ -38,11 +31,11 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
|
|
|
38
31
|
* throw when passed a non-null body, so ensure it's null here
|
|
39
32
|
* for those codes
|
|
40
33
|
*/
|
|
41
|
-
FetchResponse.isResponseWithBody(
|
|
42
|
-
?
|
|
34
|
+
FetchResponse.isResponseWithBody(responseMessage.response.status)
|
|
35
|
+
? responseMessage.response.body
|
|
43
36
|
: null,
|
|
44
37
|
{
|
|
45
|
-
...
|
|
38
|
+
...responseMessage,
|
|
46
39
|
/**
|
|
47
40
|
* Set response URL if it's not set already.
|
|
48
41
|
* @see https://github.com/mswjs/msw/issues/2030
|
|
@@ -53,9 +46,9 @@ export function createResponseListener(context: SetupWorkerInternalContext) {
|
|
|
53
46
|
)
|
|
54
47
|
|
|
55
48
|
context.emitter.emit(
|
|
56
|
-
|
|
49
|
+
responseMessage.isMockedResponse ? 'response:mocked' : 'response:bypass',
|
|
57
50
|
{
|
|
58
|
-
requestId:
|
|
51
|
+
requestId: responseMessage.request.id,
|
|
59
52
|
request,
|
|
60
53
|
response,
|
|
61
54
|
},
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
2
2
|
import { getWorkerInstance } from './utils/getWorkerInstance'
|
|
3
3
|
import { enableMocking } from './utils/enableMocking'
|
|
4
|
-
import { SetupWorkerInternalContext, StartHandler } from '../glossary'
|
|
4
|
+
import type { SetupWorkerInternalContext, StartHandler } from '../glossary'
|
|
5
5
|
import { createRequestListener } from './createRequestListener'
|
|
6
6
|
import { checkWorkerIntegrity } from '../../utils/checkWorkerIntegrity'
|
|
7
7
|
import { createResponseListener } from './createResponseListener'
|
|
8
8
|
import { validateWorkerScope } from './utils/validateWorkerScope'
|
|
9
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
9
10
|
|
|
10
11
|
export const createStartHandler = (
|
|
11
12
|
context: SetupWorkerInternalContext,
|
|
@@ -15,7 +16,7 @@ export const createStartHandler = (
|
|
|
15
16
|
// Remove all previously existing event listeners.
|
|
16
17
|
// This way none of the listeners persists between Fast refresh
|
|
17
18
|
// of the application's code.
|
|
18
|
-
context.
|
|
19
|
+
context.workerChannel.removeAllListeners()
|
|
19
20
|
|
|
20
21
|
// Handle requests signaled by the worker.
|
|
21
22
|
context.workerChannel.on(
|
|
@@ -57,17 +58,18 @@ Please consider using a custom "serviceWorker.url" option to point to the actual
|
|
|
57
58
|
throw new Error(missingWorkerMessage)
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
context.worker
|
|
61
|
+
context.workerPromise.resolve(worker)
|
|
61
62
|
context.registration = registration
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
window.addEventListener('beforeunload', () => {
|
|
64
65
|
if (worker.state !== 'redundant') {
|
|
65
66
|
// Notify the Service Worker that this client has closed.
|
|
66
67
|
// Internally, it's similar to disabling the mocking, only
|
|
67
68
|
// client close event has a handler that self-terminates
|
|
68
69
|
// the Service Worker when there are no open clients.
|
|
69
|
-
context.workerChannel.
|
|
70
|
+
context.workerChannel.postMessage('CLIENT_CLOSED')
|
|
70
71
|
}
|
|
72
|
+
|
|
71
73
|
// Make sure we're always clearing the interval - there are reports that not doing this can
|
|
72
74
|
// cause memory leaks in headless browser environments.
|
|
73
75
|
window.clearInterval(context.keepAliveInterval)
|
|
@@ -82,14 +84,13 @@ Please consider using a custom "serviceWorker.url" option to point to the actual
|
|
|
82
84
|
// by the currently installed version of MSW.
|
|
83
85
|
await checkWorkerIntegrity(context).catch((error) => {
|
|
84
86
|
devUtils.error(
|
|
85
|
-
'Error while checking the worker script integrity. Please report this on GitHub (https://github.com/mswjs/msw/issues)
|
|
87
|
+
'Error while checking the worker script integrity. Please report this on GitHub (https://github.com/mswjs/msw/issues) and include the original error below.',
|
|
86
88
|
)
|
|
87
|
-
// eslint-disable-next-line no-console
|
|
88
89
|
console.error(error)
|
|
89
90
|
})
|
|
90
91
|
|
|
91
92
|
context.keepAliveInterval = window.setInterval(
|
|
92
|
-
() => context.workerChannel.
|
|
93
|
+
() => context.workerChannel.postMessage('KEEPALIVE_REQUEST'),
|
|
93
94
|
5000,
|
|
94
95
|
)
|
|
95
96
|
|
|
@@ -104,22 +105,27 @@ Please consider using a custom "serviceWorker.url" option to point to the actual
|
|
|
104
105
|
async (registration) => {
|
|
105
106
|
const pendingInstance = registration.installing || registration.waiting
|
|
106
107
|
|
|
107
|
-
// Wait until the worker is activated.
|
|
108
|
-
// Assume the worker is already activated if there's no pending registration
|
|
109
|
-
// (i.e. when reloading the page after a successful activation).
|
|
110
108
|
if (pendingInstance) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
109
|
+
const activationPromise = new DeferredPromise<void>()
|
|
110
|
+
|
|
111
|
+
pendingInstance.addEventListener('statechange', () => {
|
|
112
|
+
if (pendingInstance.state === 'activated') {
|
|
113
|
+
activationPromise.resolve()
|
|
114
|
+
}
|
|
117
115
|
})
|
|
116
|
+
|
|
117
|
+
// Wait until the worker is activated.
|
|
118
|
+
// Assume the worker is already activated if there's no pending registration
|
|
119
|
+
// (i.e. when reloading the page after a successful activation).
|
|
120
|
+
await activationPromise
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
// Print the activation message only after the worker has been activated.
|
|
121
124
|
await enableMocking(context, options).catch((error) => {
|
|
122
|
-
|
|
125
|
+
devUtils.error(
|
|
126
|
+
'Failed to enable mocking. Please report this on GitHub (https://github.com/mswjs/msw/issues) and include the original error below.',
|
|
127
|
+
)
|
|
128
|
+
throw error
|
|
123
129
|
})
|
|
124
130
|
|
|
125
131
|
return registration
|
|
@@ -1,33 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { StartOptions, SetupWorkerInternalContext } from '../../glossary'
|
|
1
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
2
|
+
import type { StartOptions, SetupWorkerInternalContext } from '../../glossary'
|
|
3
3
|
import { printStartMessage } from './printStartMessage'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Signals the worker to enable the interception of requests.
|
|
7
7
|
*/
|
|
8
|
-
export
|
|
8
|
+
export function enableMocking(
|
|
9
9
|
context: SetupWorkerInternalContext,
|
|
10
10
|
options: StartOptions,
|
|
11
|
-
) {
|
|
12
|
-
|
|
13
|
-
const { payload } = await context.events.once('MOCKING_ENABLED')
|
|
11
|
+
): Promise<boolean> {
|
|
12
|
+
const mockingEnabledPromise = new DeferredPromise<boolean>()
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
devUtils.warn(
|
|
20
|
-
`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.`,
|
|
21
|
-
)
|
|
22
|
-
return
|
|
23
|
-
}
|
|
14
|
+
context.workerChannel.postMessage('MOCK_ACTIVATE')
|
|
15
|
+
context.workerChannel.once('MOCKING_ENABLED', async (event) => {
|
|
16
|
+
context.isMockingEnabled = true
|
|
17
|
+
const worker = await context.workerPromise
|
|
24
18
|
|
|
25
|
-
|
|
19
|
+
printStartMessage({
|
|
20
|
+
quiet: options.quiet,
|
|
21
|
+
workerScope: context.registration?.scope,
|
|
22
|
+
workerUrl: worker.scriptURL,
|
|
23
|
+
client: event.data.client,
|
|
24
|
+
})
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
quiet: options.quiet,
|
|
29
|
-
workerScope: context.registration?.scope,
|
|
30
|
-
workerUrl: context.worker?.scriptURL,
|
|
31
|
-
client: payload.client,
|
|
26
|
+
mockingEnabledPromise.resolve(true)
|
|
32
27
|
})
|
|
28
|
+
|
|
29
|
+
return mockingEnabledPromise
|
|
33
30
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { until } from '
|
|
1
|
+
import { until } from 'until-async'
|
|
2
2
|
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
3
3
|
import { getAbsoluteWorkerUrl } from '../../../utils/getAbsoluteWorkerUrl'
|
|
4
4
|
import { getWorkerByRegistration } from './getWorkerByRegistration'
|
|
@@ -52,21 +52,22 @@ export const getWorkerInstance = async (
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
// When the Service Worker wasn't found, register it anew and return the reference.
|
|
55
|
-
const registrationResult = await until<
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
55
|
+
const [registrationError, registrationResult] = await until<
|
|
56
|
+
Error,
|
|
57
|
+
ServiceWorkerInstanceTuple
|
|
58
|
+
>(async () => {
|
|
59
|
+
const registration = await navigator.serviceWorker.register(url, options)
|
|
60
|
+
return [
|
|
61
|
+
// Compare existing worker registration by its worker URL,
|
|
62
|
+
// to prevent irrelevant workers to resolve here (such as Codesandbox worker).
|
|
63
|
+
getWorkerByRegistration(registration, absoluteWorkerUrl, findWorker),
|
|
64
|
+
registration,
|
|
65
|
+
]
|
|
66
|
+
})
|
|
66
67
|
|
|
67
68
|
// Handle Service Worker registration errors.
|
|
68
|
-
if (
|
|
69
|
-
const isWorkerMissing =
|
|
69
|
+
if (registrationError) {
|
|
70
|
+
const isWorkerMissing = registrationError.message.includes('(404)')
|
|
70
71
|
|
|
71
72
|
// Produce a custom error message when given a non-existing Service Worker url.
|
|
72
73
|
// Suggest developers to check their setup.
|
|
@@ -87,10 +88,10 @@ Learn more about creating the Service Worker script: https://mswjs.io/docs/cli/i
|
|
|
87
88
|
throw new Error(
|
|
88
89
|
devUtils.formatMessage(
|
|
89
90
|
'Failed to register the Service Worker:\n\n%s',
|
|
90
|
-
|
|
91
|
+
registrationError.message,
|
|
91
92
|
),
|
|
92
93
|
)
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
return registrationResult
|
|
96
|
+
return registrationResult
|
|
96
97
|
}
|
|
@@ -19,7 +19,6 @@ export function printStartMessage(args: PrintStartMessageArgs = {}) {
|
|
|
19
19
|
|
|
20
20
|
const message = args.message || 'Mocking enabled.'
|
|
21
21
|
|
|
22
|
-
// eslint-disable-next-line no-console
|
|
23
22
|
console.groupCollapsed(
|
|
24
23
|
`%c${devUtils.formatMessage(message)}`,
|
|
25
24
|
'color:orangered;font-weight:bold;',
|
|
@@ -48,6 +47,5 @@ export function printStartMessage(args: PrintStartMessageArgs = {}) {
|
|
|
48
47
|
console.log('Client ID: %s (%s)', args.client.id, args.client.frameType)
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
// eslint-disable-next-line no-console
|
|
52
50
|
console.groupEnd()
|
|
53
51
|
}
|
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
import { devUtils } from '~/core/utils/internal/devUtils'
|
|
2
2
|
import type { SetupWorkerInternalContext } from '../setupWorker/glossary'
|
|
3
|
+
import { DeferredPromise } from '@open-draft/deferred-promise'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Check whether the registered Service Worker has been
|
|
6
7
|
* generated by the installed version of the library.
|
|
7
8
|
* Prints a warning message if the worker scripts mismatch.
|
|
8
9
|
*/
|
|
9
|
-
export
|
|
10
|
+
export function checkWorkerIntegrity(
|
|
10
11
|
context: SetupWorkerInternalContext,
|
|
11
12
|
): Promise<void> {
|
|
12
|
-
|
|
13
|
-
context.workerChannel.send('INTEGRITY_CHECK_REQUEST')
|
|
13
|
+
const integrityCheckPromise = new DeferredPromise<void>()
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
// Request the integrity checksum from the registered worker.
|
|
16
|
+
context.workerChannel.postMessage('INTEGRITY_CHECK_REQUEST')
|
|
17
|
+
context.workerChannel.once('INTEGRITY_CHECK_RESPONSE', (event) => {
|
|
18
|
+
const { checksum, packageVersion } = event.data
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
// Compare the response from the Service Worker and the
|
|
21
|
+
// global variable set during the build.
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
// The integrity is validated based on the worker script's checksum
|
|
24
|
+
// that's derived from its minified content during the build.
|
|
25
|
+
// The "SERVICE_WORKER_CHECKSUM" global variable is injected by the build.
|
|
26
|
+
if (checksum !== SERVICE_WORKER_CHECKSUM) {
|
|
27
|
+
devUtils.warn(
|
|
28
|
+
`The currently registered Service Worker has been generated by a different version of MSW (${packageVersion}) and may not be fully compatible with the installed version.
|
|
26
29
|
|
|
27
30
|
It's recommended you update your worker script by running this command:
|
|
28
31
|
|
|
29
32
|
\u2022 npx msw init <PUBLIC_DIR>
|
|
30
33
|
|
|
31
34
|
You can also automate this process and make the worker script update automatically upon the library installations. Read more: https://mswjs.io/docs/cli/init.`,
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
integrityCheckPromise.resolve()
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
return integrityCheckPromise
|
|
34
42
|
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { Emitter, TypedEvent } from 'rettime'
|
|
2
|
+
import { isObject } from '~/core/utils/internal/isObject'
|
|
3
|
+
import type { StringifiedResponse } from '../setupWorker/glossary'
|
|
4
|
+
|
|
5
|
+
export interface WorkerChannelOptions {
|
|
6
|
+
worker: Promise<ServiceWorker>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export type WorkerChannelEventMap = {
|
|
10
|
+
REQUEST: WorkerEvent<IncomingWorkerRequest>
|
|
11
|
+
RESPONSE: WorkerEvent<IncomingWorkerResponse>
|
|
12
|
+
MOCKING_ENABLED: WorkerEvent<{
|
|
13
|
+
client: {
|
|
14
|
+
id: string
|
|
15
|
+
frameType: string
|
|
16
|
+
}
|
|
17
|
+
}>
|
|
18
|
+
INTEGRITY_CHECK_RESPONSE: WorkerEvent<{
|
|
19
|
+
packageVersion: string
|
|
20
|
+
checksum: string
|
|
21
|
+
}>
|
|
22
|
+
KEEPALIVE_RESPONSE: TypedEvent<never>
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Request representation received from the worker message event.
|
|
27
|
+
*/
|
|
28
|
+
export interface IncomingWorkerRequest
|
|
29
|
+
extends Omit<
|
|
30
|
+
Request,
|
|
31
|
+
| 'text'
|
|
32
|
+
| 'body'
|
|
33
|
+
| 'json'
|
|
34
|
+
| 'blob'
|
|
35
|
+
| 'arrayBuffer'
|
|
36
|
+
| 'formData'
|
|
37
|
+
| 'clone'
|
|
38
|
+
| 'signal'
|
|
39
|
+
| 'isHistoryNavigation'
|
|
40
|
+
| 'isReloadNavigation'
|
|
41
|
+
> {
|
|
42
|
+
/**
|
|
43
|
+
* Unique ID of the request generated once the request is
|
|
44
|
+
* intercepted by the "fetch" event in the Service Worker.
|
|
45
|
+
*/
|
|
46
|
+
id: string
|
|
47
|
+
interceptedAt: number
|
|
48
|
+
body?: ArrayBuffer | null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
type IncomingWorkerResponse = {
|
|
52
|
+
isMockedResponse: boolean
|
|
53
|
+
request: IncomingWorkerRequest
|
|
54
|
+
response: Pick<
|
|
55
|
+
Response,
|
|
56
|
+
'type' | 'ok' | 'status' | 'statusText' | 'body' | 'headers' | 'redirected'
|
|
57
|
+
>
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type WorkerEventResponse = {
|
|
61
|
+
MOCK_RESPONSE: [
|
|
62
|
+
data: StringifiedResponse,
|
|
63
|
+
transfer?: [ReadableStream<Uint8Array>],
|
|
64
|
+
]
|
|
65
|
+
PASSTHROUGH: []
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export class WorkerEvent<
|
|
69
|
+
DataType,
|
|
70
|
+
ReturnType = any,
|
|
71
|
+
EventType extends string = string,
|
|
72
|
+
> extends TypedEvent<DataType, ReturnType, EventType> {
|
|
73
|
+
#workerEvent: MessageEvent
|
|
74
|
+
|
|
75
|
+
constructor(workerEvent: MessageEvent) {
|
|
76
|
+
const type = workerEvent.data.type as EventType
|
|
77
|
+
const data = workerEvent.data.payload as DataType
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @note This is the only place we're mapping { type, payload }
|
|
81
|
+
* message structure of the worker. The client references the
|
|
82
|
+
* payload via `event.data`.
|
|
83
|
+
*/
|
|
84
|
+
super(
|
|
85
|
+
// @ts-expect-error Troublesome `TypedEvent` extension.
|
|
86
|
+
type,
|
|
87
|
+
{ data },
|
|
88
|
+
)
|
|
89
|
+
this.#workerEvent = workerEvent
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get ports() {
|
|
93
|
+
return this.#workerEvent.ports
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Reply directly to this event using its `MessagePort`.
|
|
98
|
+
*/
|
|
99
|
+
public postMessage<Type extends keyof WorkerEventResponse>(
|
|
100
|
+
type: Type,
|
|
101
|
+
...rest: WorkerEventResponse[Type]
|
|
102
|
+
): void {
|
|
103
|
+
this.#workerEvent.ports[0].postMessage(
|
|
104
|
+
{ type, data: rest[0] },
|
|
105
|
+
{ transfer: rest[1] },
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Map of the events that can be sent to the Service Worker
|
|
112
|
+
* from any execution context.
|
|
113
|
+
*/
|
|
114
|
+
type OutgoingWorkerEvents =
|
|
115
|
+
| 'MOCK_ACTIVATE'
|
|
116
|
+
| 'INTEGRITY_CHECK_REQUEST'
|
|
117
|
+
| 'KEEPALIVE_REQUEST'
|
|
118
|
+
| 'CLIENT_CLOSED'
|
|
119
|
+
|
|
120
|
+
export class WorkerChannel extends Emitter<WorkerChannelEventMap> {
|
|
121
|
+
constructor(protected readonly options: WorkerChannelOptions) {
|
|
122
|
+
super()
|
|
123
|
+
|
|
124
|
+
navigator.serviceWorker.addEventListener('message', async (event) => {
|
|
125
|
+
const worker = await this.options.worker
|
|
126
|
+
|
|
127
|
+
if (event.source != null && event.source !== worker) {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (event.data && isObject(event.data) && 'type' in event.data) {
|
|
132
|
+
this.emit(new WorkerEvent<any, any, any>(event))
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Send data to the Service Worker controlling this client.
|
|
139
|
+
* This triggers the `message` event listener on ServiceWorkerGlobalScope.
|
|
140
|
+
*/
|
|
141
|
+
public postMessage(type: OutgoingWorkerEvents): void {
|
|
142
|
+
this.options.worker.then((worker) => {
|
|
143
|
+
worker.postMessage(type)
|
|
144
|
+
})
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -176,7 +176,6 @@ export class GraphQLHandler extends RequestHandler<
|
|
|
176
176
|
GraphQLHandler.parsedRequestCache.set(
|
|
177
177
|
request,
|
|
178
178
|
await parseGraphQLRequest(request).catch((error) => {
|
|
179
|
-
// eslint-disable-next-line no-console
|
|
180
179
|
console.error(error)
|
|
181
180
|
return undefined
|
|
182
181
|
}),
|
|
@@ -318,7 +317,6 @@ Consider naming this operation or using "graphql.operation()" request handler to
|
|
|
318
317
|
? `${args.parsedResult.operationType} ${args.parsedResult.operationName}`
|
|
319
318
|
: `anonymous ${args.parsedResult.operationType}`
|
|
320
319
|
|
|
321
|
-
// eslint-disable-next-line no-console
|
|
322
320
|
console.groupCollapsed(
|
|
323
321
|
devUtils.formatMessage(
|
|
324
322
|
`${getTimestamp()} ${requestInfo} (%c${loggedResponse.status} ${
|
|
@@ -334,7 +332,6 @@ Consider naming this operation or using "graphql.operation()" request handler to
|
|
|
334
332
|
console.log('Handler:', this)
|
|
335
333
|
// eslint-disable-next-line no-console
|
|
336
334
|
console.log('Response:', loggedResponse)
|
|
337
|
-
// eslint-disable-next-line no-console
|
|
338
335
|
console.groupEnd()
|
|
339
336
|
}
|
|
340
337
|
}
|
|
@@ -201,7 +201,6 @@ export class HttpHandler extends RequestHandler<
|
|
|
201
201
|
const loggedResponse = await serializeResponse(args.response)
|
|
202
202
|
const statusColor = getStatusCodeColor(loggedResponse.status)
|
|
203
203
|
|
|
204
|
-
// eslint-disable-next-line no-console
|
|
205
204
|
console.groupCollapsed(
|
|
206
205
|
devUtils.formatMessage(
|
|
207
206
|
`${getTimestamp()} ${args.request.method} ${publicUrl} (%c${
|
|
@@ -217,7 +216,6 @@ export class HttpHandler extends RequestHandler<
|
|
|
217
216
|
console.log('Handler:', this)
|
|
218
217
|
// eslint-disable-next-line no-console
|
|
219
218
|
console.log('Response', loggedResponse)
|
|
220
|
-
// eslint-disable-next-line no-console
|
|
221
219
|
console.groupEnd()
|
|
222
220
|
}
|
|
223
221
|
}
|