msw 2.3.1 → 2.3.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/core/{GraphQLHandler-Dq_WRbKe.d.mts → GraphQLHandler-L3AUWt2v.d.mts} +1 -1
- package/lib/core/{GraphQLHandler-COiPfZ8k.d.ts → GraphQLHandler-UgnlXhlx.d.ts} +1 -1
- package/lib/core/{HttpResponse-B07UKAkU.d.ts → HttpResponse-B58aIqZM.d.ts} +6 -5
- package/lib/core/{HttpResponse-C7niBMwb.d.mts → HttpResponse-fnOXxh4-.d.mts} +6 -5
- package/lib/core/HttpResponse.d.mts +2 -1
- package/lib/core/HttpResponse.d.ts +2 -1
- package/lib/core/SetupApi.d.mts +2 -1
- package/lib/core/SetupApi.d.ts +2 -1
- package/lib/core/getResponse.d.mts +2 -1
- package/lib/core/getResponse.d.ts +2 -1
- package/lib/core/graphql.d.mts +3 -2
- package/lib/core/graphql.d.ts +3 -2
- package/lib/core/handlers/GraphQLHandler.d.mts +3 -2
- package/lib/core/handlers/GraphQLHandler.d.ts +3 -2
- package/lib/core/handlers/HttpHandler.d.mts +2 -1
- package/lib/core/handlers/HttpHandler.d.ts +2 -1
- package/lib/core/handlers/RequestHandler.d.mts +2 -1
- package/lib/core/handlers/RequestHandler.d.ts +2 -1
- package/lib/core/handlers/RequestHandler.js +18 -25
- package/lib/core/handlers/RequestHandler.js.map +1 -1
- package/lib/core/handlers/RequestHandler.mjs +21 -26
- package/lib/core/handlers/RequestHandler.mjs.map +1 -1
- package/lib/core/http.d.mts +2 -1
- package/lib/core/http.d.ts +2 -1
- package/lib/core/index.d.mts +3 -2
- package/lib/core/index.d.ts +3 -2
- package/lib/core/passthrough.d.mts +2 -1
- package/lib/core/passthrough.d.ts +2 -1
- package/lib/core/utils/HttpResponse/decorators.d.mts +4 -2
- package/lib/core/utils/HttpResponse/decorators.d.ts +4 -2
- package/lib/core/utils/HttpResponse/decorators.js +16 -6
- package/lib/core/utils/HttpResponse/decorators.js.map +1 -1
- package/lib/core/utils/HttpResponse/decorators.mjs +16 -6
- package/lib/core/utils/HttpResponse/decorators.mjs.map +1 -1
- package/lib/core/utils/cookieStore.d.mts +5 -0
- package/lib/core/utils/cookieStore.d.ts +5 -0
- package/lib/core/utils/cookieStore.js +176 -0
- package/lib/core/utils/cookieStore.js.map +1 -0
- package/lib/core/utils/cookieStore.mjs +146 -0
- package/lib/core/utils/cookieStore.mjs.map +1 -0
- package/lib/core/utils/executeHandlers.d.mts +2 -1
- package/lib/core/utils/executeHandlers.d.ts +2 -1
- package/lib/core/utils/handleRequest.d.mts +2 -1
- package/lib/core/utils/handleRequest.d.ts +2 -1
- package/lib/core/utils/handleRequest.js +2 -2
- package/lib/core/utils/handleRequest.js.map +1 -1
- package/lib/core/utils/handleRequest.mjs +2 -2
- package/lib/core/utils/handleRequest.mjs.map +1 -1
- package/lib/core/utils/internal/isIterable.d.mts +16 -2
- package/lib/core/utils/internal/isIterable.d.ts +16 -2
- package/lib/core/utils/internal/isIterable.js +1 -1
- package/lib/core/utils/internal/isIterable.js.map +1 -1
- package/lib/core/utils/internal/isIterable.mjs +1 -1
- package/lib/core/utils/internal/isIterable.mjs.map +1 -1
- package/lib/core/utils/internal/parseGraphQLRequest.d.mts +3 -2
- package/lib/core/utils/internal/parseGraphQLRequest.d.ts +3 -2
- package/lib/core/utils/internal/parseMultipartData.d.mts +2 -1
- package/lib/core/utils/internal/parseMultipartData.d.ts +2 -1
- package/lib/core/utils/internal/requestHandlerUtils.d.mts +2 -1
- package/lib/core/utils/internal/requestHandlerUtils.d.ts +2 -1
- package/lib/core/utils/request/getRequestCookies.d.mts +1 -6
- package/lib/core/utils/request/getRequestCookies.d.ts +1 -6
- package/lib/core/utils/request/getRequestCookies.js +22 -20
- package/lib/core/utils/request/getRequestCookies.js.map +1 -1
- package/lib/core/utils/request/getRequestCookies.mjs +22 -20
- package/lib/core/utils/request/getRequestCookies.mjs.map +1 -1
- package/lib/core/utils/request/storeResponseCookies.d.mts +3 -0
- package/lib/core/utils/request/storeResponseCookies.d.ts +3 -0
- package/lib/core/utils/request/{readResponseCookies.js → storeResponseCookies.js} +12 -9
- package/lib/core/utils/request/storeResponseCookies.js.map +1 -0
- package/lib/core/utils/request/storeResponseCookies.mjs +12 -0
- package/lib/core/utils/request/storeResponseCookies.mjs.map +1 -0
- package/lib/iife/index.js +12204 -345
- package/lib/iife/index.js.map +1 -1
- package/lib/mockServiceWorker.js +1 -1
- package/package.json +7 -7
- package/src/core/handlers/RequestHandler.ts +51 -44
- package/src/core/utils/HttpResponse/decorators.ts +32 -16
- package/src/core/utils/cookieStore.ts +212 -0
- package/src/core/utils/handleRequest.ts +3 -3
- package/src/core/utils/internal/isIterable.ts +22 -2
- package/src/core/utils/request/getRequestCookies.ts +32 -35
- package/src/core/utils/request/storeResponseCookies.ts +17 -0
- package/lib/core/utils/request/readResponseCookies.d.mts +0 -3
- package/lib/core/utils/request/readResponseCookies.d.ts +0 -3
- package/lib/core/utils/request/readResponseCookies.js.map +0 -1
- package/lib/core/utils/request/readResponseCookies.mjs +0 -9
- package/lib/core/utils/request/readResponseCookies.mjs.map +0 -1
- package/src/core/utils/request/getRequestCookies.node.test.ts +0 -29
- package/src/core/utils/request/getRequestCookies.test.ts +0 -64
- package/src/core/utils/request/readResponseCookies.ts +0 -9
package/lib/mockServiceWorker.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* - Please do NOT serve this file on production.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const PACKAGE_VERSION = '2.3.
|
|
11
|
+
const PACKAGE_VERSION = '2.3.3'
|
|
12
12
|
const INTEGRITY_CHECKSUM = '26357c79639bfa20d64c0efca2a87423'
|
|
13
13
|
const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')
|
|
14
14
|
const activeClientIds = new Set()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "msw",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.3",
|
|
4
4
|
"description": "Seamless REST/GraphQL API mocking library for browser and Node.js.",
|
|
5
5
|
"main": "./lib/core/index.js",
|
|
6
6
|
"module": "./lib/core/index.mjs",
|
|
@@ -115,8 +115,8 @@
|
|
|
115
115
|
"dependencies": {
|
|
116
116
|
"@bundled-es-modules/cookie": "^2.0.0",
|
|
117
117
|
"@bundled-es-modules/statuses": "^1.0.1",
|
|
118
|
+
"@bundled-es-modules/tough-cookie": "^0.1.6",
|
|
118
119
|
"@inquirer/confirm": "^3.0.0",
|
|
119
|
-
"@mswjs/cookies": "^1.1.0",
|
|
120
120
|
"@mswjs/interceptors": "^0.29.0",
|
|
121
121
|
"@open-draft/until": "^2.1.0",
|
|
122
122
|
"@types/cookie": "^0.6.0",
|
|
@@ -171,7 +171,7 @@
|
|
|
171
171
|
"simple-git-hooks": "^2.9.0",
|
|
172
172
|
"ts-node": "^10.9.2",
|
|
173
173
|
"tsup": "^8.0.1",
|
|
174
|
-
"typescript": "^5.
|
|
174
|
+
"typescript": "^5.5.2",
|
|
175
175
|
"undici": "^5.20.0",
|
|
176
176
|
"url-loader": "^4.1.1",
|
|
177
177
|
"vitest": "^1.2.2",
|
|
@@ -206,12 +206,12 @@
|
|
|
206
206
|
"check:exports": "node \"./config/scripts/validate-esm.js\"",
|
|
207
207
|
"test": "pnpm test:unit && pnpm test:node && pnpm test:browser && pnpm test:native",
|
|
208
208
|
"test:unit": "vitest",
|
|
209
|
-
"test:node": "vitest run --config=./test/node/vitest.config.
|
|
210
|
-
"test:native": "vitest --config=./test/native/vitest.config.
|
|
209
|
+
"test:node": "vitest run --config=./test/node/vitest.config.mts",
|
|
210
|
+
"test:native": "vitest --config=./test/native/vitest.config.mts",
|
|
211
211
|
"test:browser": "playwright test -c ./test/browser/playwright.config.ts",
|
|
212
|
-
"test:modules:node": "vitest --config=./test/modules/node/vitest.config.
|
|
212
|
+
"test:modules:node": "vitest --config=./test/modules/node/vitest.config.mts",
|
|
213
213
|
"test:modules:browser": "playwright test -c ./test/modules/browser/playwright.config.ts",
|
|
214
|
-
"test:ts": "vitest --typecheck --config=./test/typings/vitest.config.
|
|
214
|
+
"test:ts": "vitest --typecheck --config=./test/typings/vitest.config.mts",
|
|
215
215
|
"release": "release publish",
|
|
216
216
|
"postinstall": "node -e \"try{require('./config/scripts/postinstall')}catch(e){}\""
|
|
217
217
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { invariant } from 'outvariant'
|
|
2
1
|
import { getCallFrame } from '../utils/internal/getCallFrame'
|
|
3
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
AsyncIterable,
|
|
4
|
+
Iterable,
|
|
5
|
+
isIterable,
|
|
6
|
+
} from '../utils/internal/isIterable'
|
|
4
7
|
import type { ResponseResolutionContext } from '../utils/executeHandlers'
|
|
5
8
|
import type { MaybePromise } from '../typeUtils'
|
|
6
9
|
import { StrictRequest, StrictResponse } from '..//HttpResponse'
|
|
@@ -52,7 +55,12 @@ export type AsyncResponseResolverReturnType<
|
|
|
52
55
|
ResponseBodyType extends DefaultBodyType,
|
|
53
56
|
> = MaybePromise<
|
|
54
57
|
| ResponseResolverReturnType<ResponseBodyType>
|
|
55
|
-
|
|
|
58
|
+
| Iterable<
|
|
59
|
+
MaybeAsyncResponseResolverReturnType<ResponseBodyType>,
|
|
60
|
+
MaybeAsyncResponseResolverReturnType<ResponseBodyType>,
|
|
61
|
+
MaybeAsyncResponseResolverReturnType<ResponseBodyType>
|
|
62
|
+
>
|
|
63
|
+
| AsyncIterable<
|
|
56
64
|
MaybeAsyncResponseResolverReturnType<ResponseBodyType>,
|
|
57
65
|
MaybeAsyncResponseResolverReturnType<ResponseBodyType>,
|
|
58
66
|
MaybeAsyncResponseResolverReturnType<ResponseBodyType>
|
|
@@ -117,12 +125,18 @@ export abstract class RequestHandler<
|
|
|
117
125
|
public isUsed: boolean
|
|
118
126
|
|
|
119
127
|
protected resolver: ResponseResolver<ResolverExtras, any, any>
|
|
120
|
-
private
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
128
|
+
private resolverIterator?:
|
|
129
|
+
| Iterator<
|
|
130
|
+
MaybeAsyncResponseResolverReturnType<any>,
|
|
131
|
+
MaybeAsyncResponseResolverReturnType<any>,
|
|
132
|
+
MaybeAsyncResponseResolverReturnType<any>
|
|
133
|
+
>
|
|
134
|
+
| AsyncIterator<
|
|
135
|
+
MaybeAsyncResponseResolverReturnType<any>,
|
|
136
|
+
MaybeAsyncResponseResolverReturnType<any>,
|
|
137
|
+
MaybeAsyncResponseResolverReturnType<any>
|
|
138
|
+
>
|
|
139
|
+
private resolverIteratorResult?: Response | StrictResponse<any>
|
|
126
140
|
private options?: HandlerOptions
|
|
127
141
|
|
|
128
142
|
constructor(args: RequestHandlerArgs<HandlerInfo, HandlerOptions>) {
|
|
@@ -256,6 +270,9 @@ export abstract class RequestHandler<
|
|
|
256
270
|
return null
|
|
257
271
|
}
|
|
258
272
|
|
|
273
|
+
// Preemptively mark the handler as used.
|
|
274
|
+
// Generators will undo this because only when the resolver reaches the
|
|
275
|
+
// "done" state of the generator that it considers the handler used.
|
|
259
276
|
this.isUsed = true
|
|
260
277
|
|
|
261
278
|
// Create a response extraction wrapper around the resolver
|
|
@@ -301,48 +318,38 @@ export abstract class RequestHandler<
|
|
|
301
318
|
resolver: ResponseResolver<ResolverExtras>,
|
|
302
319
|
): ResponseResolver<ResolverExtras> {
|
|
303
320
|
return async (info): Promise<ResponseResolverReturnType<any>> => {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
// Only when the generator is done, the handler will be
|
|
309
|
-
// considered used.
|
|
310
|
-
this.isUsed = false
|
|
311
|
-
|
|
312
|
-
const { value, done } = result[Symbol.iterator]().next()
|
|
313
|
-
const nextResponse = await value
|
|
314
|
-
|
|
315
|
-
if (done) {
|
|
316
|
-
this.isUsed = true
|
|
321
|
+
if (!this.resolverIterator) {
|
|
322
|
+
const result = await resolver(info)
|
|
323
|
+
if (!isIterable(result)) {
|
|
324
|
+
return result
|
|
317
325
|
}
|
|
326
|
+
this.resolverIterator =
|
|
327
|
+
Symbol.iterator in result
|
|
328
|
+
? result[Symbol.iterator]()
|
|
329
|
+
: result[Symbol.asyncIterator]()
|
|
330
|
+
}
|
|
318
331
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (!nextResponse && done) {
|
|
322
|
-
invariant(
|
|
323
|
-
this.resolverGeneratorResult,
|
|
324
|
-
'Failed to returned a previously stored generator response: the value is not a valid Response.',
|
|
325
|
-
)
|
|
326
|
-
|
|
327
|
-
// Clone the previously stored response from the generator
|
|
328
|
-
// so that it could be read again.
|
|
329
|
-
return this.resolverGeneratorResult.clone() as StrictResponse<any>
|
|
330
|
-
}
|
|
332
|
+
// Opt-out from marking this handler as used.
|
|
333
|
+
this.isUsed = false
|
|
331
334
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}
|
|
335
|
+
const { done, value } = await this.resolverIterator.next()
|
|
336
|
+
const nextResponse = await value
|
|
335
337
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
338
|
+
if (nextResponse) {
|
|
339
|
+
this.resolverIteratorResult = nextResponse.clone()
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (done) {
|
|
343
|
+
// A one-time generator resolver stops affecting the network
|
|
344
|
+
// only after it's been completely exhausted.
|
|
345
|
+
this.isUsed = true
|
|
341
346
|
|
|
342
|
-
|
|
347
|
+
// Clone the previously stored response so it can be read
|
|
348
|
+
// when receiving it repeatedly from the "done" generator.
|
|
349
|
+
return this.resolverIteratorResult?.clone()
|
|
343
350
|
}
|
|
344
351
|
|
|
345
|
-
return
|
|
352
|
+
return nextResponse
|
|
346
353
|
}
|
|
347
354
|
}
|
|
348
355
|
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import statuses from '@bundled-es-modules/statuses'
|
|
2
|
-
import type { HttpResponseInit } from '../../HttpResponse'
|
|
3
2
|
import { Headers as HeadersPolyfill } from 'headers-polyfill'
|
|
3
|
+
import type { HttpResponseInit } from '../../HttpResponse'
|
|
4
4
|
|
|
5
5
|
const { message } = statuses
|
|
6
6
|
|
|
7
|
+
export const kSetCookie = Symbol('kSetCookie')
|
|
8
|
+
|
|
7
9
|
export interface HttpResponseDecoratedInit extends HttpResponseInit {
|
|
8
10
|
status: number
|
|
9
11
|
statusText: string
|
|
@@ -38,21 +40,35 @@ export function decorateResponse(
|
|
|
38
40
|
})
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
//
|
|
45
|
-
// This is
|
|
46
|
-
//
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
const responseCookies = init.headers.get('set-cookie')
|
|
44
|
+
|
|
45
|
+
if (responseCookies) {
|
|
46
|
+
// Record the raw "Set-Cookie" response header provided
|
|
47
|
+
// in the HeadersInit. This is later used to store these cookies
|
|
48
|
+
// in cookie jar and return the right cookies in the "cookies"
|
|
49
|
+
// response resolver argument.
|
|
50
|
+
Object.defineProperty(response, kSetCookie, {
|
|
51
|
+
value: responseCookies,
|
|
52
|
+
enumerable: false,
|
|
53
|
+
writable: false,
|
|
54
|
+
})
|
|
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
|
+
}
|
|
56
72
|
}
|
|
57
73
|
}
|
|
58
74
|
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { invariant } from 'outvariant'
|
|
2
|
+
import { isNodeProcess } from 'is-node-process'
|
|
3
|
+
import toughCookie, {
|
|
4
|
+
type Cookie as CookieInstance,
|
|
5
|
+
} from '@bundled-es-modules/tough-cookie'
|
|
6
|
+
|
|
7
|
+
const { Cookie, CookieJar, Store, MemoryCookieStore, domainMatch, pathMatch } =
|
|
8
|
+
toughCookie
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Custom cookie store that uses the Web Storage API.
|
|
12
|
+
* @see https://github.com/expo/tough-cookie-web-storage-store
|
|
13
|
+
*/
|
|
14
|
+
class WebStorageCookieStore extends Store {
|
|
15
|
+
private storage: Storage
|
|
16
|
+
private storageKey: string
|
|
17
|
+
|
|
18
|
+
constructor() {
|
|
19
|
+
super()
|
|
20
|
+
|
|
21
|
+
invariant(
|
|
22
|
+
typeof localStorage !== 'undefined',
|
|
23
|
+
'Failed to create a WebStorageCookieStore: `localStorage` is not available in this environment. This is likely an issue with MSW. Please report it on GitHub: https://github.com/mswjs/msw/issues',
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
this.synchronous = true
|
|
27
|
+
this.storage = localStorage
|
|
28
|
+
this.storageKey = '__msw-cookie-store__'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
findCookie(
|
|
32
|
+
domain: string,
|
|
33
|
+
path: string,
|
|
34
|
+
key: string,
|
|
35
|
+
callback: (error: Error | null, cookie: CookieInstance | null) => void,
|
|
36
|
+
): void {
|
|
37
|
+
try {
|
|
38
|
+
const store = this.getStore()
|
|
39
|
+
const cookies = this.filterCookiesFromList(store, { domain, path, key })
|
|
40
|
+
callback(null, cookies[0] || null)
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (error instanceof Error) {
|
|
43
|
+
callback(error, null)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
findCookies(
|
|
49
|
+
domain: string,
|
|
50
|
+
path: string,
|
|
51
|
+
allowSpecialUseDomain: boolean,
|
|
52
|
+
callback: (error: Error | null, cookie: Array<CookieInstance>) => void,
|
|
53
|
+
): void {
|
|
54
|
+
if (!domain) {
|
|
55
|
+
callback(null, [])
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
const store = this.getStore()
|
|
61
|
+
const results = this.filterCookiesFromList(store, {
|
|
62
|
+
domain,
|
|
63
|
+
path,
|
|
64
|
+
})
|
|
65
|
+
callback(null, results)
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (error instanceof Error) {
|
|
68
|
+
callback(error, [])
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
putCookie(
|
|
74
|
+
cookie: CookieInstance,
|
|
75
|
+
callback: (error: Error | null) => void,
|
|
76
|
+
): void {
|
|
77
|
+
try {
|
|
78
|
+
const store = this.getStore()
|
|
79
|
+
store.push(cookie)
|
|
80
|
+
this.updateStore(store)
|
|
81
|
+
} catch (error) {
|
|
82
|
+
if (error instanceof Error) {
|
|
83
|
+
callback(error)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
updateCookie(
|
|
89
|
+
oldCookie: CookieInstance,
|
|
90
|
+
newCookie: CookieInstance,
|
|
91
|
+
callback: (error: Error | null) => void,
|
|
92
|
+
): void {
|
|
93
|
+
this.putCookie(newCookie, callback)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
removeCookie(
|
|
97
|
+
domain: string,
|
|
98
|
+
path: string,
|
|
99
|
+
key: string,
|
|
100
|
+
callback: (error: Error | null) => void,
|
|
101
|
+
): void {
|
|
102
|
+
try {
|
|
103
|
+
const store = this.getStore()
|
|
104
|
+
const nextStore = this.deleteCookiesFromList(store, { domain, path, key })
|
|
105
|
+
this.updateStore(nextStore)
|
|
106
|
+
callback(null)
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof Error) {
|
|
109
|
+
callback(error)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
removeCookies(
|
|
115
|
+
domain: string,
|
|
116
|
+
path: string,
|
|
117
|
+
callback: (error: Error | null) => void,
|
|
118
|
+
): void {
|
|
119
|
+
try {
|
|
120
|
+
const store = this.getStore()
|
|
121
|
+
const nextStore = this.deleteCookiesFromList(store, { domain, path })
|
|
122
|
+
this.updateStore(nextStore)
|
|
123
|
+
callback(null)
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (error instanceof Error) {
|
|
126
|
+
callback(error)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
getAllCookies(
|
|
132
|
+
callback: (error: Error | null, cookie: Array<CookieInstance>) => void,
|
|
133
|
+
): void {
|
|
134
|
+
try {
|
|
135
|
+
callback(null, this.getStore())
|
|
136
|
+
} catch (error) {
|
|
137
|
+
if (error instanceof Error) {
|
|
138
|
+
callback(error, [])
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private getStore(): Array<CookieInstance> {
|
|
144
|
+
try {
|
|
145
|
+
const json = this.storage.getItem(this.storageKey)
|
|
146
|
+
|
|
147
|
+
if (json == null) {
|
|
148
|
+
return []
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const rawCookies = JSON.parse(json) as Array<Record<string, any>>
|
|
152
|
+
const cookies: Array<CookieInstance> = []
|
|
153
|
+
for (const rawCookie of rawCookies) {
|
|
154
|
+
const cookie = Cookie.fromJSON(rawCookie)
|
|
155
|
+
if (cookie != null) {
|
|
156
|
+
cookies.push(cookie)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return cookies
|
|
160
|
+
} catch {
|
|
161
|
+
return []
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
private updateStore(nextStore: Array<CookieInstance>) {
|
|
166
|
+
this.storage.setItem(
|
|
167
|
+
this.storageKey,
|
|
168
|
+
JSON.stringify(nextStore.map((cookie) => cookie.toJSON())),
|
|
169
|
+
)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private filterCookiesFromList(
|
|
173
|
+
cookies: Array<CookieInstance>,
|
|
174
|
+
matches: { domain?: string; path?: string; key?: string },
|
|
175
|
+
): Array<CookieInstance> {
|
|
176
|
+
const result: Array<CookieInstance> = []
|
|
177
|
+
|
|
178
|
+
for (const cookie of cookies) {
|
|
179
|
+
if (matches.domain && !domainMatch(matches.domain, cookie.domain || '')) {
|
|
180
|
+
continue
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (matches.path && !pathMatch(matches.path, cookie.path || '')) {
|
|
184
|
+
continue
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (matches.key && cookie.key !== matches.key) {
|
|
188
|
+
continue
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
result.push(cookie)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
console.log('filter result:', { cookies, matches, result })
|
|
195
|
+
|
|
196
|
+
return result
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
private deleteCookiesFromList(
|
|
200
|
+
cookies: Array<CookieInstance>,
|
|
201
|
+
matches: { domain?: string; path?: string; key?: string },
|
|
202
|
+
) {
|
|
203
|
+
const matchingCookies = this.filterCookiesFromList(cookies, matches)
|
|
204
|
+
return cookies.filter((cookie) => !matchingCookies.includes(cookie))
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const store = isNodeProcess()
|
|
209
|
+
? new MemoryCookieStore()
|
|
210
|
+
: new WebStorageCookieStore()
|
|
211
|
+
|
|
212
|
+
export const cookieStore = new CookieJar(store)
|
|
@@ -5,7 +5,7 @@ import { LifeCycleEventsMap, SharedOptions } from '../sharedOptions'
|
|
|
5
5
|
import { RequiredDeep } from '../typeUtils'
|
|
6
6
|
import { HandlersExecutionResult, executeHandlers } from './executeHandlers'
|
|
7
7
|
import { onUnhandledRequest } from './request/onUnhandledRequest'
|
|
8
|
-
import {
|
|
8
|
+
import { storeResponseCookies } from './request/storeResponseCookies'
|
|
9
9
|
|
|
10
10
|
export interface HandleRequestOptions {
|
|
11
11
|
/**
|
|
@@ -110,8 +110,8 @@ export async function handleRequest(
|
|
|
110
110
|
return
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
// Store all the received response cookies in the
|
|
114
|
-
|
|
113
|
+
// Store all the received response cookies in the cookie jar.
|
|
114
|
+
storeResponseCookies(request, response)
|
|
115
115
|
|
|
116
116
|
emitter.emit('request:match', { request, requestId })
|
|
117
117
|
|
|
@@ -1,12 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is the same as TypeScript's `Iterable`, but with all three type parameters.
|
|
3
|
+
* @todo Remove once TypeScript 5.6 is the minimum.
|
|
4
|
+
*/
|
|
5
|
+
export interface Iterable<T, TReturn, TNext> {
|
|
6
|
+
[Symbol.iterator](): Iterator<T, TReturn, TNext>
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* This is the same as TypeScript's `AsyncIterable`, but with all three type parameters.
|
|
11
|
+
* @todo Remove once TypeScript 5.6 is the minimum.
|
|
12
|
+
*/
|
|
13
|
+
export interface AsyncIterable<T, TReturn, TNext> {
|
|
14
|
+
[Symbol.asyncIterator](): AsyncIterator<T, TReturn, TNext>
|
|
15
|
+
}
|
|
16
|
+
|
|
1
17
|
/**
|
|
2
18
|
* Determines if the given function is an iterator.
|
|
3
19
|
*/
|
|
4
20
|
export function isIterable<IteratorType>(
|
|
5
21
|
fn: any,
|
|
6
|
-
): fn is
|
|
22
|
+
): fn is
|
|
23
|
+
| Iterable<IteratorType, IteratorType, IteratorType>
|
|
24
|
+
| AsyncIterable<IteratorType, IteratorType, IteratorType> {
|
|
7
25
|
if (!fn) {
|
|
8
26
|
return false
|
|
9
27
|
}
|
|
10
28
|
|
|
11
|
-
return
|
|
29
|
+
return (
|
|
30
|
+
Reflect.has(fn, Symbol.iterator) || Reflect.has(fn, Symbol.asyncIterator)
|
|
31
|
+
)
|
|
12
32
|
}
|
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
import cookieUtils from '@bundled-es-modules/cookie'
|
|
2
|
-
import {
|
|
2
|
+
import { cookieStore } from '../cookieStore'
|
|
3
3
|
|
|
4
4
|
function getAllDocumentCookies() {
|
|
5
5
|
return cookieUtils.parse(document.cookie)
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Returns relevant document cookies based on the request `credentials` option.
|
|
11
|
-
*/
|
|
12
|
-
export function getRequestCookies(request: Request): Record<string, string> {
|
|
13
|
-
/**
|
|
14
|
-
* @note No cookies persist on the document in Node.js: no document.
|
|
15
|
-
*/
|
|
8
|
+
function getDocumentCookies(request: Request): Record<string, string> {
|
|
16
9
|
if (typeof document === 'undefined' || typeof location === 'undefined') {
|
|
17
10
|
return {}
|
|
18
11
|
}
|
|
19
12
|
|
|
20
13
|
switch (request.credentials) {
|
|
21
14
|
case 'same-origin': {
|
|
22
|
-
const
|
|
15
|
+
const requestUrl = new URL(request.url)
|
|
23
16
|
|
|
24
17
|
// Return document cookies only when requested a resource
|
|
25
18
|
// from the same origin as the current document.
|
|
26
|
-
return location.origin ===
|
|
19
|
+
return location.origin === requestUrl.origin
|
|
20
|
+
? getAllDocumentCookies()
|
|
21
|
+
: {}
|
|
27
22
|
}
|
|
28
23
|
|
|
29
24
|
case 'include': {
|
|
@@ -38,38 +33,40 @@ export function getRequestCookies(request: Request): Record<string, string> {
|
|
|
38
33
|
}
|
|
39
34
|
|
|
40
35
|
export function getAllRequestCookies(request: Request): Record<string, string> {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
/**
|
|
37
|
+
* @note While the "cookie" header is a forbidden header field
|
|
38
|
+
* in the browser, you can read it in Node.js. We need to respect
|
|
39
|
+
* it for mocking in Node.js.
|
|
40
|
+
*/
|
|
41
|
+
const requestCookieHeader = request.headers.get('cookie')
|
|
42
|
+
const cookiesFromHeaders = requestCookieHeader
|
|
43
|
+
? cookieUtils.parse(requestCookieHeader)
|
|
44
44
|
: {}
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const cookiesFromStore = Array.from(store.get(request)?.entries()).reduce<
|
|
49
|
-
Record<string, string>
|
|
50
|
-
>((cookies, [name, { value }]) => {
|
|
51
|
-
return Object.assign(cookies, { [name.trim()]: value })
|
|
52
|
-
}, {})
|
|
53
|
-
|
|
54
|
-
const cookiesFromDocument = getRequestCookies(request)
|
|
46
|
+
const cookiesFromDocument = getDocumentCookies(request)
|
|
55
47
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
// Forward the document cookies to the request headers.
|
|
49
|
+
for (const name in cookiesFromDocument) {
|
|
50
|
+
request.headers.append(
|
|
51
|
+
'cookie',
|
|
52
|
+
cookieUtils.serialize(name, cookiesFromDocument[name]),
|
|
53
|
+
)
|
|
59
54
|
}
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
56
|
+
const cookiesFromStore = cookieStore.getCookiesSync(request.url)
|
|
57
|
+
const storedCookiesObject = Object.fromEntries(
|
|
58
|
+
cookiesFromStore.map((cookie) => [cookie.key, cookie.value]),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
// Forward the raw stored cookies to request headers
|
|
62
|
+
// so they contain metadata like "expires", "secure", etc.
|
|
63
|
+
for (const cookie of cookiesFromStore) {
|
|
64
|
+
request.headers.append('cookie', cookie.toString())
|
|
69
65
|
}
|
|
70
66
|
|
|
71
67
|
return {
|
|
72
|
-
...
|
|
68
|
+
...cookiesFromDocument,
|
|
69
|
+
...storedCookiesObject,
|
|
73
70
|
...cookiesFromHeaders,
|
|
74
71
|
}
|
|
75
72
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { cookieStore } from '../cookieStore'
|
|
2
|
+
import { kSetCookie } from '../HttpResponse/decorators'
|
|
3
|
+
|
|
4
|
+
export function storeResponseCookies(
|
|
5
|
+
request: Request,
|
|
6
|
+
response: Response,
|
|
7
|
+
): void {
|
|
8
|
+
// Grab the raw "Set-Cookie" response header provided
|
|
9
|
+
// in the HeadersInit for this mocked response.
|
|
10
|
+
const responseCookies = Reflect.get(response, kSetCookie) as
|
|
11
|
+
| string
|
|
12
|
+
| undefined
|
|
13
|
+
|
|
14
|
+
if (responseCookies) {
|
|
15
|
+
cookieStore.setCookie(responseCookies, request.url)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/request/readResponseCookies.ts"],"sourcesContent":["import { store } from '@mswjs/cookies'\n\nexport function readResponseCookies(\n request: Request,\n response: Response,\n): void {\n store.add({ ...request, url: request.url.toString() }, response)\n store.persist()\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAsB;AAEf,SAAS,oBACd,SACA,UACM;AACN,uBAAM,IAAI,EAAE,GAAG,SAAS,KAAK,QAAQ,IAAI,SAAS,EAAE,GAAG,QAAQ;AAC/D,uBAAM,QAAQ;AAChB;","names":[]}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { store } from "@mswjs/cookies";
|
|
2
|
-
function readResponseCookies(request, response) {
|
|
3
|
-
store.add({ ...request, url: request.url.toString() }, response);
|
|
4
|
-
store.persist();
|
|
5
|
-
}
|
|
6
|
-
export {
|
|
7
|
-
readResponseCookies
|
|
8
|
-
};
|
|
9
|
-
//# sourceMappingURL=readResponseCookies.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/request/readResponseCookies.ts"],"sourcesContent":["import { store } from '@mswjs/cookies'\n\nexport function readResponseCookies(\n request: Request,\n response: Response,\n): void {\n store.add({ ...request, url: request.url.toString() }, response)\n store.persist()\n}\n"],"mappings":"AAAA,SAAS,aAAa;AAEf,SAAS,oBACd,SACA,UACM;AACN,QAAM,IAAI,EAAE,GAAG,SAAS,KAAK,QAAQ,IAAI,SAAS,EAAE,GAAG,QAAQ;AAC/D,QAAM,QAAQ;AAChB;","names":[]}
|