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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/handlers/GraphQLHandler.ts"],"sourcesContent":["import type { DocumentNode, GraphQLError, OperationTypeNode } from 'graphql'\nimport {\n DefaultBodyType,\n RequestHandler,\n RequestHandlerDefaultInfo,\n RequestHandlerOptions,\n ResponseResolver,\n} from './RequestHandler'\nimport { getTimestamp } from '../utils/logging/getTimestamp'\nimport { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'\nimport { serializeRequest } from '../utils/logging/serializeRequest'\nimport { serializeResponse } from '../utils/logging/serializeResponse'\nimport { Match, matchRequestUrl, Path } from '../utils/matching/matchRequestUrl'\nimport {\n ParsedGraphQLRequest,\n GraphQLMultipartRequestBody,\n parseGraphQLRequest,\n parseDocumentNode,\n} from '../utils/internal/parseGraphQLRequest'\nimport { toPublicUrl } from '../utils/request/toPublicUrl'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { getAllRequestCookies } from '../utils/request/getRequestCookies'\n\nexport type GraphQLOperationType = OperationTypeNode | 'all'\nexport type GraphQLHandlerNameSelector = DocumentNode | RegExp | string\n\nexport type GraphQLQuery = Record<string, any> | null\nexport type GraphQLVariables = Record<string, any>\n\nexport interface GraphQLHandlerInfo extends RequestHandlerDefaultInfo {\n operationType: GraphQLOperationType\n operationName: GraphQLHandlerNameSelector | GraphQLCustomPredicate\n}\n\nexport type GraphQLRequestParsedResult = {\n match: Match\n cookies: Record<string, string>\n} & (\n | ParsedGraphQLRequest<GraphQLVariables>\n /**\n * An empty version of the ParsedGraphQLRequest\n * which simplifies the return type of the resolver\n * when the request is to a non-matching endpoint\n */\n | {\n operationType?: undefined\n operationName?: undefined\n query?: undefined\n variables?: undefined\n }\n)\n\nexport type GraphQLResolverExtras<Variables extends GraphQLVariables> = {\n query: string\n operationName: string\n variables: Variables\n cookies: Record<string, string>\n}\n\nexport type GraphQLRequestBody<VariablesType extends GraphQLVariables> =\n | GraphQLJsonRequestBody<VariablesType>\n | GraphQLMultipartRequestBody\n | Record<string, any>\n | undefined\n\nexport interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {\n query: string\n variables?: Variables\n}\n\nexport type GraphQLResponseBody<BodyType extends DefaultBodyType> =\n | {\n data?: BodyType | null\n errors?: readonly Partial<GraphQLError>[] | null\n extensions?: Record<string, any>\n }\n | null\n | undefined\n\nexport type GraphQLCustomPredicate = (args: {\n request: Request\n query: string\n operationType: GraphQLOperationType\n operationName: string\n variables: GraphQLVariables\n cookies: Record<string, string>\n}) => GraphQLCustomPredicateResult | Promise<GraphQLCustomPredicateResult>\n\nexport type GraphQLCustomPredicateResult = boolean | { matches: boolean }\n\nexport type GraphQLPredicate =\n | GraphQLHandlerNameSelector\n | GraphQLCustomPredicate\n\nexport function isDocumentNode(\n value: DocumentNode | any,\n): value is DocumentNode {\n if (value == null) {\n return false\n }\n\n return typeof value === 'object' && 'kind' in value && 'definitions' in value\n}\n\nexport class GraphQLHandler extends RequestHandler<\n GraphQLHandlerInfo,\n GraphQLRequestParsedResult,\n GraphQLResolverExtras<any>\n> {\n private endpoint: Path\n\n static parsedRequestCache = new WeakMap<\n Request,\n ParsedGraphQLRequest<GraphQLVariables>\n >()\n\n constructor(\n operationType: GraphQLOperationType,\n predicate: GraphQLPredicate,\n endpoint: Path,\n resolver: ResponseResolver<GraphQLResolverExtras<any>, any, any>,\n options?: RequestHandlerOptions,\n ) {\n let resolvedOperationName = predicate\n\n if (isDocumentNode(resolvedOperationName)) {\n const parsedNode = parseDocumentNode(resolvedOperationName)\n\n if (parsedNode.operationType !== operationType) {\n throw new Error(\n `Failed to create a GraphQL handler: provided a DocumentNode with a mismatched operation type (expected \"${operationType}\", but got \"${parsedNode.operationType}\").`,\n )\n }\n\n if (!parsedNode.operationName) {\n throw new Error(\n `Failed to create a GraphQL handler: provided a DocumentNode with no operation name.`,\n )\n }\n\n resolvedOperationName = parsedNode.operationName\n }\n\n const displayOperationName =\n typeof resolvedOperationName === 'function'\n ? '[custom predicate]'\n : resolvedOperationName\n\n const header =\n operationType === 'all'\n ? `${operationType} (origin: ${endpoint.toString()})`\n : `${operationType}${displayOperationName ? ` ${displayOperationName}` : ''} (origin: ${endpoint.toString()})`\n\n super({\n info: {\n header,\n operationType,\n operationName: resolvedOperationName,\n },\n resolver,\n options,\n })\n\n this.endpoint = endpoint\n }\n\n /**\n * Parses the request body, once per request, cached across all\n * GraphQL handlers. This is done to avoid multiple parsing of the\n * request body, which each requires a clone of the request.\n */\n async parseGraphQLRequestOrGetFromCache(\n request: Request,\n ): Promise<ParsedGraphQLRequest<GraphQLVariables>> {\n if (!GraphQLHandler.parsedRequestCache.has(request)) {\n GraphQLHandler.parsedRequestCache.set(\n request,\n await parseGraphQLRequest(request).catch((error) => {\n // eslint-disable-next-line no-console\n console.error(error)\n return undefined\n }),\n )\n }\n\n return GraphQLHandler.parsedRequestCache.get(request)\n }\n\n async parse(args: { request: Request }): Promise<GraphQLRequestParsedResult> {\n /**\n * If the request doesn't match a specified endpoint, there's no\n * need to parse it since there's no case where we would handle this\n */\n const match = matchRequestUrl(new URL(args.request.url), this.endpoint)\n const cookies = getAllRequestCookies(args.request)\n\n if (!match.matches) {\n return {\n match,\n cookies,\n }\n }\n\n const parsedResult = await this.parseGraphQLRequestOrGetFromCache(\n args.request,\n )\n\n if (typeof parsedResult === 'undefined') {\n return {\n match,\n cookies,\n }\n }\n\n return {\n match,\n cookies,\n query: parsedResult.query,\n operationType: parsedResult.operationType,\n operationName: parsedResult.operationName,\n variables: parsedResult.variables,\n }\n }\n\n async predicate(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }): Promise<boolean> {\n if (args.parsedResult.operationType === undefined) {\n return false\n }\n\n if (!args.parsedResult.operationName && this.info.operationType !== 'all') {\n const publicUrl = toPublicUrl(args.request.url)\n\n devUtils.warn(`\\\nFailed to intercept a GraphQL request at \"${args.request.method} ${publicUrl}\": anonymous GraphQL operations are not supported.\n\nConsider naming this operation or using \"graphql.operation()\" request handler to intercept GraphQL requests regardless of their operation name/type. Read more: https://mswjs.io/docs/api/graphql/#graphqloperationresolver`)\n return false\n }\n\n const hasMatchingOperationType =\n this.info.operationType === 'all' ||\n args.parsedResult.operationType === this.info.operationType\n\n /**\n * Check if the operation name matches the outgoing GraphQL request.\n * @note Unlike the HTTP handler, the custom predicate functions are invoked\n * during predicate, not parsing, because GraphQL request parsing happens first,\n * and non-GraphQL requests are filtered out automatically.\n */\n const hasMatchingOperationName = await this.matchOperationName({\n request: args.request,\n parsedResult: args.parsedResult,\n })\n\n return (\n args.parsedResult.match.matches &&\n hasMatchingOperationType &&\n hasMatchingOperationName\n )\n }\n\n private async matchOperationName(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }): Promise<boolean> {\n if (typeof this.info.operationName === 'function') {\n const customPredicateResult = await this.info.operationName({\n request: args.request,\n ...this.extendResolverArgs({\n request: args.request,\n parsedResult: args.parsedResult,\n }),\n })\n\n /**\n * @note Keep the { matches } signature in case we decide to support path parameters\n * in GraphQL handlers. If that happens, the custom predicate would have to be moved\n * to the parsing phase, the same as we have for the HttpHandler, and the user will\n * have a possibility to return parsed path parameters from the custom predicate.\n */\n return typeof customPredicateResult === 'boolean'\n ? customPredicateResult\n : customPredicateResult.matches\n }\n\n if (this.info.operationName instanceof RegExp) {\n return this.info.operationName.test(args.parsedResult.operationName || '')\n }\n\n return args.parsedResult.operationName === this.info.operationName\n }\n\n protected extendResolverArgs(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }) {\n return {\n query: args.parsedResult.query || '',\n operationType: args.parsedResult.operationType!,\n operationName: args.parsedResult.operationName || '',\n variables: args.parsedResult.variables || {},\n cookies: args.parsedResult.cookies,\n }\n }\n\n async log(args: {\n request: Request\n response: Response\n parsedResult: GraphQLRequestParsedResult\n }) {\n const loggedRequest = await serializeRequest(args.request)\n const loggedResponse = await serializeResponse(args.response)\n const statusColor = getStatusCodeColor(loggedResponse.status)\n const requestInfo = args.parsedResult.operationName\n ? `${args.parsedResult.operationType} ${args.parsedResult.operationName}`\n : `anonymous ${args.parsedResult.operationType}`\n\n // eslint-disable-next-line no-console\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} ${requestInfo} (%c${loggedResponse.status} ${\n loggedResponse.statusText\n }%c)`,\n ),\n `color:${statusColor}`,\n 'color:inherit',\n )\n // eslint-disable-next-line no-console\n console.log('Request:', loggedRequest)\n // eslint-disable-next-line no-console\n console.log('Handler:', this)\n // eslint-disable-next-line no-console\n console.log('Response:', loggedResponse)\n // eslint-disable-next-line no-console\n console.groupEnd()\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/handlers/GraphQLHandler.ts"],"sourcesContent":["import type { DocumentNode, GraphQLError, OperationTypeNode } from 'graphql'\nimport {\n DefaultBodyType,\n RequestHandler,\n RequestHandlerDefaultInfo,\n RequestHandlerOptions,\n ResponseResolver,\n} from './RequestHandler'\nimport { getTimestamp } from '../utils/logging/getTimestamp'\nimport { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'\nimport { serializeRequest } from '../utils/logging/serializeRequest'\nimport { serializeResponse } from '../utils/logging/serializeResponse'\nimport { Match, matchRequestUrl, Path } from '../utils/matching/matchRequestUrl'\nimport {\n ParsedGraphQLRequest,\n GraphQLMultipartRequestBody,\n parseGraphQLRequest,\n parseDocumentNode,\n} from '../utils/internal/parseGraphQLRequest'\nimport { toPublicUrl } from '../utils/request/toPublicUrl'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { getAllRequestCookies } from '../utils/request/getRequestCookies'\n\nexport type GraphQLOperationType = OperationTypeNode | 'all'\nexport type GraphQLHandlerNameSelector = DocumentNode | RegExp | string\n\nexport type GraphQLQuery = Record<string, any> | null\nexport type GraphQLVariables = Record<string, any>\n\nexport interface GraphQLHandlerInfo extends RequestHandlerDefaultInfo {\n operationType: GraphQLOperationType\n operationName: GraphQLHandlerNameSelector | GraphQLCustomPredicate\n}\n\nexport type GraphQLRequestParsedResult = {\n match: Match\n cookies: Record<string, string>\n} & (\n | ParsedGraphQLRequest<GraphQLVariables>\n /**\n * An empty version of the ParsedGraphQLRequest\n * which simplifies the return type of the resolver\n * when the request is to a non-matching endpoint\n */\n | {\n operationType?: undefined\n operationName?: undefined\n query?: undefined\n variables?: undefined\n }\n)\n\nexport type GraphQLResolverExtras<Variables extends GraphQLVariables> = {\n query: string\n operationName: string\n variables: Variables\n cookies: Record<string, string>\n}\n\nexport type GraphQLRequestBody<VariablesType extends GraphQLVariables> =\n | GraphQLJsonRequestBody<VariablesType>\n | GraphQLMultipartRequestBody\n | Record<string, any>\n | undefined\n\nexport interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {\n query: string\n variables?: Variables\n}\n\nexport type GraphQLResponseBody<BodyType extends DefaultBodyType> =\n | {\n data?: BodyType | null\n errors?: readonly Partial<GraphQLError>[] | null\n extensions?: Record<string, any>\n }\n | null\n | undefined\n\nexport type GraphQLCustomPredicate = (args: {\n request: Request\n query: string\n operationType: GraphQLOperationType\n operationName: string\n variables: GraphQLVariables\n cookies: Record<string, string>\n}) => GraphQLCustomPredicateResult | Promise<GraphQLCustomPredicateResult>\n\nexport type GraphQLCustomPredicateResult = boolean | { matches: boolean }\n\nexport type GraphQLPredicate =\n | GraphQLHandlerNameSelector\n | GraphQLCustomPredicate\n\nexport function isDocumentNode(\n value: DocumentNode | any,\n): value is DocumentNode {\n if (value == null) {\n return false\n }\n\n return typeof value === 'object' && 'kind' in value && 'definitions' in value\n}\n\nexport class GraphQLHandler extends RequestHandler<\n GraphQLHandlerInfo,\n GraphQLRequestParsedResult,\n GraphQLResolverExtras<any>\n> {\n private endpoint: Path\n\n static parsedRequestCache = new WeakMap<\n Request,\n ParsedGraphQLRequest<GraphQLVariables>\n >()\n\n constructor(\n operationType: GraphQLOperationType,\n predicate: GraphQLPredicate,\n endpoint: Path,\n resolver: ResponseResolver<GraphQLResolverExtras<any>, any, any>,\n options?: RequestHandlerOptions,\n ) {\n let resolvedOperationName = predicate\n\n if (isDocumentNode(resolvedOperationName)) {\n const parsedNode = parseDocumentNode(resolvedOperationName)\n\n if (parsedNode.operationType !== operationType) {\n throw new Error(\n `Failed to create a GraphQL handler: provided a DocumentNode with a mismatched operation type (expected \"${operationType}\", but got \"${parsedNode.operationType}\").`,\n )\n }\n\n if (!parsedNode.operationName) {\n throw new Error(\n `Failed to create a GraphQL handler: provided a DocumentNode with no operation name.`,\n )\n }\n\n resolvedOperationName = parsedNode.operationName\n }\n\n const displayOperationName =\n typeof resolvedOperationName === 'function'\n ? '[custom predicate]'\n : resolvedOperationName\n\n const header =\n operationType === 'all'\n ? `${operationType} (origin: ${endpoint.toString()})`\n : `${operationType}${displayOperationName ? ` ${displayOperationName}` : ''} (origin: ${endpoint.toString()})`\n\n super({\n info: {\n header,\n operationType,\n operationName: resolvedOperationName,\n },\n resolver,\n options,\n })\n\n this.endpoint = endpoint\n }\n\n /**\n * Parses the request body, once per request, cached across all\n * GraphQL handlers. This is done to avoid multiple parsing of the\n * request body, which each requires a clone of the request.\n */\n async parseGraphQLRequestOrGetFromCache(\n request: Request,\n ): Promise<ParsedGraphQLRequest<GraphQLVariables>> {\n if (!GraphQLHandler.parsedRequestCache.has(request)) {\n GraphQLHandler.parsedRequestCache.set(\n request,\n await parseGraphQLRequest(request).catch((error) => {\n console.error(error)\n return undefined\n }),\n )\n }\n\n return GraphQLHandler.parsedRequestCache.get(request)\n }\n\n async parse(args: { request: Request }): Promise<GraphQLRequestParsedResult> {\n /**\n * If the request doesn't match a specified endpoint, there's no\n * need to parse it since there's no case where we would handle this\n */\n const match = matchRequestUrl(new URL(args.request.url), this.endpoint)\n const cookies = getAllRequestCookies(args.request)\n\n if (!match.matches) {\n return {\n match,\n cookies,\n }\n }\n\n const parsedResult = await this.parseGraphQLRequestOrGetFromCache(\n args.request,\n )\n\n if (typeof parsedResult === 'undefined') {\n return {\n match,\n cookies,\n }\n }\n\n return {\n match,\n cookies,\n query: parsedResult.query,\n operationType: parsedResult.operationType,\n operationName: parsedResult.operationName,\n variables: parsedResult.variables,\n }\n }\n\n async predicate(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }): Promise<boolean> {\n if (args.parsedResult.operationType === undefined) {\n return false\n }\n\n if (!args.parsedResult.operationName && this.info.operationType !== 'all') {\n const publicUrl = toPublicUrl(args.request.url)\n\n devUtils.warn(`\\\nFailed to intercept a GraphQL request at \"${args.request.method} ${publicUrl}\": anonymous GraphQL operations are not supported.\n\nConsider naming this operation or using \"graphql.operation()\" request handler to intercept GraphQL requests regardless of their operation name/type. Read more: https://mswjs.io/docs/api/graphql/#graphqloperationresolver`)\n return false\n }\n\n const hasMatchingOperationType =\n this.info.operationType === 'all' ||\n args.parsedResult.operationType === this.info.operationType\n\n /**\n * Check if the operation name matches the outgoing GraphQL request.\n * @note Unlike the HTTP handler, the custom predicate functions are invoked\n * during predicate, not parsing, because GraphQL request parsing happens first,\n * and non-GraphQL requests are filtered out automatically.\n */\n const hasMatchingOperationName = await this.matchOperationName({\n request: args.request,\n parsedResult: args.parsedResult,\n })\n\n return (\n args.parsedResult.match.matches &&\n hasMatchingOperationType &&\n hasMatchingOperationName\n )\n }\n\n private async matchOperationName(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }): Promise<boolean> {\n if (typeof this.info.operationName === 'function') {\n const customPredicateResult = await this.info.operationName({\n request: args.request,\n ...this.extendResolverArgs({\n request: args.request,\n parsedResult: args.parsedResult,\n }),\n })\n\n /**\n * @note Keep the { matches } signature in case we decide to support path parameters\n * in GraphQL handlers. If that happens, the custom predicate would have to be moved\n * to the parsing phase, the same as we have for the HttpHandler, and the user will\n * have a possibility to return parsed path parameters from the custom predicate.\n */\n return typeof customPredicateResult === 'boolean'\n ? customPredicateResult\n : customPredicateResult.matches\n }\n\n if (this.info.operationName instanceof RegExp) {\n return this.info.operationName.test(args.parsedResult.operationName || '')\n }\n\n return args.parsedResult.operationName === this.info.operationName\n }\n\n protected extendResolverArgs(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }) {\n return {\n query: args.parsedResult.query || '',\n operationType: args.parsedResult.operationType!,\n operationName: args.parsedResult.operationName || '',\n variables: args.parsedResult.variables || {},\n cookies: args.parsedResult.cookies,\n }\n }\n\n async log(args: {\n request: Request\n response: Response\n parsedResult: GraphQLRequestParsedResult\n }) {\n const loggedRequest = await serializeRequest(args.request)\n const loggedResponse = await serializeResponse(args.response)\n const statusColor = getStatusCodeColor(loggedResponse.status)\n const requestInfo = args.parsedResult.operationName\n ? `${args.parsedResult.operationType} ${args.parsedResult.operationName}`\n : `anonymous ${args.parsedResult.operationType}`\n\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} ${requestInfo} (%c${loggedResponse.status} ${\n loggedResponse.statusText\n }%c)`,\n ),\n `color:${statusColor}`,\n 'color:inherit',\n )\n // eslint-disable-next-line no-console\n console.log('Request:', loggedRequest)\n // eslint-disable-next-line no-console\n console.log('Handler:', this)\n // eslint-disable-next-line no-console\n console.log('Response:', loggedResponse)\n console.groupEnd()\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/handlers/GraphQLHandler.ts"],"sourcesContent":["import type { DocumentNode, GraphQLError, OperationTypeNode } from 'graphql'\nimport {\n DefaultBodyType,\n RequestHandler,\n RequestHandlerDefaultInfo,\n RequestHandlerOptions,\n ResponseResolver,\n} from './RequestHandler'\nimport { getTimestamp } from '../utils/logging/getTimestamp'\nimport { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'\nimport { serializeRequest } from '../utils/logging/serializeRequest'\nimport { serializeResponse } from '../utils/logging/serializeResponse'\nimport { Match, matchRequestUrl, Path } from '../utils/matching/matchRequestUrl'\nimport {\n ParsedGraphQLRequest,\n GraphQLMultipartRequestBody,\n parseGraphQLRequest,\n parseDocumentNode,\n} from '../utils/internal/parseGraphQLRequest'\nimport { toPublicUrl } from '../utils/request/toPublicUrl'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { getAllRequestCookies } from '../utils/request/getRequestCookies'\n\nexport type GraphQLOperationType = OperationTypeNode | 'all'\nexport type GraphQLHandlerNameSelector = DocumentNode | RegExp | string\n\nexport type GraphQLQuery = Record<string, any> | null\nexport type GraphQLVariables = Record<string, any>\n\nexport interface GraphQLHandlerInfo extends RequestHandlerDefaultInfo {\n operationType: GraphQLOperationType\n operationName: GraphQLHandlerNameSelector | GraphQLCustomPredicate\n}\n\nexport type GraphQLRequestParsedResult = {\n match: Match\n cookies: Record<string, string>\n} & (\n | ParsedGraphQLRequest<GraphQLVariables>\n /**\n * An empty version of the ParsedGraphQLRequest\n * which simplifies the return type of the resolver\n * when the request is to a non-matching endpoint\n */\n | {\n operationType?: undefined\n operationName?: undefined\n query?: undefined\n variables?: undefined\n }\n)\n\nexport type GraphQLResolverExtras<Variables extends GraphQLVariables> = {\n query: string\n operationName: string\n variables: Variables\n cookies: Record<string, string>\n}\n\nexport type GraphQLRequestBody<VariablesType extends GraphQLVariables> =\n | GraphQLJsonRequestBody<VariablesType>\n | GraphQLMultipartRequestBody\n | Record<string, any>\n | undefined\n\nexport interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {\n query: string\n variables?: Variables\n}\n\nexport type GraphQLResponseBody<BodyType extends DefaultBodyType> =\n | {\n data?: BodyType | null\n errors?: readonly Partial<GraphQLError>[] | null\n extensions?: Record<string, any>\n }\n | null\n | undefined\n\nexport type GraphQLCustomPredicate = (args: {\n request: Request\n query: string\n operationType: GraphQLOperationType\n operationName: string\n variables: GraphQLVariables\n cookies: Record<string, string>\n}) => GraphQLCustomPredicateResult | Promise<GraphQLCustomPredicateResult>\n\nexport type GraphQLCustomPredicateResult = boolean | { matches: boolean }\n\nexport type GraphQLPredicate =\n | GraphQLHandlerNameSelector\n | GraphQLCustomPredicate\n\nexport function isDocumentNode(\n value: DocumentNode | any,\n): value is DocumentNode {\n if (value == null) {\n return false\n }\n\n return typeof value === 'object' && 'kind' in value && 'definitions' in value\n}\n\nexport class GraphQLHandler extends RequestHandler<\n GraphQLHandlerInfo,\n GraphQLRequestParsedResult,\n GraphQLResolverExtras<any>\n> {\n private endpoint: Path\n\n static parsedRequestCache = new WeakMap<\n Request,\n ParsedGraphQLRequest<GraphQLVariables>\n >()\n\n constructor(\n operationType: GraphQLOperationType,\n predicate: GraphQLPredicate,\n endpoint: Path,\n resolver: ResponseResolver<GraphQLResolverExtras<any>, any, any>,\n options?: RequestHandlerOptions,\n ) {\n let resolvedOperationName = predicate\n\n if (isDocumentNode(resolvedOperationName)) {\n const parsedNode = parseDocumentNode(resolvedOperationName)\n\n if (parsedNode.operationType !== operationType) {\n throw new Error(\n `Failed to create a GraphQL handler: provided a DocumentNode with a mismatched operation type (expected \"${operationType}\", but got \"${parsedNode.operationType}\").`,\n )\n }\n\n if (!parsedNode.operationName) {\n throw new Error(\n `Failed to create a GraphQL handler: provided a DocumentNode with no operation name.`,\n )\n }\n\n resolvedOperationName = parsedNode.operationName\n }\n\n const displayOperationName =\n typeof resolvedOperationName === 'function'\n ? '[custom predicate]'\n : resolvedOperationName\n\n const header =\n operationType === 'all'\n ? `${operationType} (origin: ${endpoint.toString()})`\n : `${operationType}${displayOperationName ? ` ${displayOperationName}` : ''} (origin: ${endpoint.toString()})`\n\n super({\n info: {\n header,\n operationType,\n operationName: resolvedOperationName,\n },\n resolver,\n options,\n })\n\n this.endpoint = endpoint\n }\n\n /**\n * Parses the request body, once per request, cached across all\n * GraphQL handlers. This is done to avoid multiple parsing of the\n * request body, which each requires a clone of the request.\n */\n async parseGraphQLRequestOrGetFromCache(\n request: Request,\n ): Promise<ParsedGraphQLRequest<GraphQLVariables>> {\n if (!GraphQLHandler.parsedRequestCache.has(request)) {\n GraphQLHandler.parsedRequestCache.set(\n request,\n await parseGraphQLRequest(request).catch((error) => {\n // eslint-disable-next-line no-console\n console.error(error)\n return undefined\n }),\n )\n }\n\n return GraphQLHandler.parsedRequestCache.get(request)\n }\n\n async parse(args: { request: Request }): Promise<GraphQLRequestParsedResult> {\n /**\n * If the request doesn't match a specified endpoint, there's no\n * need to parse it since there's no case where we would handle this\n */\n const match = matchRequestUrl(new URL(args.request.url), this.endpoint)\n const cookies = getAllRequestCookies(args.request)\n\n if (!match.matches) {\n return {\n match,\n cookies,\n }\n }\n\n const parsedResult = await this.parseGraphQLRequestOrGetFromCache(\n args.request,\n )\n\n if (typeof parsedResult === 'undefined') {\n return {\n match,\n cookies,\n }\n }\n\n return {\n match,\n cookies,\n query: parsedResult.query,\n operationType: parsedResult.operationType,\n operationName: parsedResult.operationName,\n variables: parsedResult.variables,\n }\n }\n\n async predicate(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }): Promise<boolean> {\n if (args.parsedResult.operationType === undefined) {\n return false\n }\n\n if (!args.parsedResult.operationName && this.info.operationType !== 'all') {\n const publicUrl = toPublicUrl(args.request.url)\n\n devUtils.warn(`\\\nFailed to intercept a GraphQL request at \"${args.request.method} ${publicUrl}\": anonymous GraphQL operations are not supported.\n\nConsider naming this operation or using \"graphql.operation()\" request handler to intercept GraphQL requests regardless of their operation name/type. Read more: https://mswjs.io/docs/api/graphql/#graphqloperationresolver`)\n return false\n }\n\n const hasMatchingOperationType =\n this.info.operationType === 'all' ||\n args.parsedResult.operationType === this.info.operationType\n\n /**\n * Check if the operation name matches the outgoing GraphQL request.\n * @note Unlike the HTTP handler, the custom predicate functions are invoked\n * during predicate, not parsing, because GraphQL request parsing happens first,\n * and non-GraphQL requests are filtered out automatically.\n */\n const hasMatchingOperationName = await this.matchOperationName({\n request: args.request,\n parsedResult: args.parsedResult,\n })\n\n return (\n args.parsedResult.match.matches &&\n hasMatchingOperationType &&\n hasMatchingOperationName\n )\n }\n\n private async matchOperationName(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }): Promise<boolean> {\n if (typeof this.info.operationName === 'function') {\n const customPredicateResult = await this.info.operationName({\n request: args.request,\n ...this.extendResolverArgs({\n request: args.request,\n parsedResult: args.parsedResult,\n }),\n })\n\n /**\n * @note Keep the { matches } signature in case we decide to support path parameters\n * in GraphQL handlers. If that happens, the custom predicate would have to be moved\n * to the parsing phase, the same as we have for the HttpHandler, and the user will\n * have a possibility to return parsed path parameters from the custom predicate.\n */\n return typeof customPredicateResult === 'boolean'\n ? customPredicateResult\n : customPredicateResult.matches\n }\n\n if (this.info.operationName instanceof RegExp) {\n return this.info.operationName.test(args.parsedResult.operationName || '')\n }\n\n return args.parsedResult.operationName === this.info.operationName\n }\n\n protected extendResolverArgs(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }) {\n return {\n query: args.parsedResult.query || '',\n operationType: args.parsedResult.operationType!,\n operationName: args.parsedResult.operationName || '',\n variables: args.parsedResult.variables || {},\n cookies: args.parsedResult.cookies,\n }\n }\n\n async log(args: {\n request: Request\n response: Response\n parsedResult: GraphQLRequestParsedResult\n }) {\n const loggedRequest = await serializeRequest(args.request)\n const loggedResponse = await serializeResponse(args.response)\n const statusColor = getStatusCodeColor(loggedResponse.status)\n const requestInfo = args.parsedResult.operationName\n ? `${args.parsedResult.operationType} ${args.parsedResult.operationName}`\n : `anonymous ${args.parsedResult.operationType}`\n\n // eslint-disable-next-line no-console\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} ${requestInfo} (%c${loggedResponse.status} ${\n loggedResponse.statusText\n }%c)`,\n ),\n `color:${statusColor}`,\n 'color:inherit',\n )\n // eslint-disable-next-line no-console\n console.log('Request:', loggedRequest)\n // eslint-disable-next-line no-console\n console.log('Handler:', this)\n // eslint-disable-next-line no-console\n console.log('Response:', loggedResponse)\n // eslint-disable-next-line no-console\n console.groupEnd()\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/handlers/GraphQLHandler.ts"],"sourcesContent":["import type { DocumentNode, GraphQLError, OperationTypeNode } from 'graphql'\nimport {\n DefaultBodyType,\n RequestHandler,\n RequestHandlerDefaultInfo,\n RequestHandlerOptions,\n ResponseResolver,\n} from './RequestHandler'\nimport { getTimestamp } from '../utils/logging/getTimestamp'\nimport { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'\nimport { serializeRequest } from '../utils/logging/serializeRequest'\nimport { serializeResponse } from '../utils/logging/serializeResponse'\nimport { Match, matchRequestUrl, Path } from '../utils/matching/matchRequestUrl'\nimport {\n ParsedGraphQLRequest,\n GraphQLMultipartRequestBody,\n parseGraphQLRequest,\n parseDocumentNode,\n} from '../utils/internal/parseGraphQLRequest'\nimport { toPublicUrl } from '../utils/request/toPublicUrl'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { getAllRequestCookies } from '../utils/request/getRequestCookies'\n\nexport type GraphQLOperationType = OperationTypeNode | 'all'\nexport type GraphQLHandlerNameSelector = DocumentNode | RegExp | string\n\nexport type GraphQLQuery = Record<string, any> | null\nexport type GraphQLVariables = Record<string, any>\n\nexport interface GraphQLHandlerInfo extends RequestHandlerDefaultInfo {\n operationType: GraphQLOperationType\n operationName: GraphQLHandlerNameSelector | GraphQLCustomPredicate\n}\n\nexport type GraphQLRequestParsedResult = {\n match: Match\n cookies: Record<string, string>\n} & (\n | ParsedGraphQLRequest<GraphQLVariables>\n /**\n * An empty version of the ParsedGraphQLRequest\n * which simplifies the return type of the resolver\n * when the request is to a non-matching endpoint\n */\n | {\n operationType?: undefined\n operationName?: undefined\n query?: undefined\n variables?: undefined\n }\n)\n\nexport type GraphQLResolverExtras<Variables extends GraphQLVariables> = {\n query: string\n operationName: string\n variables: Variables\n cookies: Record<string, string>\n}\n\nexport type GraphQLRequestBody<VariablesType extends GraphQLVariables> =\n | GraphQLJsonRequestBody<VariablesType>\n | GraphQLMultipartRequestBody\n | Record<string, any>\n | undefined\n\nexport interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {\n query: string\n variables?: Variables\n}\n\nexport type GraphQLResponseBody<BodyType extends DefaultBodyType> =\n | {\n data?: BodyType | null\n errors?: readonly Partial<GraphQLError>[] | null\n extensions?: Record<string, any>\n }\n | null\n | undefined\n\nexport type GraphQLCustomPredicate = (args: {\n request: Request\n query: string\n operationType: GraphQLOperationType\n operationName: string\n variables: GraphQLVariables\n cookies: Record<string, string>\n}) => GraphQLCustomPredicateResult | Promise<GraphQLCustomPredicateResult>\n\nexport type GraphQLCustomPredicateResult = boolean | { matches: boolean }\n\nexport type GraphQLPredicate =\n | GraphQLHandlerNameSelector\n | GraphQLCustomPredicate\n\nexport function isDocumentNode(\n value: DocumentNode | any,\n): value is DocumentNode {\n if (value == null) {\n return false\n }\n\n return typeof value === 'object' && 'kind' in value && 'definitions' in value\n}\n\nexport class GraphQLHandler extends RequestHandler<\n GraphQLHandlerInfo,\n GraphQLRequestParsedResult,\n GraphQLResolverExtras<any>\n> {\n private endpoint: Path\n\n static parsedRequestCache = new WeakMap<\n Request,\n ParsedGraphQLRequest<GraphQLVariables>\n >()\n\n constructor(\n operationType: GraphQLOperationType,\n predicate: GraphQLPredicate,\n endpoint: Path,\n resolver: ResponseResolver<GraphQLResolverExtras<any>, any, any>,\n options?: RequestHandlerOptions,\n ) {\n let resolvedOperationName = predicate\n\n if (isDocumentNode(resolvedOperationName)) {\n const parsedNode = parseDocumentNode(resolvedOperationName)\n\n if (parsedNode.operationType !== operationType) {\n throw new Error(\n `Failed to create a GraphQL handler: provided a DocumentNode with a mismatched operation type (expected \"${operationType}\", but got \"${parsedNode.operationType}\").`,\n )\n }\n\n if (!parsedNode.operationName) {\n throw new Error(\n `Failed to create a GraphQL handler: provided a DocumentNode with no operation name.`,\n )\n }\n\n resolvedOperationName = parsedNode.operationName\n }\n\n const displayOperationName =\n typeof resolvedOperationName === 'function'\n ? '[custom predicate]'\n : resolvedOperationName\n\n const header =\n operationType === 'all'\n ? `${operationType} (origin: ${endpoint.toString()})`\n : `${operationType}${displayOperationName ? ` ${displayOperationName}` : ''} (origin: ${endpoint.toString()})`\n\n super({\n info: {\n header,\n operationType,\n operationName: resolvedOperationName,\n },\n resolver,\n options,\n })\n\n this.endpoint = endpoint\n }\n\n /**\n * Parses the request body, once per request, cached across all\n * GraphQL handlers. This is done to avoid multiple parsing of the\n * request body, which each requires a clone of the request.\n */\n async parseGraphQLRequestOrGetFromCache(\n request: Request,\n ): Promise<ParsedGraphQLRequest<GraphQLVariables>> {\n if (!GraphQLHandler.parsedRequestCache.has(request)) {\n GraphQLHandler.parsedRequestCache.set(\n request,\n await parseGraphQLRequest(request).catch((error) => {\n console.error(error)\n return undefined\n }),\n )\n }\n\n return GraphQLHandler.parsedRequestCache.get(request)\n }\n\n async parse(args: { request: Request }): Promise<GraphQLRequestParsedResult> {\n /**\n * If the request doesn't match a specified endpoint, there's no\n * need to parse it since there's no case where we would handle this\n */\n const match = matchRequestUrl(new URL(args.request.url), this.endpoint)\n const cookies = getAllRequestCookies(args.request)\n\n if (!match.matches) {\n return {\n match,\n cookies,\n }\n }\n\n const parsedResult = await this.parseGraphQLRequestOrGetFromCache(\n args.request,\n )\n\n if (typeof parsedResult === 'undefined') {\n return {\n match,\n cookies,\n }\n }\n\n return {\n match,\n cookies,\n query: parsedResult.query,\n operationType: parsedResult.operationType,\n operationName: parsedResult.operationName,\n variables: parsedResult.variables,\n }\n }\n\n async predicate(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }): Promise<boolean> {\n if (args.parsedResult.operationType === undefined) {\n return false\n }\n\n if (!args.parsedResult.operationName && this.info.operationType !== 'all') {\n const publicUrl = toPublicUrl(args.request.url)\n\n devUtils.warn(`\\\nFailed to intercept a GraphQL request at \"${args.request.method} ${publicUrl}\": anonymous GraphQL operations are not supported.\n\nConsider naming this operation or using \"graphql.operation()\" request handler to intercept GraphQL requests regardless of their operation name/type. Read more: https://mswjs.io/docs/api/graphql/#graphqloperationresolver`)\n return false\n }\n\n const hasMatchingOperationType =\n this.info.operationType === 'all' ||\n args.parsedResult.operationType === this.info.operationType\n\n /**\n * Check if the operation name matches the outgoing GraphQL request.\n * @note Unlike the HTTP handler, the custom predicate functions are invoked\n * during predicate, not parsing, because GraphQL request parsing happens first,\n * and non-GraphQL requests are filtered out automatically.\n */\n const hasMatchingOperationName = await this.matchOperationName({\n request: args.request,\n parsedResult: args.parsedResult,\n })\n\n return (\n args.parsedResult.match.matches &&\n hasMatchingOperationType &&\n hasMatchingOperationName\n )\n }\n\n private async matchOperationName(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }): Promise<boolean> {\n if (typeof this.info.operationName === 'function') {\n const customPredicateResult = await this.info.operationName({\n request: args.request,\n ...this.extendResolverArgs({\n request: args.request,\n parsedResult: args.parsedResult,\n }),\n })\n\n /**\n * @note Keep the { matches } signature in case we decide to support path parameters\n * in GraphQL handlers. If that happens, the custom predicate would have to be moved\n * to the parsing phase, the same as we have for the HttpHandler, and the user will\n * have a possibility to return parsed path parameters from the custom predicate.\n */\n return typeof customPredicateResult === 'boolean'\n ? customPredicateResult\n : customPredicateResult.matches\n }\n\n if (this.info.operationName instanceof RegExp) {\n return this.info.operationName.test(args.parsedResult.operationName || '')\n }\n\n return args.parsedResult.operationName === this.info.operationName\n }\n\n protected extendResolverArgs(args: {\n request: Request\n parsedResult: GraphQLRequestParsedResult\n }) {\n return {\n query: args.parsedResult.query || '',\n operationType: args.parsedResult.operationType!,\n operationName: args.parsedResult.operationName || '',\n variables: args.parsedResult.variables || {},\n cookies: args.parsedResult.cookies,\n }\n }\n\n async log(args: {\n request: Request\n response: Response\n parsedResult: GraphQLRequestParsedResult\n }) {\n const loggedRequest = await serializeRequest(args.request)\n const loggedResponse = await serializeResponse(args.response)\n const statusColor = getStatusCodeColor(loggedResponse.status)\n const requestInfo = args.parsedResult.operationName\n ? `${args.parsedResult.operationType} ${args.parsedResult.operationName}`\n : `anonymous ${args.parsedResult.operationType}`\n\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} ${requestInfo} (%c${loggedResponse.status} ${\n loggedResponse.statusText\n }%c)`,\n ),\n `color:${statusColor}`,\n 'color:inherit',\n )\n // eslint-disable-next-line no-console\n console.log('Request:', loggedRequest)\n // eslint-disable-next-line no-console\n console.log('Handler:', this)\n // eslint-disable-next-line no-console\n console.log('Response:', loggedResponse)\n console.groupEnd()\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/handlers/HttpHandler.ts"],"sourcesContent":["import { ResponseResolutionContext } from '../utils/executeHandlers'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { isStringEqual } from '../utils/internal/isStringEqual'\nimport { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'\nimport { getTimestamp } from '../utils/logging/getTimestamp'\nimport { serializeRequest } from '../utils/logging/serializeRequest'\nimport { serializeResponse } from '../utils/logging/serializeResponse'\nimport {\n matchRequestUrl,\n Match,\n Path,\n PathParams,\n} from '../utils/matching/matchRequestUrl'\nimport { toPublicUrl } from '../utils/request/toPublicUrl'\nimport { getAllRequestCookies } from '../utils/request/getRequestCookies'\nimport { cleanUrl, getSearchParams } from '../utils/url/cleanUrl'\nimport {\n RequestHandler,\n RequestHandlerDefaultInfo,\n RequestHandlerOptions,\n ResponseResolver,\n} from './RequestHandler'\n\ntype HttpHandlerMethod = string | RegExp\n\nexport interface HttpHandlerInfo extends RequestHandlerDefaultInfo {\n method: HttpHandlerMethod\n path: HttpRequestPredicate<PathParams>\n}\n\nexport enum HttpMethods {\n HEAD = 'HEAD',\n GET = 'GET',\n POST = 'POST',\n PUT = 'PUT',\n PATCH = 'PATCH',\n OPTIONS = 'OPTIONS',\n DELETE = 'DELETE',\n}\n\nexport type RequestQuery = {\n [queryName: string]: string\n}\n\nexport type HttpRequestParsedResult = {\n match: Match\n cookies: Record<string, string>\n}\n\nexport type HttpRequestResolverExtras<Params extends PathParams> = {\n params: Params\n cookies: Record<string, string>\n}\n\nexport type HttpCustomPredicate<Params extends PathParams> = (args: {\n request: Request\n cookies: Record<string, string>\n}) =>\n | HttpCustomPredicateResult<Params>\n | Promise<HttpCustomPredicateResult<Params>>\n\nexport type HttpCustomPredicateResult<Params extends PathParams> =\n | boolean\n | {\n matches: boolean\n params: Params\n }\n\nexport type HttpRequestPredicate<Params extends PathParams> =\n | Path\n | HttpCustomPredicate<Params>\n\n/**\n * Request handler for HTTP requests.\n * Provides request matching based on method and URL.\n */\nexport class HttpHandler extends RequestHandler<\n HttpHandlerInfo,\n HttpRequestParsedResult,\n HttpRequestResolverExtras<any>\n> {\n constructor(\n method: HttpHandlerMethod,\n predicate: HttpRequestPredicate<PathParams>,\n resolver: ResponseResolver<HttpRequestResolverExtras<any>, any, any>,\n options?: RequestHandlerOptions,\n ) {\n const displayPath =\n typeof predicate === 'function' ? '[custom predicate]' : predicate\n\n super({\n info: {\n header: `${method}${displayPath ? ` ${displayPath}` : ''}`,\n path: predicate,\n method,\n },\n resolver,\n options,\n })\n\n this.checkRedundantQueryParameters()\n }\n\n private checkRedundantQueryParameters() {\n const { method, path } = this.info\n\n if (!path || path instanceof RegExp || typeof path === 'function') {\n return\n }\n\n const url = cleanUrl(path)\n\n // Bypass request handler URLs that have no redundant characters.\n if (url === path) {\n return\n }\n\n const searchParams = getSearchParams(path)\n const queryParams: Array<string> = []\n\n searchParams.forEach((_, paramName) => {\n queryParams.push(paramName)\n })\n\n devUtils.warn(\n `Found a redundant usage of query parameters in the request handler URL for \"${method} ${path}\". Please match against a path instead and access query parameters using \"new URL(request.url).searchParams\" instead. Learn more: https://mswjs.io/docs/http/intercepting-requests#querysearch-parameters`,\n )\n }\n\n async parse(args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }) {\n const url = new URL(args.request.url)\n const cookies = getAllRequestCookies(args.request)\n\n /**\n * Handle custom predicate functions.\n * @note Invoke this during parsing so the user can parse the path parameters\n * manually. Otherwise, `params` is always an empty object, which isn't nice.\n */\n if (typeof this.info.path === 'function') {\n const customPredicateResult = await this.info.path({\n request: args.request,\n cookies,\n })\n\n const match =\n typeof customPredicateResult === 'boolean'\n ? {\n matches: customPredicateResult,\n params: {},\n }\n : customPredicateResult\n\n return {\n match,\n cookies,\n }\n }\n\n const match = this.info.path\n ? matchRequestUrl(url, this.info.path, args.resolutionContext?.baseUrl)\n : { matches: false, params: {} }\n\n return {\n match,\n cookies,\n }\n }\n\n async predicate(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n resolutionContext?: ResponseResolutionContext\n }) {\n const hasMatchingMethod = this.matchMethod(args.request.method)\n const hasMatchingUrl = args.parsedResult.match.matches\n return hasMatchingMethod && hasMatchingUrl\n }\n\n private matchMethod(actualMethod: string): boolean {\n return this.info.method instanceof RegExp\n ? this.info.method.test(actualMethod)\n : isStringEqual(this.info.method, actualMethod)\n }\n\n protected extendResolverArgs(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n }) {\n return {\n params: args.parsedResult.match?.params || {},\n cookies: args.parsedResult.cookies,\n }\n }\n\n async log(args: { request: Request; response: Response }) {\n const publicUrl = toPublicUrl(args.request.url)\n const loggedRequest = await serializeRequest(args.request)\n const loggedResponse = await serializeResponse(args.response)\n const statusColor = getStatusCodeColor(loggedResponse.status)\n\n
|
|
1
|
+
{"version":3,"sources":["../../../src/core/handlers/HttpHandler.ts"],"sourcesContent":["import { ResponseResolutionContext } from '../utils/executeHandlers'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { isStringEqual } from '../utils/internal/isStringEqual'\nimport { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'\nimport { getTimestamp } from '../utils/logging/getTimestamp'\nimport { serializeRequest } from '../utils/logging/serializeRequest'\nimport { serializeResponse } from '../utils/logging/serializeResponse'\nimport {\n matchRequestUrl,\n Match,\n Path,\n PathParams,\n} from '../utils/matching/matchRequestUrl'\nimport { toPublicUrl } from '../utils/request/toPublicUrl'\nimport { getAllRequestCookies } from '../utils/request/getRequestCookies'\nimport { cleanUrl, getSearchParams } from '../utils/url/cleanUrl'\nimport {\n RequestHandler,\n RequestHandlerDefaultInfo,\n RequestHandlerOptions,\n ResponseResolver,\n} from './RequestHandler'\n\ntype HttpHandlerMethod = string | RegExp\n\nexport interface HttpHandlerInfo extends RequestHandlerDefaultInfo {\n method: HttpHandlerMethod\n path: HttpRequestPredicate<PathParams>\n}\n\nexport enum HttpMethods {\n HEAD = 'HEAD',\n GET = 'GET',\n POST = 'POST',\n PUT = 'PUT',\n PATCH = 'PATCH',\n OPTIONS = 'OPTIONS',\n DELETE = 'DELETE',\n}\n\nexport type RequestQuery = {\n [queryName: string]: string\n}\n\nexport type HttpRequestParsedResult = {\n match: Match\n cookies: Record<string, string>\n}\n\nexport type HttpRequestResolverExtras<Params extends PathParams> = {\n params: Params\n cookies: Record<string, string>\n}\n\nexport type HttpCustomPredicate<Params extends PathParams> = (args: {\n request: Request\n cookies: Record<string, string>\n}) =>\n | HttpCustomPredicateResult<Params>\n | Promise<HttpCustomPredicateResult<Params>>\n\nexport type HttpCustomPredicateResult<Params extends PathParams> =\n | boolean\n | {\n matches: boolean\n params: Params\n }\n\nexport type HttpRequestPredicate<Params extends PathParams> =\n | Path\n | HttpCustomPredicate<Params>\n\n/**\n * Request handler for HTTP requests.\n * Provides request matching based on method and URL.\n */\nexport class HttpHandler extends RequestHandler<\n HttpHandlerInfo,\n HttpRequestParsedResult,\n HttpRequestResolverExtras<any>\n> {\n constructor(\n method: HttpHandlerMethod,\n predicate: HttpRequestPredicate<PathParams>,\n resolver: ResponseResolver<HttpRequestResolverExtras<any>, any, any>,\n options?: RequestHandlerOptions,\n ) {\n const displayPath =\n typeof predicate === 'function' ? '[custom predicate]' : predicate\n\n super({\n info: {\n header: `${method}${displayPath ? ` ${displayPath}` : ''}`,\n path: predicate,\n method,\n },\n resolver,\n options,\n })\n\n this.checkRedundantQueryParameters()\n }\n\n private checkRedundantQueryParameters() {\n const { method, path } = this.info\n\n if (!path || path instanceof RegExp || typeof path === 'function') {\n return\n }\n\n const url = cleanUrl(path)\n\n // Bypass request handler URLs that have no redundant characters.\n if (url === path) {\n return\n }\n\n const searchParams = getSearchParams(path)\n const queryParams: Array<string> = []\n\n searchParams.forEach((_, paramName) => {\n queryParams.push(paramName)\n })\n\n devUtils.warn(\n `Found a redundant usage of query parameters in the request handler URL for \"${method} ${path}\". Please match against a path instead and access query parameters using \"new URL(request.url).searchParams\" instead. Learn more: https://mswjs.io/docs/http/intercepting-requests#querysearch-parameters`,\n )\n }\n\n async parse(args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }) {\n const url = new URL(args.request.url)\n const cookies = getAllRequestCookies(args.request)\n\n /**\n * Handle custom predicate functions.\n * @note Invoke this during parsing so the user can parse the path parameters\n * manually. Otherwise, `params` is always an empty object, which isn't nice.\n */\n if (typeof this.info.path === 'function') {\n const customPredicateResult = await this.info.path({\n request: args.request,\n cookies,\n })\n\n const match =\n typeof customPredicateResult === 'boolean'\n ? {\n matches: customPredicateResult,\n params: {},\n }\n : customPredicateResult\n\n return {\n match,\n cookies,\n }\n }\n\n const match = this.info.path\n ? matchRequestUrl(url, this.info.path, args.resolutionContext?.baseUrl)\n : { matches: false, params: {} }\n\n return {\n match,\n cookies,\n }\n }\n\n async predicate(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n resolutionContext?: ResponseResolutionContext\n }) {\n const hasMatchingMethod = this.matchMethod(args.request.method)\n const hasMatchingUrl = args.parsedResult.match.matches\n return hasMatchingMethod && hasMatchingUrl\n }\n\n private matchMethod(actualMethod: string): boolean {\n return this.info.method instanceof RegExp\n ? this.info.method.test(actualMethod)\n : isStringEqual(this.info.method, actualMethod)\n }\n\n protected extendResolverArgs(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n }) {\n return {\n params: args.parsedResult.match?.params || {},\n cookies: args.parsedResult.cookies,\n }\n }\n\n async log(args: { request: Request; response: Response }) {\n const publicUrl = toPublicUrl(args.request.url)\n const loggedRequest = await serializeRequest(args.request)\n const loggedResponse = await serializeResponse(args.response)\n const statusColor = getStatusCodeColor(loggedResponse.status)\n\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} ${args.request.method} ${publicUrl} (%c${\n loggedResponse.status\n } ${loggedResponse.statusText}%c)`,\n ),\n `color:${statusColor}`,\n 'color:inherit',\n )\n // eslint-disable-next-line no-console\n console.log('Request', loggedRequest)\n // eslint-disable-next-line no-console\n console.log('Handler:', this)\n // eslint-disable-next-line no-console\n console.log('Response', loggedResponse)\n console.groupEnd()\n }\n}\n"],"mappings":"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","names":["HttpMethods","match"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/handlers/HttpHandler.ts"],"sourcesContent":["import { ResponseResolutionContext } from '../utils/executeHandlers'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { isStringEqual } from '../utils/internal/isStringEqual'\nimport { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'\nimport { getTimestamp } from '../utils/logging/getTimestamp'\nimport { serializeRequest } from '../utils/logging/serializeRequest'\nimport { serializeResponse } from '../utils/logging/serializeResponse'\nimport {\n matchRequestUrl,\n Match,\n Path,\n PathParams,\n} from '../utils/matching/matchRequestUrl'\nimport { toPublicUrl } from '../utils/request/toPublicUrl'\nimport { getAllRequestCookies } from '../utils/request/getRequestCookies'\nimport { cleanUrl, getSearchParams } from '../utils/url/cleanUrl'\nimport {\n RequestHandler,\n RequestHandlerDefaultInfo,\n RequestHandlerOptions,\n ResponseResolver,\n} from './RequestHandler'\n\ntype HttpHandlerMethod = string | RegExp\n\nexport interface HttpHandlerInfo extends RequestHandlerDefaultInfo {\n method: HttpHandlerMethod\n path: HttpRequestPredicate<PathParams>\n}\n\nexport enum HttpMethods {\n HEAD = 'HEAD',\n GET = 'GET',\n POST = 'POST',\n PUT = 'PUT',\n PATCH = 'PATCH',\n OPTIONS = 'OPTIONS',\n DELETE = 'DELETE',\n}\n\nexport type RequestQuery = {\n [queryName: string]: string\n}\n\nexport type HttpRequestParsedResult = {\n match: Match\n cookies: Record<string, string>\n}\n\nexport type HttpRequestResolverExtras<Params extends PathParams> = {\n params: Params\n cookies: Record<string, string>\n}\n\nexport type HttpCustomPredicate<Params extends PathParams> = (args: {\n request: Request\n cookies: Record<string, string>\n}) =>\n | HttpCustomPredicateResult<Params>\n | Promise<HttpCustomPredicateResult<Params>>\n\nexport type HttpCustomPredicateResult<Params extends PathParams> =\n | boolean\n | {\n matches: boolean\n params: Params\n }\n\nexport type HttpRequestPredicate<Params extends PathParams> =\n | Path\n | HttpCustomPredicate<Params>\n\n/**\n * Request handler for HTTP requests.\n * Provides request matching based on method and URL.\n */\nexport class HttpHandler extends RequestHandler<\n HttpHandlerInfo,\n HttpRequestParsedResult,\n HttpRequestResolverExtras<any>\n> {\n constructor(\n method: HttpHandlerMethod,\n predicate: HttpRequestPredicate<PathParams>,\n resolver: ResponseResolver<HttpRequestResolverExtras<any>, any, any>,\n options?: RequestHandlerOptions,\n ) {\n const displayPath =\n typeof predicate === 'function' ? '[custom predicate]' : predicate\n\n super({\n info: {\n header: `${method}${displayPath ? ` ${displayPath}` : ''}`,\n path: predicate,\n method,\n },\n resolver,\n options,\n })\n\n this.checkRedundantQueryParameters()\n }\n\n private checkRedundantQueryParameters() {\n const { method, path } = this.info\n\n if (!path || path instanceof RegExp || typeof path === 'function') {\n return\n }\n\n const url = cleanUrl(path)\n\n // Bypass request handler URLs that have no redundant characters.\n if (url === path) {\n return\n }\n\n const searchParams = getSearchParams(path)\n const queryParams: Array<string> = []\n\n searchParams.forEach((_, paramName) => {\n queryParams.push(paramName)\n })\n\n devUtils.warn(\n `Found a redundant usage of query parameters in the request handler URL for \"${method} ${path}\". Please match against a path instead and access query parameters using \"new URL(request.url).searchParams\" instead. Learn more: https://mswjs.io/docs/http/intercepting-requests#querysearch-parameters`,\n )\n }\n\n async parse(args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }) {\n const url = new URL(args.request.url)\n const cookies = getAllRequestCookies(args.request)\n\n /**\n * Handle custom predicate functions.\n * @note Invoke this during parsing so the user can parse the path parameters\n * manually. Otherwise, `params` is always an empty object, which isn't nice.\n */\n if (typeof this.info.path === 'function') {\n const customPredicateResult = await this.info.path({\n request: args.request,\n cookies,\n })\n\n const match =\n typeof customPredicateResult === 'boolean'\n ? {\n matches: customPredicateResult,\n params: {},\n }\n : customPredicateResult\n\n return {\n match,\n cookies,\n }\n }\n\n const match = this.info.path\n ? matchRequestUrl(url, this.info.path, args.resolutionContext?.baseUrl)\n : { matches: false, params: {} }\n\n return {\n match,\n cookies,\n }\n }\n\n async predicate(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n resolutionContext?: ResponseResolutionContext\n }) {\n const hasMatchingMethod = this.matchMethod(args.request.method)\n const hasMatchingUrl = args.parsedResult.match.matches\n return hasMatchingMethod && hasMatchingUrl\n }\n\n private matchMethod(actualMethod: string): boolean {\n return this.info.method instanceof RegExp\n ? this.info.method.test(actualMethod)\n : isStringEqual(this.info.method, actualMethod)\n }\n\n protected extendResolverArgs(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n }) {\n return {\n params: args.parsedResult.match?.params || {},\n cookies: args.parsedResult.cookies,\n }\n }\n\n async log(args: { request: Request; response: Response }) {\n const publicUrl = toPublicUrl(args.request.url)\n const loggedRequest = await serializeRequest(args.request)\n const loggedResponse = await serializeResponse(args.response)\n const statusColor = getStatusCodeColor(loggedResponse.status)\n\n
|
|
1
|
+
{"version":3,"sources":["../../../src/core/handlers/HttpHandler.ts"],"sourcesContent":["import { ResponseResolutionContext } from '../utils/executeHandlers'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { isStringEqual } from '../utils/internal/isStringEqual'\nimport { getStatusCodeColor } from '../utils/logging/getStatusCodeColor'\nimport { getTimestamp } from '../utils/logging/getTimestamp'\nimport { serializeRequest } from '../utils/logging/serializeRequest'\nimport { serializeResponse } from '../utils/logging/serializeResponse'\nimport {\n matchRequestUrl,\n Match,\n Path,\n PathParams,\n} from '../utils/matching/matchRequestUrl'\nimport { toPublicUrl } from '../utils/request/toPublicUrl'\nimport { getAllRequestCookies } from '../utils/request/getRequestCookies'\nimport { cleanUrl, getSearchParams } from '../utils/url/cleanUrl'\nimport {\n RequestHandler,\n RequestHandlerDefaultInfo,\n RequestHandlerOptions,\n ResponseResolver,\n} from './RequestHandler'\n\ntype HttpHandlerMethod = string | RegExp\n\nexport interface HttpHandlerInfo extends RequestHandlerDefaultInfo {\n method: HttpHandlerMethod\n path: HttpRequestPredicate<PathParams>\n}\n\nexport enum HttpMethods {\n HEAD = 'HEAD',\n GET = 'GET',\n POST = 'POST',\n PUT = 'PUT',\n PATCH = 'PATCH',\n OPTIONS = 'OPTIONS',\n DELETE = 'DELETE',\n}\n\nexport type RequestQuery = {\n [queryName: string]: string\n}\n\nexport type HttpRequestParsedResult = {\n match: Match\n cookies: Record<string, string>\n}\n\nexport type HttpRequestResolverExtras<Params extends PathParams> = {\n params: Params\n cookies: Record<string, string>\n}\n\nexport type HttpCustomPredicate<Params extends PathParams> = (args: {\n request: Request\n cookies: Record<string, string>\n}) =>\n | HttpCustomPredicateResult<Params>\n | Promise<HttpCustomPredicateResult<Params>>\n\nexport type HttpCustomPredicateResult<Params extends PathParams> =\n | boolean\n | {\n matches: boolean\n params: Params\n }\n\nexport type HttpRequestPredicate<Params extends PathParams> =\n | Path\n | HttpCustomPredicate<Params>\n\n/**\n * Request handler for HTTP requests.\n * Provides request matching based on method and URL.\n */\nexport class HttpHandler extends RequestHandler<\n HttpHandlerInfo,\n HttpRequestParsedResult,\n HttpRequestResolverExtras<any>\n> {\n constructor(\n method: HttpHandlerMethod,\n predicate: HttpRequestPredicate<PathParams>,\n resolver: ResponseResolver<HttpRequestResolverExtras<any>, any, any>,\n options?: RequestHandlerOptions,\n ) {\n const displayPath =\n typeof predicate === 'function' ? '[custom predicate]' : predicate\n\n super({\n info: {\n header: `${method}${displayPath ? ` ${displayPath}` : ''}`,\n path: predicate,\n method,\n },\n resolver,\n options,\n })\n\n this.checkRedundantQueryParameters()\n }\n\n private checkRedundantQueryParameters() {\n const { method, path } = this.info\n\n if (!path || path instanceof RegExp || typeof path === 'function') {\n return\n }\n\n const url = cleanUrl(path)\n\n // Bypass request handler URLs that have no redundant characters.\n if (url === path) {\n return\n }\n\n const searchParams = getSearchParams(path)\n const queryParams: Array<string> = []\n\n searchParams.forEach((_, paramName) => {\n queryParams.push(paramName)\n })\n\n devUtils.warn(\n `Found a redundant usage of query parameters in the request handler URL for \"${method} ${path}\". Please match against a path instead and access query parameters using \"new URL(request.url).searchParams\" instead. Learn more: https://mswjs.io/docs/http/intercepting-requests#querysearch-parameters`,\n )\n }\n\n async parse(args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }) {\n const url = new URL(args.request.url)\n const cookies = getAllRequestCookies(args.request)\n\n /**\n * Handle custom predicate functions.\n * @note Invoke this during parsing so the user can parse the path parameters\n * manually. Otherwise, `params` is always an empty object, which isn't nice.\n */\n if (typeof this.info.path === 'function') {\n const customPredicateResult = await this.info.path({\n request: args.request,\n cookies,\n })\n\n const match =\n typeof customPredicateResult === 'boolean'\n ? {\n matches: customPredicateResult,\n params: {},\n }\n : customPredicateResult\n\n return {\n match,\n cookies,\n }\n }\n\n const match = this.info.path\n ? matchRequestUrl(url, this.info.path, args.resolutionContext?.baseUrl)\n : { matches: false, params: {} }\n\n return {\n match,\n cookies,\n }\n }\n\n async predicate(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n resolutionContext?: ResponseResolutionContext\n }) {\n const hasMatchingMethod = this.matchMethod(args.request.method)\n const hasMatchingUrl = args.parsedResult.match.matches\n return hasMatchingMethod && hasMatchingUrl\n }\n\n private matchMethod(actualMethod: string): boolean {\n return this.info.method instanceof RegExp\n ? this.info.method.test(actualMethod)\n : isStringEqual(this.info.method, actualMethod)\n }\n\n protected extendResolverArgs(args: {\n request: Request\n parsedResult: HttpRequestParsedResult\n }) {\n return {\n params: args.parsedResult.match?.params || {},\n cookies: args.parsedResult.cookies,\n }\n }\n\n async log(args: { request: Request; response: Response }) {\n const publicUrl = toPublicUrl(args.request.url)\n const loggedRequest = await serializeRequest(args.request)\n const loggedResponse = await serializeResponse(args.response)\n const statusColor = getStatusCodeColor(loggedResponse.status)\n\n console.groupCollapsed(\n devUtils.formatMessage(\n `${getTimestamp()} ${args.request.method} ${publicUrl} (%c${\n loggedResponse.status\n } ${loggedResponse.statusText}%c)`,\n ),\n `color:${statusColor}`,\n 'color:inherit',\n )\n // eslint-disable-next-line no-console\n console.log('Request', loggedRequest)\n // eslint-disable-next-line no-console\n console.log('Handler:', this)\n // eslint-disable-next-line no-console\n console.log('Response', loggedResponse)\n console.groupEnd()\n }\n}\n"],"mappings":"AACA,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAC9B,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AACjC,SAAS,yBAAyB;AAClC;AAAA,EACE;AAAA,OAIK;AACP,SAAS,mBAAmB;AAC5B,SAAS,4BAA4B;AACrC,SAAS,UAAU,uBAAuB;AAC1C;AAAA,EACE;AAAA,OAIK;AASA,IAAK,cAAL,kBAAKA,iBAAL;AACL,EAAAA,aAAA,UAAO;AACP,EAAAA,aAAA,SAAM;AACN,EAAAA,aAAA,UAAO;AACP,EAAAA,aAAA,SAAM;AACN,EAAAA,aAAA,WAAQ;AACR,EAAAA,aAAA,aAAU;AACV,EAAAA,aAAA,YAAS;AAPC,SAAAA;AAAA,GAAA;AA8CL,MAAM,oBAAoB,eAI/B;AAAA,EACA,YACE,QACA,WACA,UACA,SACA;AACA,UAAM,cACJ,OAAO,cAAc,aAAa,uBAAuB;AAE3D,UAAM;AAAA,MACJ,MAAM;AAAA,QACJ,QAAQ,GAAG,MAAM,GAAG,cAAc,IAAI,WAAW,KAAK,EAAE;AAAA,QACxD,MAAM;AAAA,QACN;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,8BAA8B;AAAA,EACrC;AAAA,EAEQ,gCAAgC;AACtC,UAAM,EAAE,QAAQ,KAAK,IAAI,KAAK;AAE9B,QAAI,CAAC,QAAQ,gBAAgB,UAAU,OAAO,SAAS,YAAY;AACjE;AAAA,IACF;AAEA,UAAM,MAAM,SAAS,IAAI;AAGzB,QAAI,QAAQ,MAAM;AAChB;AAAA,IACF;AAEA,UAAM,eAAe,gBAAgB,IAAI;AACzC,UAAM,cAA6B,CAAC;AAEpC,iBAAa,QAAQ,CAAC,GAAG,cAAc;AACrC,kBAAY,KAAK,SAAS;AAAA,IAC5B,CAAC;AAED,aAAS;AAAA,MACP,+EAA+E,MAAM,IAAI,IAAI;AAAA,IAC/F;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,MAGT;AACD,UAAM,MAAM,IAAI,IAAI,KAAK,QAAQ,GAAG;AACpC,UAAM,UAAU,qBAAqB,KAAK,OAAO;AAOjD,QAAI,OAAO,KAAK,KAAK,SAAS,YAAY;AACxC,YAAM,wBAAwB,MAAM,KAAK,KAAK,KAAK;AAAA,QACjD,SAAS,KAAK;AAAA,QACd;AAAA,MACF,CAAC;AAED,YAAMC,SACJ,OAAO,0BAA0B,YAC7B;AAAA,QACE,SAAS;AAAA,QACT,QAAQ,CAAC;AAAA,MACX,IACA;AAEN,aAAO;AAAA,QACL,OAAAA;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,KAAK,OACpB,gBAAgB,KAAK,KAAK,KAAK,MAAM,KAAK,mBAAmB,OAAO,IACpE,EAAE,SAAS,OAAO,QAAQ,CAAC,EAAE;AAEjC,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,MAIb;AACD,UAAM,oBAAoB,KAAK,YAAY,KAAK,QAAQ,MAAM;AAC9D,UAAM,iBAAiB,KAAK,aAAa,MAAM;AAC/C,WAAO,qBAAqB;AAAA,EAC9B;AAAA,EAEQ,YAAY,cAA+B;AACjD,WAAO,KAAK,KAAK,kBAAkB,SAC/B,KAAK,KAAK,OAAO,KAAK,YAAY,IAClC,cAAc,KAAK,KAAK,QAAQ,YAAY;AAAA,EAClD;AAAA,EAEU,mBAAmB,MAG1B;AACD,WAAO;AAAA,MACL,QAAQ,KAAK,aAAa,OAAO,UAAU,CAAC;AAAA,MAC5C,SAAS,KAAK,aAAa;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,MAAgD;AACxD,UAAM,YAAY,YAAY,KAAK,QAAQ,GAAG;AAC9C,UAAM,gBAAgB,MAAM,iBAAiB,KAAK,OAAO;AACzD,UAAM,iBAAiB,MAAM,kBAAkB,KAAK,QAAQ;AAC5D,UAAM,cAAc,mBAAmB,eAAe,MAAM;AAE5D,YAAQ;AAAA,MACN,SAAS;AAAA,QACP,GAAG,aAAa,CAAC,IAAI,KAAK,QAAQ,MAAM,IAAI,SAAS,OACnD,eAAe,MACjB,IAAI,eAAe,UAAU;AAAA,MAC/B;AAAA,MACA,SAAS,WAAW;AAAA,MACpB;AAAA,IACF;AAEA,YAAQ,IAAI,WAAW,aAAa;AAEpC,YAAQ,IAAI,YAAY,IAAI;AAE5B,YAAQ,IAAI,YAAY,cAAc;AACtC,YAAQ,SAAS;AAAA,EACnB;AACF;","names":["HttpMethods","match"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/internal/devUtils.ts"],"sourcesContent":["import { format } from 'outvariant'\n\nconst LIBRARY_PREFIX = '[MSW]'\n\n/**\n * Formats a given message by appending the library's prefix string.\n */\nfunction formatMessage(message: string, ...positionals: any[]): string {\n const interpolatedMessage = format(message, ...positionals)\n return `${LIBRARY_PREFIX} ${interpolatedMessage}`\n}\n\n/**\n * Prints a library-specific warning.\n */\nfunction warn(message: string, ...positionals: any[]): void {\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/internal/devUtils.ts"],"sourcesContent":["import { format } from 'outvariant'\n\nconst LIBRARY_PREFIX = '[MSW]'\n\n/**\n * Formats a given message by appending the library's prefix string.\n */\nfunction formatMessage(message: string, ...positionals: any[]): string {\n const interpolatedMessage = format(message, ...positionals)\n return `${LIBRARY_PREFIX} ${interpolatedMessage}`\n}\n\n/**\n * Prints a library-specific warning.\n */\nfunction warn(message: string, ...positionals: any[]): void {\n console.warn(formatMessage(message, ...positionals))\n}\n\n/**\n * Prints a library-specific error.\n */\nfunction error(message: string, ...positionals: any[]): void {\n console.error(formatMessage(message, ...positionals))\n}\n\nexport const devUtils = {\n formatMessage,\n warn,\n error,\n}\n\n/**\n * Internal error instance.\n * Used to differentiate the library errors that must be forwarded\n * to the user from the unhandled exceptions. Use this if you don't\n * wish for the error to be coerced to a 500 fallback response.\n */\nexport class InternalError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InternalError'\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAuB;AAEvB,MAAM,iBAAiB;AAKvB,SAAS,cAAc,YAAoB,aAA4B;AACrE,QAAM,0BAAsB,0BAAO,SAAS,GAAG,WAAW;AAC1D,SAAO,GAAG,cAAc,IAAI,mBAAmB;AACjD;AAKA,SAAS,KAAK,YAAoB,aAA0B;AAC1D,UAAQ,KAAK,cAAc,SAAS,GAAG,WAAW,CAAC;AACrD;AAKA,SAAS,MAAM,YAAoB,aAA0B;AAC3D,UAAQ,MAAM,cAAc,SAAS,GAAG,WAAW,CAAC;AACtD;AAEO,MAAM,WAAW;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF;AAQO,MAAM,sBAAsB,MAAM;AAAA,EACvC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/internal/devUtils.ts"],"sourcesContent":["import { format } from 'outvariant'\n\nconst LIBRARY_PREFIX = '[MSW]'\n\n/**\n * Formats a given message by appending the library's prefix string.\n */\nfunction formatMessage(message: string, ...positionals: any[]): string {\n const interpolatedMessage = format(message, ...positionals)\n return `${LIBRARY_PREFIX} ${interpolatedMessage}`\n}\n\n/**\n * Prints a library-specific warning.\n */\nfunction warn(message: string, ...positionals: any[]): void {\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/internal/devUtils.ts"],"sourcesContent":["import { format } from 'outvariant'\n\nconst LIBRARY_PREFIX = '[MSW]'\n\n/**\n * Formats a given message by appending the library's prefix string.\n */\nfunction formatMessage(message: string, ...positionals: any[]): string {\n const interpolatedMessage = format(message, ...positionals)\n return `${LIBRARY_PREFIX} ${interpolatedMessage}`\n}\n\n/**\n * Prints a library-specific warning.\n */\nfunction warn(message: string, ...positionals: any[]): void {\n console.warn(formatMessage(message, ...positionals))\n}\n\n/**\n * Prints a library-specific error.\n */\nfunction error(message: string, ...positionals: any[]): void {\n console.error(formatMessage(message, ...positionals))\n}\n\nexport const devUtils = {\n formatMessage,\n warn,\n error,\n}\n\n/**\n * Internal error instance.\n * Used to differentiate the library errors that must be forwarded\n * to the user from the unhandled exceptions. Use this if you don't\n * wish for the error to be coerced to a 500 fallback response.\n */\nexport class InternalError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InternalError'\n }\n}\n"],"mappings":"AAAA,SAAS,cAAc;AAEvB,MAAM,iBAAiB;AAKvB,SAAS,cAAc,YAAoB,aAA4B;AACrE,QAAM,sBAAsB,OAAO,SAAS,GAAG,WAAW;AAC1D,SAAO,GAAG,cAAc,IAAI,mBAAmB;AACjD;AAKA,SAAS,KAAK,YAAoB,aAA0B;AAC1D,UAAQ,KAAK,cAAc,SAAS,GAAG,WAAW,CAAC;AACrD;AAKA,SAAS,MAAM,YAAoB,aAA0B;AAC3D,UAAQ,MAAM,cAAc,SAAS,GAAG,WAAW,CAAC;AACtD;AAEO,MAAM,WAAW;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF;AAQO,MAAM,sBAAsB,MAAM;AAAA,EACvC,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;","names":[]}
|
|
@@ -21,8 +21,8 @@ __export(getCallFrame_exports, {
|
|
|
21
21
|
getCallFrame: () => getCallFrame
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(getCallFrame_exports);
|
|
24
|
-
const SOURCE_FRAME = /[
|
|
25
|
-
const BUILD_FRAME = /(node_modules)?[
|
|
24
|
+
const SOURCE_FRAME = /[/\\]msw[/\\]src[/\\](.+)/;
|
|
25
|
+
const BUILD_FRAME = /(node_modules)?[/\\]lib[/\\](core|browser|node|native|iife)[/\\]|^[^/\\]*$/;
|
|
26
26
|
function getCallFrame(error) {
|
|
27
27
|
const stack = error.stack;
|
|
28
28
|
if (!stack) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/internal/getCallFrame.ts"],"sourcesContent":["// Ignore the source files traces for local testing.\nconst SOURCE_FRAME = /[
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/internal/getCallFrame.ts"],"sourcesContent":["// Ignore the source files traces for local testing.\nconst SOURCE_FRAME = /[/\\\\]msw[/\\\\]src[/\\\\](.+)/\n\nconst BUILD_FRAME =\n /(node_modules)?[/\\\\]lib[/\\\\](core|browser|node|native|iife)[/\\\\]|^[^/\\\\]*$/\n\n/**\n * Return the stack trace frame of a function's invocation.\n */\nexport function getCallFrame(error: Error) {\n // In <IE11, new Error may return an undefined stack\n const stack = error.stack\n\n if (!stack) {\n return\n }\n\n const frames: string[] = stack.split('\\n').slice(1)\n\n // Get the first frame that doesn't reference the library's internal trace.\n // Assume that frame is the invocation frame.\n const declarationFrame = frames.find((frame) => {\n return !(SOURCE_FRAME.test(frame) || BUILD_FRAME.test(frame))\n })\n\n if (!declarationFrame) {\n return\n }\n\n // Extract file reference from the stack frame.\n const declarationPath = declarationFrame\n .replace(/\\s*at [^()]*\\(([^)]+)\\)/, '$1')\n .replace(/^@/, '')\n return declarationPath\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,MAAM,eAAe;AAErB,MAAM,cACJ;AAKK,SAAS,aAAa,OAAc;AAEzC,QAAM,QAAQ,MAAM;AAEpB,MAAI,CAAC,OAAO;AACV;AAAA,EACF;AAEA,QAAM,SAAmB,MAAM,MAAM,IAAI,EAAE,MAAM,CAAC;AAIlD,QAAM,mBAAmB,OAAO,KAAK,CAAC,UAAU;AAC9C,WAAO,EAAE,aAAa,KAAK,KAAK,KAAK,YAAY,KAAK,KAAK;AAAA,EAC7D,CAAC;AAED,MAAI,CAAC,kBAAkB;AACrB;AAAA,EACF;AAGA,QAAM,kBAAkB,iBACrB,QAAQ,2BAA2B,IAAI,EACvC,QAAQ,MAAM,EAAE;AACnB,SAAO;AACT;","names":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const SOURCE_FRAME = /[
|
|
2
|
-
const BUILD_FRAME = /(node_modules)?[
|
|
1
|
+
const SOURCE_FRAME = /[/\\]msw[/\\]src[/\\](.+)/;
|
|
2
|
+
const BUILD_FRAME = /(node_modules)?[/\\]lib[/\\](core|browser|node|native|iife)[/\\]|^[^/\\]*$/;
|
|
3
3
|
function getCallFrame(error) {
|
|
4
4
|
const stack = error.stack;
|
|
5
5
|
if (!stack) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/internal/getCallFrame.ts"],"sourcesContent":["// Ignore the source files traces for local testing.\nconst SOURCE_FRAME = /[
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/internal/getCallFrame.ts"],"sourcesContent":["// Ignore the source files traces for local testing.\nconst SOURCE_FRAME = /[/\\\\]msw[/\\\\]src[/\\\\](.+)/\n\nconst BUILD_FRAME =\n /(node_modules)?[/\\\\]lib[/\\\\](core|browser|node|native|iife)[/\\\\]|^[^/\\\\]*$/\n\n/**\n * Return the stack trace frame of a function's invocation.\n */\nexport function getCallFrame(error: Error) {\n // In <IE11, new Error may return an undefined stack\n const stack = error.stack\n\n if (!stack) {\n return\n }\n\n const frames: string[] = stack.split('\\n').slice(1)\n\n // Get the first frame that doesn't reference the library's internal trace.\n // Assume that frame is the invocation frame.\n const declarationFrame = frames.find((frame) => {\n return !(SOURCE_FRAME.test(frame) || BUILD_FRAME.test(frame))\n })\n\n if (!declarationFrame) {\n return\n }\n\n // Extract file reference from the stack frame.\n const declarationPath = declarationFrame\n .replace(/\\s*at [^()]*\\(([^)]+)\\)/, '$1')\n .replace(/^@/, '')\n return declarationPath\n}\n"],"mappings":"AACA,MAAM,eAAe;AAErB,MAAM,cACJ;AAKK,SAAS,aAAa,OAAc;AAEzC,QAAM,QAAQ,MAAM;AAEpB,MAAI,CAAC,OAAO;AACV;AAAA,EACF;AAEA,QAAM,SAAmB,MAAM,MAAM,IAAI,EAAE,MAAM,CAAC;AAIlD,QAAM,mBAAmB,OAAO,KAAK,CAAC,UAAU;AAC9C,WAAO,EAAE,aAAa,KAAK,KAAK,KAAK,YAAY,KAAK,KAAK;AAAA,EAC7D,CAAC;AAED,MAAI,CAAC,kBAAkB;AACrB;AAAA,EACF;AAGA,QAAM,kBAAkB,iBACrB,QAAQ,2BAA2B,IAAI,EACvC,QAAQ,MAAM,EAAE;AACnB,SAAO;AACT;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/internal/parseGraphQLRequest.ts"],"sourcesContent":["import type {\n DocumentNode,\n OperationDefinitionNode,\n OperationTypeNode,\n} from 'graphql'\nimport type { GraphQLVariables } from '../../handlers/GraphQLHandler'\nimport { toPublicUrl } from '../request/toPublicUrl'\nimport { devUtils } from './devUtils'\nimport { jsonParse } from './jsonParse'\nimport { parseMultipartData } from './parseMultipartData'\n\ninterface GraphQLInput {\n query: string | null\n variables?: GraphQLVariables\n}\n\nexport interface ParsedGraphQLQuery {\n operationType: OperationTypeNode\n operationName?: string\n}\n\nexport type ParsedGraphQLRequest<\n VariablesType extends GraphQLVariables = GraphQLVariables,\n> =\n | (ParsedGraphQLQuery & {\n query: string\n variables?: VariablesType\n })\n | undefined\n\nexport function parseDocumentNode(node: DocumentNode): ParsedGraphQLQuery {\n const operationDef = node.definitions.find((definition) => {\n return definition.kind === 'OperationDefinition'\n }) as OperationDefinitionNode\n\n return {\n operationType: operationDef?.operation,\n operationName: operationDef?.name?.value,\n }\n}\n\nasync function parseQuery(query: string): Promise<ParsedGraphQLQuery | Error> {\n /**\n * @note Use `require` to get the \"graphql\" module here.\n * It has to be scoped to this function because this module leaks to the\n * root export. It has to be `require` because tools like Jest have trouble\n * handling dynamic imports. It gets replaced with a dynamic import on build time.\n */\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { parse } = require('graphql')\n\n try {\n const ast = parse(query)\n return parseDocumentNode(ast)\n } catch (error) {\n return error as Error\n }\n}\n\nexport type GraphQLParsedOperationsMap = Record<string, string[]>\nexport type GraphQLMultipartRequestBody = {\n operations: string\n map?: string\n} & {\n [fileName: string]: File\n}\n\nfunction extractMultipartVariables<VariablesType extends GraphQLVariables>(\n variables: VariablesType,\n map: GraphQLParsedOperationsMap,\n files: Record<string, File>,\n) {\n const operations = { variables }\n\n for (const [key, pathArray] of Object.entries(map)) {\n if (!(key in files)) {\n throw new Error(`Given files do not have a key '${key}' .`)\n }\n\n for (const dotPath of pathArray) {\n const [lastPath, ...reversedPaths] = dotPath.split('.').reverse()\n const paths = reversedPaths.reverse()\n let target: Record<string, any> = operations\n\n for (const path of paths) {\n if (!(path in target)) {\n throw new Error(`Property '${paths}' is not in operations.`)\n }\n\n target = target[path]\n }\n\n target[lastPath] = files[key]\n }\n }\n\n return operations.variables\n}\n\nasync function getGraphQLInput(request: Request): Promise<GraphQLInput | null> {\n switch (request.method) {\n case 'GET': {\n const url = new URL(request.url)\n const query = url.searchParams.get('query')\n const variables = url.searchParams.get('variables') || ''\n\n return {\n query,\n variables: jsonParse(variables),\n }\n }\n\n case 'POST': {\n // Clone the request so we could read its body without locking\n // the body stream to the downward consumers.\n const requestClone = request.clone()\n\n // Handle multipart body GraphQL operations.\n if (\n request.headers.get('content-type')?.includes('multipart/form-data')\n ) {\n const responseJson = parseMultipartData<GraphQLMultipartRequestBody>(\n await requestClone.text(),\n request.headers,\n )\n\n if (!responseJson) {\n return null\n }\n\n const { operations, map, ...files } = responseJson\n const parsedOperations =\n jsonParse<{ query?: string; variables?: GraphQLVariables }>(\n operations,\n ) || {}\n\n if (!parsedOperations.query) {\n return null\n }\n\n const parsedMap = jsonParse<GraphQLParsedOperationsMap>(map || '') || {}\n const variables = parsedOperations.variables\n ? extractMultipartVariables(\n parsedOperations.variables,\n parsedMap,\n files,\n )\n : {}\n\n return {\n query: parsedOperations.query,\n variables,\n }\n }\n\n // Handle plain POST GraphQL operations.\n const requestJson: {\n query: string\n variables?: GraphQLVariables\n operations?: any /** @todo Annotate this */\n } = await requestClone.json().catch(() => null)\n\n if (requestJson?.query) {\n const { query, variables } = requestJson\n\n return {\n query,\n variables,\n }\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Determines if a given request can be considered a GraphQL request.\n * Does not parse the query and does not guarantee its validity.\n */\nexport async function parseGraphQLRequest(\n request: Request,\n): Promise<ParsedGraphQLRequest> {\n const input = await getGraphQLInput(request)\n\n if (!input || !input.query) {\n return\n }\n\n const { query, variables } = input\n const parsedResult = await parseQuery(query)\n\n if (parsedResult instanceof Error) {\n const requestPublicUrl = toPublicUrl(request.url)\n\n throw new Error(\n devUtils.formatMessage(\n 'Failed to intercept a GraphQL request to \"%s %s\": cannot parse query. See the error message from the parser below.\\n\\n%s',\n request.method,\n requestPublicUrl,\n parsedResult.message,\n ),\n )\n }\n\n return {\n query: input.query,\n operationType: parsedResult.operationType,\n operationName: parsedResult.operationName,\n variables,\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA,yBAA4B;AAC5B,sBAAyB;AACzB,uBAA0B;AAC1B,gCAAmC;AAqB5B,SAAS,kBAAkB,MAAwC;AACxE,QAAM,eAAe,KAAK,YAAY,KAAK,CAAC,eAAe;AACzD,WAAO,WAAW,SAAS;AAAA,EAC7B,CAAC;AAED,SAAO;AAAA,IACL,eAAe,cAAc;AAAA,IAC7B,eAAe,cAAc,MAAM;AAAA,EACrC;AACF;AAEA,eAAe,WAAW,OAAoD;AAQ5E,QAAM,EAAE,MAAM,IAAI,QAAQ,SAAS;AAEnC,MAAI;AACF,UAAM,MAAM,MAAM,KAAK;AACvB,WAAO,kBAAkB,GAAG;AAAA,EAC9B,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAUA,SAAS,0BACP,WACA,KACA,OACA;AACA,QAAM,aAAa,EAAE,UAAU;AAE/B,aAAW,CAAC,KAAK,SAAS,KAAK,OAAO,QAAQ,GAAG,GAAG;AAClD,QAAI,EAAE,OAAO,QAAQ;AACnB,YAAM,IAAI,MAAM,kCAAkC,GAAG,KAAK;AAAA,IAC5D;AAEA,eAAW,WAAW,WAAW;AAC/B,YAAM,CAAC,UAAU,GAAG,aAAa,IAAI,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAChE,YAAM,QAAQ,cAAc,QAAQ;AACpC,UAAI,SAA8B;AAElC,iBAAW,QAAQ,OAAO;AACxB,YAAI,EAAE,QAAQ,SAAS;AACrB,gBAAM,IAAI,MAAM,aAAa,KAAK,yBAAyB;AAAA,QAC7D;AAEA,iBAAS,OAAO,IAAI;AAAA,MACtB;AAEA,aAAO,QAAQ,IAAI,MAAM,GAAG;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO,WAAW;AACpB;AAEA,eAAe,gBAAgB,SAAgD;AAC7E,UAAQ,QAAQ,QAAQ;AAAA,IACtB,KAAK,OAAO;AACV,YAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,YAAM,QAAQ,IAAI,aAAa,IAAI,OAAO;AAC1C,YAAM,YAAY,IAAI,aAAa,IAAI,WAAW,KAAK;AAEvD,aAAO;AAAA,QACL;AAAA,QACA,eAAW,4BAAU,SAAS;AAAA,MAChC;AAAA,IACF;AAAA,IAEA,KAAK,QAAQ;AAGX,YAAM,eAAe,QAAQ,MAAM;AAGnC,UACE,QAAQ,QAAQ,IAAI,cAAc,GAAG,SAAS,qBAAqB,GACnE;AACA,cAAM,mBAAe;AAAA,UACnB,MAAM,aAAa,KAAK;AAAA,UACxB,QAAQ;AAAA,QACV;AAEA,YAAI,CAAC,cAAc;AACjB,iBAAO;AAAA,QACT;AAEA,cAAM,EAAE,YAAY,KAAK,GAAG,MAAM,IAAI;AACtC,cAAM,uBACJ;AAAA,UACE;AAAA,QACF,KAAK,CAAC;AAER,YAAI,CAAC,iBAAiB,OAAO;AAC3B,iBAAO;AAAA,QACT;AAEA,cAAM,gBAAY,4BAAsC,OAAO,EAAE,KAAK,CAAC;AACvE,cAAM,YAAY,iBAAiB,YAC/B;AAAA,UACE,iBAAiB;AAAA,UACjB;AAAA,UACA;AAAA,QACF,IACA,CAAC;AAEL,eAAO;AAAA,UACL,OAAO,iBAAiB;AAAA,UACxB;AAAA,QACF;AAAA,MACF;AAGA,YAAM,cAIF,MAAM,aAAa,KAAK,EAAE,MAAM,MAAM,IAAI;AAE9C,UAAI,aAAa,OAAO;AACtB,cAAM,EAAE,OAAO,UAAU,IAAI;AAE7B,eAAO;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/internal/parseGraphQLRequest.ts"],"sourcesContent":["import type {\n DocumentNode,\n OperationDefinitionNode,\n OperationTypeNode,\n} from 'graphql'\nimport type { GraphQLVariables } from '../../handlers/GraphQLHandler'\nimport { toPublicUrl } from '../request/toPublicUrl'\nimport { devUtils } from './devUtils'\nimport { jsonParse } from './jsonParse'\nimport { parseMultipartData } from './parseMultipartData'\n\ninterface GraphQLInput {\n query: string | null\n variables?: GraphQLVariables\n}\n\nexport interface ParsedGraphQLQuery {\n operationType: OperationTypeNode\n operationName?: string\n}\n\nexport type ParsedGraphQLRequest<\n VariablesType extends GraphQLVariables = GraphQLVariables,\n> =\n | (ParsedGraphQLQuery & {\n query: string\n variables?: VariablesType\n })\n | undefined\n\nexport function parseDocumentNode(node: DocumentNode): ParsedGraphQLQuery {\n const operationDef = node.definitions.find((definition) => {\n return definition.kind === 'OperationDefinition'\n }) as OperationDefinitionNode\n\n return {\n operationType: operationDef?.operation,\n operationName: operationDef?.name?.value,\n }\n}\n\nasync function parseQuery(query: string): Promise<ParsedGraphQLQuery | Error> {\n /**\n * @note Use `require` to get the \"graphql\" module here.\n * It has to be scoped to this function because this module leaks to the\n * root export. It has to be `require` because tools like Jest have trouble\n * handling dynamic imports. It gets replaced with a dynamic import on build time.\n */\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { parse } = require('graphql')\n\n try {\n const ast = parse(query)\n return parseDocumentNode(ast)\n } catch (error) {\n return error as Error\n }\n}\n\nexport type GraphQLParsedOperationsMap = Record<string, string[]>\nexport type GraphQLMultipartRequestBody = {\n operations: string\n map?: string\n} & {\n [fileName: string]: File\n}\n\nfunction extractMultipartVariables<VariablesType extends GraphQLVariables>(\n variables: VariablesType,\n map: GraphQLParsedOperationsMap,\n files: Record<string, File>,\n) {\n const operations = { variables }\n\n for (const [key, pathArray] of Object.entries(map)) {\n if (!(key in files)) {\n throw new Error(`Given files do not have a key '${key}' .`)\n }\n\n for (const dotPath of pathArray) {\n const [lastPath, ...reversedPaths] = dotPath.split('.').reverse()\n const paths = reversedPaths.reverse()\n let target: Record<string, any> = operations\n\n for (const path of paths) {\n if (!(path in target)) {\n throw new Error(`Property '${paths}' is not in operations.`)\n }\n\n target = target[path]\n }\n\n target[lastPath] = files[key]\n }\n }\n\n return operations.variables\n}\n\nasync function getGraphQLInput(request: Request): Promise<GraphQLInput | null> {\n switch (request.method) {\n case 'GET': {\n const url = new URL(request.url)\n const query = url.searchParams.get('query')\n const variables = url.searchParams.get('variables') || ''\n\n return {\n query,\n variables: jsonParse(variables),\n }\n }\n\n case 'POST': {\n // Clone the request so we could read its body without locking\n // the body stream to the downward consumers.\n const requestClone = request.clone()\n\n // Handle multipart body GraphQL operations.\n if (\n request.headers.get('content-type')?.includes('multipart/form-data')\n ) {\n const responseJson = parseMultipartData<GraphQLMultipartRequestBody>(\n await requestClone.text(),\n request.headers,\n )\n\n if (!responseJson) {\n return null\n }\n\n const { operations, map, ...files } = responseJson\n const parsedOperations =\n jsonParse<{ query?: string; variables?: GraphQLVariables }>(\n operations,\n ) || {}\n\n if (!parsedOperations.query) {\n return null\n }\n\n const parsedMap = jsonParse<GraphQLParsedOperationsMap>(map || '') || {}\n const variables = parsedOperations.variables\n ? extractMultipartVariables(\n parsedOperations.variables,\n parsedMap,\n files,\n )\n : {}\n\n return {\n query: parsedOperations.query,\n variables,\n }\n }\n\n // Handle plain POST GraphQL operations.\n const requestJson: {\n query: string\n variables?: GraphQLVariables\n operations?: any /** @todo Annotate this */\n } = await requestClone.json().catch(() => null)\n\n if (requestJson?.query) {\n const { query, variables } = requestJson\n\n return {\n query,\n variables,\n }\n }\n return null\n }\n\n default:\n return null\n }\n}\n\n/**\n * Determines if a given request can be considered a GraphQL request.\n * Does not parse the query and does not guarantee its validity.\n */\nexport async function parseGraphQLRequest(\n request: Request,\n): Promise<ParsedGraphQLRequest> {\n const input = await getGraphQLInput(request)\n\n if (!input || !input.query) {\n return\n }\n\n const { query, variables } = input\n const parsedResult = await parseQuery(query)\n\n if (parsedResult instanceof Error) {\n const requestPublicUrl = toPublicUrl(request.url)\n\n throw new Error(\n devUtils.formatMessage(\n 'Failed to intercept a GraphQL request to \"%s %s\": cannot parse query. See the error message from the parser below.\\n\\n%s',\n request.method,\n requestPublicUrl,\n parsedResult.message,\n ),\n )\n }\n\n return {\n query: input.query,\n operationType: parsedResult.operationType,\n operationName: parsedResult.operationName,\n variables,\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/internal/parseGraphQLRequest.ts"],"sourcesContent":["import type {\n DocumentNode,\n OperationDefinitionNode,\n OperationTypeNode,\n} from 'graphql'\nimport type { GraphQLVariables } from '../../handlers/GraphQLHandler'\nimport { toPublicUrl } from '../request/toPublicUrl'\nimport { devUtils } from './devUtils'\nimport { jsonParse } from './jsonParse'\nimport { parseMultipartData } from './parseMultipartData'\n\ninterface GraphQLInput {\n query: string | null\n variables?: GraphQLVariables\n}\n\nexport interface ParsedGraphQLQuery {\n operationType: OperationTypeNode\n operationName?: string\n}\n\nexport type ParsedGraphQLRequest<\n VariablesType extends GraphQLVariables = GraphQLVariables,\n> =\n | (ParsedGraphQLQuery & {\n query: string\n variables?: VariablesType\n })\n | undefined\n\nexport function parseDocumentNode(node: DocumentNode): ParsedGraphQLQuery {\n const operationDef = node.definitions.find((definition) => {\n return definition.kind === 'OperationDefinition'\n }) as OperationDefinitionNode\n\n return {\n operationType: operationDef?.operation,\n operationName: operationDef?.name?.value,\n }\n}\n\nasync function parseQuery(query: string): Promise<ParsedGraphQLQuery | Error> {\n /**\n * @note Use `require` to get the \"graphql\" module here.\n * It has to be scoped to this function because this module leaks to the\n * root export. It has to be `require` because tools like Jest have trouble\n * handling dynamic imports. It gets replaced with a dynamic import on build time.\n */\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { parse } =await import('graphql').catch((error) => {console.error('[MSW] Failed to parse a GraphQL query: cannot import the \"graphql\" module. Please make sure you install it if you wish to intercept GraphQL requests. See the original import error below.'); throw error})\n\n try {\n const ast = parse(query)\n return parseDocumentNode(ast)\n } catch (error) {\n return error as Error\n }\n}\n\nexport type GraphQLParsedOperationsMap = Record<string, string[]>\nexport type GraphQLMultipartRequestBody = {\n operations: string\n map?: string\n} & {\n [fileName: string]: File\n}\n\nfunction extractMultipartVariables<VariablesType extends GraphQLVariables>(\n variables: VariablesType,\n map: GraphQLParsedOperationsMap,\n files: Record<string, File>,\n) {\n const operations = { variables }\n\n for (const [key, pathArray] of Object.entries(map)) {\n if (!(key in files)) {\n throw new Error(`Given files do not have a key '${key}' .`)\n }\n\n for (const dotPath of pathArray) {\n const [lastPath, ...reversedPaths] = dotPath.split('.').reverse()\n const paths = reversedPaths.reverse()\n let target: Record<string, any> = operations\n\n for (const path of paths) {\n if (!(path in target)) {\n throw new Error(`Property '${paths}' is not in operations.`)\n }\n\n target = target[path]\n }\n\n target[lastPath] = files[key]\n }\n }\n\n return operations.variables\n}\n\nasync function getGraphQLInput(request: Request): Promise<GraphQLInput | null> {\n switch (request.method) {\n case 'GET': {\n const url = new URL(request.url)\n const query = url.searchParams.get('query')\n const variables = url.searchParams.get('variables') || ''\n\n return {\n query,\n variables: jsonParse(variables),\n }\n }\n\n case 'POST': {\n // Clone the request so we could read its body without locking\n // the body stream to the downward consumers.\n const requestClone = request.clone()\n\n // Handle multipart body GraphQL operations.\n if (\n request.headers.get('content-type')?.includes('multipart/form-data')\n ) {\n const responseJson = parseMultipartData<GraphQLMultipartRequestBody>(\n await requestClone.text(),\n request.headers,\n )\n\n if (!responseJson) {\n return null\n }\n\n const { operations, map, ...files } = responseJson\n const parsedOperations =\n jsonParse<{ query?: string; variables?: GraphQLVariables }>(\n operations,\n ) || {}\n\n if (!parsedOperations.query) {\n return null\n }\n\n const parsedMap = jsonParse<GraphQLParsedOperationsMap>(map || '') || {}\n const variables = parsedOperations.variables\n ? extractMultipartVariables(\n parsedOperations.variables,\n parsedMap,\n files,\n )\n : {}\n\n return {\n query: parsedOperations.query,\n variables,\n }\n }\n\n // Handle plain POST GraphQL operations.\n const requestJson: {\n query: string\n variables?: GraphQLVariables\n operations?: any /** @todo Annotate this */\n } = await requestClone.json().catch(() => null)\n\n if (requestJson?.query) {\n const { query, variables } = requestJson\n\n return {\n query,\n variables,\n }\n }\n }\n\n default:\n return null\n }\n}\n\n/**\n * Determines if a given request can be considered a GraphQL request.\n * Does not parse the query and does not guarantee its validity.\n */\nexport async function parseGraphQLRequest(\n request: Request,\n): Promise<ParsedGraphQLRequest> {\n const input = await getGraphQLInput(request)\n\n if (!input || !input.query) {\n return\n }\n\n const { query, variables } = input\n const parsedResult = await parseQuery(query)\n\n if (parsedResult instanceof Error) {\n const requestPublicUrl = toPublicUrl(request.url)\n\n throw new Error(\n devUtils.formatMessage(\n 'Failed to intercept a GraphQL request to \"%s %s\": cannot parse query. See the error message from the parser below.\\n\\n%s',\n request.method,\n requestPublicUrl,\n parsedResult.message,\n ),\n )\n }\n\n return {\n query: input.query,\n operationType: parsedResult.operationType,\n operationName: parsedResult.operationName,\n variables,\n }\n}\n"],"mappings":"AAMA,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,0BAA0B;AAqB5B,SAAS,kBAAkB,MAAwC;AACxE,QAAM,eAAe,KAAK,YAAY,KAAK,CAAC,eAAe;AACzD,WAAO,WAAW,SAAS;AAAA,EAC7B,CAAC;AAED,SAAO;AAAA,IACL,eAAe,cAAc;AAAA,IAC7B,eAAe,cAAc,MAAM;AAAA,EACrC;AACF;AAEA,eAAe,WAAW,OAAoD;AAQ5E,QAAM,EAAE,MAAM,IAAG,MAAM,OAAO,SAAS,EAAE,MAAM,CAAC,UAAU;AAAC,YAAQ,MAAM,4LAA4L;AAAG,UAAM;AAAA,EAAK,CAAC;AAEpR,MAAI;AACF,UAAM,MAAM,MAAM,KAAK;AACvB,WAAO,kBAAkB,GAAG;AAAA,EAC9B,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAUA,SAAS,0BACP,WACA,KACA,OACA;AACA,QAAM,aAAa,EAAE,UAAU;AAE/B,aAAW,CAAC,KAAK,SAAS,KAAK,OAAO,QAAQ,GAAG,GAAG;AAClD,QAAI,EAAE,OAAO,QAAQ;AACnB,YAAM,IAAI,MAAM,kCAAkC,GAAG,KAAK;AAAA,IAC5D;AAEA,eAAW,WAAW,WAAW;AAC/B,YAAM,CAAC,UAAU,GAAG,aAAa,IAAI,QAAQ,MAAM,GAAG,EAAE,QAAQ;AAChE,YAAM,QAAQ,cAAc,QAAQ;AACpC,UAAI,SAA8B;AAElC,iBAAW,QAAQ,OAAO;AACxB,YAAI,EAAE,QAAQ,SAAS;AACrB,gBAAM,IAAI,MAAM,aAAa,KAAK,yBAAyB;AAAA,QAC7D;AAEA,iBAAS,OAAO,IAAI;AAAA,MACtB;AAEA,aAAO,QAAQ,IAAI,MAAM,GAAG;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO,WAAW;AACpB;AAEA,eAAe,gBAAgB,SAAgD;AAC7E,UAAQ,QAAQ,QAAQ;AAAA,IACtB,KAAK,OAAO;AACV,YAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,YAAM,QAAQ,IAAI,aAAa,IAAI,OAAO;AAC1C,YAAM,YAAY,IAAI,aAAa,IAAI,WAAW,KAAK;AAEvD,aAAO;AAAA,QACL;AAAA,QACA,WAAW,UAAU,SAAS;AAAA,MAChC;AAAA,IACF;AAAA,IAEA,KAAK,QAAQ;AAGX,YAAM,eAAe,QAAQ,MAAM;AAGnC,UACE,QAAQ,QAAQ,IAAI,cAAc,GAAG,SAAS,qBAAqB,GACnE;AACA,cAAM,eAAe;AAAA,UACnB,MAAM,aAAa,KAAK;AAAA,UACxB,QAAQ;AAAA,QACV;AAEA,YAAI,CAAC,cAAc;AACjB,iBAAO;AAAA,QACT;AAEA,cAAM,EAAE,YAAY,KAAK,GAAG,MAAM,IAAI;AACtC,cAAM,mBACJ;AAAA,UACE;AAAA,QACF,KAAK,CAAC;AAER,YAAI,CAAC,iBAAiB,OAAO;AAC3B,iBAAO;AAAA,QACT;AAEA,cAAM,YAAY,UAAsC,OAAO,EAAE,KAAK,CAAC;AACvE,cAAM,YAAY,iBAAiB,YAC/B;AAAA,UACE,iBAAiB;AAAA,UACjB;AAAA,UACA;AAAA,QACF,IACA,CAAC;AAEL,eAAO;AAAA,UACL,OAAO,iBAAiB;AAAA,UACxB;AAAA,QACF;AAAA,MACF;AAGA,YAAM,cAIF,MAAM,aAAa,KAAK,EAAE,MAAM,MAAM,IAAI;AAE9C,UAAI,aAAa,OAAO;AACtB,cAAM,EAAE,OAAO,UAAU,IAAI;AAE7B,eAAO;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/internal/parseGraphQLRequest.ts"],"sourcesContent":["import type {\n DocumentNode,\n OperationDefinitionNode,\n OperationTypeNode,\n} from 'graphql'\nimport type { GraphQLVariables } from '../../handlers/GraphQLHandler'\nimport { toPublicUrl } from '../request/toPublicUrl'\nimport { devUtils } from './devUtils'\nimport { jsonParse } from './jsonParse'\nimport { parseMultipartData } from './parseMultipartData'\n\ninterface GraphQLInput {\n query: string | null\n variables?: GraphQLVariables\n}\n\nexport interface ParsedGraphQLQuery {\n operationType: OperationTypeNode\n operationName?: string\n}\n\nexport type ParsedGraphQLRequest<\n VariablesType extends GraphQLVariables = GraphQLVariables,\n> =\n | (ParsedGraphQLQuery & {\n query: string\n variables?: VariablesType\n })\n | undefined\n\nexport function parseDocumentNode(node: DocumentNode): ParsedGraphQLQuery {\n const operationDef = node.definitions.find((definition) => {\n return definition.kind === 'OperationDefinition'\n }) as OperationDefinitionNode\n\n return {\n operationType: operationDef?.operation,\n operationName: operationDef?.name?.value,\n }\n}\n\nasync function parseQuery(query: string): Promise<ParsedGraphQLQuery | Error> {\n /**\n * @note Use `require` to get the \"graphql\" module here.\n * It has to be scoped to this function because this module leaks to the\n * root export. It has to be `require` because tools like Jest have trouble\n * handling dynamic imports. It gets replaced with a dynamic import on build time.\n */\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { parse } =await import('graphql').catch((error) => {console.error('[MSW] Failed to parse a GraphQL query: cannot import the \"graphql\" module. Please make sure you install it if you wish to intercept GraphQL requests. See the original import error below.'); throw error})\n\n try {\n const ast = parse(query)\n return parseDocumentNode(ast)\n } catch (error) {\n return error as Error\n }\n}\n\nexport type GraphQLParsedOperationsMap = Record<string, string[]>\nexport type GraphQLMultipartRequestBody = {\n operations: string\n map?: string\n} & {\n [fileName: string]: File\n}\n\nfunction extractMultipartVariables<VariablesType extends GraphQLVariables>(\n variables: VariablesType,\n map: GraphQLParsedOperationsMap,\n files: Record<string, File>,\n) {\n const operations = { variables }\n\n for (const [key, pathArray] of Object.entries(map)) {\n if (!(key in files)) {\n throw new Error(`Given files do not have a key '${key}' .`)\n }\n\n for (const dotPath of pathArray) {\n const [lastPath, ...reversedPaths] = dotPath.split('.').reverse()\n const paths = reversedPaths.reverse()\n let target: Record<string, any> = operations\n\n for (const path of paths) {\n if (!(path in target)) {\n throw new Error(`Property '${paths}' is not in operations.`)\n }\n\n target = target[path]\n }\n\n target[lastPath] = files[key]\n }\n }\n\n return operations.variables\n}\n\nasync function getGraphQLInput(request: Request): Promise<GraphQLInput | null> {\n switch (request.method) {\n case 'GET': {\n const url = new URL(request.url)\n const query = url.searchParams.get('query')\n const variables = url.searchParams.get('variables') || ''\n\n return {\n query,\n variables: jsonParse(variables),\n }\n }\n\n case 'POST': {\n // Clone the request so we could read its body without locking\n // the body stream to the downward consumers.\n const requestClone = request.clone()\n\n // Handle multipart body GraphQL operations.\n if (\n request.headers.get('content-type')?.includes('multipart/form-data')\n ) {\n const responseJson = parseMultipartData<GraphQLMultipartRequestBody>(\n await requestClone.text(),\n request.headers,\n )\n\n if (!responseJson) {\n return null\n }\n\n const { operations, map, ...files } = responseJson\n const parsedOperations =\n jsonParse<{ query?: string; variables?: GraphQLVariables }>(\n operations,\n ) || {}\n\n if (!parsedOperations.query) {\n return null\n }\n\n const parsedMap = jsonParse<GraphQLParsedOperationsMap>(map || '') || {}\n const variables = parsedOperations.variables\n ? extractMultipartVariables(\n parsedOperations.variables,\n parsedMap,\n files,\n )\n : {}\n\n return {\n query: parsedOperations.query,\n variables,\n }\n }\n\n // Handle plain POST GraphQL operations.\n const requestJson: {\n query: string\n variables?: GraphQLVariables\n operations?: any /** @todo Annotate this */\n } = await requestClone.json().catch(() => null)\n\n if (requestJson?.query) {\n const { query, variables } = requestJson\n\n return {\n query,\n variables,\n }\n }\n return null\n }\n\n default:\n return null\n }\n}\n\n/**\n * Determines if a given request can be considered a GraphQL request.\n * Does not parse the query and does not guarantee its validity.\n */\nexport async function parseGraphQLRequest(\n request: Request,\n): Promise<ParsedGraphQLRequest> {\n const input = await getGraphQLInput(request)\n\n if (!input || !input.query) {\n return\n }\n\n const { query, variables } = input\n const parsedResult = await parseQuery(query)\n\n if (parsedResult instanceof Error) {\n const requestPublicUrl = toPublicUrl(request.url)\n\n throw new Error(\n devUtils.formatMessage(\n 'Failed to intercept a GraphQL request to \"%s %s\": cannot parse query. See the error message from the parser below.\\n\\n%s',\n request.method,\n requestPublicUrl,\n parsedResult.message,\n ),\n )\n }\n\n return {\n query: input.query,\n operationType: parsedResult.operationType,\n operationName: parsedResult.operationName,\n variables,\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -36,7 +36,7 @@ function coercePath(path) {
|
|
|
36
36
|
}
|
|
37
37
|
return parameterName.startsWith(":") ? `${parameterName}${wildcard}` : `${parameterName}${expression}`;
|
|
38
38
|
}
|
|
39
|
-
).replace(/([
|
|
39
|
+
).replace(/([^/])(:)(?=\d+)/, "$1\\$2").replace(/^([^/]+)(:)(?=\/\/)/, "$1\\$2");
|
|
40
40
|
}
|
|
41
41
|
function matchRequestUrl(url, path, baseUrl) {
|
|
42
42
|
const normalizedPath = (0, import_normalizePath.normalizePath)(path, baseUrl);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/matching/matchRequestUrl.ts"],"sourcesContent":["import { match } from 'path-to-regexp'\nimport { getCleanUrl } from '@mswjs/interceptors'\nimport { normalizePath } from './normalizePath'\n\nexport type Path = string | RegExp\nexport type PathParams<KeyType extends keyof any = string> = {\n [ParamName in KeyType]?: string | ReadonlyArray<string>\n}\n\nexport interface Match {\n matches: boolean\n params?: PathParams\n}\n\n/**\n * Coerce a path supported by MSW into a path\n * supported by \"path-to-regexp\".\n */\nexport function coercePath(path: string): string {\n return (\n path\n /**\n * Replace wildcards (\"*\") with unnamed capturing groups\n * because \"path-to-regexp\" doesn't support wildcards.\n * Ignore path parameter' modifiers (i.e. \":name*\").\n */\n .replace(\n /([:a-zA-Z_-]*)(\\*{1,2})+/g,\n (_, parameterName: string | undefined, wildcard: string) => {\n const expression = '(.*)'\n\n if (!parameterName) {\n return expression\n }\n\n return parameterName.startsWith(':')\n ? `${parameterName}${wildcard}`\n : `${parameterName}${expression}`\n },\n )\n /**\n * Escape the port so that \"path-to-regexp\" can match\n * absolute URLs including port numbers.\n */\n .replace(/([
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/matching/matchRequestUrl.ts"],"sourcesContent":["import { match } from 'path-to-regexp'\nimport { getCleanUrl } from '@mswjs/interceptors'\nimport { normalizePath } from './normalizePath'\n\nexport type Path = string | RegExp\nexport type PathParams<KeyType extends keyof any = string> = {\n [ParamName in KeyType]?: string | ReadonlyArray<string>\n}\n\nexport interface Match {\n matches: boolean\n params?: PathParams\n}\n\n/**\n * Coerce a path supported by MSW into a path\n * supported by \"path-to-regexp\".\n */\nexport function coercePath(path: string): string {\n return (\n path\n /**\n * Replace wildcards (\"*\") with unnamed capturing groups\n * because \"path-to-regexp\" doesn't support wildcards.\n * Ignore path parameter' modifiers (i.e. \":name*\").\n */\n .replace(\n /([:a-zA-Z_-]*)(\\*{1,2})+/g,\n (_, parameterName: string | undefined, wildcard: string) => {\n const expression = '(.*)'\n\n if (!parameterName) {\n return expression\n }\n\n return parameterName.startsWith(':')\n ? `${parameterName}${wildcard}`\n : `${parameterName}${expression}`\n },\n )\n /**\n * Escape the port so that \"path-to-regexp\" can match\n * absolute URLs including port numbers.\n */\n .replace(/([^/])(:)(?=\\d+)/, '$1\\\\$2')\n /**\n * Escape the protocol so that \"path-to-regexp\" could match\n * absolute URL.\n * @see https://github.com/pillarjs/path-to-regexp/issues/259\n */\n .replace(/^([^/]+)(:)(?=\\/\\/)/, '$1\\\\$2')\n )\n}\n\n/**\n * Returns the result of matching given request URL against a mask.\n */\nexport function matchRequestUrl(url: URL, path: Path, baseUrl?: string): Match {\n const normalizedPath = normalizePath(path, baseUrl)\n const cleanPath =\n typeof normalizedPath === 'string'\n ? coercePath(normalizedPath)\n : normalizedPath\n\n const cleanUrl = getCleanUrl(url)\n const result = match(cleanPath, { decode: decodeURIComponent })(cleanUrl)\n const params = (result && (result.params as PathParams)) || {}\n\n return {\n matches: result !== false,\n params,\n }\n}\n\nexport function isPath(value: unknown): value is Path {\n return typeof value === 'string' || value instanceof RegExp\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4BAAsB;AACtB,0BAA4B;AAC5B,2BAA8B;AAgBvB,SAAS,WAAW,MAAsB;AAC/C,SACE,KAMG;AAAA,IACC;AAAA,IACA,CAAC,GAAG,eAAmC,aAAqB;AAC1D,YAAM,aAAa;AAEnB,UAAI,CAAC,eAAe;AAClB,eAAO;AAAA,MACT;AAEA,aAAO,cAAc,WAAW,GAAG,IAC/B,GAAG,aAAa,GAAG,QAAQ,KAC3B,GAAG,aAAa,GAAG,UAAU;AAAA,IACnC;AAAA,EACF,EAKC,QAAQ,oBAAoB,QAAQ,EAMpC,QAAQ,uBAAuB,QAAQ;AAE9C;AAKO,SAAS,gBAAgB,KAAU,MAAY,SAAyB;AAC7E,QAAM,qBAAiB,oCAAc,MAAM,OAAO;AAClD,QAAM,YACJ,OAAO,mBAAmB,WACtB,WAAW,cAAc,IACzB;AAEN,QAAM,eAAW,iCAAY,GAAG;AAChC,QAAM,aAAS,6BAAM,WAAW,EAAE,QAAQ,mBAAmB,CAAC,EAAE,QAAQ;AACxE,QAAM,SAAU,UAAW,OAAO,UAA0B,CAAC;AAE7D,SAAO;AAAA,IACL,SAAS,WAAW;AAAA,IACpB;AAAA,EACF;AACF;AAEO,SAAS,OAAO,OAA+B;AACpD,SAAO,OAAO,UAAU,YAAY,iBAAiB;AACvD;","names":[]}
|
|
@@ -11,7 +11,7 @@ function coercePath(path) {
|
|
|
11
11
|
}
|
|
12
12
|
return parameterName.startsWith(":") ? `${parameterName}${wildcard}` : `${parameterName}${expression}`;
|
|
13
13
|
}
|
|
14
|
-
).replace(/([
|
|
14
|
+
).replace(/([^/])(:)(?=\d+)/, "$1\\$2").replace(/^([^/]+)(:)(?=\/\/)/, "$1\\$2");
|
|
15
15
|
}
|
|
16
16
|
function matchRequestUrl(url, path, baseUrl) {
|
|
17
17
|
const normalizedPath = normalizePath(path, baseUrl);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/matching/matchRequestUrl.ts"],"sourcesContent":["import { match } from 'path-to-regexp'\nimport { getCleanUrl } from '@mswjs/interceptors'\nimport { normalizePath } from './normalizePath'\n\nexport type Path = string | RegExp\nexport type PathParams<KeyType extends keyof any = string> = {\n [ParamName in KeyType]?: string | ReadonlyArray<string>\n}\n\nexport interface Match {\n matches: boolean\n params?: PathParams\n}\n\n/**\n * Coerce a path supported by MSW into a path\n * supported by \"path-to-regexp\".\n */\nexport function coercePath(path: string): string {\n return (\n path\n /**\n * Replace wildcards (\"*\") with unnamed capturing groups\n * because \"path-to-regexp\" doesn't support wildcards.\n * Ignore path parameter' modifiers (i.e. \":name*\").\n */\n .replace(\n /([:a-zA-Z_-]*)(\\*{1,2})+/g,\n (_, parameterName: string | undefined, wildcard: string) => {\n const expression = '(.*)'\n\n if (!parameterName) {\n return expression\n }\n\n return parameterName.startsWith(':')\n ? `${parameterName}${wildcard}`\n : `${parameterName}${expression}`\n },\n )\n /**\n * Escape the port so that \"path-to-regexp\" can match\n * absolute URLs including port numbers.\n */\n .replace(/([
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/matching/matchRequestUrl.ts"],"sourcesContent":["import { match } from 'path-to-regexp'\nimport { getCleanUrl } from '@mswjs/interceptors'\nimport { normalizePath } from './normalizePath'\n\nexport type Path = string | RegExp\nexport type PathParams<KeyType extends keyof any = string> = {\n [ParamName in KeyType]?: string | ReadonlyArray<string>\n}\n\nexport interface Match {\n matches: boolean\n params?: PathParams\n}\n\n/**\n * Coerce a path supported by MSW into a path\n * supported by \"path-to-regexp\".\n */\nexport function coercePath(path: string): string {\n return (\n path\n /**\n * Replace wildcards (\"*\") with unnamed capturing groups\n * because \"path-to-regexp\" doesn't support wildcards.\n * Ignore path parameter' modifiers (i.e. \":name*\").\n */\n .replace(\n /([:a-zA-Z_-]*)(\\*{1,2})+/g,\n (_, parameterName: string | undefined, wildcard: string) => {\n const expression = '(.*)'\n\n if (!parameterName) {\n return expression\n }\n\n return parameterName.startsWith(':')\n ? `${parameterName}${wildcard}`\n : `${parameterName}${expression}`\n },\n )\n /**\n * Escape the port so that \"path-to-regexp\" can match\n * absolute URLs including port numbers.\n */\n .replace(/([^/])(:)(?=\\d+)/, '$1\\\\$2')\n /**\n * Escape the protocol so that \"path-to-regexp\" could match\n * absolute URL.\n * @see https://github.com/pillarjs/path-to-regexp/issues/259\n */\n .replace(/^([^/]+)(:)(?=\\/\\/)/, '$1\\\\$2')\n )\n}\n\n/**\n * Returns the result of matching given request URL against a mask.\n */\nexport function matchRequestUrl(url: URL, path: Path, baseUrl?: string): Match {\n const normalizedPath = normalizePath(path, baseUrl)\n const cleanPath =\n typeof normalizedPath === 'string'\n ? coercePath(normalizedPath)\n : normalizedPath\n\n const cleanUrl = getCleanUrl(url)\n const result = match(cleanPath, { decode: decodeURIComponent })(cleanUrl)\n const params = (result && (result.params as PathParams)) || {}\n\n return {\n matches: result !== false,\n params,\n }\n}\n\nexport function isPath(value: unknown): value is Path {\n return typeof value === 'string' || value instanceof RegExp\n}\n"],"mappings":"AAAA,SAAS,aAAa;AACtB,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAgBvB,SAAS,WAAW,MAAsB;AAC/C,SACE,KAMG;AAAA,IACC;AAAA,IACA,CAAC,GAAG,eAAmC,aAAqB;AAC1D,YAAM,aAAa;AAEnB,UAAI,CAAC,eAAe;AAClB,eAAO;AAAA,MACT;AAEA,aAAO,cAAc,WAAW,GAAG,IAC/B,GAAG,aAAa,GAAG,QAAQ,KAC3B,GAAG,aAAa,GAAG,UAAU;AAAA,IACnC;AAAA,EACF,EAKC,QAAQ,oBAAoB,QAAQ,EAMpC,QAAQ,uBAAuB,QAAQ;AAE9C;AAKO,SAAS,gBAAgB,KAAU,MAAY,SAAyB;AAC7E,QAAM,iBAAiB,cAAc,MAAM,OAAO;AAClD,QAAM,YACJ,OAAO,mBAAmB,WACtB,WAAW,cAAc,IACzB;AAEN,QAAM,WAAW,YAAY,GAAG;AAChC,QAAM,SAAS,MAAM,WAAW,EAAE,QAAQ,mBAAmB,CAAC,EAAE,QAAQ;AACxE,QAAM,SAAU,UAAW,OAAO,UAA0B,CAAC;AAE7D,SAAO;AAAA,IACL,SAAS,WAAW;AAAA,IACpB;AAAA,EACF;AACF;AAEO,SAAS,OAAO,OAA+B;AACpD,SAAO,OAAO,UAAU,YAAY,iBAAiB;AACvD;","names":[]}
|
|
@@ -22,7 +22,7 @@ __export(cleanUrl_exports, {
|
|
|
22
22
|
getSearchParams: () => getSearchParams
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(cleanUrl_exports);
|
|
25
|
-
const REDUNDANT_CHARACTERS_EXP = /[
|
|
25
|
+
const REDUNDANT_CHARACTERS_EXP = /[?|#].*$/g;
|
|
26
26
|
function getSearchParams(path) {
|
|
27
27
|
return new URL(`/${path}`, "http://localhost").searchParams;
|
|
28
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/url/cleanUrl.ts"],"sourcesContent":["const REDUNDANT_CHARACTERS_EXP = /[
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/url/cleanUrl.ts"],"sourcesContent":["const REDUNDANT_CHARACTERS_EXP = /[?|#].*$/g\n\nexport function getSearchParams(path: string) {\n return new URL(`/${path}`, 'http://localhost').searchParams\n}\n\n/**\n * Removes search parameters and the fragment\n * from a given URL string.\n */\nexport function cleanUrl(path: string): string {\n // If the path ends with an optional path parameter,\n // return it as-is.\n if (path.endsWith('?')) {\n return path\n }\n\n // Otherwise, remove the search and fragment from it.\n return path.replace(REDUNDANT_CHARACTERS_EXP, '')\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAAM,2BAA2B;AAE1B,SAAS,gBAAgB,MAAc;AAC5C,SAAO,IAAI,IAAI,IAAI,IAAI,IAAI,kBAAkB,EAAE;AACjD;AAMO,SAAS,SAAS,MAAsB;AAG7C,MAAI,KAAK,SAAS,GAAG,GAAG;AACtB,WAAO;AAAA,EACT;AAGA,SAAO,KAAK,QAAQ,0BAA0B,EAAE;AAClD;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/url/cleanUrl.ts"],"sourcesContent":["const REDUNDANT_CHARACTERS_EXP = /[
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/url/cleanUrl.ts"],"sourcesContent":["const REDUNDANT_CHARACTERS_EXP = /[?|#].*$/g\n\nexport function getSearchParams(path: string) {\n return new URL(`/${path}`, 'http://localhost').searchParams\n}\n\n/**\n * Removes search parameters and the fragment\n * from a given URL string.\n */\nexport function cleanUrl(path: string): string {\n // If the path ends with an optional path parameter,\n // return it as-is.\n if (path.endsWith('?')) {\n return path\n }\n\n // Otherwise, remove the search and fragment from it.\n return path.replace(REDUNDANT_CHARACTERS_EXP, '')\n}\n"],"mappings":"AAAA,MAAM,2BAA2B;AAE1B,SAAS,gBAAgB,MAAc;AAC5C,SAAO,IAAI,IAAI,IAAI,IAAI,IAAI,kBAAkB,EAAE;AACjD;AAMO,SAAS,SAAS,MAAsB;AAG7C,MAAI,KAAK,SAAS,GAAG,GAAG;AACtB,WAAO;AAAA,EACT;AAGA,SAAO,KAAK,QAAQ,0BAA0B,EAAE;AAClD;","names":[]}
|
|
@@ -22,6 +22,6 @@ __export(isAbsoluteUrl_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(isAbsoluteUrl_exports);
|
|
24
24
|
function isAbsoluteUrl(url) {
|
|
25
|
-
return /^([a-z][a-z\d
|
|
25
|
+
return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url);
|
|
26
26
|
}
|
|
27
27
|
//# sourceMappingURL=isAbsoluteUrl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/url/isAbsoluteUrl.ts"],"sourcesContent":["/**\n * Determines if the given URL string is an absolute URL.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return /^([a-z][a-z\\d
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/url/isAbsoluteUrl.ts"],"sourcesContent":["/**\n * Determines if the given URL string is an absolute URL.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return /^([a-z][a-z\\d+\\-.]*:)?\\/\\//i.test(url)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,SAAS,cAAc,KAAsB;AAClD,SAAO,8BAA8B,KAAK,GAAG;AAC/C;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/utils/url/isAbsoluteUrl.ts"],"sourcesContent":["/**\n * Determines if the given URL string is an absolute URL.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return /^([a-z][a-z\\d
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/utils/url/isAbsoluteUrl.ts"],"sourcesContent":["/**\n * Determines if the given URL string is an absolute URL.\n */\nexport function isAbsoluteUrl(url: string): boolean {\n return /^([a-z][a-z\\d+\\-.]*:)?\\/\\//i.test(url)\n}\n"],"mappings":"AAGO,SAAS,cAAc,KAAsB;AAClD,SAAO,8BAA8B,KAAK,GAAG;AAC/C;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/ws/WebSocketIndexedDBClientStore.ts"],"sourcesContent":["import { DeferredPromise } from '@open-draft/deferred-promise'\nimport { WebSocketClientConnectionProtocol } from '@mswjs/interceptors/lib/browser/interceptors/WebSocket'\nimport {\n type SerializedWebSocketClient,\n WebSocketClientStore,\n} from './WebSocketClientStore'\n\nconst DB_NAME = 'msw-websocket-clients'\nconst DB_STORE_NAME = 'clients'\n\nexport class WebSocketIndexedDBClientStore implements WebSocketClientStore {\n private db: Promise<IDBDatabase>\n\n constructor() {\n this.db = this.createDatabase()\n }\n\n public async add(client: WebSocketClientConnectionProtocol): Promise<void> {\n const promise = new DeferredPromise<void>()\n const store = await this.getStore()\n\n /**\n * @note Use `.put()` instead of `.add()` to allow setting clients\n * that already exist in the database. This can happen if a single page\n * has multiple event handlers. Each handler will receive the \"connection\"\n * event in parallel, and try to set that WebSocket client in the database.\n */\n const request = store.put({\n id: client.id,\n url: client.url.href,\n } satisfies SerializedWebSocketClient)\n\n request.onsuccess = () => {\n promise.resolve()\n }\n request.onerror = () => {\n
|
|
1
|
+
{"version":3,"sources":["../../../src/core/ws/WebSocketIndexedDBClientStore.ts"],"sourcesContent":["import { DeferredPromise } from '@open-draft/deferred-promise'\nimport { WebSocketClientConnectionProtocol } from '@mswjs/interceptors/lib/browser/interceptors/WebSocket'\nimport {\n type SerializedWebSocketClient,\n WebSocketClientStore,\n} from './WebSocketClientStore'\n\nconst DB_NAME = 'msw-websocket-clients'\nconst DB_STORE_NAME = 'clients'\n\nexport class WebSocketIndexedDBClientStore implements WebSocketClientStore {\n private db: Promise<IDBDatabase>\n\n constructor() {\n this.db = this.createDatabase()\n }\n\n public async add(client: WebSocketClientConnectionProtocol): Promise<void> {\n const promise = new DeferredPromise<void>()\n const store = await this.getStore()\n\n /**\n * @note Use `.put()` instead of `.add()` to allow setting clients\n * that already exist in the database. This can happen if a single page\n * has multiple event handlers. Each handler will receive the \"connection\"\n * event in parallel, and try to set that WebSocket client in the database.\n */\n const request = store.put({\n id: client.id,\n url: client.url.href,\n } satisfies SerializedWebSocketClient)\n\n request.onsuccess = () => {\n promise.resolve()\n }\n request.onerror = () => {\n console.error(request.error)\n promise.reject(\n new Error(\n `Failed to add WebSocket client \"${client.id}\". There is likely an additional output above.`,\n ),\n )\n }\n\n return promise\n }\n\n public async getAll(): Promise<Array<SerializedWebSocketClient>> {\n const promise = new DeferredPromise<Array<SerializedWebSocketClient>>()\n const store = await this.getStore()\n const request = store.getAll() as IDBRequest<\n Array<SerializedWebSocketClient>\n >\n\n request.onsuccess = () => {\n promise.resolve(request.result)\n }\n request.onerror = () => {\n // eslint-disable-next-line no-console\n console.log(request.error)\n promise.reject(\n new Error(\n `Failed to get all WebSocket clients. There is likely an additional output above.`,\n ),\n )\n }\n\n return promise\n }\n\n public async deleteMany(clientIds: Array<string>): Promise<void> {\n const promise = new DeferredPromise<void>()\n const store = await this.getStore()\n\n for (const clientId of clientIds) {\n store.delete(clientId)\n }\n\n store.transaction.oncomplete = () => {\n promise.resolve()\n }\n store.transaction.onerror = () => {\n console.error(store.transaction.error)\n promise.reject(\n new Error(\n `Failed to delete WebSocket clients [${clientIds.join(', ')}]. There is likely an additional output above.`,\n ),\n )\n }\n\n return promise\n }\n\n private async createDatabase(): Promise<IDBDatabase> {\n const promise = new DeferredPromise<IDBDatabase>()\n const request = indexedDB.open(DB_NAME, 1)\n\n request.onsuccess = ({ currentTarget }) => {\n const db = Reflect.get(currentTarget!, 'result') as IDBDatabase\n\n if (db.objectStoreNames.contains(DB_STORE_NAME)) {\n return promise.resolve(db)\n }\n }\n\n request.onupgradeneeded = async ({ currentTarget }) => {\n const db = Reflect.get(currentTarget!, 'result') as IDBDatabase\n if (db.objectStoreNames.contains(DB_STORE_NAME)) {\n return\n }\n\n const store = db.createObjectStore(DB_STORE_NAME, { keyPath: 'id' })\n store.transaction.oncomplete = () => {\n promise.resolve(db)\n }\n store.transaction.onerror = () => {\n console.error(store.transaction.error)\n promise.reject(\n new Error(\n 'Failed to create WebSocket client store. There is likely an additional output above.',\n ),\n )\n }\n }\n request.onerror = () => {\n console.error(request.error)\n promise.reject(\n new Error(\n 'Failed to open an IndexedDB database. There is likely an additional output above.',\n ),\n )\n }\n\n return promise\n }\n\n private async getStore(): Promise<IDBObjectStore> {\n const db = await this.db\n return db.transaction(DB_STORE_NAME, 'readwrite').objectStore(DB_STORE_NAME)\n }\n}\n"],"mappings":"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","names":[]}
|