55 * Mock Service Worker.
66 * @see https://github.com/mswjs/msw
77 * - Please do NOT modify this file.
8- * - Please do NOT serve this file on production.
98 */
109
11- const PACKAGE_VERSION = '2.3.1 '
12- const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423 '
10+ const PACKAGE_VERSION = '2.10.5 '
11+ const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af '
1312const IS_MOCKED_RESPONSE = Symbol ( 'isMockedResponse' )
1413const activeClientIds = new Set ( )
1514
16- self . addEventListener ( 'install' , function ( ) {
15+ addEventListener ( 'install' , function ( ) {
1716 self . skipWaiting ( )
1817} )
1918
20- self . addEventListener ( 'activate' , function ( event ) {
19+ addEventListener ( 'activate' , function ( event ) {
2120 event . waitUntil ( self . clients . claim ( ) )
2221} )
2322
24- self . addEventListener ( 'message' , async function ( event ) {
25- const clientId = event . source . id
23+ addEventListener ( 'message' , async function ( event ) {
24+ const clientId = Reflect . get ( event . source || { } , 'id' )
2625
2726 if ( ! clientId || ! self . clients ) {
2827 return
@@ -62,7 +61,12 @@ self.addEventListener('message', async function (event) {
6261
6362 sendToClient ( client , {
6463 type : 'MOCKING_ENABLED' ,
65- payload : true ,
64+ payload : {
65+ client : {
66+ id : client . id ,
67+ frameType : client . frameType ,
68+ } ,
69+ } ,
6670 } )
6771 break
6872 }
@@ -89,17 +93,18 @@ self.addEventListener('message', async function (event) {
8993 }
9094} )
9195
92- self . addEventListener ( 'fetch' , function ( event ) {
93- const { request } = event
94-
96+ addEventListener ( 'fetch' , function ( event ) {
9597 // Bypass navigation requests.
96- if ( request . mode === 'navigate' ) {
98+ if ( event . request . mode === 'navigate' ) {
9799 return
98100 }
99101
100102 // Opening the DevTools triggers the "only-if-cached" request
101103 // that cannot be handled by the worker. Bypass such requests.
102- if ( request . cache === 'only-if-cached' && request . mode !== 'same-origin' ) {
104+ if (
105+ event . request . cache === 'only-if-cached' &&
106+ event . request . mode !== 'same-origin'
107+ ) {
103108 return
104109 }
105110
@@ -110,51 +115,69 @@ self.addEventListener('fetch', function (event) {
110115 return
111116 }
112117
113- // Generate unique request ID.
114118 const requestId = crypto . randomUUID ( )
115119 event . respondWith ( handleRequest ( event , requestId ) )
116120} )
117121
122+ /**
123+ * @param {FetchEvent } event
124+ * @param {string } requestId
125+ */
118126async function handleRequest ( event , requestId ) {
119127 const client = await resolveMainClient ( event )
128+ const requestCloneForEvents = event . request . clone ( )
120129 const response = await getResponse ( event , client , requestId )
121130
122131 // Send back the response clone for the "response:*" life-cycle events.
123132 // Ensure MSW is active and ready to handle the message, otherwise
124133 // this message will pend indefinitely.
125134 if ( client && activeClientIds . has ( client . id ) ) {
126- ; ( async function ( ) {
127- const responseClone = response . clone ( )
128-
129- sendToClient (
130- client ,
131- {
132- type : 'RESPONSE' ,
133- payload : {
134- requestId,
135- isMockedResponse : IS_MOCKED_RESPONSE in response ,
135+ const serializedRequest = await serializeRequest ( requestCloneForEvents )
136+
137+ // Clone the response so both the client and the library could consume it.
138+ const responseClone = response . clone ( )
139+
140+ sendToClient (
141+ client ,
142+ {
143+ type : 'RESPONSE' ,
144+ payload : {
145+ isMockedResponse : IS_MOCKED_RESPONSE in response ,
146+ request : {
147+ id : requestId ,
148+ ...serializedRequest ,
149+ } ,
150+ response : {
136151 type : responseClone . type ,
137152 status : responseClone . status ,
138153 statusText : responseClone . statusText ,
139- body : responseClone . body ,
140154 headers : Object . fromEntries ( responseClone . headers . entries ( ) ) ,
155+ body : responseClone . body ,
141156 } ,
142157 } ,
143- [ responseClone . body ] ,
144- )
145- } ) ( )
158+ } ,
159+ responseClone . body ? [ serializedRequest . body , responseClone . body ] : [ ] ,
160+ )
146161 }
147162
148163 return response
149164}
150165
151- // Resolve the main client for the given event.
152- // Client that issues a request doesn't necessarily equal the client
153- // that registered the worker. It's with the latter the worker should
154- // communicate with during the response resolving phase.
166+ /**
167+ * Resolve the main client for the given event.
168+ * Client that issues a request doesn't necessarily equal the client
169+ * that registered the worker. It's with the latter the worker should
170+ * communicate with during the response resolving phase.
171+ * @param {FetchEvent } event
172+ * @returns {Promise<Client | undefined> }
173+ */
155174async function resolveMainClient ( event ) {
156175 const client = await self . clients . get ( event . clientId )
157176
177+ if ( activeClientIds . has ( event . clientId ) ) {
178+ return client
179+ }
180+
158181 if ( client ?. frameType === 'top-level' ) {
159182 return client
160183 }
@@ -175,20 +198,38 @@ async function resolveMainClient(event) {
175198 } )
176199}
177200
201+ /**
202+ * @param {FetchEvent } event
203+ * @param {Client | undefined } client
204+ * @param {string } requestId
205+ * @returns {Promise<Response> }
206+ */
178207async function getResponse ( event , client , requestId ) {
179- const { request } = event
180-
181208 // Clone the request because it might've been already used
182209 // (i.e. its body has been read and sent to the client).
183- const requestClone = request . clone ( )
210+ const requestClone = event . request . clone ( )
184211
185212 function passthrough ( ) {
186- const headers = Object . fromEntries ( requestClone . headers . entries ( ) )
213+ // Cast the request headers to a new Headers instance
214+ // so the headers can be manipulated with.
215+ const headers = new Headers ( requestClone . headers )
216+
217+ // Remove the "accept" header value that marked this request as passthrough.
218+ // This prevents request alteration and also keeps it compliant with the
219+ // user-defined CORS policies.
220+ const acceptHeader = headers . get ( 'accept' )
221+ if ( acceptHeader ) {
222+ const values = acceptHeader . split ( ',' ) . map ( ( value ) => value . trim ( ) )
223+ const filteredValues = values . filter (
224+ ( value ) => value !== 'msw/passthrough' ,
225+ )
187226
188- // Remove internal MSW request header so the passthrough request
189- // complies with any potential CORS preflight checks on the server.
190- // Some servers forbid unknown request headers.
191- delete headers [ 'x-msw-intention' ]
227+ if ( filteredValues . length > 0 ) {
228+ headers . set ( 'accept' , filteredValues . join ( ', ' ) )
229+ } else {
230+ headers . delete ( 'accept' )
231+ }
232+ }
192233
193234 return fetch ( requestClone , { headers } )
194235 }
@@ -207,29 +248,17 @@ async function getResponse(event, client, requestId) {
207248 }
208249
209250 // Notify the client that a request has been intercepted.
210- const requestBuffer = await request . arrayBuffer ( )
251+ const serializedRequest = await serializeRequest ( event . request )
211252 const clientMessage = await sendToClient (
212253 client ,
213254 {
214255 type : 'REQUEST' ,
215256 payload : {
216257 id : requestId ,
217- url : request . url ,
218- mode : request . mode ,
219- method : request . method ,
220- headers : Object . fromEntries ( request . headers . entries ( ) ) ,
221- cache : request . cache ,
222- credentials : request . credentials ,
223- destination : request . destination ,
224- integrity : request . integrity ,
225- redirect : request . redirect ,
226- referrer : request . referrer ,
227- referrerPolicy : request . referrerPolicy ,
228- body : requestBuffer ,
229- keepalive : request . keepalive ,
258+ ...serializedRequest ,
230259 } ,
231260 } ,
232- [ requestBuffer ] ,
261+ [ serializedRequest . body ] ,
233262 )
234263
235264 switch ( clientMessage . type ) {
@@ -245,6 +274,12 @@ async function getResponse(event, client, requestId) {
245274 return passthrough ( )
246275}
247276
277+ /**
278+ * @param {Client } client
279+ * @param {any } message
280+ * @param {Array<Transferable> } transferrables
281+ * @returns {Promise<any> }
282+ */
248283function sendToClient ( client , message , transferrables = [ ] ) {
249284 return new Promise ( ( resolve , reject ) => {
250285 const channel = new MessageChannel ( )
@@ -257,14 +292,18 @@ function sendToClient(client, message, transferrables = []) {
257292 resolve ( event . data )
258293 }
259294
260- client . postMessage (
261- message ,
262- [ channel . port2 ] . concat ( transferrables . filter ( Boolean ) ) ,
263- )
295+ client . postMessage ( message , [
296+ channel . port2 ,
297+ ... transferrables . filter ( Boolean ) ,
298+ ] )
264299 } )
265300}
266301
267- async function respondWithMock ( response ) {
302+ /**
303+ * @param {Response } response
304+ * @returns {Response }
305+ */
306+ function respondWithMock ( response ) {
268307 // Setting response status code to 0 is a no-op.
269308 // However, when responding with a "Response.error()", the produced Response
270309 // instance will have status code set to 0. Since it's not possible to create
@@ -282,3 +321,24 @@ async function respondWithMock(response) {
282321
283322 return mockedResponse
284323}
324+
325+ /**
326+ * @param {Request } request
327+ */
328+ async function serializeRequest ( request ) {
329+ return {
330+ url : request . url ,
331+ mode : request . mode ,
332+ method : request . method ,
333+ headers : Object . fromEntries ( request . headers . entries ( ) ) ,
334+ cache : request . cache ,
335+ credentials : request . credentials ,
336+ destination : request . destination ,
337+ integrity : request . integrity ,
338+ redirect : request . redirect ,
339+ referrer : request . referrer ,
340+ referrerPolicy : request . referrerPolicy ,
341+ body : await request . arrayBuffer ( ) ,
342+ keepalive : request . keepalive ,
343+ }
344+ }
0 commit comments