🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

msw

Package Overview
Dependencies
Maintainers
1
Versions
337
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

msw - npm Package Compare versions

Comparing version
2.14.3
to
2.14.4
+371
lib/core/HttpResponse-BFS34nkx.d.ts
import { FetchResponse } from '@mswjs/interceptors';
import { Iterable, AsyncIterable } from './utils/internal/isIterable.js';
import { MaybePromise, NoInfer } from './typeUtils.js';
import { OperationTypeNode, DocumentNode, GraphQLError } from 'graphql';
import { Match, Path } from './utils/matching/matchRequestUrl.js';
interface HandlersExecutionResult {
handler: RequestHandler;
parsedResult?: any;
response?: Response;
}
interface ResponseResolutionContext {
/**
* A base url to use when resolving relative urls.
* @note This is primarily used by the `@mswjs/http-middleware`
* to resolve relative urls in the context of the running server
*/
baseUrl?: string;
quiet?: boolean;
}
/**
* Executes the list of request handlers against the given request.
* Returns the execution result object containing any matching request
* handler and any mocked response it returned.
*/
declare const executeHandlers: <Handlers extends Array<RequestHandler>>({ request, requestId, handlers, resolutionContext, }: {
request: Request;
requestId: string;
handlers: Handlers;
resolutionContext?: ResponseResolutionContext;
}) => Promise<HandlersExecutionResult | null>;
interface ParsedGraphQLQuery {
operationType: OperationTypeNode;
operationName?: string;
}
type ParsedGraphQLRequest<VariablesType extends GraphQLVariables = GraphQLVariables> = (ParsedGraphQLQuery & {
query: string;
variables?: VariablesType;
}) | undefined;
declare function parseDocumentNode(node: DocumentNode): ParsedGraphQLQuery;
type GraphQLParsedOperationsMap = Record<string, string[]>;
type GraphQLMultipartRequestBody = {
operations: string;
map?: string;
} & {
[fileName: string]: File;
};
/**
* Determines if a given request can be considered a GraphQL request.
* Does not parse the query and does not guarantee its validity.
*/
declare function parseGraphQLRequest(request: Request): Promise<ParsedGraphQLRequest>;
interface DocumentTypeDecoration<Result = {
[key: string]: any;
}, Variables = {
[key: string]: any;
}> {
__apiType?: (variables: Variables) => Result;
__resultType?: Result;
__variablesType?: Variables;
}
type GraphQLOperationType = OperationTypeNode | 'all';
type GraphQLHandlerNameSelector = DocumentNode | RegExp | string;
type GraphQLQuery = Record<string, any> | null;
type GraphQLVariables = Record<string, any>;
interface GraphQLHandlerInfo extends RequestHandlerDefaultInfo {
operationType: GraphQLOperationType;
operationName: GraphQLHandlerNameSelector | GraphQLCustomPredicate;
}
type GraphQLRequestParsedResult = {
match: Match;
cookies: Record<string, string>;
} & (ParsedGraphQLRequest<GraphQLVariables>
/**
* An empty version of the ParsedGraphQLRequest
* which simplifies the return type of the resolver
* when the request is to a non-matching endpoint
*/
| {
operationType?: undefined;
operationName?: undefined;
query?: undefined;
variables?: undefined;
});
type GraphQLResolverExtras<Variables extends GraphQLVariables> = {
query: string;
operationName: string;
variables: Variables;
cookies: Record<string, string>;
};
type GraphQLRequestBody<VariablesType extends GraphQLVariables> = GraphQLJsonRequestBody<VariablesType> | GraphQLMultipartRequestBody | Record<string, any> | undefined;
interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {
query: string;
variables?: Variables;
}
type GraphQLResponseBody<BodyType extends DefaultBodyType> = {
data?: BodyType | null;
errors?: readonly Partial<GraphQLError>[] | null;
extensions?: Record<string, any>;
} | null | undefined;
type GraphQLCustomPredicate = (args: {
request: Request;
query: string;
operationType: GraphQLOperationType;
operationName: string;
variables: GraphQLVariables;
cookies: Record<string, string>;
}) => GraphQLCustomPredicateResult | Promise<GraphQLCustomPredicateResult>;
type GraphQLCustomPredicateResult = boolean | {
matches: boolean;
};
type GraphQLPredicate<Query = any, Variables = any> = GraphQLHandlerNameSelector | DocumentTypeDecoration<Query, Variables> | GraphQLCustomPredicate;
declare function isDocumentNode(value: DocumentNode | any): value is DocumentNode;
declare class GraphQLHandler extends RequestHandler<GraphQLHandlerInfo, GraphQLRequestParsedResult, GraphQLResolverExtras<any>> {
#private;
private endpoint;
static parsedRequestCache: WeakMap<Request, ParsedGraphQLRequest<GraphQLVariables>>;
constructor(operationType: GraphQLOperationType, predicate: GraphQLPredicate, endpoint: Path, resolver: ResponseResolver<GraphQLResolverExtras<any>, any, any>, options?: RequestHandlerOptions);
/**
* Parses the request body, once per request, cached across all
* GraphQL handlers. This is done to avoid multiple parsing of the
* request body, which each requires a clone of the request.
*/
parseGraphQLRequestOrGetFromCache(request: Request): Promise<ParsedGraphQLRequest<GraphQLVariables>>;
parse(args: {
request: Request;
}): Promise<GraphQLRequestParsedResult>;
predicate(args: {
request: Request;
parsedResult: GraphQLRequestParsedResult;
}): Promise<boolean>;
run(args: {
request: StrictRequest<any>;
requestId: string;
resolutionContext?: ResponseResolutionContext;
}): Promise<RequestHandlerExecutionResult<GraphQLRequestParsedResult> | null>;
private matchOperationName;
protected extendResolverArgs(args: {
request: Request;
parsedResult: GraphQLRequestParsedResult;
}): {
query: string;
operationType: OperationTypeNode;
operationName: string;
variables: GraphQLVariables;
cookies: Record<string, string>;
};
log(args: {
request: Request;
response: Response;
parsedResult: GraphQLRequestParsedResult;
}): Promise<void>;
}
type DefaultRequestMultipartBody = Record<string, string | File | Array<string | File>>;
type DefaultBodyType = Record<string, any> | DefaultRequestMultipartBody | string | number | boolean | null | undefined;
type JsonBodyType = Record<string, any> | string | number | boolean | null | undefined;
interface RequestHandlerDefaultInfo {
header: string;
}
interface RequestHandlerInternalInfo {
callFrame?: string;
}
type ResponseResolverReturnType<ResponseBodyType extends DefaultBodyType = undefined> = ([ResponseBodyType] extends [undefined] ? Response : ResponseBodyType extends GraphQLRequestBody<any> ? HttpResponse<ResponseBodyType> | DefaultUnsafeFetchResponse : HttpResponse<ResponseBodyType>) | undefined | void;
type MaybeAsyncResponseResolverReturnType<ResponseBodyType extends DefaultBodyType> = MaybePromise<ResponseResolverReturnType<ResponseBodyType>>;
type AsyncResponseResolverReturnType<ResponseBodyType extends DefaultBodyType> = MaybePromise<ResponseResolverReturnType<ResponseBodyType> | Iterable<MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>> | AsyncIterable<MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>>>;
type ResponseResolverInfo<ResolverExtraInfo extends Record<string, unknown>, RequestBodyType extends DefaultBodyType = DefaultBodyType> = {
request: StrictRequest<RequestBodyType>;
requestId: string;
/**
* Schedule a callback to run after this response resolver completes.
* Handy for cleaning up the side effects introduced in the resolver.
* @example
* sse('/', ({ client, finalize }) => {
* const interval = setInterval(() => client.send({ data: 'ping' }))
* finalize(() => clearInterval(interval))
* })
*/
finalize: ResponseResolverFinalizeFunction;
} & ResolverExtraInfo;
type ResponseResolverFinalizeFunction = (callback: () => MaybePromise<void>) => void;
type ResponseResolver<ResolverExtraInfo extends Record<string, unknown> = Record<string, unknown>, RequestBodyType extends DefaultBodyType = DefaultBodyType, ResponseBodyType extends DefaultBodyType = undefined> = (info: ResponseResolverInfo<ResolverExtraInfo, RequestBodyType>) => AsyncResponseResolverReturnType<ResponseBodyType>;
interface RequestHandlerArgs<HandlerInfo, HandlerOptions extends RequestHandlerOptions> {
info: HandlerInfo;
resolver: ResponseResolver<any>;
options?: HandlerOptions;
}
interface RequestHandlerOptions {
once?: boolean;
}
interface RequestHandlerExecutionResult<ParsedResult extends object | undefined> {
handler: RequestHandler;
parsedResult?: ParsedResult;
request: Request;
requestId: string;
response?: Response;
}
declare abstract class RequestHandler<HandlerInfo extends RequestHandlerDefaultInfo = RequestHandlerDefaultInfo, ParsedResult extends Record<string, any> | undefined = any, ResolverExtras extends Record<string, unknown> = any, HandlerOptions extends RequestHandlerOptions = RequestHandlerOptions> {
static cache: WeakMap<StrictRequest<DefaultBodyType>, StrictRequest<DefaultBodyType>>;
readonly kind: "request";
protected resolver: ResponseResolver<ResolverExtras, any, any>;
private resolverIterator?;
private resolverIteratorResult?;
private resolverIteratorCleanups?;
private options?;
private scheduledCleanups;
info: HandlerInfo & RequestHandlerInternalInfo;
/**
* Indicates whether this request handler has been used
* (its resolver has successfully executed).
*/
isUsed: boolean;
constructor(args: RequestHandlerArgs<HandlerInfo, HandlerOptions>);
/**
* Reset the runtime state accumulated during response resolution,
* such as generator iterator progress. Called when this handler is
* removed from the active handlers list so re-adding it later starts
* from a clean state.
*/
protected reset(): void;
/**
* Restore this handler so it can match requests again after being
* exhausted (e.g. via `{ once: true }`). Also clears any accumulated
* resolution state.
*/
protected restore(): void;
/**
* Determine if the intercepted request should be mocked.
*/
abstract predicate(args: {
request: Request;
parsedResult: ParsedResult;
resolutionContext?: ResponseResolutionContext;
}): boolean | Promise<boolean>;
/**
* Print out the successfully handled request.
*/
abstract log(args: {
request: Request;
response: Response;
parsedResult: ParsedResult;
}): void;
/**
* Parse the intercepted request to extract additional information from it.
* Parsed result is then exposed to other methods of this request handler.
*/
parse(_args: {
request: Request;
resolutionContext?: ResponseResolutionContext;
}): Promise<ParsedResult>;
/**
* Test if this handler matches the given request.
*
* This method is not used internally but is exposed
* as a convenience method for consumers writing custom
* handlers.
*/
test(args: {
request: Request;
resolutionContext?: ResponseResolutionContext;
}): Promise<boolean>;
protected extendResolverArgs(_args: {
request: Request;
parsedResult: ParsedResult;
}): ResolverExtras;
private cloneRequestOrGetFromCache;
/**
* Execute this request handler and produce a mocked response
* using the given resolver function.
*/
run(args: {
request: StrictRequest<any>;
requestId: string;
resolutionContext?: ResponseResolutionContext;
}): Promise<RequestHandlerExecutionResult<ParsedResult> | null>;
private wrapResolver;
private createExecutionResult;
private scheduleCleanup;
private exhaustCleanups;
private runScheduledCleanups;
}
/**
* Forwards the cookies from the given response to `document.cookie`.
*/
declare function forwardResponseCookies(response: Response): void;
interface HttpResponseInit extends ResponseInit {
type?: ResponseType;
}
declare const bodyType: unique symbol;
type DefaultUnsafeFetchResponse = Response & {
[bodyType]?: never;
};
interface StrictRequest<BodyType extends JsonBodyType> extends Request {
json(): Promise<BodyType>;
clone(): StrictRequest<BodyType>;
}
/**
* Opaque `Response` type that supports strict body type.
*
* @deprecated Please use {@link HttpResponse} instead.
*/
type StrictResponse<BodyType extends DefaultBodyType> = HttpResponse<BodyType>;
declare const kDefaultContentType: unique symbol;
/**
* A drop-in replacement for the standard `Response` class
* to allow additional features, like mocking the response `Set-Cookie` header.
*
* @example
* new HttpResponse('Hello world', { status: 201 })
* HttpResponse.json({ name: 'John' })
* HttpResponse.formData(form)
*
* @see {@link https://mswjs.io/docs/api/http-response `HttpResponse` API reference}
*/
declare class HttpResponse<BodyType extends DefaultBodyType> extends FetchResponse {
readonly [bodyType]: BodyType;
constructor(body?: NoInfer<BodyType> | null, init?: HttpResponseInit);
static error(): HttpResponse<any>;
/**
* Create a `Response` with a `Content-Type: "text/plain"` body.
* @example
* HttpResponse.text('hello world')
* HttpResponse.text('Error', { status: 500 })
*/
static text<BodyType extends string>(body?: NoInfer<BodyType> | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "application/json"` body.
* @example
* HttpResponse.json({ firstName: 'John' })
* HttpResponse.json({ error: 'Not Authorized' }, { status: 401 })
*/
static json<BodyType extends JsonBodyType>(body?: NoInfer<BodyType> | null | undefined, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "application/xml"` body.
* @example
* HttpResponse.xml(`<user name="John" />`)
* HttpResponse.xml(`<article id="abc-123" />`, { status: 201 })
*/
static xml<BodyType extends string>(body?: BodyType | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "text/html"` body.
* @example
* HttpResponse.html(`<p class="author">Jane Doe</p>`)
* HttpResponse.html(`<main id="abc-123">Main text</main>`, { status: 201 })
*/
static html<BodyType extends string>(body?: BodyType | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with an `ArrayBuffer` body.
* @example
* const buffer = new ArrayBuffer(3)
* const view = new Uint8Array(buffer)
* view.set([1, 2, 3])
*
* HttpResponse.arrayBuffer(buffer)
*/
static arrayBuffer<BodyType extends ArrayBuffer | SharedArrayBuffer>(body?: BodyType, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `FormData` body.
* @example
* const data = new FormData()
* data.set('name', 'Alice')
*
* HttpResponse.formData(data)
*/
static formData(body?: FormData, init?: HttpResponseInit): HttpResponse<FormData>;
}
export { type AsyncResponseResolverReturnType as A, type GraphQLHandlerNameSelector as B, type GraphQLHandlerInfo as C, type DefaultBodyType as D, type GraphQLRequestParsedResult as E, type GraphQLCustomPredicateResult as F, GraphQLHandler as G, HttpResponse as H, isDocumentNode as I, type JsonBodyType as J, type RequestHandlerInternalInfo as K, type RequestHandlerArgs as L, type MaybeAsyncResponseResolverReturnType as M, type RequestHandlerExecutionResult as N, forwardResponseCookies as O, type ParsedGraphQLRequest as P, bodyType as Q, RequestHandler as R, type StrictRequest as S, type DefaultUnsafeFetchResponse as T, kDefaultContentType as U, type ResponseResolver as a, type ResponseResolverReturnType as b, type RequestHandlerOptions as c, type DefaultRequestMultipartBody as d, type ResponseResolverInfo as e, type GraphQLQuery as f, type GraphQLVariables as g, type GraphQLRequestBody as h, type GraphQLResponseBody as i, type GraphQLJsonRequestBody as j, type GraphQLOperationType as k, type GraphQLCustomPredicate as l, type ResponseResolutionContext as m, type HttpResponseInit as n, type StrictResponse as o, type GraphQLPredicate as p, type GraphQLResolverExtras as q, type RequestHandlerDefaultInfo as r, type HandlersExecutionResult as s, executeHandlers as t, type ParsedGraphQLQuery as u, parseDocumentNode as v, type GraphQLParsedOperationsMap as w, type GraphQLMultipartRequestBody as x, parseGraphQLRequest as y, type DocumentTypeDecoration as z };
import { FetchResponse } from '@mswjs/interceptors';
import { Iterable, AsyncIterable } from './utils/internal/isIterable.mjs';
import { MaybePromise, NoInfer } from './typeUtils.mjs';
import { OperationTypeNode, DocumentNode, GraphQLError } from 'graphql';
import { Match, Path } from './utils/matching/matchRequestUrl.mjs';
interface HandlersExecutionResult {
handler: RequestHandler;
parsedResult?: any;
response?: Response;
}
interface ResponseResolutionContext {
/**
* A base url to use when resolving relative urls.
* @note This is primarily used by the `@mswjs/http-middleware`
* to resolve relative urls in the context of the running server
*/
baseUrl?: string;
quiet?: boolean;
}
/**
* Executes the list of request handlers against the given request.
* Returns the execution result object containing any matching request
* handler and any mocked response it returned.
*/
declare const executeHandlers: <Handlers extends Array<RequestHandler>>({ request, requestId, handlers, resolutionContext, }: {
request: Request;
requestId: string;
handlers: Handlers;
resolutionContext?: ResponseResolutionContext;
}) => Promise<HandlersExecutionResult | null>;
interface ParsedGraphQLQuery {
operationType: OperationTypeNode;
operationName?: string;
}
type ParsedGraphQLRequest<VariablesType extends GraphQLVariables = GraphQLVariables> = (ParsedGraphQLQuery & {
query: string;
variables?: VariablesType;
}) | undefined;
declare function parseDocumentNode(node: DocumentNode): ParsedGraphQLQuery;
type GraphQLParsedOperationsMap = Record<string, string[]>;
type GraphQLMultipartRequestBody = {
operations: string;
map?: string;
} & {
[fileName: string]: File;
};
/**
* Determines if a given request can be considered a GraphQL request.
* Does not parse the query and does not guarantee its validity.
*/
declare function parseGraphQLRequest(request: Request): Promise<ParsedGraphQLRequest>;
interface DocumentTypeDecoration<Result = {
[key: string]: any;
}, Variables = {
[key: string]: any;
}> {
__apiType?: (variables: Variables) => Result;
__resultType?: Result;
__variablesType?: Variables;
}
type GraphQLOperationType = OperationTypeNode | 'all';
type GraphQLHandlerNameSelector = DocumentNode | RegExp | string;
type GraphQLQuery = Record<string, any> | null;
type GraphQLVariables = Record<string, any>;
interface GraphQLHandlerInfo extends RequestHandlerDefaultInfo {
operationType: GraphQLOperationType;
operationName: GraphQLHandlerNameSelector | GraphQLCustomPredicate;
}
type GraphQLRequestParsedResult = {
match: Match;
cookies: Record<string, string>;
} & (ParsedGraphQLRequest<GraphQLVariables>
/**
* An empty version of the ParsedGraphQLRequest
* which simplifies the return type of the resolver
* when the request is to a non-matching endpoint
*/
| {
operationType?: undefined;
operationName?: undefined;
query?: undefined;
variables?: undefined;
});
type GraphQLResolverExtras<Variables extends GraphQLVariables> = {
query: string;
operationName: string;
variables: Variables;
cookies: Record<string, string>;
};
type GraphQLRequestBody<VariablesType extends GraphQLVariables> = GraphQLJsonRequestBody<VariablesType> | GraphQLMultipartRequestBody | Record<string, any> | undefined;
interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {
query: string;
variables?: Variables;
}
type GraphQLResponseBody<BodyType extends DefaultBodyType> = {
data?: BodyType | null;
errors?: readonly Partial<GraphQLError>[] | null;
extensions?: Record<string, any>;
} | null | undefined;
type GraphQLCustomPredicate = (args: {
request: Request;
query: string;
operationType: GraphQLOperationType;
operationName: string;
variables: GraphQLVariables;
cookies: Record<string, string>;
}) => GraphQLCustomPredicateResult | Promise<GraphQLCustomPredicateResult>;
type GraphQLCustomPredicateResult = boolean | {
matches: boolean;
};
type GraphQLPredicate<Query = any, Variables = any> = GraphQLHandlerNameSelector | DocumentTypeDecoration<Query, Variables> | GraphQLCustomPredicate;
declare function isDocumentNode(value: DocumentNode | any): value is DocumentNode;
declare class GraphQLHandler extends RequestHandler<GraphQLHandlerInfo, GraphQLRequestParsedResult, GraphQLResolverExtras<any>> {
#private;
private endpoint;
static parsedRequestCache: WeakMap<Request, ParsedGraphQLRequest<GraphQLVariables>>;
constructor(operationType: GraphQLOperationType, predicate: GraphQLPredicate, endpoint: Path, resolver: ResponseResolver<GraphQLResolverExtras<any>, any, any>, options?: RequestHandlerOptions);
/**
* Parses the request body, once per request, cached across all
* GraphQL handlers. This is done to avoid multiple parsing of the
* request body, which each requires a clone of the request.
*/
parseGraphQLRequestOrGetFromCache(request: Request): Promise<ParsedGraphQLRequest<GraphQLVariables>>;
parse(args: {
request: Request;
}): Promise<GraphQLRequestParsedResult>;
predicate(args: {
request: Request;
parsedResult: GraphQLRequestParsedResult;
}): Promise<boolean>;
run(args: {
request: StrictRequest<any>;
requestId: string;
resolutionContext?: ResponseResolutionContext;
}): Promise<RequestHandlerExecutionResult<GraphQLRequestParsedResult> | null>;
private matchOperationName;
protected extendResolverArgs(args: {
request: Request;
parsedResult: GraphQLRequestParsedResult;
}): {
query: string;
operationType: OperationTypeNode;
operationName: string;
variables: GraphQLVariables;
cookies: Record<string, string>;
};
log(args: {
request: Request;
response: Response;
parsedResult: GraphQLRequestParsedResult;
}): Promise<void>;
}
type DefaultRequestMultipartBody = Record<string, string | File | Array<string | File>>;
type DefaultBodyType = Record<string, any> | DefaultRequestMultipartBody | string | number | boolean | null | undefined;
type JsonBodyType = Record<string, any> | string | number | boolean | null | undefined;
interface RequestHandlerDefaultInfo {
header: string;
}
interface RequestHandlerInternalInfo {
callFrame?: string;
}
type ResponseResolverReturnType<ResponseBodyType extends DefaultBodyType = undefined> = ([ResponseBodyType] extends [undefined] ? Response : ResponseBodyType extends GraphQLRequestBody<any> ? HttpResponse<ResponseBodyType> | DefaultUnsafeFetchResponse : HttpResponse<ResponseBodyType>) | undefined | void;
type MaybeAsyncResponseResolverReturnType<ResponseBodyType extends DefaultBodyType> = MaybePromise<ResponseResolverReturnType<ResponseBodyType>>;
type AsyncResponseResolverReturnType<ResponseBodyType extends DefaultBodyType> = MaybePromise<ResponseResolverReturnType<ResponseBodyType> | Iterable<MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>> | AsyncIterable<MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>>>;
type ResponseResolverInfo<ResolverExtraInfo extends Record<string, unknown>, RequestBodyType extends DefaultBodyType = DefaultBodyType> = {
request: StrictRequest<RequestBodyType>;
requestId: string;
/**
* Schedule a callback to run after this response resolver completes.
* Handy for cleaning up the side effects introduced in the resolver.
* @example
* sse('/', ({ client, finalize }) => {
* const interval = setInterval(() => client.send({ data: 'ping' }))
* finalize(() => clearInterval(interval))
* })
*/
finalize: ResponseResolverFinalizeFunction;
} & ResolverExtraInfo;
type ResponseResolverFinalizeFunction = (callback: () => MaybePromise<void>) => void;
type ResponseResolver<ResolverExtraInfo extends Record<string, unknown> = Record<string, unknown>, RequestBodyType extends DefaultBodyType = DefaultBodyType, ResponseBodyType extends DefaultBodyType = undefined> = (info: ResponseResolverInfo<ResolverExtraInfo, RequestBodyType>) => AsyncResponseResolverReturnType<ResponseBodyType>;
interface RequestHandlerArgs<HandlerInfo, HandlerOptions extends RequestHandlerOptions> {
info: HandlerInfo;
resolver: ResponseResolver<any>;
options?: HandlerOptions;
}
interface RequestHandlerOptions {
once?: boolean;
}
interface RequestHandlerExecutionResult<ParsedResult extends object | undefined> {
handler: RequestHandler;
parsedResult?: ParsedResult;
request: Request;
requestId: string;
response?: Response;
}
declare abstract class RequestHandler<HandlerInfo extends RequestHandlerDefaultInfo = RequestHandlerDefaultInfo, ParsedResult extends Record<string, any> | undefined = any, ResolverExtras extends Record<string, unknown> = any, HandlerOptions extends RequestHandlerOptions = RequestHandlerOptions> {
static cache: WeakMap<StrictRequest<DefaultBodyType>, StrictRequest<DefaultBodyType>>;
readonly kind: "request";
protected resolver: ResponseResolver<ResolverExtras, any, any>;
private resolverIterator?;
private resolverIteratorResult?;
private resolverIteratorCleanups?;
private options?;
private scheduledCleanups;
info: HandlerInfo & RequestHandlerInternalInfo;
/**
* Indicates whether this request handler has been used
* (its resolver has successfully executed).
*/
isUsed: boolean;
constructor(args: RequestHandlerArgs<HandlerInfo, HandlerOptions>);
/**
* Reset the runtime state accumulated during response resolution,
* such as generator iterator progress. Called when this handler is
* removed from the active handlers list so re-adding it later starts
* from a clean state.
*/
protected reset(): void;
/**
* Restore this handler so it can match requests again after being
* exhausted (e.g. via `{ once: true }`). Also clears any accumulated
* resolution state.
*/
protected restore(): void;
/**
* Determine if the intercepted request should be mocked.
*/
abstract predicate(args: {
request: Request;
parsedResult: ParsedResult;
resolutionContext?: ResponseResolutionContext;
}): boolean | Promise<boolean>;
/**
* Print out the successfully handled request.
*/
abstract log(args: {
request: Request;
response: Response;
parsedResult: ParsedResult;
}): void;
/**
* Parse the intercepted request to extract additional information from it.
* Parsed result is then exposed to other methods of this request handler.
*/
parse(_args: {
request: Request;
resolutionContext?: ResponseResolutionContext;
}): Promise<ParsedResult>;
/**
* Test if this handler matches the given request.
*
* This method is not used internally but is exposed
* as a convenience method for consumers writing custom
* handlers.
*/
test(args: {
request: Request;
resolutionContext?: ResponseResolutionContext;
}): Promise<boolean>;
protected extendResolverArgs(_args: {
request: Request;
parsedResult: ParsedResult;
}): ResolverExtras;
private cloneRequestOrGetFromCache;
/**
* Execute this request handler and produce a mocked response
* using the given resolver function.
*/
run(args: {
request: StrictRequest<any>;
requestId: string;
resolutionContext?: ResponseResolutionContext;
}): Promise<RequestHandlerExecutionResult<ParsedResult> | null>;
private wrapResolver;
private createExecutionResult;
private scheduleCleanup;
private exhaustCleanups;
private runScheduledCleanups;
}
/**
* Forwards the cookies from the given response to `document.cookie`.
*/
declare function forwardResponseCookies(response: Response): void;
interface HttpResponseInit extends ResponseInit {
type?: ResponseType;
}
declare const bodyType: unique symbol;
type DefaultUnsafeFetchResponse = Response & {
[bodyType]?: never;
};
interface StrictRequest<BodyType extends JsonBodyType> extends Request {
json(): Promise<BodyType>;
clone(): StrictRequest<BodyType>;
}
/**
* Opaque `Response` type that supports strict body type.
*
* @deprecated Please use {@link HttpResponse} instead.
*/
type StrictResponse<BodyType extends DefaultBodyType> = HttpResponse<BodyType>;
declare const kDefaultContentType: unique symbol;
/**
* A drop-in replacement for the standard `Response` class
* to allow additional features, like mocking the response `Set-Cookie` header.
*
* @example
* new HttpResponse('Hello world', { status: 201 })
* HttpResponse.json({ name: 'John' })
* HttpResponse.formData(form)
*
* @see {@link https://mswjs.io/docs/api/http-response `HttpResponse` API reference}
*/
declare class HttpResponse<BodyType extends DefaultBodyType> extends FetchResponse {
readonly [bodyType]: BodyType;
constructor(body?: NoInfer<BodyType> | null, init?: HttpResponseInit);
static error(): HttpResponse<any>;
/**
* Create a `Response` with a `Content-Type: "text/plain"` body.
* @example
* HttpResponse.text('hello world')
* HttpResponse.text('Error', { status: 500 })
*/
static text<BodyType extends string>(body?: NoInfer<BodyType> | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "application/json"` body.
* @example
* HttpResponse.json({ firstName: 'John' })
* HttpResponse.json({ error: 'Not Authorized' }, { status: 401 })
*/
static json<BodyType extends JsonBodyType>(body?: NoInfer<BodyType> | null | undefined, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "application/xml"` body.
* @example
* HttpResponse.xml(`<user name="John" />`)
* HttpResponse.xml(`<article id="abc-123" />`, { status: 201 })
*/
static xml<BodyType extends string>(body?: BodyType | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "text/html"` body.
* @example
* HttpResponse.html(`<p class="author">Jane Doe</p>`)
* HttpResponse.html(`<main id="abc-123">Main text</main>`, { status: 201 })
*/
static html<BodyType extends string>(body?: BodyType | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with an `ArrayBuffer` body.
* @example
* const buffer = new ArrayBuffer(3)
* const view = new Uint8Array(buffer)
* view.set([1, 2, 3])
*
* HttpResponse.arrayBuffer(buffer)
*/
static arrayBuffer<BodyType extends ArrayBuffer | SharedArrayBuffer>(body?: BodyType, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `FormData` body.
* @example
* const data = new FormData()
* data.set('name', 'Alice')
*
* HttpResponse.formData(data)
*/
static formData(body?: FormData, init?: HttpResponseInit): HttpResponse<FormData>;
}
export { type AsyncResponseResolverReturnType as A, type GraphQLHandlerNameSelector as B, type GraphQLHandlerInfo as C, type DefaultBodyType as D, type GraphQLRequestParsedResult as E, type GraphQLCustomPredicateResult as F, GraphQLHandler as G, HttpResponse as H, isDocumentNode as I, type JsonBodyType as J, type RequestHandlerInternalInfo as K, type RequestHandlerArgs as L, type MaybeAsyncResponseResolverReturnType as M, type RequestHandlerExecutionResult as N, forwardResponseCookies as O, type ParsedGraphQLRequest as P, bodyType as Q, RequestHandler as R, type StrictRequest as S, type DefaultUnsafeFetchResponse as T, kDefaultContentType as U, type ResponseResolver as a, type ResponseResolverReturnType as b, type RequestHandlerOptions as c, type DefaultRequestMultipartBody as d, type ResponseResolverInfo as e, type GraphQLQuery as f, type GraphQLVariables as g, type GraphQLRequestBody as h, type GraphQLResponseBody as i, type GraphQLJsonRequestBody as j, type GraphQLOperationType as k, type GraphQLCustomPredicate as l, type ResponseResolutionContext as m, type HttpResponseInit as n, type StrictResponse as o, type GraphQLPredicate as p, type GraphQLResolverExtras as q, type RequestHandlerDefaultInfo as r, type HandlersExecutionResult as s, executeHandlers as t, type ParsedGraphQLQuery as u, parseDocumentNode as v, type GraphQLParsedOperationsMap as w, type GraphQLMultipartRequestBody as x, parseGraphQLRequest as y, type DocumentTypeDecoration as z };
+1
-1

@@ -5,3 +5,3 @@ import { UnhandledRequestStrategy } from '../utils/request/onUnhandledRequest.mjs';

import './handlers-controller.mjs';
import '../HttpResponse-CxHR1nNN.mjs';
import '../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -8,0 +8,0 @@ import '../utils/internal/isIterable.mjs';

@@ -5,3 +5,3 @@ import { UnhandledRequestStrategy } from '../utils/request/onUnhandledRequest.js';

import './handlers-controller.js';
import '../HttpResponse-aGiIzO91.js';
import '../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -8,0 +8,0 @@ import '../utils/internal/isIterable.js';

@@ -5,3 +5,3 @@ import { Emitter, DefaultEventMap } from 'rettime';

import { AnyHandler, HandlersController } from './handlers-controller.mjs';
import '../HttpResponse-CxHR1nNN.mjs';
import '../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -8,0 +8,0 @@ import '../utils/internal/isIterable.mjs';

@@ -5,3 +5,3 @@ import { Emitter, DefaultEventMap } from 'rettime';

import { AnyHandler, HandlersController } from './handlers-controller.js';
import '../HttpResponse-aGiIzO91.js';
import '../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -8,0 +8,0 @@ import '../utils/internal/isIterable.js';

import { TypedEvent } from 'rettime';
import { N as NetworkFrame, b as UnhandledFrameHandle, a as NetworkFrameResolutionContext } from '../../on-unhandled-frame-Cr1KOZ0I.mjs';
import { HandlersController, AnyHandler } from '../handlers-controller.mjs';
import { R as RequestHandler } from '../../HttpResponse-CxHR1nNN.mjs';
import { R as RequestHandler } from '../../HttpResponse-CQwYpuKo.mjs';
import '../../handlers/WebSocketHandler.mjs';

@@ -6,0 +6,0 @@ import 'strict-event-emitter';

import { TypedEvent } from 'rettime';
import { N as NetworkFrame, b as UnhandledFrameHandle, a as NetworkFrameResolutionContext } from '../../on-unhandled-frame-BBR-P3kV.js';
import { HandlersController, AnyHandler } from '../handlers-controller.js';
import { R as RequestHandler } from '../../HttpResponse-aGiIzO91.js';
import { R as RequestHandler } from '../../HttpResponse-BFS34nkx.js';
import '../../handlers/WebSocketHandler.js';

@@ -6,0 +6,0 @@ import 'strict-event-emitter';

import 'rettime';
import '../handlers-controller.mjs';
export { A as AnyNetworkFrame, E as ExtractFrameEvents, N as NetworkFrame, a as NetworkFrameResolutionContext } from '../../on-unhandled-frame-Cr1KOZ0I.mjs';
import '../../HttpResponse-CxHR1nNN.mjs';
import '../../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -6,0 +6,0 @@ import '../../utils/internal/isIterable.mjs';

import 'rettime';
import '../handlers-controller.js';
export { A as AnyNetworkFrame, E as ExtractFrameEvents, N as NetworkFrame, a as NetworkFrameResolutionContext } from '../../on-unhandled-frame-BBR-P3kV.js';
import '../../HttpResponse-aGiIzO91.js';
import '../../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -6,0 +6,0 @@ import '../../utils/internal/isIterable.js';

@@ -8,3 +8,3 @@ import { TypedEvent } from 'rettime';

import '../../utils/matching/matchRequestUrl.mjs';
import '../../HttpResponse-CxHR1nNN.mjs';
import '../../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -11,0 +11,0 @@ import '../../utils/internal/isIterable.mjs';

@@ -8,3 +8,3 @@ import { TypedEvent } from 'rettime';

import '../../utils/matching/matchRequestUrl.js';
import '../../HttpResponse-aGiIzO91.js';
import '../../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -11,0 +11,0 @@ import '../../utils/internal/isIterable.js';

@@ -1,2 +0,2 @@

import { R as RequestHandler } from '../HttpResponse-CxHR1nNN.mjs';
import { R as RequestHandler } from '../HttpResponse-CQwYpuKo.mjs';
import { WebSocketHandler } from '../handlers/WebSocketHandler.mjs';

@@ -3,0 +3,0 @@ import '@mswjs/interceptors';

@@ -1,2 +0,2 @@

import { R as RequestHandler } from '../HttpResponse-aGiIzO91.js';
import { R as RequestHandler } from '../HttpResponse-BFS34nkx.js';
import { WebSocketHandler } from '../handlers/WebSocketHandler.js';

@@ -3,0 +3,0 @@ import '@mswjs/interceptors';

@@ -11,3 +11,3 @@ export { DefineNetworkOptions, NetworkApi, defineNetwork } from './define-network.mjs';

import '@mswjs/interceptors/WebSocket';
import '../HttpResponse-CxHR1nNN.mjs';
import '../HttpResponse-CQwYpuKo.mjs';
import '../utils/internal/isIterable.mjs';

@@ -14,0 +14,0 @@ import '../typeUtils.mjs';

@@ -11,3 +11,3 @@ export { DefineNetworkOptions, NetworkApi, defineNetwork } from './define-network.js';

import '@mswjs/interceptors/WebSocket';
import '../HttpResponse-aGiIzO91.js';
import '../HttpResponse-BFS34nkx.js';
import '../utils/internal/isIterable.js';

@@ -14,0 +14,0 @@ import '../typeUtils.js';

export { U as UnhandledFrameCallback, d as UnhandledFrameDefaults, b as UnhandledFrameHandle, c as UnhandledFrameStrategy, e as executeUnhandledFrameHandle } from '../on-unhandled-frame-Cr1KOZ0I.mjs';
import 'rettime';
import './handlers-controller.mjs';
import '../HttpResponse-CxHR1nNN.mjs';
import '../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -6,0 +6,0 @@ import '../utils/internal/isIterable.mjs';

export { U as UnhandledFrameCallback, d as UnhandledFrameDefaults, b as UnhandledFrameHandle, c as UnhandledFrameStrategy, e as executeUnhandledFrameHandle } from '../on-unhandled-frame-BBR-P3kV.js';
import 'rettime';
import './handlers-controller.js';
import '../HttpResponse-aGiIzO91.js';
import '../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -6,0 +6,0 @@ import '../utils/internal/isIterable.js';

@@ -6,3 +6,3 @@ import { DefaultEventMap, Emitter } from 'rettime';

import '../utils/request/onUnhandledRequest.mjs';
import '../HttpResponse-CxHR1nNN.mjs';
import '../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -9,0 +9,0 @@ import '../utils/internal/isIterable.mjs';

@@ -6,3 +6,3 @@ import { DefaultEventMap, Emitter } from 'rettime';

import '../utils/request/onUnhandledRequest.js';
import '../HttpResponse-aGiIzO91.js';
import '../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -9,0 +9,0 @@ import '../utils/internal/isIterable.js';

@@ -7,3 +7,3 @@ import { Interceptor, HttpRequestEventMap } from '@mswjs/interceptors';

import '../handlers-controller.mjs';
import '../../HttpResponse-CxHR1nNN.mjs';
import '../../HttpResponse-CQwYpuKo.mjs';
import '../../utils/internal/isIterable.mjs';

@@ -10,0 +10,0 @@ import '../../typeUtils.mjs';

@@ -7,3 +7,3 @@ import { Interceptor, HttpRequestEventMap } from '@mswjs/interceptors';

import '../handlers-controller.js';
import '../../HttpResponse-aGiIzO91.js';
import '../../HttpResponse-BFS34nkx.js';
import '../../utils/internal/isIterable.js';

@@ -10,0 +10,0 @@ import '../../typeUtils.js';

import { Emitter, TypedEvent, TypedListenerOptions } from 'rettime';
import { A as AnyNetworkFrame, E as ExtractFrameEvents } from '../../on-unhandled-frame-Cr1KOZ0I.mjs';
import '../handlers-controller.mjs';
import '../../HttpResponse-CxHR1nNN.mjs';
import '../../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -6,0 +6,0 @@ import '../../utils/internal/isIterable.mjs';

import { Emitter, TypedEvent, TypedListenerOptions } from 'rettime';
import { A as AnyNetworkFrame, E as ExtractFrameEvents } from '../../on-unhandled-frame-BBR-P3kV.js';
import '../handlers-controller.js';
import '../../HttpResponse-aGiIzO91.js';
import '../../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -6,0 +6,0 @@ import '../../utils/internal/isIterable.js';

@@ -1,2 +0,2 @@

import { R as RequestHandler, m as ResponseResolutionContext } from './HttpResponse-CxHR1nNN.mjs';
import { R as RequestHandler, m as ResponseResolutionContext } from './HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import './utils/internal/isIterable.mjs';

@@ -1,2 +0,2 @@

import { R as RequestHandler, m as ResponseResolutionContext } from './HttpResponse-aGiIzO91.js';
import { R as RequestHandler, m as ResponseResolutionContext } from './HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import './utils/internal/isIterable.js';

@@ -1,2 +0,2 @@

import { f as GraphQLQuery, g as GraphQLVariables, p as GraphQLPredicate, a as ResponseResolver, q as GraphQLResolverExtras, i as GraphQLResponseBody, c as RequestHandlerOptions, G as GraphQLHandler } from './HttpResponse-CxHR1nNN.mjs';
import { f as GraphQLQuery, g as GraphQLVariables, p as GraphQLPredicate, a as ResponseResolver, q as GraphQLResolverExtras, i as GraphQLResponseBody, c as RequestHandlerOptions, G as GraphQLHandler } from './HttpResponse-CQwYpuKo.mjs';
import { Path } from './utils/matching/matchRequestUrl.mjs';

@@ -3,0 +3,0 @@ import '@mswjs/interceptors';

@@ -1,2 +0,2 @@

import { f as GraphQLQuery, g as GraphQLVariables, p as GraphQLPredicate, a as ResponseResolver, q as GraphQLResolverExtras, i as GraphQLResponseBody, c as RequestHandlerOptions, G as GraphQLHandler } from './HttpResponse-aGiIzO91.js';
import { f as GraphQLQuery, g as GraphQLVariables, p as GraphQLPredicate, a as ResponseResolver, q as GraphQLResolverExtras, i as GraphQLResponseBody, c as RequestHandlerOptions, G as GraphQLHandler } from './HttpResponse-BFS34nkx.js';
import { Path } from './utils/matching/matchRequestUrl.js';

@@ -3,0 +3,0 @@ import '@mswjs/interceptors';

import 'graphql';
export { z as DocumentTypeDecoration, l as GraphQLCustomPredicate, F as GraphQLCustomPredicateResult, G as GraphQLHandler, C as GraphQLHandlerInfo, B as GraphQLHandlerNameSelector, j as GraphQLJsonRequestBody, k as GraphQLOperationType, p as GraphQLPredicate, f as GraphQLQuery, h as GraphQLRequestBody, E as GraphQLRequestParsedResult, q as GraphQLResolverExtras, i as GraphQLResponseBody, g as GraphQLVariables, I as isDocumentNode } from '../HttpResponse-CxHR1nNN.mjs';
export { z as DocumentTypeDecoration, l as GraphQLCustomPredicate, F as GraphQLCustomPredicateResult, G as GraphQLHandler, C as GraphQLHandlerInfo, B as GraphQLHandlerNameSelector, j as GraphQLJsonRequestBody, k as GraphQLOperationType, p as GraphQLPredicate, f as GraphQLQuery, h as GraphQLRequestBody, E as GraphQLRequestParsedResult, q as GraphQLResolverExtras, i as GraphQLResponseBody, g as GraphQLVariables, I as isDocumentNode } from '../HttpResponse-CQwYpuKo.mjs';
import '../utils/matching/matchRequestUrl.mjs';

@@ -4,0 +4,0 @@ import '@mswjs/interceptors';

import 'graphql';
export { z as DocumentTypeDecoration, l as GraphQLCustomPredicate, F as GraphQLCustomPredicateResult, G as GraphQLHandler, C as GraphQLHandlerInfo, B as GraphQLHandlerNameSelector, j as GraphQLJsonRequestBody, k as GraphQLOperationType, p as GraphQLPredicate, f as GraphQLQuery, h as GraphQLRequestBody, E as GraphQLRequestParsedResult, q as GraphQLResolverExtras, i as GraphQLResponseBody, g as GraphQLVariables, I as isDocumentNode } from '../HttpResponse-aGiIzO91.js';
export { z as DocumentTypeDecoration, l as GraphQLCustomPredicate, F as GraphQLCustomPredicateResult, G as GraphQLHandler, C as GraphQLHandlerInfo, B as GraphQLHandlerNameSelector, j as GraphQLJsonRequestBody, k as GraphQLOperationType, p as GraphQLPredicate, f as GraphQLQuery, h as GraphQLRequestBody, E as GraphQLRequestParsedResult, q as GraphQLResolverExtras, i as GraphQLResponseBody, g as GraphQLVariables, I as isDocumentNode } from '../HttpResponse-BFS34nkx.js';
import '../utils/matching/matchRequestUrl.js';

@@ -4,0 +4,0 @@ import '@mswjs/interceptors';

@@ -1,2 +0,2 @@

import { R as RequestHandler, r as RequestHandlerDefaultInfo, a as ResponseResolver, c as RequestHandlerOptions, m as ResponseResolutionContext } from '../HttpResponse-CxHR1nNN.mjs';
import { R as RequestHandler, r as RequestHandlerDefaultInfo, a as ResponseResolver, c as RequestHandlerOptions, m as ResponseResolutionContext } from '../HttpResponse-CQwYpuKo.mjs';
import { PathParams, Path, Match } from '../utils/matching/matchRequestUrl.mjs';

@@ -3,0 +3,0 @@ import '@mswjs/interceptors';

@@ -1,2 +0,2 @@

import { R as RequestHandler, r as RequestHandlerDefaultInfo, a as ResponseResolver, c as RequestHandlerOptions, m as ResponseResolutionContext } from '../HttpResponse-aGiIzO91.js';
import { R as RequestHandler, r as RequestHandlerDefaultInfo, a as ResponseResolver, c as RequestHandlerOptions, m as ResponseResolutionContext } from '../HttpResponse-BFS34nkx.js';
import { PathParams, Path, Match } from '../utils/matching/matchRequestUrl.js';

@@ -3,0 +3,0 @@ import '@mswjs/interceptors';

import '../utils/internal/isIterable.mjs';
export { A as AsyncResponseResolverReturnType, D as DefaultBodyType, d as DefaultRequestMultipartBody, J as JsonBodyType, M as MaybeAsyncResponseResolverReturnType, R as RequestHandler, L as RequestHandlerArgs, r as RequestHandlerDefaultInfo, N as RequestHandlerExecutionResult, K as RequestHandlerInternalInfo, c as RequestHandlerOptions, a as ResponseResolver, e as ResponseResolverInfo, b as ResponseResolverReturnType, O as forwardResponseCookies } from '../HttpResponse-CxHR1nNN.mjs';
export { A as AsyncResponseResolverReturnType, D as DefaultBodyType, d as DefaultRequestMultipartBody, J as JsonBodyType, M as MaybeAsyncResponseResolverReturnType, R as RequestHandler, L as RequestHandlerArgs, r as RequestHandlerDefaultInfo, N as RequestHandlerExecutionResult, K as RequestHandlerInternalInfo, c as RequestHandlerOptions, a as ResponseResolver, e as ResponseResolverInfo, b as ResponseResolverReturnType, O as forwardResponseCookies } from '../HttpResponse-CQwYpuKo.mjs';
import '../typeUtils.mjs';

@@ -4,0 +4,0 @@ import '@mswjs/interceptors';

import '../utils/internal/isIterable.js';
export { A as AsyncResponseResolverReturnType, D as DefaultBodyType, d as DefaultRequestMultipartBody, J as JsonBodyType, M as MaybeAsyncResponseResolverReturnType, R as RequestHandler, L as RequestHandlerArgs, r as RequestHandlerDefaultInfo, N as RequestHandlerExecutionResult, K as RequestHandlerInternalInfo, c as RequestHandlerOptions, a as ResponseResolver, e as ResponseResolverInfo, b as ResponseResolverReturnType, O as forwardResponseCookies } from '../HttpResponse-aGiIzO91.js';
export { A as AsyncResponseResolverReturnType, D as DefaultBodyType, d as DefaultRequestMultipartBody, J as JsonBodyType, M as MaybeAsyncResponseResolverReturnType, R as RequestHandler, L as RequestHandlerArgs, r as RequestHandlerDefaultInfo, N as RequestHandlerExecutionResult, K as RequestHandlerInternalInfo, c as RequestHandlerOptions, a as ResponseResolver, e as ResponseResolverInfo, b as ResponseResolverReturnType, O as forwardResponseCookies } from '../HttpResponse-BFS34nkx.js';
import '../typeUtils.js';

@@ -4,0 +4,0 @@ import '@mswjs/interceptors';

@@ -29,2 +29,3 @@ "use strict";

var import_HttpResponse = require("../HttpResponse");
var import_devUtils = require("../utils/internal/devUtils");
var import_decorators = require("../utils/HttpResponse/decorators");

@@ -37,3 +38,5 @@ class RequestHandler {

resolverIteratorResult;
resolverIteratorCleanups;
options;
scheduledCleanups;
info;

@@ -48,2 +51,3 @@ /**

this.options = args.options;
this.scheduledCleanups = /* @__PURE__ */ new Map();
const callFrame = (0, import_getCallFrame.getCallFrame)(new Error());

@@ -63,5 +67,7 @@ this.info = {

reset() {
this.scheduledCleanups.clear();
const iterator = this.resolverIterator;
this.resolverIterator = void 0;
this.resolverIteratorResult = void 0;
this.resolverIteratorCleanups = void 0;
if (typeof iterator?.return === "function") {

@@ -152,4 +158,16 @@ void Promise.resolve(iterator.return());

});
const listenerController = new AbortController();
args.request.signal.addEventListener(
"abort",
() => this.runScheduledCleanups(args.requestId),
{
once: true,
signal: listenerController.signal
}
);
const mockedResponsePromise = executeResolver({
...resolverExtras,
finalize: (callback) => {
this.scheduleCleanup(args.requestId, callback);
},
requestId: args.requestId,

@@ -162,2 +180,4 @@ request: args.request

throw errorOrResponse;
}).finally(() => {
listenerController.abort();
});

@@ -181,6 +201,18 @@ const mockedResponse = await mockedResponsePromise;

if (!this.resolverIterator) {
const result = await resolver(info);
let result;
try {
result = await resolver(info);
} catch (error) {
await this.runScheduledCleanups(info.requestId);
throw error;
}
if (!(0, import_isIterable.isIterable)(result)) {
await this.runScheduledCleanups(info.requestId);
return result;
}
const existingCleanups = this.scheduledCleanups.get(info.requestId);
if (existingCleanups != null && existingCleanups.length > 0) {
this.resolverIteratorCleanups = existingCleanups;
this.scheduledCleanups.delete(info.requestId);
}
this.resolverIterator = Symbol.iterator in result ? result[Symbol.iterator]() : result[Symbol.asyncIterator]();

@@ -196,2 +228,3 @@ }

this.isUsed = true;
await this.runScheduledCleanups(info.requestId);
return this.resolverIteratorResult?.clone();

@@ -211,2 +244,50 @@ }

}
scheduleCleanup(requestId, callback) {
if (this.resolverIterator) {
;
(this.resolverIteratorCleanups ||= []).unshift(callback);
return;
}
const cleanups = this.scheduledCleanups.get(requestId) || [];
cleanups.unshift(callback);
this.scheduledCleanups.set(requestId, cleanups);
}
async exhaustCleanups(cleanups) {
const errors = [];
for (const cleanup of cleanups) {
try {
await cleanup();
} catch (error) {
if (error instanceof Error) {
errors.push(error);
}
}
}
if (errors.length > 0) {
import_devUtils.devUtils.error(
'Failed to execute cleanup for request handler "%s"',
this.info.header,
new AggregateError(
errors,
`Failed to execute cleanup for request handler "${this.info.header}"`
)
);
}
}
async runScheduledCleanups(requestId) {
if (this.resolverIterator && this.resolverIteratorCleanups != null && this.resolverIteratorCleanups.length > 0) {
try {
await this.exhaustCleanups(this.resolverIteratorCleanups);
} finally {
this.resolverIteratorCleanups = void 0;
}
return;
}
const cleanups = this.scheduledCleanups.get(requestId);
if (!cleanups || cleanups.length == 0) {
return;
}
await this.exhaustCleanups(cleanups);
this.scheduledCleanups.delete(requestId);
}
}

@@ -213,0 +294,0 @@ function forwardResponseCookies(response) {

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../../src/core/handlers/RequestHandler.ts"],"sourcesContent":["import { Headers as HeadersPolyfill } from 'headers-polyfill'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\nimport {\n isIterable,\n type AsyncIterable,\n type Iterable,\n} from '../utils/internal/isIterable'\nimport type { ResponseResolutionContext } from '../utils/executeHandlers'\nimport type { MaybePromise } from '../typeUtils'\nimport type { HttpResponse } from '../HttpResponse'\nimport {\n type StrictRequest,\n type DefaultUnsafeFetchResponse,\n} from '../HttpResponse'\nimport type { GraphQLRequestBody } from './GraphQLHandler'\nimport { getRawSetCookie } from '../utils/HttpResponse/decorators'\n\nexport type DefaultRequestMultipartBody = Record<\n string,\n string | File | Array<string | File>\n>\n\nexport type DefaultBodyType =\n | Record<string, any>\n | DefaultRequestMultipartBody\n | string\n | number\n | boolean\n | null\n | undefined\n\nexport type JsonBodyType =\n | Record<string, any>\n | string\n | number\n | boolean\n | null\n | undefined\n\nexport interface RequestHandlerDefaultInfo {\n header: string\n}\n\nexport interface RequestHandlerInternalInfo {\n callFrame?: string\n}\n\nexport type ResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType = undefined,\n> =\n // If ResponseBodyType is a union and one of the types is `undefined`,\n // allow plain Response as the type.\n | ([ResponseBodyType] extends [undefined]\n ? Response\n : /**\n * Treat GraphQL response body type as a special case.\n * For esome reason, making the default HttpResponse<T> | DefaultUnsafeFetchResponse\n * union breaks the body type inference for HTTP requests.\n * @see https://github.com/mswjs/msw/issues/2130\n */\n ResponseBodyType extends GraphQLRequestBody<any>\n ? HttpResponse<ResponseBodyType> | DefaultUnsafeFetchResponse\n : HttpResponse<ResponseBodyType>)\n | undefined\n | void\n\nexport type MaybeAsyncResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType,\n> = MaybePromise<ResponseResolverReturnType<ResponseBodyType>>\n\nexport type AsyncResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType,\n> = MaybePromise<\n | ResponseResolverReturnType<ResponseBodyType>\n | Iterable<\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>\n >\n | AsyncIterable<\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>\n >\n>\n\nexport type ResponseResolverInfo<\n ResolverExtraInfo extends Record<string, unknown>,\n RequestBodyType extends DefaultBodyType = DefaultBodyType,\n> = {\n request: StrictRequest<RequestBodyType>\n requestId: string\n} & ResolverExtraInfo\n\nexport type ResponseResolver<\n ResolverExtraInfo extends Record<string, unknown> = Record<string, unknown>,\n RequestBodyType extends DefaultBodyType = DefaultBodyType,\n ResponseBodyType extends DefaultBodyType = undefined,\n> = (\n info: ResponseResolverInfo<ResolverExtraInfo, RequestBodyType>,\n) => AsyncResponseResolverReturnType<ResponseBodyType>\n\nexport interface RequestHandlerArgs<\n HandlerInfo,\n HandlerOptions extends RequestHandlerOptions,\n> {\n info: HandlerInfo\n resolver: ResponseResolver<any>\n options?: HandlerOptions\n}\n\nexport interface RequestHandlerOptions {\n once?: boolean\n}\n\nexport interface RequestHandlerExecutionResult<\n ParsedResult extends object | undefined,\n> {\n handler: RequestHandler\n parsedResult?: ParsedResult\n request: Request\n requestId: string\n response?: Response\n}\n\nexport abstract class RequestHandler<\n HandlerInfo extends RequestHandlerDefaultInfo = RequestHandlerDefaultInfo,\n ParsedResult extends Record<string, any> | undefined = any,\n ResolverExtras extends Record<string, unknown> = any,\n HandlerOptions extends RequestHandlerOptions = RequestHandlerOptions,\n> {\n static cache = new WeakMap<\n StrictRequest<DefaultBodyType>,\n StrictRequest<DefaultBodyType>\n >()\n\n public readonly kind = 'request' as const\n\n protected resolver: ResponseResolver<ResolverExtras, any, any>\n private resolverIterator?:\n | Iterator<\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>\n >\n | AsyncIterator<\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>\n >\n private resolverIteratorResult?: Response | HttpResponse<any>\n private options?: HandlerOptions\n\n public info: HandlerInfo & RequestHandlerInternalInfo\n\n /**\n * Indicates whether this request handler has been used\n * (its resolver has successfully executed).\n */\n public isUsed: boolean\n\n constructor(args: RequestHandlerArgs<HandlerInfo, HandlerOptions>) {\n this.resolver = args.resolver\n this.options = args.options\n\n const callFrame = getCallFrame(new Error())\n\n this.info = {\n ...args.info,\n callFrame,\n }\n\n this.isUsed = false\n }\n\n /**\n * Reset the runtime state accumulated during response resolution,\n * such as generator iterator progress. Called when this handler is\n * removed from the active handlers list so re-adding it later starts\n * from a clean state.\n */\n protected reset(): void {\n const iterator = this.resolverIterator\n this.resolverIterator = undefined\n this.resolverIteratorResult = undefined\n\n if (typeof iterator?.return === 'function') {\n void Promise.resolve(iterator.return())\n }\n }\n\n /**\n * Restore this handler so it can match requests again after being\n * exhausted (e.g. via `{ once: true }`). Also clears any accumulated\n * resolution state.\n */\n protected restore(): void {\n if (this.options?.once) {\n this.reset()\n this.isUsed = false\n }\n }\n\n /**\n * Determine if the intercepted request should be mocked.\n */\n abstract predicate(args: {\n request: Request\n parsedResult: ParsedResult\n resolutionContext?: ResponseResolutionContext\n }): boolean | Promise<boolean>\n\n /**\n * Print out the successfully handled request.\n */\n abstract log(args: {\n request: Request\n response: Response\n parsedResult: ParsedResult\n }): void\n\n /**\n * Parse the intercepted request to extract additional information from it.\n * Parsed result is then exposed to other methods of this request handler.\n */\n async parse(_args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }): Promise<ParsedResult> {\n return {} as ParsedResult\n }\n\n /**\n * Test if this handler matches the given request.\n *\n * This method is not used internally but is exposed\n * as a convenience method for consumers writing custom\n * handlers.\n */\n public async test(args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }): Promise<boolean> {\n const parsedResult = await this.parse({\n request: args.request,\n resolutionContext: args.resolutionContext,\n })\n\n return this.predicate({\n request: args.request,\n parsedResult,\n resolutionContext: args.resolutionContext,\n })\n }\n\n protected extendResolverArgs(_args: {\n request: Request\n parsedResult: ParsedResult\n }): ResolverExtras {\n return {} as ResolverExtras\n }\n\n // Clone the request instance before it's passed to the handler phases\n // and the response resolver so we can always read it for logging.\n // We only clone it once per request to avoid unnecessary overhead.\n private cloneRequestOrGetFromCache(\n request: StrictRequest<DefaultBodyType>,\n ): StrictRequest<DefaultBodyType> {\n const existingClone = RequestHandler.cache.get(request)\n\n if (typeof existingClone !== 'undefined') {\n return existingClone\n }\n\n const clonedRequest = request.clone()\n RequestHandler.cache.set(request, clonedRequest)\n\n return clonedRequest\n }\n\n /**\n * Execute this request handler and produce a mocked response\n * using the given resolver function.\n */\n public async run(args: {\n request: StrictRequest<any>\n requestId: string\n resolutionContext?: ResponseResolutionContext\n }): Promise<RequestHandlerExecutionResult<ParsedResult> | null> {\n if (this.isUsed && this.options?.once) {\n return null\n }\n\n // Clone the request.\n // If this is the first time MSW handles this request, a fresh clone\n // will be created and cached. Upon further handling of the same request,\n // the request clone from the cache will be reused to prevent abundant\n // \"abort\" listeners and save up resources on cloning.\n const requestClone = this.cloneRequestOrGetFromCache(args.request)\n\n const parsedResult = await this.parse({\n request: args.request,\n resolutionContext: args.resolutionContext,\n })\n const shouldInterceptRequest = await this.predicate({\n request: args.request,\n parsedResult,\n resolutionContext: args.resolutionContext,\n })\n\n if (!shouldInterceptRequest) {\n return null\n }\n\n // Re-check isUsed, in case another request hit this handler while we were\n // asynchronously parsing the request.\n if (this.isUsed && this.options?.once) {\n return null\n }\n\n // Preemptively mark the handler as used.\n // Generators will undo this because only when the resolver reaches the\n // \"done\" state of the generator that it considers the handler used.\n this.isUsed = true\n\n // Create a response extraction wrapper around the resolver\n // since it can be both an async function and a generator.\n const executeResolver = this.wrapResolver(this.resolver)\n\n const resolverExtras = this.extendResolverArgs({\n request: args.request,\n parsedResult,\n })\n\n const mockedResponsePromise = (\n executeResolver({\n ...resolverExtras,\n requestId: args.requestId,\n request: args.request,\n }) as Promise<Response | undefined>\n ).catch((errorOrResponse) => {\n // Allow throwing a Response instance in a response resolver.\n if (errorOrResponse instanceof Response) {\n return errorOrResponse\n }\n\n // Otherwise, throw the error as-is.\n throw errorOrResponse\n })\n\n const mockedResponse = await mockedResponsePromise\n\n if (mockedResponse) {\n forwardResponseCookies(mockedResponse)\n }\n\n const executionResult = this.createExecutionResult({\n // Pass the cloned request to the result so that logging\n // and other consumers could read its body once more.\n request: requestClone,\n requestId: args.requestId,\n response: mockedResponse,\n parsedResult,\n })\n\n return executionResult\n }\n\n private wrapResolver(\n resolver: ResponseResolver<ResolverExtras>,\n ): ResponseResolver<ResolverExtras> {\n return async (info): Promise<ResponseResolverReturnType<any>> => {\n if (!this.resolverIterator) {\n const result = await resolver(info)\n\n if (!isIterable(result)) {\n return result\n }\n\n this.resolverIterator =\n Symbol.iterator in result\n ? result[Symbol.iterator]()\n : result[Symbol.asyncIterator]()\n }\n\n // Opt-out from marking this handler as used.\n this.isUsed = false\n\n const { done, value } = await this.resolverIterator.next()\n const nextResponse = await value\n\n if (nextResponse) {\n this.resolverIteratorResult = nextResponse.clone()\n }\n\n if (done) {\n // A one-time generator resolver stops affecting the network\n // only after it's been completely exhausted.\n this.isUsed = true\n\n // Clone the previously stored response so it can be read\n // when receiving it repeatedly from the \"done\" generator.\n return this.resolverIteratorResult?.clone()\n }\n\n return nextResponse\n }\n }\n\n private createExecutionResult(args: {\n request: Request\n requestId: string\n parsedResult: ParsedResult\n response?: Response\n }): RequestHandlerExecutionResult<ParsedResult> {\n return {\n handler: this,\n request: args.request,\n requestId: args.requestId,\n response: args.response,\n parsedResult: args.parsedResult,\n }\n }\n}\n\n/**\n * Forwards the cookies from the given response to `document.cookie`.\n */\nexport function forwardResponseCookies(response: Response): void {\n // Cookie forwarding is only relevant in the browser.\n if (typeof document === 'undefined') {\n return\n }\n\n const responseCookies = getRawSetCookie(response)\n\n if (!responseCookies) {\n return\n }\n\n // Write the mocked response cookies to the document.\n // Use `headers-polyfill` to get the Set-Cookie header value correctly.\n // This is an alternative until TypeScript 5.2\n // and Node.js v20 become the minimum supported versions\n // and \"Headers.prototype.getSetCookie\" can be used directly.\n const allResponseCookies = HeadersPolyfill.prototype.getSetCookie.call(\n new Headers([['set-cookie', responseCookies]]),\n )\n\n for (const cookieString of allResponseCookies) {\n document.cookie = cookieString\n }\n}\n"],"mappings":"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","names":["HeadersPolyfill"]}
{"version":3,"sources":["../../../src/core/handlers/RequestHandler.ts"],"sourcesContent":["import { Headers as HeadersPolyfill } from 'headers-polyfill'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\nimport {\n isIterable,\n type AsyncIterable,\n type Iterable,\n} from '../utils/internal/isIterable'\nimport type { ResponseResolutionContext } from '../utils/executeHandlers'\nimport type { MaybePromise } from '../typeUtils'\nimport type { HttpResponse } from '../HttpResponse'\nimport {\n type StrictRequest,\n type DefaultUnsafeFetchResponse,\n} from '../HttpResponse'\nimport type { GraphQLRequestBody } from './GraphQLHandler'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { getRawSetCookie } from '../utils/HttpResponse/decorators'\n\nexport type DefaultRequestMultipartBody = Record<\n string,\n string | File | Array<string | File>\n>\n\nexport type DefaultBodyType =\n | Record<string, any>\n | DefaultRequestMultipartBody\n | string\n | number\n | boolean\n | null\n | undefined\n\nexport type JsonBodyType =\n | Record<string, any>\n | string\n | number\n | boolean\n | null\n | undefined\n\nexport interface RequestHandlerDefaultInfo {\n header: string\n}\n\nexport interface RequestHandlerInternalInfo {\n callFrame?: string\n}\n\nexport type ResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType = undefined,\n> =\n // If ResponseBodyType is a union and one of the types is `undefined`,\n // allow plain Response as the type.\n | ([ResponseBodyType] extends [undefined]\n ? Response\n : /**\n * Treat GraphQL response body type as a special case.\n * For esome reason, making the default HttpResponse<T> | DefaultUnsafeFetchResponse\n * union breaks the body type inference for HTTP requests.\n * @see https://github.com/mswjs/msw/issues/2130\n */\n ResponseBodyType extends GraphQLRequestBody<any>\n ? HttpResponse<ResponseBodyType> | DefaultUnsafeFetchResponse\n : HttpResponse<ResponseBodyType>)\n | undefined\n | void\n\nexport type MaybeAsyncResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType,\n> = MaybePromise<ResponseResolverReturnType<ResponseBodyType>>\n\nexport type AsyncResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType,\n> = MaybePromise<\n | ResponseResolverReturnType<ResponseBodyType>\n | Iterable<\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>\n >\n | AsyncIterable<\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>\n >\n>\n\nexport type ResponseResolverInfo<\n ResolverExtraInfo extends Record<string, unknown>,\n RequestBodyType extends DefaultBodyType = DefaultBodyType,\n> = {\n request: StrictRequest<RequestBodyType>\n requestId: string\n /**\n * Schedule a callback to run after this response resolver completes.\n * Handy for cleaning up the side effects introduced in the resolver.\n * @example\n * sse('/', ({ client, finalize }) => {\n * const interval = setInterval(() => client.send({ data: 'ping' }))\n * finalize(() => clearInterval(interval))\n * })\n */\n finalize: ResponseResolverFinalizeFunction\n} & ResolverExtraInfo\n\ntype ResponseResolverFinalizeFunction = (\n callback: () => MaybePromise<void>,\n) => void\n\nexport type ResponseResolver<\n ResolverExtraInfo extends Record<string, unknown> = Record<string, unknown>,\n RequestBodyType extends DefaultBodyType = DefaultBodyType,\n ResponseBodyType extends DefaultBodyType = undefined,\n> = (\n info: ResponseResolverInfo<ResolverExtraInfo, RequestBodyType>,\n) => AsyncResponseResolverReturnType<ResponseBodyType>\n\nexport interface RequestHandlerArgs<\n HandlerInfo,\n HandlerOptions extends RequestHandlerOptions,\n> {\n info: HandlerInfo\n resolver: ResponseResolver<any>\n options?: HandlerOptions\n}\n\nexport interface RequestHandlerOptions {\n once?: boolean\n}\n\nexport interface RequestHandlerExecutionResult<\n ParsedResult extends object | undefined,\n> {\n handler: RequestHandler\n parsedResult?: ParsedResult\n request: Request\n requestId: string\n response?: Response\n}\n\nexport abstract class RequestHandler<\n HandlerInfo extends RequestHandlerDefaultInfo = RequestHandlerDefaultInfo,\n ParsedResult extends Record<string, any> | undefined = any,\n ResolverExtras extends Record<string, unknown> = any,\n HandlerOptions extends RequestHandlerOptions = RequestHandlerOptions,\n> {\n static cache = new WeakMap<\n StrictRequest<DefaultBodyType>,\n StrictRequest<DefaultBodyType>\n >()\n\n public readonly kind = 'request' as const\n\n protected resolver: ResponseResolver<ResolverExtras, any, any>\n private resolverIterator?:\n | Iterator<\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>\n >\n | AsyncIterator<\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>\n >\n private resolverIteratorResult?: Response | HttpResponse<any>\n private resolverIteratorCleanups?: Array<() => MaybePromise<void>>\n private options?: HandlerOptions\n private scheduledCleanups: Map<string, Array<() => MaybePromise<void>>>\n\n public info: HandlerInfo & RequestHandlerInternalInfo\n\n /**\n * Indicates whether this request handler has been used\n * (its resolver has successfully executed).\n */\n public isUsed: boolean\n\n constructor(args: RequestHandlerArgs<HandlerInfo, HandlerOptions>) {\n this.resolver = args.resolver\n this.options = args.options\n this.scheduledCleanups = new Map()\n\n const callFrame = getCallFrame(new Error())\n\n this.info = {\n ...args.info,\n callFrame,\n }\n\n this.isUsed = false\n }\n\n /**\n * Reset the runtime state accumulated during response resolution,\n * such as generator iterator progress. Called when this handler is\n * removed from the active handlers list so re-adding it later starts\n * from a clean state.\n */\n protected reset(): void {\n this.scheduledCleanups.clear()\n\n const iterator = this.resolverIterator\n this.resolverIterator = undefined\n this.resolverIteratorResult = undefined\n this.resolverIteratorCleanups = undefined\n\n if (typeof iterator?.return === 'function') {\n void Promise.resolve(iterator.return())\n }\n }\n\n /**\n * Restore this handler so it can match requests again after being\n * exhausted (e.g. via `{ once: true }`). Also clears any accumulated\n * resolution state.\n */\n protected restore(): void {\n if (this.options?.once) {\n this.reset()\n this.isUsed = false\n }\n }\n\n /**\n * Determine if the intercepted request should be mocked.\n */\n abstract predicate(args: {\n request: Request\n parsedResult: ParsedResult\n resolutionContext?: ResponseResolutionContext\n }): boolean | Promise<boolean>\n\n /**\n * Print out the successfully handled request.\n */\n abstract log(args: {\n request: Request\n response: Response\n parsedResult: ParsedResult\n }): void\n\n /**\n * Parse the intercepted request to extract additional information from it.\n * Parsed result is then exposed to other methods of this request handler.\n */\n async parse(_args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }): Promise<ParsedResult> {\n return {} as ParsedResult\n }\n\n /**\n * Test if this handler matches the given request.\n *\n * This method is not used internally but is exposed\n * as a convenience method for consumers writing custom\n * handlers.\n */\n public async test(args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }): Promise<boolean> {\n const parsedResult = await this.parse({\n request: args.request,\n resolutionContext: args.resolutionContext,\n })\n\n return this.predicate({\n request: args.request,\n parsedResult,\n resolutionContext: args.resolutionContext,\n })\n }\n\n protected extendResolverArgs(_args: {\n request: Request\n parsedResult: ParsedResult\n }): ResolverExtras {\n return {} as ResolverExtras\n }\n\n // Clone the request instance before it's passed to the handler phases\n // and the response resolver so we can always read it for logging.\n // We only clone it once per request to avoid unnecessary overhead.\n private cloneRequestOrGetFromCache(\n request: StrictRequest<DefaultBodyType>,\n ): StrictRequest<DefaultBodyType> {\n const existingClone = RequestHandler.cache.get(request)\n\n if (typeof existingClone !== 'undefined') {\n return existingClone\n }\n\n const clonedRequest = request.clone()\n RequestHandler.cache.set(request, clonedRequest)\n\n return clonedRequest\n }\n\n /**\n * Execute this request handler and produce a mocked response\n * using the given resolver function.\n */\n public async run(args: {\n request: StrictRequest<any>\n requestId: string\n resolutionContext?: ResponseResolutionContext\n }): Promise<RequestHandlerExecutionResult<ParsedResult> | null> {\n if (this.isUsed && this.options?.once) {\n return null\n }\n\n // Clone the request.\n // If this is the first time MSW handles this request, a fresh clone\n // will be created and cached. Upon further handling of the same request,\n // the request clone from the cache will be reused to prevent abundant\n // \"abort\" listeners and save up resources on cloning.\n const requestClone = this.cloneRequestOrGetFromCache(args.request)\n\n const parsedResult = await this.parse({\n request: args.request,\n resolutionContext: args.resolutionContext,\n })\n const shouldInterceptRequest = await this.predicate({\n request: args.request,\n parsedResult,\n resolutionContext: args.resolutionContext,\n })\n\n if (!shouldInterceptRequest) {\n return null\n }\n\n // Re-check isUsed, in case another request hit this handler while we were\n // asynchronously parsing the request.\n if (this.isUsed && this.options?.once) {\n return null\n }\n\n // Preemptively mark the handler as used.\n // Generators will undo this because only when the resolver reaches the\n // \"done\" state of the generator that it considers the handler used.\n this.isUsed = true\n\n // Create a response extraction wrapper around the resolver\n // since it can be both an async function and a generator.\n const executeResolver = this.wrapResolver(this.resolver)\n\n const resolverExtras = this.extendResolverArgs({\n request: args.request,\n parsedResult,\n })\n\n const listenerController = new AbortController()\n\n args.request.signal.addEventListener(\n 'abort',\n () => this.runScheduledCleanups(args.requestId),\n {\n once: true,\n signal: listenerController.signal,\n },\n )\n\n const mockedResponsePromise = (\n executeResolver({\n ...resolverExtras,\n finalize: (callback) => {\n this.scheduleCleanup(args.requestId, callback)\n },\n requestId: args.requestId,\n request: args.request,\n }) as Promise<Response>\n )\n .catch((errorOrResponse) => {\n // Allow throwing a Response instance in a response resolver.\n if (errorOrResponse instanceof Response) {\n return errorOrResponse\n }\n\n // Otherwise, throw the error as-is.\n throw errorOrResponse\n })\n .finally(() => {\n listenerController.abort()\n })\n\n const mockedResponse = await mockedResponsePromise\n\n if (mockedResponse) {\n forwardResponseCookies(mockedResponse)\n }\n\n const executionResult = this.createExecutionResult({\n // Pass the cloned request to the result so that logging\n // and other consumers could read its body once more.\n request: requestClone,\n requestId: args.requestId,\n response: mockedResponse,\n parsedResult,\n })\n\n return executionResult\n }\n\n private wrapResolver(\n resolver: ResponseResolver<ResolverExtras>,\n ): ResponseResolver<ResolverExtras> {\n return async (info): Promise<ResponseResolverReturnType<any>> => {\n if (!this.resolverIterator) {\n let result\n\n try {\n result = await resolver(info)\n } catch (error) {\n // Ensure cleanup if the resolver throws, regardless of the returned type.\n await this.runScheduledCleanups(info.requestId)\n\n // Re-throw the error for the \"run()\" method to handle (e.g. thrown responses).\n throw error\n }\n\n if (!isIterable(result)) {\n // Otherwise, run the cleanup immediately if it's a plain response resolver.\n await this.runScheduledCleanups(info.requestId)\n return result\n }\n\n /**\n * @note Carry over any previously registered cleanups onto the iterator cleanups.\n * This is only relevant if \"finalize()\" is called in a regular resolver that\n * returns an iterator.\n * @example\n * http.get('/', async ({ finalize }) => {\n * finalize(cleanup)\n * return (async function*() {})()\n * })\n */\n const existingCleanups = this.scheduledCleanups.get(info.requestId)\n if (existingCleanups != null && existingCleanups.length > 0) {\n this.resolverIteratorCleanups = existingCleanups\n this.scheduledCleanups.delete(info.requestId)\n }\n\n this.resolverIterator =\n Symbol.iterator in result\n ? result[Symbol.iterator]()\n : result[Symbol.asyncIterator]()\n }\n\n // Opt-out from marking this handler as used.\n this.isUsed = false\n\n const { done, value } = await this.resolverIterator.next()\n const nextResponse = await value\n\n if (nextResponse) {\n this.resolverIteratorResult = nextResponse.clone()\n }\n\n if (done) {\n // A one-time generator resolver stops affecting the network\n // only after it's been completely exhausted.\n this.isUsed = true\n\n await this.runScheduledCleanups(info.requestId)\n\n // Clone the previously stored response so it can be read\n // when receiving it repeatedly from the \"done\" generator.\n return this.resolverIteratorResult?.clone()\n }\n\n return nextResponse\n }\n }\n\n private createExecutionResult(args: {\n request: Request\n requestId: string\n parsedResult: ParsedResult\n response?: Response\n }): RequestHandlerExecutionResult<ParsedResult> {\n return {\n handler: this,\n request: args.request,\n requestId: args.requestId,\n response: args.response,\n parsedResult: args.parsedResult,\n }\n }\n\n private scheduleCleanup(\n requestId: string,\n callback: () => MaybePromise<void>,\n ): void {\n if (this.resolverIterator) {\n ;(this.resolverIteratorCleanups ||= []).unshift(callback)\n return\n }\n\n const cleanups = this.scheduledCleanups.get(requestId) || []\n cleanups.unshift(callback)\n this.scheduledCleanups.set(requestId, cleanups)\n }\n\n private async exhaustCleanups(\n cleanups: Array<() => MaybePromise<void>>,\n ): Promise<void> {\n const errors: Array<Error> = []\n\n for (const cleanup of cleanups) {\n try {\n await cleanup()\n } catch (error) {\n if (error instanceof Error) {\n errors.push(error)\n }\n }\n }\n\n if (errors.length > 0) {\n devUtils.error(\n 'Failed to execute cleanup for request handler \"%s\"',\n this.info.header,\n new AggregateError(\n errors,\n `Failed to execute cleanup for request handler \"${this.info.header}\"`,\n ),\n )\n }\n }\n\n private async runScheduledCleanups(requestId: string): Promise<void> {\n if (\n this.resolverIterator &&\n this.resolverIteratorCleanups != null &&\n this.resolverIteratorCleanups.length > 0\n ) {\n try {\n await this.exhaustCleanups(this.resolverIteratorCleanups)\n } finally {\n this.resolverIteratorCleanups = undefined\n }\n return\n }\n\n const cleanups = this.scheduledCleanups.get(requestId)\n\n if (!cleanups || cleanups.length == 0) {\n return\n }\n\n await this.exhaustCleanups(cleanups)\n this.scheduledCleanups.delete(requestId)\n }\n}\n\n/**\n * Forwards the cookies from the given response to `document.cookie`.\n */\nexport function forwardResponseCookies(response: Response): void {\n // Cookie forwarding is only relevant in the browser.\n if (typeof document === 'undefined') {\n return\n }\n\n const responseCookies = getRawSetCookie(response)\n\n if (!responseCookies) {\n return\n }\n\n // Write the mocked response cookies to the document.\n // Use `headers-polyfill` to get the Set-Cookie header value correctly.\n // This is an alternative until TypeScript 5.2\n // and Node.js v20 become the minimum supported versions\n // and \"Headers.prototype.getSetCookie\" can be used directly.\n const allResponseCookies = HeadersPolyfill.prototype.getSetCookie.call(\n new Headers([['set-cookie', responseCookies]]),\n )\n\n for (const cookieString of allResponseCookies) {\n document.cookie = cookieString\n }\n}\n"],"mappings":"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","names":["HeadersPolyfill"]}

@@ -8,2 +8,3 @@ import { Headers as HeadersPolyfill } from "headers-polyfill";

} from '../HttpResponse.mjs';
import { devUtils } from '../utils/internal/devUtils.mjs';
import { getRawSetCookie } from '../utils/HttpResponse/decorators.mjs';

@@ -16,3 +17,5 @@ class RequestHandler {

resolverIteratorResult;
resolverIteratorCleanups;
options;
scheduledCleanups;
info;

@@ -27,2 +30,3 @@ /**

this.options = args.options;
this.scheduledCleanups = /* @__PURE__ */ new Map();
const callFrame = getCallFrame(new Error());

@@ -42,5 +46,7 @@ this.info = {

reset() {
this.scheduledCleanups.clear();
const iterator = this.resolverIterator;
this.resolverIterator = void 0;
this.resolverIteratorResult = void 0;
this.resolverIteratorCleanups = void 0;
if (typeof iterator?.return === "function") {

@@ -131,4 +137,16 @@ void Promise.resolve(iterator.return());

});
const listenerController = new AbortController();
args.request.signal.addEventListener(
"abort",
() => this.runScheduledCleanups(args.requestId),
{
once: true,
signal: listenerController.signal
}
);
const mockedResponsePromise = executeResolver({
...resolverExtras,
finalize: (callback) => {
this.scheduleCleanup(args.requestId, callback);
},
requestId: args.requestId,

@@ -141,2 +159,4 @@ request: args.request

throw errorOrResponse;
}).finally(() => {
listenerController.abort();
});

@@ -160,6 +180,18 @@ const mockedResponse = await mockedResponsePromise;

if (!this.resolverIterator) {
const result = await resolver(info);
let result;
try {
result = await resolver(info);
} catch (error) {
await this.runScheduledCleanups(info.requestId);
throw error;
}
if (!isIterable(result)) {
await this.runScheduledCleanups(info.requestId);
return result;
}
const existingCleanups = this.scheduledCleanups.get(info.requestId);
if (existingCleanups != null && existingCleanups.length > 0) {
this.resolverIteratorCleanups = existingCleanups;
this.scheduledCleanups.delete(info.requestId);
}
this.resolverIterator = Symbol.iterator in result ? result[Symbol.iterator]() : result[Symbol.asyncIterator]();

@@ -175,2 +207,3 @@ }

this.isUsed = true;
await this.runScheduledCleanups(info.requestId);
return this.resolverIteratorResult?.clone();

@@ -190,2 +223,50 @@ }

}
scheduleCleanup(requestId, callback) {
if (this.resolverIterator) {
;
(this.resolverIteratorCleanups ||= []).unshift(callback);
return;
}
const cleanups = this.scheduledCleanups.get(requestId) || [];
cleanups.unshift(callback);
this.scheduledCleanups.set(requestId, cleanups);
}
async exhaustCleanups(cleanups) {
const errors = [];
for (const cleanup of cleanups) {
try {
await cleanup();
} catch (error) {
if (error instanceof Error) {
errors.push(error);
}
}
}
if (errors.length > 0) {
devUtils.error(
'Failed to execute cleanup for request handler "%s"',
this.info.header,
new AggregateError(
errors,
`Failed to execute cleanup for request handler "${this.info.header}"`
)
);
}
}
async runScheduledCleanups(requestId) {
if (this.resolverIterator && this.resolverIteratorCleanups != null && this.resolverIteratorCleanups.length > 0) {
try {
await this.exhaustCleanups(this.resolverIteratorCleanups);
} finally {
this.resolverIteratorCleanups = void 0;
}
return;
}
const cleanups = this.scheduledCleanups.get(requestId);
if (!cleanups || cleanups.length == 0) {
return;
}
await this.exhaustCleanups(cleanups);
this.scheduledCleanups.delete(requestId);
}
}

@@ -192,0 +273,0 @@ function forwardResponseCookies(response) {

@@ -1,1 +0,1 @@

{"version":3,"sources":["../../../src/core/handlers/RequestHandler.ts"],"sourcesContent":["import { Headers as HeadersPolyfill } from 'headers-polyfill'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\nimport {\n isIterable,\n type AsyncIterable,\n type Iterable,\n} from '../utils/internal/isIterable'\nimport type { ResponseResolutionContext } from '../utils/executeHandlers'\nimport type { MaybePromise } from '../typeUtils'\nimport type { HttpResponse } from '../HttpResponse'\nimport {\n type StrictRequest,\n type DefaultUnsafeFetchResponse,\n} from '../HttpResponse'\nimport type { GraphQLRequestBody } from './GraphQLHandler'\nimport { getRawSetCookie } from '../utils/HttpResponse/decorators'\n\nexport type DefaultRequestMultipartBody = Record<\n string,\n string | File | Array<string | File>\n>\n\nexport type DefaultBodyType =\n | Record<string, any>\n | DefaultRequestMultipartBody\n | string\n | number\n | boolean\n | null\n | undefined\n\nexport type JsonBodyType =\n | Record<string, any>\n | string\n | number\n | boolean\n | null\n | undefined\n\nexport interface RequestHandlerDefaultInfo {\n header: string\n}\n\nexport interface RequestHandlerInternalInfo {\n callFrame?: string\n}\n\nexport type ResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType = undefined,\n> =\n // If ResponseBodyType is a union and one of the types is `undefined`,\n // allow plain Response as the type.\n | ([ResponseBodyType] extends [undefined]\n ? Response\n : /**\n * Treat GraphQL response body type as a special case.\n * For esome reason, making the default HttpResponse<T> | DefaultUnsafeFetchResponse\n * union breaks the body type inference for HTTP requests.\n * @see https://github.com/mswjs/msw/issues/2130\n */\n ResponseBodyType extends GraphQLRequestBody<any>\n ? HttpResponse<ResponseBodyType> | DefaultUnsafeFetchResponse\n : HttpResponse<ResponseBodyType>)\n | undefined\n | void\n\nexport type MaybeAsyncResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType,\n> = MaybePromise<ResponseResolverReturnType<ResponseBodyType>>\n\nexport type AsyncResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType,\n> = MaybePromise<\n | ResponseResolverReturnType<ResponseBodyType>\n | Iterable<\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>\n >\n | AsyncIterable<\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>\n >\n>\n\nexport type ResponseResolverInfo<\n ResolverExtraInfo extends Record<string, unknown>,\n RequestBodyType extends DefaultBodyType = DefaultBodyType,\n> = {\n request: StrictRequest<RequestBodyType>\n requestId: string\n} & ResolverExtraInfo\n\nexport type ResponseResolver<\n ResolverExtraInfo extends Record<string, unknown> = Record<string, unknown>,\n RequestBodyType extends DefaultBodyType = DefaultBodyType,\n ResponseBodyType extends DefaultBodyType = undefined,\n> = (\n info: ResponseResolverInfo<ResolverExtraInfo, RequestBodyType>,\n) => AsyncResponseResolverReturnType<ResponseBodyType>\n\nexport interface RequestHandlerArgs<\n HandlerInfo,\n HandlerOptions extends RequestHandlerOptions,\n> {\n info: HandlerInfo\n resolver: ResponseResolver<any>\n options?: HandlerOptions\n}\n\nexport interface RequestHandlerOptions {\n once?: boolean\n}\n\nexport interface RequestHandlerExecutionResult<\n ParsedResult extends object | undefined,\n> {\n handler: RequestHandler\n parsedResult?: ParsedResult\n request: Request\n requestId: string\n response?: Response\n}\n\nexport abstract class RequestHandler<\n HandlerInfo extends RequestHandlerDefaultInfo = RequestHandlerDefaultInfo,\n ParsedResult extends Record<string, any> | undefined = any,\n ResolverExtras extends Record<string, unknown> = any,\n HandlerOptions extends RequestHandlerOptions = RequestHandlerOptions,\n> {\n static cache = new WeakMap<\n StrictRequest<DefaultBodyType>,\n StrictRequest<DefaultBodyType>\n >()\n\n public readonly kind = 'request' as const\n\n protected resolver: ResponseResolver<ResolverExtras, any, any>\n private resolverIterator?:\n | Iterator<\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>\n >\n | AsyncIterator<\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>\n >\n private resolverIteratorResult?: Response | HttpResponse<any>\n private options?: HandlerOptions\n\n public info: HandlerInfo & RequestHandlerInternalInfo\n\n /**\n * Indicates whether this request handler has been used\n * (its resolver has successfully executed).\n */\n public isUsed: boolean\n\n constructor(args: RequestHandlerArgs<HandlerInfo, HandlerOptions>) {\n this.resolver = args.resolver\n this.options = args.options\n\n const callFrame = getCallFrame(new Error())\n\n this.info = {\n ...args.info,\n callFrame,\n }\n\n this.isUsed = false\n }\n\n /**\n * Reset the runtime state accumulated during response resolution,\n * such as generator iterator progress. Called when this handler is\n * removed from the active handlers list so re-adding it later starts\n * from a clean state.\n */\n protected reset(): void {\n const iterator = this.resolverIterator\n this.resolverIterator = undefined\n this.resolverIteratorResult = undefined\n\n if (typeof iterator?.return === 'function') {\n void Promise.resolve(iterator.return())\n }\n }\n\n /**\n * Restore this handler so it can match requests again after being\n * exhausted (e.g. via `{ once: true }`). Also clears any accumulated\n * resolution state.\n */\n protected restore(): void {\n if (this.options?.once) {\n this.reset()\n this.isUsed = false\n }\n }\n\n /**\n * Determine if the intercepted request should be mocked.\n */\n abstract predicate(args: {\n request: Request\n parsedResult: ParsedResult\n resolutionContext?: ResponseResolutionContext\n }): boolean | Promise<boolean>\n\n /**\n * Print out the successfully handled request.\n */\n abstract log(args: {\n request: Request\n response: Response\n parsedResult: ParsedResult\n }): void\n\n /**\n * Parse the intercepted request to extract additional information from it.\n * Parsed result is then exposed to other methods of this request handler.\n */\n async parse(_args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }): Promise<ParsedResult> {\n return {} as ParsedResult\n }\n\n /**\n * Test if this handler matches the given request.\n *\n * This method is not used internally but is exposed\n * as a convenience method for consumers writing custom\n * handlers.\n */\n public async test(args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }): Promise<boolean> {\n const parsedResult = await this.parse({\n request: args.request,\n resolutionContext: args.resolutionContext,\n })\n\n return this.predicate({\n request: args.request,\n parsedResult,\n resolutionContext: args.resolutionContext,\n })\n }\n\n protected extendResolverArgs(_args: {\n request: Request\n parsedResult: ParsedResult\n }): ResolverExtras {\n return {} as ResolverExtras\n }\n\n // Clone the request instance before it's passed to the handler phases\n // and the response resolver so we can always read it for logging.\n // We only clone it once per request to avoid unnecessary overhead.\n private cloneRequestOrGetFromCache(\n request: StrictRequest<DefaultBodyType>,\n ): StrictRequest<DefaultBodyType> {\n const existingClone = RequestHandler.cache.get(request)\n\n if (typeof existingClone !== 'undefined') {\n return existingClone\n }\n\n const clonedRequest = request.clone()\n RequestHandler.cache.set(request, clonedRequest)\n\n return clonedRequest\n }\n\n /**\n * Execute this request handler and produce a mocked response\n * using the given resolver function.\n */\n public async run(args: {\n request: StrictRequest<any>\n requestId: string\n resolutionContext?: ResponseResolutionContext\n }): Promise<RequestHandlerExecutionResult<ParsedResult> | null> {\n if (this.isUsed && this.options?.once) {\n return null\n }\n\n // Clone the request.\n // If this is the first time MSW handles this request, a fresh clone\n // will be created and cached. Upon further handling of the same request,\n // the request clone from the cache will be reused to prevent abundant\n // \"abort\" listeners and save up resources on cloning.\n const requestClone = this.cloneRequestOrGetFromCache(args.request)\n\n const parsedResult = await this.parse({\n request: args.request,\n resolutionContext: args.resolutionContext,\n })\n const shouldInterceptRequest = await this.predicate({\n request: args.request,\n parsedResult,\n resolutionContext: args.resolutionContext,\n })\n\n if (!shouldInterceptRequest) {\n return null\n }\n\n // Re-check isUsed, in case another request hit this handler while we were\n // asynchronously parsing the request.\n if (this.isUsed && this.options?.once) {\n return null\n }\n\n // Preemptively mark the handler as used.\n // Generators will undo this because only when the resolver reaches the\n // \"done\" state of the generator that it considers the handler used.\n this.isUsed = true\n\n // Create a response extraction wrapper around the resolver\n // since it can be both an async function and a generator.\n const executeResolver = this.wrapResolver(this.resolver)\n\n const resolverExtras = this.extendResolverArgs({\n request: args.request,\n parsedResult,\n })\n\n const mockedResponsePromise = (\n executeResolver({\n ...resolverExtras,\n requestId: args.requestId,\n request: args.request,\n }) as Promise<Response | undefined>\n ).catch((errorOrResponse) => {\n // Allow throwing a Response instance in a response resolver.\n if (errorOrResponse instanceof Response) {\n return errorOrResponse\n }\n\n // Otherwise, throw the error as-is.\n throw errorOrResponse\n })\n\n const mockedResponse = await mockedResponsePromise\n\n if (mockedResponse) {\n forwardResponseCookies(mockedResponse)\n }\n\n const executionResult = this.createExecutionResult({\n // Pass the cloned request to the result so that logging\n // and other consumers could read its body once more.\n request: requestClone,\n requestId: args.requestId,\n response: mockedResponse,\n parsedResult,\n })\n\n return executionResult\n }\n\n private wrapResolver(\n resolver: ResponseResolver<ResolverExtras>,\n ): ResponseResolver<ResolverExtras> {\n return async (info): Promise<ResponseResolverReturnType<any>> => {\n if (!this.resolverIterator) {\n const result = await resolver(info)\n\n if (!isIterable(result)) {\n return result\n }\n\n this.resolverIterator =\n Symbol.iterator in result\n ? result[Symbol.iterator]()\n : result[Symbol.asyncIterator]()\n }\n\n // Opt-out from marking this handler as used.\n this.isUsed = false\n\n const { done, value } = await this.resolverIterator.next()\n const nextResponse = await value\n\n if (nextResponse) {\n this.resolverIteratorResult = nextResponse.clone()\n }\n\n if (done) {\n // A one-time generator resolver stops affecting the network\n // only after it's been completely exhausted.\n this.isUsed = true\n\n // Clone the previously stored response so it can be read\n // when receiving it repeatedly from the \"done\" generator.\n return this.resolverIteratorResult?.clone()\n }\n\n return nextResponse\n }\n }\n\n private createExecutionResult(args: {\n request: Request\n requestId: string\n parsedResult: ParsedResult\n response?: Response\n }): RequestHandlerExecutionResult<ParsedResult> {\n return {\n handler: this,\n request: args.request,\n requestId: args.requestId,\n response: args.response,\n parsedResult: args.parsedResult,\n }\n }\n}\n\n/**\n * Forwards the cookies from the given response to `document.cookie`.\n */\nexport function forwardResponseCookies(response: Response): void {\n // Cookie forwarding is only relevant in the browser.\n if (typeof document === 'undefined') {\n return\n }\n\n const responseCookies = getRawSetCookie(response)\n\n if (!responseCookies) {\n return\n }\n\n // Write the mocked response cookies to the document.\n // Use `headers-polyfill` to get the Set-Cookie header value correctly.\n // This is an alternative until TypeScript 5.2\n // and Node.js v20 become the minimum supported versions\n // and \"Headers.prototype.getSetCookie\" can be used directly.\n const allResponseCookies = HeadersPolyfill.prototype.getSetCookie.call(\n new Headers([['set-cookie', responseCookies]]),\n )\n\n for (const cookieString of allResponseCookies) {\n document.cookie = cookieString\n }\n}\n"],"mappings":"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","names":[]}
{"version":3,"sources":["../../../src/core/handlers/RequestHandler.ts"],"sourcesContent":["import { Headers as HeadersPolyfill } from 'headers-polyfill'\nimport { getCallFrame } from '../utils/internal/getCallFrame'\nimport {\n isIterable,\n type AsyncIterable,\n type Iterable,\n} from '../utils/internal/isIterable'\nimport type { ResponseResolutionContext } from '../utils/executeHandlers'\nimport type { MaybePromise } from '../typeUtils'\nimport type { HttpResponse } from '../HttpResponse'\nimport {\n type StrictRequest,\n type DefaultUnsafeFetchResponse,\n} from '../HttpResponse'\nimport type { GraphQLRequestBody } from './GraphQLHandler'\nimport { devUtils } from '../utils/internal/devUtils'\nimport { getRawSetCookie } from '../utils/HttpResponse/decorators'\n\nexport type DefaultRequestMultipartBody = Record<\n string,\n string | File | Array<string | File>\n>\n\nexport type DefaultBodyType =\n | Record<string, any>\n | DefaultRequestMultipartBody\n | string\n | number\n | boolean\n | null\n | undefined\n\nexport type JsonBodyType =\n | Record<string, any>\n | string\n | number\n | boolean\n | null\n | undefined\n\nexport interface RequestHandlerDefaultInfo {\n header: string\n}\n\nexport interface RequestHandlerInternalInfo {\n callFrame?: string\n}\n\nexport type ResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType = undefined,\n> =\n // If ResponseBodyType is a union and one of the types is `undefined`,\n // allow plain Response as the type.\n | ([ResponseBodyType] extends [undefined]\n ? Response\n : /**\n * Treat GraphQL response body type as a special case.\n * For esome reason, making the default HttpResponse<T> | DefaultUnsafeFetchResponse\n * union breaks the body type inference for HTTP requests.\n * @see https://github.com/mswjs/msw/issues/2130\n */\n ResponseBodyType extends GraphQLRequestBody<any>\n ? HttpResponse<ResponseBodyType> | DefaultUnsafeFetchResponse\n : HttpResponse<ResponseBodyType>)\n | undefined\n | void\n\nexport type MaybeAsyncResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType,\n> = MaybePromise<ResponseResolverReturnType<ResponseBodyType>>\n\nexport type AsyncResponseResolverReturnType<\n ResponseBodyType extends DefaultBodyType,\n> = MaybePromise<\n | ResponseResolverReturnType<ResponseBodyType>\n | Iterable<\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>\n >\n | AsyncIterable<\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>,\n MaybeAsyncResponseResolverReturnType<ResponseBodyType>\n >\n>\n\nexport type ResponseResolverInfo<\n ResolverExtraInfo extends Record<string, unknown>,\n RequestBodyType extends DefaultBodyType = DefaultBodyType,\n> = {\n request: StrictRequest<RequestBodyType>\n requestId: string\n /**\n * Schedule a callback to run after this response resolver completes.\n * Handy for cleaning up the side effects introduced in the resolver.\n * @example\n * sse('/', ({ client, finalize }) => {\n * const interval = setInterval(() => client.send({ data: 'ping' }))\n * finalize(() => clearInterval(interval))\n * })\n */\n finalize: ResponseResolverFinalizeFunction\n} & ResolverExtraInfo\n\ntype ResponseResolverFinalizeFunction = (\n callback: () => MaybePromise<void>,\n) => void\n\nexport type ResponseResolver<\n ResolverExtraInfo extends Record<string, unknown> = Record<string, unknown>,\n RequestBodyType extends DefaultBodyType = DefaultBodyType,\n ResponseBodyType extends DefaultBodyType = undefined,\n> = (\n info: ResponseResolverInfo<ResolverExtraInfo, RequestBodyType>,\n) => AsyncResponseResolverReturnType<ResponseBodyType>\n\nexport interface RequestHandlerArgs<\n HandlerInfo,\n HandlerOptions extends RequestHandlerOptions,\n> {\n info: HandlerInfo\n resolver: ResponseResolver<any>\n options?: HandlerOptions\n}\n\nexport interface RequestHandlerOptions {\n once?: boolean\n}\n\nexport interface RequestHandlerExecutionResult<\n ParsedResult extends object | undefined,\n> {\n handler: RequestHandler\n parsedResult?: ParsedResult\n request: Request\n requestId: string\n response?: Response\n}\n\nexport abstract class RequestHandler<\n HandlerInfo extends RequestHandlerDefaultInfo = RequestHandlerDefaultInfo,\n ParsedResult extends Record<string, any> | undefined = any,\n ResolverExtras extends Record<string, unknown> = any,\n HandlerOptions extends RequestHandlerOptions = RequestHandlerOptions,\n> {\n static cache = new WeakMap<\n StrictRequest<DefaultBodyType>,\n StrictRequest<DefaultBodyType>\n >()\n\n public readonly kind = 'request' as const\n\n protected resolver: ResponseResolver<ResolverExtras, any, any>\n private resolverIterator?:\n | Iterator<\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>\n >\n | AsyncIterator<\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>,\n MaybeAsyncResponseResolverReturnType<any>\n >\n private resolverIteratorResult?: Response | HttpResponse<any>\n private resolverIteratorCleanups?: Array<() => MaybePromise<void>>\n private options?: HandlerOptions\n private scheduledCleanups: Map<string, Array<() => MaybePromise<void>>>\n\n public info: HandlerInfo & RequestHandlerInternalInfo\n\n /**\n * Indicates whether this request handler has been used\n * (its resolver has successfully executed).\n */\n public isUsed: boolean\n\n constructor(args: RequestHandlerArgs<HandlerInfo, HandlerOptions>) {\n this.resolver = args.resolver\n this.options = args.options\n this.scheduledCleanups = new Map()\n\n const callFrame = getCallFrame(new Error())\n\n this.info = {\n ...args.info,\n callFrame,\n }\n\n this.isUsed = false\n }\n\n /**\n * Reset the runtime state accumulated during response resolution,\n * such as generator iterator progress. Called when this handler is\n * removed from the active handlers list so re-adding it later starts\n * from a clean state.\n */\n protected reset(): void {\n this.scheduledCleanups.clear()\n\n const iterator = this.resolverIterator\n this.resolverIterator = undefined\n this.resolverIteratorResult = undefined\n this.resolverIteratorCleanups = undefined\n\n if (typeof iterator?.return === 'function') {\n void Promise.resolve(iterator.return())\n }\n }\n\n /**\n * Restore this handler so it can match requests again after being\n * exhausted (e.g. via `{ once: true }`). Also clears any accumulated\n * resolution state.\n */\n protected restore(): void {\n if (this.options?.once) {\n this.reset()\n this.isUsed = false\n }\n }\n\n /**\n * Determine if the intercepted request should be mocked.\n */\n abstract predicate(args: {\n request: Request\n parsedResult: ParsedResult\n resolutionContext?: ResponseResolutionContext\n }): boolean | Promise<boolean>\n\n /**\n * Print out the successfully handled request.\n */\n abstract log(args: {\n request: Request\n response: Response\n parsedResult: ParsedResult\n }): void\n\n /**\n * Parse the intercepted request to extract additional information from it.\n * Parsed result is then exposed to other methods of this request handler.\n */\n async parse(_args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }): Promise<ParsedResult> {\n return {} as ParsedResult\n }\n\n /**\n * Test if this handler matches the given request.\n *\n * This method is not used internally but is exposed\n * as a convenience method for consumers writing custom\n * handlers.\n */\n public async test(args: {\n request: Request\n resolutionContext?: ResponseResolutionContext\n }): Promise<boolean> {\n const parsedResult = await this.parse({\n request: args.request,\n resolutionContext: args.resolutionContext,\n })\n\n return this.predicate({\n request: args.request,\n parsedResult,\n resolutionContext: args.resolutionContext,\n })\n }\n\n protected extendResolverArgs(_args: {\n request: Request\n parsedResult: ParsedResult\n }): ResolverExtras {\n return {} as ResolverExtras\n }\n\n // Clone the request instance before it's passed to the handler phases\n // and the response resolver so we can always read it for logging.\n // We only clone it once per request to avoid unnecessary overhead.\n private cloneRequestOrGetFromCache(\n request: StrictRequest<DefaultBodyType>,\n ): StrictRequest<DefaultBodyType> {\n const existingClone = RequestHandler.cache.get(request)\n\n if (typeof existingClone !== 'undefined') {\n return existingClone\n }\n\n const clonedRequest = request.clone()\n RequestHandler.cache.set(request, clonedRequest)\n\n return clonedRequest\n }\n\n /**\n * Execute this request handler and produce a mocked response\n * using the given resolver function.\n */\n public async run(args: {\n request: StrictRequest<any>\n requestId: string\n resolutionContext?: ResponseResolutionContext\n }): Promise<RequestHandlerExecutionResult<ParsedResult> | null> {\n if (this.isUsed && this.options?.once) {\n return null\n }\n\n // Clone the request.\n // If this is the first time MSW handles this request, a fresh clone\n // will be created and cached. Upon further handling of the same request,\n // the request clone from the cache will be reused to prevent abundant\n // \"abort\" listeners and save up resources on cloning.\n const requestClone = this.cloneRequestOrGetFromCache(args.request)\n\n const parsedResult = await this.parse({\n request: args.request,\n resolutionContext: args.resolutionContext,\n })\n const shouldInterceptRequest = await this.predicate({\n request: args.request,\n parsedResult,\n resolutionContext: args.resolutionContext,\n })\n\n if (!shouldInterceptRequest) {\n return null\n }\n\n // Re-check isUsed, in case another request hit this handler while we were\n // asynchronously parsing the request.\n if (this.isUsed && this.options?.once) {\n return null\n }\n\n // Preemptively mark the handler as used.\n // Generators will undo this because only when the resolver reaches the\n // \"done\" state of the generator that it considers the handler used.\n this.isUsed = true\n\n // Create a response extraction wrapper around the resolver\n // since it can be both an async function and a generator.\n const executeResolver = this.wrapResolver(this.resolver)\n\n const resolverExtras = this.extendResolverArgs({\n request: args.request,\n parsedResult,\n })\n\n const listenerController = new AbortController()\n\n args.request.signal.addEventListener(\n 'abort',\n () => this.runScheduledCleanups(args.requestId),\n {\n once: true,\n signal: listenerController.signal,\n },\n )\n\n const mockedResponsePromise = (\n executeResolver({\n ...resolverExtras,\n finalize: (callback) => {\n this.scheduleCleanup(args.requestId, callback)\n },\n requestId: args.requestId,\n request: args.request,\n }) as Promise<Response>\n )\n .catch((errorOrResponse) => {\n // Allow throwing a Response instance in a response resolver.\n if (errorOrResponse instanceof Response) {\n return errorOrResponse\n }\n\n // Otherwise, throw the error as-is.\n throw errorOrResponse\n })\n .finally(() => {\n listenerController.abort()\n })\n\n const mockedResponse = await mockedResponsePromise\n\n if (mockedResponse) {\n forwardResponseCookies(mockedResponse)\n }\n\n const executionResult = this.createExecutionResult({\n // Pass the cloned request to the result so that logging\n // and other consumers could read its body once more.\n request: requestClone,\n requestId: args.requestId,\n response: mockedResponse,\n parsedResult,\n })\n\n return executionResult\n }\n\n private wrapResolver(\n resolver: ResponseResolver<ResolverExtras>,\n ): ResponseResolver<ResolverExtras> {\n return async (info): Promise<ResponseResolverReturnType<any>> => {\n if (!this.resolverIterator) {\n let result\n\n try {\n result = await resolver(info)\n } catch (error) {\n // Ensure cleanup if the resolver throws, regardless of the returned type.\n await this.runScheduledCleanups(info.requestId)\n\n // Re-throw the error for the \"run()\" method to handle (e.g. thrown responses).\n throw error\n }\n\n if (!isIterable(result)) {\n // Otherwise, run the cleanup immediately if it's a plain response resolver.\n await this.runScheduledCleanups(info.requestId)\n return result\n }\n\n /**\n * @note Carry over any previously registered cleanups onto the iterator cleanups.\n * This is only relevant if \"finalize()\" is called in a regular resolver that\n * returns an iterator.\n * @example\n * http.get('/', async ({ finalize }) => {\n * finalize(cleanup)\n * return (async function*() {})()\n * })\n */\n const existingCleanups = this.scheduledCleanups.get(info.requestId)\n if (existingCleanups != null && existingCleanups.length > 0) {\n this.resolverIteratorCleanups = existingCleanups\n this.scheduledCleanups.delete(info.requestId)\n }\n\n this.resolverIterator =\n Symbol.iterator in result\n ? result[Symbol.iterator]()\n : result[Symbol.asyncIterator]()\n }\n\n // Opt-out from marking this handler as used.\n this.isUsed = false\n\n const { done, value } = await this.resolverIterator.next()\n const nextResponse = await value\n\n if (nextResponse) {\n this.resolverIteratorResult = nextResponse.clone()\n }\n\n if (done) {\n // A one-time generator resolver stops affecting the network\n // only after it's been completely exhausted.\n this.isUsed = true\n\n await this.runScheduledCleanups(info.requestId)\n\n // Clone the previously stored response so it can be read\n // when receiving it repeatedly from the \"done\" generator.\n return this.resolverIteratorResult?.clone()\n }\n\n return nextResponse\n }\n }\n\n private createExecutionResult(args: {\n request: Request\n requestId: string\n parsedResult: ParsedResult\n response?: Response\n }): RequestHandlerExecutionResult<ParsedResult> {\n return {\n handler: this,\n request: args.request,\n requestId: args.requestId,\n response: args.response,\n parsedResult: args.parsedResult,\n }\n }\n\n private scheduleCleanup(\n requestId: string,\n callback: () => MaybePromise<void>,\n ): void {\n if (this.resolverIterator) {\n ;(this.resolverIteratorCleanups ||= []).unshift(callback)\n return\n }\n\n const cleanups = this.scheduledCleanups.get(requestId) || []\n cleanups.unshift(callback)\n this.scheduledCleanups.set(requestId, cleanups)\n }\n\n private async exhaustCleanups(\n cleanups: Array<() => MaybePromise<void>>,\n ): Promise<void> {\n const errors: Array<Error> = []\n\n for (const cleanup of cleanups) {\n try {\n await cleanup()\n } catch (error) {\n if (error instanceof Error) {\n errors.push(error)\n }\n }\n }\n\n if (errors.length > 0) {\n devUtils.error(\n 'Failed to execute cleanup for request handler \"%s\"',\n this.info.header,\n new AggregateError(\n errors,\n `Failed to execute cleanup for request handler \"${this.info.header}\"`,\n ),\n )\n }\n }\n\n private async runScheduledCleanups(requestId: string): Promise<void> {\n if (\n this.resolverIterator &&\n this.resolverIteratorCleanups != null &&\n this.resolverIteratorCleanups.length > 0\n ) {\n try {\n await this.exhaustCleanups(this.resolverIteratorCleanups)\n } finally {\n this.resolverIteratorCleanups = undefined\n }\n return\n }\n\n const cleanups = this.scheduledCleanups.get(requestId)\n\n if (!cleanups || cleanups.length == 0) {\n return\n }\n\n await this.exhaustCleanups(cleanups)\n this.scheduledCleanups.delete(requestId)\n }\n}\n\n/**\n * Forwards the cookies from the given response to `document.cookie`.\n */\nexport function forwardResponseCookies(response: Response): void {\n // Cookie forwarding is only relevant in the browser.\n if (typeof document === 'undefined') {\n return\n }\n\n const responseCookies = getRawSetCookie(response)\n\n if (!responseCookies) {\n return\n }\n\n // Write the mocked response cookies to the document.\n // Use `headers-polyfill` to get the Set-Cookie header value correctly.\n // This is an alternative until TypeScript 5.2\n // and Node.js v20 become the minimum supported versions\n // and \"Headers.prototype.getSetCookie\" can be used directly.\n const allResponseCookies = HeadersPolyfill.prototype.getSetCookie.call(\n new Headers([['set-cookie', responseCookies]]),\n )\n\n for (const cookieString of allResponseCookies) {\n document.cookie = cookieString\n }\n}\n"],"mappings":"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","names":[]}

@@ -1,2 +0,2 @@

import { D as DefaultBodyType, a as ResponseResolver, c as RequestHandlerOptions } from './HttpResponse-CxHR1nNN.mjs';
import { D as DefaultBodyType, a as ResponseResolver, c as RequestHandlerOptions } from './HttpResponse-CQwYpuKo.mjs';
import { HttpRequestPredicate, HttpRequestResolverExtras, HttpHandler } from './handlers/HttpHandler.mjs';

@@ -3,0 +3,0 @@ import { PathParams } from './utils/matching/matchRequestUrl.mjs';

@@ -1,2 +0,2 @@

import { D as DefaultBodyType, a as ResponseResolver, c as RequestHandlerOptions } from './HttpResponse-aGiIzO91.js';
import { D as DefaultBodyType, a as ResponseResolver, c as RequestHandlerOptions } from './HttpResponse-BFS34nkx.js';
import { HttpRequestPredicate, HttpRequestResolverExtras, HttpHandler } from './handlers/HttpHandler.js';

@@ -3,0 +3,0 @@ import { PathParams } from './utils/matching/matchRequestUrl.js';

import '@mswjs/interceptors';
export { T as DefaultUnsafeFetchResponse, H as HttpResponse, n as HttpResponseInit, S as StrictRequest, o as StrictResponse, Q as bodyType, U as kDefaultContentType } from './HttpResponse-CxHR1nNN.mjs';
export { T as DefaultUnsafeFetchResponse, H as HttpResponse, n as HttpResponseInit, S as StrictRequest, o as StrictResponse, Q as bodyType, U as kDefaultContentType } from './HttpResponse-CQwYpuKo.mjs';
import './typeUtils.mjs';

@@ -4,0 +4,0 @@ import './utils/internal/isIterable.mjs';

import '@mswjs/interceptors';
export { T as DefaultUnsafeFetchResponse, H as HttpResponse, n as HttpResponseInit, S as StrictRequest, o as StrictResponse, Q as bodyType, U as kDefaultContentType } from './HttpResponse-aGiIzO91.js';
export { T as DefaultUnsafeFetchResponse, H as HttpResponse, n as HttpResponseInit, S as StrictRequest, o as StrictResponse, Q as bodyType, U as kDefaultContentType } from './HttpResponse-BFS34nkx.js';
import './typeUtils.js';

@@ -4,0 +4,0 @@ import './utils/internal/isIterable.js';

export { SetupApi } from './experimental/setup-api.mjs';
export { A as AsyncResponseResolverReturnType, D as DefaultBodyType, d as DefaultRequestMultipartBody, l as GraphQLCustomPredicate, G as GraphQLHandler, j as GraphQLJsonRequestBody, k as GraphQLOperationType, f as GraphQLQuery, h as GraphQLRequestBody, i as GraphQLResponseBody, g as GraphQLVariables, H as HttpResponse, n as HttpResponseInit, J as JsonBodyType, P as ParsedGraphQLRequest, R as RequestHandler, c as RequestHandlerOptions, m as ResponseResolutionContext, a as ResponseResolver, e as ResponseResolverInfo, b as ResponseResolverReturnType, S as StrictRequest, o as StrictResponse } from './HttpResponse-CxHR1nNN.mjs';
export { A as AsyncResponseResolverReturnType, D as DefaultBodyType, d as DefaultRequestMultipartBody, l as GraphQLCustomPredicate, G as GraphQLHandler, j as GraphQLJsonRequestBody, k as GraphQLOperationType, f as GraphQLQuery, h as GraphQLRequestBody, i as GraphQLResponseBody, g as GraphQLVariables, H as HttpResponse, n as HttpResponseInit, J as JsonBodyType, P as ParsedGraphQLRequest, R as RequestHandler, c as RequestHandlerOptions, m as ResponseResolutionContext, a as ResponseResolver, e as ResponseResolverInfo, b as ResponseResolverReturnType, S as StrictRequest, o as StrictResponse } from './HttpResponse-CQwYpuKo.mjs';
export { HttpRequestHandler, HttpResponseResolver, http } from './http.mjs';

@@ -4,0 +4,0 @@ export { HttpCustomPredicate, HttpHandler, HttpHandlerInfo, HttpHandlerMethod, HttpMethods, HttpRequestParsedResult, HttpRequestResolverExtras, RequestQuery } from './handlers/HttpHandler.mjs';

export { SetupApi } from './experimental/setup-api.js';
export { A as AsyncResponseResolverReturnType, D as DefaultBodyType, d as DefaultRequestMultipartBody, l as GraphQLCustomPredicate, G as GraphQLHandler, j as GraphQLJsonRequestBody, k as GraphQLOperationType, f as GraphQLQuery, h as GraphQLRequestBody, i as GraphQLResponseBody, g as GraphQLVariables, H as HttpResponse, n as HttpResponseInit, J as JsonBodyType, P as ParsedGraphQLRequest, R as RequestHandler, c as RequestHandlerOptions, m as ResponseResolutionContext, a as ResponseResolver, e as ResponseResolverInfo, b as ResponseResolverReturnType, S as StrictRequest, o as StrictResponse } from './HttpResponse-aGiIzO91.js';
export { A as AsyncResponseResolverReturnType, D as DefaultBodyType, d as DefaultRequestMultipartBody, l as GraphQLCustomPredicate, G as GraphQLHandler, j as GraphQLJsonRequestBody, k as GraphQLOperationType, f as GraphQLQuery, h as GraphQLRequestBody, i as GraphQLResponseBody, g as GraphQLVariables, H as HttpResponse, n as HttpResponseInit, J as JsonBodyType, P as ParsedGraphQLRequest, R as RequestHandler, c as RequestHandlerOptions, m as ResponseResolutionContext, a as ResponseResolver, e as ResponseResolverInfo, b as ResponseResolverReturnType, S as StrictRequest, o as StrictResponse } from './HttpResponse-BFS34nkx.js';
export { HttpRequestHandler, HttpResponseResolver, http } from './http.js';

@@ -4,0 +4,0 @@ export { HttpCustomPredicate, HttpHandler, HttpHandlerInfo, HttpHandlerMethod, HttpMethods, HttpRequestParsedResult, HttpRequestResolverExtras, RequestQuery } from './handlers/HttpHandler.js';

@@ -1,2 +0,2 @@

import { H as HttpResponse } from './HttpResponse-CxHR1nNN.mjs';
import { H as HttpResponse } from './HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import './utils/internal/isIterable.mjs';

@@ -1,2 +0,2 @@

import { H as HttpResponse } from './HttpResponse-aGiIzO91.js';
import { H as HttpResponse } from './HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import './utils/internal/isIterable.js';

@@ -1,2 +0,2 @@

import { a as ResponseResolver } from './HttpResponse-CxHR1nNN.mjs';
import { a as ResponseResolver } from './HttpResponse-CQwYpuKo.mjs';
import { HttpRequestResolverExtras, HttpHandler } from './handlers/HttpHandler.mjs';

@@ -3,0 +3,0 @@ import { PathParams, Path } from './utils/matching/matchRequestUrl.mjs';

@@ -1,2 +0,2 @@

import { a as ResponseResolver } from './HttpResponse-aGiIzO91.js';
import { a as ResponseResolver } from './HttpResponse-BFS34nkx.js';
import { HttpRequestResolverExtras, HttpHandler } from './handlers/HttpHandler.js';

@@ -3,0 +3,0 @@ import { PathParams, Path } from './utils/matching/matchRequestUrl.js';

@@ -1,2 +0,2 @@

export { s as HandlersExecutionResult, m as ResponseResolutionContext, t as executeHandlers } from '../HttpResponse-CxHR1nNN.mjs';
export { s as HandlersExecutionResult, m as ResponseResolutionContext, t as executeHandlers } from '../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import './internal/isIterable.mjs';

@@ -1,2 +0,2 @@

export { s as HandlersExecutionResult, m as ResponseResolutionContext, t as executeHandlers } from '../HttpResponse-aGiIzO91.js';
export { s as HandlersExecutionResult, m as ResponseResolutionContext, t as executeHandlers } from '../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import './internal/isIterable.js';

import { Emitter } from 'strict-event-emitter';
import { SharedOptions, LifeCycleEventsMap } from '../sharedOptions.mjs';
import { RequiredDeep } from '../typeUtils.mjs';
import { R as RequestHandler, m as ResponseResolutionContext, s as HandlersExecutionResult } from '../HttpResponse-CxHR1nNN.mjs';
import { R as RequestHandler, m as ResponseResolutionContext, s as HandlersExecutionResult } from '../HttpResponse-CQwYpuKo.mjs';
import 'rettime';

@@ -6,0 +6,0 @@ import './request/onUnhandledRequest.mjs';

import { Emitter } from 'strict-event-emitter';
import { SharedOptions, LifeCycleEventsMap } from '../sharedOptions.js';
import { RequiredDeep } from '../typeUtils.js';
import { R as RequestHandler, m as ResponseResolutionContext, s as HandlersExecutionResult } from '../HttpResponse-aGiIzO91.js';
import { R as RequestHandler, m as ResponseResolutionContext, s as HandlersExecutionResult } from '../HttpResponse-BFS34nkx.js';
import 'rettime';

@@ -6,0 +6,0 @@ import './request/onUnhandledRequest.js';

@@ -1,2 +0,2 @@

import { n as HttpResponseInit } from '../../HttpResponse-CxHR1nNN.mjs';
import { n as HttpResponseInit } from '../../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import '../internal/isIterable.mjs';

@@ -1,2 +0,2 @@

import { n as HttpResponseInit } from '../../HttpResponse-aGiIzO91.js';
import { n as HttpResponseInit } from '../../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import '../internal/isIterable.js';

import { AnyHandler } from '../../experimental/handlers-controller.mjs';
import '../../HttpResponse-CxHR1nNN.mjs';
import '../../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -4,0 +4,0 @@ import './isIterable.mjs';

import { AnyHandler } from '../../experimental/handlers-controller.js';
import '../../HttpResponse-aGiIzO91.js';
import '../../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -4,0 +4,0 @@ import './isIterable.js';

import { AnyHandler } from '../../experimental/handlers-controller.mjs';
import { R as RequestHandler } from '../../HttpResponse-CxHR1nNN.mjs';
import { R as RequestHandler } from '../../HttpResponse-CQwYpuKo.mjs';
import { WebSocketHandler } from '../../handlers/WebSocketHandler.mjs';

@@ -4,0 +4,0 @@ import '@mswjs/interceptors';

import { AnyHandler } from '../../experimental/handlers-controller.js';
import { R as RequestHandler } from '../../HttpResponse-aGiIzO91.js';
import { R as RequestHandler } from '../../HttpResponse-BFS34nkx.js';
import { WebSocketHandler } from '../../handlers/WebSocketHandler.js';

@@ -4,0 +4,0 @@ import '@mswjs/interceptors';

import 'graphql';
export { x as GraphQLMultipartRequestBody, w as GraphQLParsedOperationsMap, u as ParsedGraphQLQuery, P as ParsedGraphQLRequest, v as parseDocumentNode, y as parseGraphQLRequest } from '../../HttpResponse-CxHR1nNN.mjs';
export { x as GraphQLMultipartRequestBody, w as GraphQLParsedOperationsMap, u as ParsedGraphQLQuery, P as ParsedGraphQLRequest, v as parseDocumentNode, y as parseGraphQLRequest } from '../../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -4,0 +4,0 @@ import './isIterable.mjs';

import 'graphql';
export { x as GraphQLMultipartRequestBody, w as GraphQLParsedOperationsMap, u as ParsedGraphQLQuery, P as ParsedGraphQLRequest, v as parseDocumentNode, y as parseGraphQLRequest } from '../../HttpResponse-aGiIzO91.js';
export { x as GraphQLMultipartRequestBody, w as GraphQLParsedOperationsMap, u as ParsedGraphQLQuery, P as ParsedGraphQLRequest, v as parseDocumentNode, y as parseGraphQLRequest } from '../../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -4,0 +4,0 @@ import './isIterable.js';

@@ -1,2 +0,2 @@

import { d as DefaultRequestMultipartBody } from '../../HttpResponse-CxHR1nNN.mjs';
import { d as DefaultRequestMultipartBody } from '../../HttpResponse-CQwYpuKo.mjs';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import './isIterable.mjs';

@@ -1,2 +0,2 @@

import { d as DefaultRequestMultipartBody } from '../../HttpResponse-aGiIzO91.js';
import { d as DefaultRequestMultipartBody } from '../../HttpResponse-BFS34nkx.js';
import '@mswjs/interceptors';

@@ -3,0 +3,0 @@ import './isIterable.js';

import { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket';
import { R as RequestHandler } from '../HttpResponse-CxHR1nNN.mjs';
import { R as RequestHandler } from '../HttpResponse-CQwYpuKo.mjs';
import { WebSocketHandler } from '../handlers/WebSocketHandler.mjs';

@@ -4,0 +4,0 @@ import { UnhandledRequestStrategy } from '../utils/request/onUnhandledRequest.mjs';

import { WebSocketConnectionData } from '@mswjs/interceptors/WebSocket';
import { R as RequestHandler } from '../HttpResponse-aGiIzO91.js';
import { R as RequestHandler } from '../HttpResponse-BFS34nkx.js';
import { WebSocketHandler } from '../handlers/WebSocketHandler.js';

@@ -4,0 +4,0 @@ import { UnhandledRequestStrategy } from '../utils/request/onUnhandledRequest.js';

@@ -10,3 +10,3 @@ /* eslint-disable */

const PACKAGE_VERSION = '2.14.3'
const PACKAGE_VERSION = '2.14.4'
const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'

@@ -13,0 +13,0 @@ const IS_MOCKED_RESPONSE = Symbol('isMockedResponse')

{
"name": "msw",
"version": "2.14.3",
"version": "2.14.4",
"description": "Seamless REST/GraphQL API mocking library for browser and Node.js.",

@@ -289,3 +289,3 @@ "type": "commonjs",

"webpack-http-server": "^0.5.0",
"msw": "^2.14.3"
"msw": "^2.14.4"
},

@@ -292,0 +292,0 @@ "peerDependencies": {

@@ -16,2 +16,3 @@ import { Headers as HeadersPolyfill } from 'headers-polyfill'

import type { GraphQLRequestBody } from './GraphQLHandler'
import { devUtils } from '../utils/internal/devUtils'
import { getRawSetCookie } from '../utils/HttpResponse/decorators'

@@ -94,4 +95,18 @@

requestId: string
/**
* Schedule a callback to run after this response resolver completes.
* Handy for cleaning up the side effects introduced in the resolver.
* @example
* sse('/', ({ client, finalize }) => {
* const interval = setInterval(() => client.send({ data: 'ping' }))
* finalize(() => clearInterval(interval))
* })
*/
finalize: ResponseResolverFinalizeFunction
} & ResolverExtraInfo
type ResponseResolverFinalizeFunction = (
callback: () => MaybePromise<void>,
) => void
export type ResponseResolver<

@@ -154,3 +169,5 @@ ResolverExtraInfo extends Record<string, unknown> = Record<string, unknown>,

private resolverIteratorResult?: Response | HttpResponse<any>
private resolverIteratorCleanups?: Array<() => MaybePromise<void>>
private options?: HandlerOptions
private scheduledCleanups: Map<string, Array<() => MaybePromise<void>>>

@@ -168,2 +185,3 @@ public info: HandlerInfo & RequestHandlerInternalInfo

this.options = args.options
this.scheduledCleanups = new Map()

@@ -187,5 +205,8 @@ const callFrame = getCallFrame(new Error())

protected reset(): void {
this.scheduledCleanups.clear()
const iterator = this.resolverIterator
this.resolverIterator = undefined
this.resolverIteratorResult = undefined
this.resolverIteratorCleanups = undefined

@@ -340,17 +361,35 @@ if (typeof iterator?.return === 'function') {

const listenerController = new AbortController()
args.request.signal.addEventListener(
'abort',
() => this.runScheduledCleanups(args.requestId),
{
once: true,
signal: listenerController.signal,
},
)
const mockedResponsePromise = (
executeResolver({
...resolverExtras,
finalize: (callback) => {
this.scheduleCleanup(args.requestId, callback)
},
requestId: args.requestId,
request: args.request,
}) as Promise<Response | undefined>
).catch((errorOrResponse) => {
// Allow throwing a Response instance in a response resolver.
if (errorOrResponse instanceof Response) {
return errorOrResponse
}
}) as Promise<Response>
)
.catch((errorOrResponse) => {
// Allow throwing a Response instance in a response resolver.
if (errorOrResponse instanceof Response) {
return errorOrResponse
}
// Otherwise, throw the error as-is.
throw errorOrResponse
})
// Otherwise, throw the error as-is.
throw errorOrResponse
})
.finally(() => {
listenerController.abort()
})

@@ -380,8 +419,36 @@ const mockedResponse = await mockedResponsePromise

if (!this.resolverIterator) {
const result = await resolver(info)
let result
try {
result = await resolver(info)
} catch (error) {
// Ensure cleanup if the resolver throws, regardless of the returned type.
await this.runScheduledCleanups(info.requestId)
// Re-throw the error for the "run()" method to handle (e.g. thrown responses).
throw error
}
if (!isIterable(result)) {
// Otherwise, run the cleanup immediately if it's a plain response resolver.
await this.runScheduledCleanups(info.requestId)
return result
}
/**
* @note Carry over any previously registered cleanups onto the iterator cleanups.
* This is only relevant if "finalize()" is called in a regular resolver that
* returns an iterator.
* @example
* http.get('/', async ({ finalize }) => {
* finalize(cleanup)
* return (async function*() {})()
* })
*/
const existingCleanups = this.scheduledCleanups.get(info.requestId)
if (existingCleanups != null && existingCleanups.length > 0) {
this.resolverIteratorCleanups = existingCleanups
this.scheduledCleanups.delete(info.requestId)
}
this.resolverIterator =

@@ -408,2 +475,4 @@ Symbol.iterator in result

await this.runScheduledCleanups(info.requestId)
// Clone the previously stored response so it can be read

@@ -432,2 +501,67 @@ // when receiving it repeatedly from the "done" generator.

}
private scheduleCleanup(
requestId: string,
callback: () => MaybePromise<void>,
): void {
if (this.resolverIterator) {
;(this.resolverIteratorCleanups ||= []).unshift(callback)
return
}
const cleanups = this.scheduledCleanups.get(requestId) || []
cleanups.unshift(callback)
this.scheduledCleanups.set(requestId, cleanups)
}
private async exhaustCleanups(
cleanups: Array<() => MaybePromise<void>>,
): Promise<void> {
const errors: Array<Error> = []
for (const cleanup of cleanups) {
try {
await cleanup()
} catch (error) {
if (error instanceof Error) {
errors.push(error)
}
}
}
if (errors.length > 0) {
devUtils.error(
'Failed to execute cleanup for request handler "%s"',
this.info.header,
new AggregateError(
errors,
`Failed to execute cleanup for request handler "${this.info.header}"`,
),
)
}
}
private async runScheduledCleanups(requestId: string): Promise<void> {
if (
this.resolverIterator &&
this.resolverIteratorCleanups != null &&
this.resolverIteratorCleanups.length > 0
) {
try {
await this.exhaustCleanups(this.resolverIteratorCleanups)
} finally {
this.resolverIteratorCleanups = undefined
}
return
}
const cleanups = this.scheduledCleanups.get(requestId)
if (!cleanups || cleanups.length == 0) {
return
}
await this.exhaustCleanups(cleanups)
this.scheduledCleanups.delete(requestId)
}
}

@@ -434,0 +568,0 @@

import { FetchResponse } from '@mswjs/interceptors';
import { Iterable, AsyncIterable } from './utils/internal/isIterable.js';
import { MaybePromise, NoInfer } from './typeUtils.js';
import { OperationTypeNode, DocumentNode, GraphQLError } from 'graphql';
import { Match, Path } from './utils/matching/matchRequestUrl.js';
interface HandlersExecutionResult {
handler: RequestHandler;
parsedResult?: any;
response?: Response;
}
interface ResponseResolutionContext {
/**
* A base url to use when resolving relative urls.
* @note This is primarily used by the `@mswjs/http-middleware`
* to resolve relative urls in the context of the running server
*/
baseUrl?: string;
quiet?: boolean;
}
/**
* Executes the list of request handlers against the given request.
* Returns the execution result object containing any matching request
* handler and any mocked response it returned.
*/
declare const executeHandlers: <Handlers extends Array<RequestHandler>>({ request, requestId, handlers, resolutionContext, }: {
request: Request;
requestId: string;
handlers: Handlers;
resolutionContext?: ResponseResolutionContext;
}) => Promise<HandlersExecutionResult | null>;
interface ParsedGraphQLQuery {
operationType: OperationTypeNode;
operationName?: string;
}
type ParsedGraphQLRequest<VariablesType extends GraphQLVariables = GraphQLVariables> = (ParsedGraphQLQuery & {
query: string;
variables?: VariablesType;
}) | undefined;
declare function parseDocumentNode(node: DocumentNode): ParsedGraphQLQuery;
type GraphQLParsedOperationsMap = Record<string, string[]>;
type GraphQLMultipartRequestBody = {
operations: string;
map?: string;
} & {
[fileName: string]: File;
};
/**
* Determines if a given request can be considered a GraphQL request.
* Does not parse the query and does not guarantee its validity.
*/
declare function parseGraphQLRequest(request: Request): Promise<ParsedGraphQLRequest>;
interface DocumentTypeDecoration<Result = {
[key: string]: any;
}, Variables = {
[key: string]: any;
}> {
__apiType?: (variables: Variables) => Result;
__resultType?: Result;
__variablesType?: Variables;
}
type GraphQLOperationType = OperationTypeNode | 'all';
type GraphQLHandlerNameSelector = DocumentNode | RegExp | string;
type GraphQLQuery = Record<string, any> | null;
type GraphQLVariables = Record<string, any>;
interface GraphQLHandlerInfo extends RequestHandlerDefaultInfo {
operationType: GraphQLOperationType;
operationName: GraphQLHandlerNameSelector | GraphQLCustomPredicate;
}
type GraphQLRequestParsedResult = {
match: Match;
cookies: Record<string, string>;
} & (ParsedGraphQLRequest<GraphQLVariables>
/**
* An empty version of the ParsedGraphQLRequest
* which simplifies the return type of the resolver
* when the request is to a non-matching endpoint
*/
| {
operationType?: undefined;
operationName?: undefined;
query?: undefined;
variables?: undefined;
});
type GraphQLResolverExtras<Variables extends GraphQLVariables> = {
query: string;
operationName: string;
variables: Variables;
cookies: Record<string, string>;
};
type GraphQLRequestBody<VariablesType extends GraphQLVariables> = GraphQLJsonRequestBody<VariablesType> | GraphQLMultipartRequestBody | Record<string, any> | undefined;
interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {
query: string;
variables?: Variables;
}
type GraphQLResponseBody<BodyType extends DefaultBodyType> = {
data?: BodyType | null;
errors?: readonly Partial<GraphQLError>[] | null;
extensions?: Record<string, any>;
} | null | undefined;
type GraphQLCustomPredicate = (args: {
request: Request;
query: string;
operationType: GraphQLOperationType;
operationName: string;
variables: GraphQLVariables;
cookies: Record<string, string>;
}) => GraphQLCustomPredicateResult | Promise<GraphQLCustomPredicateResult>;
type GraphQLCustomPredicateResult = boolean | {
matches: boolean;
};
type GraphQLPredicate<Query = any, Variables = any> = GraphQLHandlerNameSelector | DocumentTypeDecoration<Query, Variables> | GraphQLCustomPredicate;
declare function isDocumentNode(value: DocumentNode | any): value is DocumentNode;
declare class GraphQLHandler extends RequestHandler<GraphQLHandlerInfo, GraphQLRequestParsedResult, GraphQLResolverExtras<any>> {
#private;
private endpoint;
static parsedRequestCache: WeakMap<Request, ParsedGraphQLRequest<GraphQLVariables>>;
constructor(operationType: GraphQLOperationType, predicate: GraphQLPredicate, endpoint: Path, resolver: ResponseResolver<GraphQLResolverExtras<any>, any, any>, options?: RequestHandlerOptions);
/**
* Parses the request body, once per request, cached across all
* GraphQL handlers. This is done to avoid multiple parsing of the
* request body, which each requires a clone of the request.
*/
parseGraphQLRequestOrGetFromCache(request: Request): Promise<ParsedGraphQLRequest<GraphQLVariables>>;
parse(args: {
request: Request;
}): Promise<GraphQLRequestParsedResult>;
predicate(args: {
request: Request;
parsedResult: GraphQLRequestParsedResult;
}): Promise<boolean>;
run(args: {
request: StrictRequest<any>;
requestId: string;
resolutionContext?: ResponseResolutionContext;
}): Promise<RequestHandlerExecutionResult<GraphQLRequestParsedResult> | null>;
private matchOperationName;
protected extendResolverArgs(args: {
request: Request;
parsedResult: GraphQLRequestParsedResult;
}): {
query: string;
operationType: OperationTypeNode;
operationName: string;
variables: GraphQLVariables;
cookies: Record<string, string>;
};
log(args: {
request: Request;
response: Response;
parsedResult: GraphQLRequestParsedResult;
}): Promise<void>;
}
type DefaultRequestMultipartBody = Record<string, string | File | Array<string | File>>;
type DefaultBodyType = Record<string, any> | DefaultRequestMultipartBody | string | number | boolean | null | undefined;
type JsonBodyType = Record<string, any> | string | number | boolean | null | undefined;
interface RequestHandlerDefaultInfo {
header: string;
}
interface RequestHandlerInternalInfo {
callFrame?: string;
}
type ResponseResolverReturnType<ResponseBodyType extends DefaultBodyType = undefined> = ([ResponseBodyType] extends [undefined] ? Response : ResponseBodyType extends GraphQLRequestBody<any> ? HttpResponse<ResponseBodyType> | DefaultUnsafeFetchResponse : HttpResponse<ResponseBodyType>) | undefined | void;
type MaybeAsyncResponseResolverReturnType<ResponseBodyType extends DefaultBodyType> = MaybePromise<ResponseResolverReturnType<ResponseBodyType>>;
type AsyncResponseResolverReturnType<ResponseBodyType extends DefaultBodyType> = MaybePromise<ResponseResolverReturnType<ResponseBodyType> | Iterable<MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>> | AsyncIterable<MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>>>;
type ResponseResolverInfo<ResolverExtraInfo extends Record<string, unknown>, RequestBodyType extends DefaultBodyType = DefaultBodyType> = {
request: StrictRequest<RequestBodyType>;
requestId: string;
} & ResolverExtraInfo;
type ResponseResolver<ResolverExtraInfo extends Record<string, unknown> = Record<string, unknown>, RequestBodyType extends DefaultBodyType = DefaultBodyType, ResponseBodyType extends DefaultBodyType = undefined> = (info: ResponseResolverInfo<ResolverExtraInfo, RequestBodyType>) => AsyncResponseResolverReturnType<ResponseBodyType>;
interface RequestHandlerArgs<HandlerInfo, HandlerOptions extends RequestHandlerOptions> {
info: HandlerInfo;
resolver: ResponseResolver<any>;
options?: HandlerOptions;
}
interface RequestHandlerOptions {
once?: boolean;
}
interface RequestHandlerExecutionResult<ParsedResult extends object | undefined> {
handler: RequestHandler;
parsedResult?: ParsedResult;
request: Request;
requestId: string;
response?: Response;
}
declare abstract class RequestHandler<HandlerInfo extends RequestHandlerDefaultInfo = RequestHandlerDefaultInfo, ParsedResult extends Record<string, any> | undefined = any, ResolverExtras extends Record<string, unknown> = any, HandlerOptions extends RequestHandlerOptions = RequestHandlerOptions> {
static cache: WeakMap<StrictRequest<DefaultBodyType>, StrictRequest<DefaultBodyType>>;
readonly kind: "request";
protected resolver: ResponseResolver<ResolverExtras, any, any>;
private resolverIterator?;
private resolverIteratorResult?;
private options?;
info: HandlerInfo & RequestHandlerInternalInfo;
/**
* Indicates whether this request handler has been used
* (its resolver has successfully executed).
*/
isUsed: boolean;
constructor(args: RequestHandlerArgs<HandlerInfo, HandlerOptions>);
/**
* Reset the runtime state accumulated during response resolution,
* such as generator iterator progress. Called when this handler is
* removed from the active handlers list so re-adding it later starts
* from a clean state.
*/
protected reset(): void;
/**
* Restore this handler so it can match requests again after being
* exhausted (e.g. via `{ once: true }`). Also clears any accumulated
* resolution state.
*/
protected restore(): void;
/**
* Determine if the intercepted request should be mocked.
*/
abstract predicate(args: {
request: Request;
parsedResult: ParsedResult;
resolutionContext?: ResponseResolutionContext;
}): boolean | Promise<boolean>;
/**
* Print out the successfully handled request.
*/
abstract log(args: {
request: Request;
response: Response;
parsedResult: ParsedResult;
}): void;
/**
* Parse the intercepted request to extract additional information from it.
* Parsed result is then exposed to other methods of this request handler.
*/
parse(_args: {
request: Request;
resolutionContext?: ResponseResolutionContext;
}): Promise<ParsedResult>;
/**
* Test if this handler matches the given request.
*
* This method is not used internally but is exposed
* as a convenience method for consumers writing custom
* handlers.
*/
test(args: {
request: Request;
resolutionContext?: ResponseResolutionContext;
}): Promise<boolean>;
protected extendResolverArgs(_args: {
request: Request;
parsedResult: ParsedResult;
}): ResolverExtras;
private cloneRequestOrGetFromCache;
/**
* Execute this request handler and produce a mocked response
* using the given resolver function.
*/
run(args: {
request: StrictRequest<any>;
requestId: string;
resolutionContext?: ResponseResolutionContext;
}): Promise<RequestHandlerExecutionResult<ParsedResult> | null>;
private wrapResolver;
private createExecutionResult;
}
/**
* Forwards the cookies from the given response to `document.cookie`.
*/
declare function forwardResponseCookies(response: Response): void;
interface HttpResponseInit extends ResponseInit {
type?: ResponseType;
}
declare const bodyType: unique symbol;
type DefaultUnsafeFetchResponse = Response & {
[bodyType]?: never;
};
interface StrictRequest<BodyType extends JsonBodyType> extends Request {
json(): Promise<BodyType>;
clone(): StrictRequest<BodyType>;
}
/**
* Opaque `Response` type that supports strict body type.
*
* @deprecated Please use {@link HttpResponse} instead.
*/
type StrictResponse<BodyType extends DefaultBodyType> = HttpResponse<BodyType>;
declare const kDefaultContentType: unique symbol;
/**
* A drop-in replacement for the standard `Response` class
* to allow additional features, like mocking the response `Set-Cookie` header.
*
* @example
* new HttpResponse('Hello world', { status: 201 })
* HttpResponse.json({ name: 'John' })
* HttpResponse.formData(form)
*
* @see {@link https://mswjs.io/docs/api/http-response `HttpResponse` API reference}
*/
declare class HttpResponse<BodyType extends DefaultBodyType> extends FetchResponse {
readonly [bodyType]: BodyType;
constructor(body?: NoInfer<BodyType> | null, init?: HttpResponseInit);
static error(): HttpResponse<any>;
/**
* Create a `Response` with a `Content-Type: "text/plain"` body.
* @example
* HttpResponse.text('hello world')
* HttpResponse.text('Error', { status: 500 })
*/
static text<BodyType extends string>(body?: NoInfer<BodyType> | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "application/json"` body.
* @example
* HttpResponse.json({ firstName: 'John' })
* HttpResponse.json({ error: 'Not Authorized' }, { status: 401 })
*/
static json<BodyType extends JsonBodyType>(body?: NoInfer<BodyType> | null | undefined, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "application/xml"` body.
* @example
* HttpResponse.xml(`<user name="John" />`)
* HttpResponse.xml(`<article id="abc-123" />`, { status: 201 })
*/
static xml<BodyType extends string>(body?: BodyType | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "text/html"` body.
* @example
* HttpResponse.html(`<p class="author">Jane Doe</p>`)
* HttpResponse.html(`<main id="abc-123">Main text</main>`, { status: 201 })
*/
static html<BodyType extends string>(body?: BodyType | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with an `ArrayBuffer` body.
* @example
* const buffer = new ArrayBuffer(3)
* const view = new Uint8Array(buffer)
* view.set([1, 2, 3])
*
* HttpResponse.arrayBuffer(buffer)
*/
static arrayBuffer<BodyType extends ArrayBuffer | SharedArrayBuffer>(body?: BodyType, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `FormData` body.
* @example
* const data = new FormData()
* data.set('name', 'Alice')
*
* HttpResponse.formData(data)
*/
static formData(body?: FormData, init?: HttpResponseInit): HttpResponse<FormData>;
}
export { type AsyncResponseResolverReturnType as A, type GraphQLHandlerNameSelector as B, type GraphQLHandlerInfo as C, type DefaultBodyType as D, type GraphQLRequestParsedResult as E, type GraphQLCustomPredicateResult as F, GraphQLHandler as G, HttpResponse as H, isDocumentNode as I, type JsonBodyType as J, type RequestHandlerInternalInfo as K, type RequestHandlerArgs as L, type MaybeAsyncResponseResolverReturnType as M, type RequestHandlerExecutionResult as N, forwardResponseCookies as O, type ParsedGraphQLRequest as P, bodyType as Q, RequestHandler as R, type StrictRequest as S, type DefaultUnsafeFetchResponse as T, kDefaultContentType as U, type ResponseResolver as a, type ResponseResolverReturnType as b, type RequestHandlerOptions as c, type DefaultRequestMultipartBody as d, type ResponseResolverInfo as e, type GraphQLQuery as f, type GraphQLVariables as g, type GraphQLRequestBody as h, type GraphQLResponseBody as i, type GraphQLJsonRequestBody as j, type GraphQLOperationType as k, type GraphQLCustomPredicate as l, type ResponseResolutionContext as m, type HttpResponseInit as n, type StrictResponse as o, type GraphQLPredicate as p, type GraphQLResolverExtras as q, type RequestHandlerDefaultInfo as r, type HandlersExecutionResult as s, executeHandlers as t, type ParsedGraphQLQuery as u, parseDocumentNode as v, type GraphQLParsedOperationsMap as w, type GraphQLMultipartRequestBody as x, parseGraphQLRequest as y, type DocumentTypeDecoration as z };
import { FetchResponse } from '@mswjs/interceptors';
import { Iterable, AsyncIterable } from './utils/internal/isIterable.mjs';
import { MaybePromise, NoInfer } from './typeUtils.mjs';
import { OperationTypeNode, DocumentNode, GraphQLError } from 'graphql';
import { Match, Path } from './utils/matching/matchRequestUrl.mjs';
interface HandlersExecutionResult {
handler: RequestHandler;
parsedResult?: any;
response?: Response;
}
interface ResponseResolutionContext {
/**
* A base url to use when resolving relative urls.
* @note This is primarily used by the `@mswjs/http-middleware`
* to resolve relative urls in the context of the running server
*/
baseUrl?: string;
quiet?: boolean;
}
/**
* Executes the list of request handlers against the given request.
* Returns the execution result object containing any matching request
* handler and any mocked response it returned.
*/
declare const executeHandlers: <Handlers extends Array<RequestHandler>>({ request, requestId, handlers, resolutionContext, }: {
request: Request;
requestId: string;
handlers: Handlers;
resolutionContext?: ResponseResolutionContext;
}) => Promise<HandlersExecutionResult | null>;
interface ParsedGraphQLQuery {
operationType: OperationTypeNode;
operationName?: string;
}
type ParsedGraphQLRequest<VariablesType extends GraphQLVariables = GraphQLVariables> = (ParsedGraphQLQuery & {
query: string;
variables?: VariablesType;
}) | undefined;
declare function parseDocumentNode(node: DocumentNode): ParsedGraphQLQuery;
type GraphQLParsedOperationsMap = Record<string, string[]>;
type GraphQLMultipartRequestBody = {
operations: string;
map?: string;
} & {
[fileName: string]: File;
};
/**
* Determines if a given request can be considered a GraphQL request.
* Does not parse the query and does not guarantee its validity.
*/
declare function parseGraphQLRequest(request: Request): Promise<ParsedGraphQLRequest>;
interface DocumentTypeDecoration<Result = {
[key: string]: any;
}, Variables = {
[key: string]: any;
}> {
__apiType?: (variables: Variables) => Result;
__resultType?: Result;
__variablesType?: Variables;
}
type GraphQLOperationType = OperationTypeNode | 'all';
type GraphQLHandlerNameSelector = DocumentNode | RegExp | string;
type GraphQLQuery = Record<string, any> | null;
type GraphQLVariables = Record<string, any>;
interface GraphQLHandlerInfo extends RequestHandlerDefaultInfo {
operationType: GraphQLOperationType;
operationName: GraphQLHandlerNameSelector | GraphQLCustomPredicate;
}
type GraphQLRequestParsedResult = {
match: Match;
cookies: Record<string, string>;
} & (ParsedGraphQLRequest<GraphQLVariables>
/**
* An empty version of the ParsedGraphQLRequest
* which simplifies the return type of the resolver
* when the request is to a non-matching endpoint
*/
| {
operationType?: undefined;
operationName?: undefined;
query?: undefined;
variables?: undefined;
});
type GraphQLResolverExtras<Variables extends GraphQLVariables> = {
query: string;
operationName: string;
variables: Variables;
cookies: Record<string, string>;
};
type GraphQLRequestBody<VariablesType extends GraphQLVariables> = GraphQLJsonRequestBody<VariablesType> | GraphQLMultipartRequestBody | Record<string, any> | undefined;
interface GraphQLJsonRequestBody<Variables extends GraphQLVariables> {
query: string;
variables?: Variables;
}
type GraphQLResponseBody<BodyType extends DefaultBodyType> = {
data?: BodyType | null;
errors?: readonly Partial<GraphQLError>[] | null;
extensions?: Record<string, any>;
} | null | undefined;
type GraphQLCustomPredicate = (args: {
request: Request;
query: string;
operationType: GraphQLOperationType;
operationName: string;
variables: GraphQLVariables;
cookies: Record<string, string>;
}) => GraphQLCustomPredicateResult | Promise<GraphQLCustomPredicateResult>;
type GraphQLCustomPredicateResult = boolean | {
matches: boolean;
};
type GraphQLPredicate<Query = any, Variables = any> = GraphQLHandlerNameSelector | DocumentTypeDecoration<Query, Variables> | GraphQLCustomPredicate;
declare function isDocumentNode(value: DocumentNode | any): value is DocumentNode;
declare class GraphQLHandler extends RequestHandler<GraphQLHandlerInfo, GraphQLRequestParsedResult, GraphQLResolverExtras<any>> {
#private;
private endpoint;
static parsedRequestCache: WeakMap<Request, ParsedGraphQLRequest<GraphQLVariables>>;
constructor(operationType: GraphQLOperationType, predicate: GraphQLPredicate, endpoint: Path, resolver: ResponseResolver<GraphQLResolverExtras<any>, any, any>, options?: RequestHandlerOptions);
/**
* Parses the request body, once per request, cached across all
* GraphQL handlers. This is done to avoid multiple parsing of the
* request body, which each requires a clone of the request.
*/
parseGraphQLRequestOrGetFromCache(request: Request): Promise<ParsedGraphQLRequest<GraphQLVariables>>;
parse(args: {
request: Request;
}): Promise<GraphQLRequestParsedResult>;
predicate(args: {
request: Request;
parsedResult: GraphQLRequestParsedResult;
}): Promise<boolean>;
run(args: {
request: StrictRequest<any>;
requestId: string;
resolutionContext?: ResponseResolutionContext;
}): Promise<RequestHandlerExecutionResult<GraphQLRequestParsedResult> | null>;
private matchOperationName;
protected extendResolverArgs(args: {
request: Request;
parsedResult: GraphQLRequestParsedResult;
}): {
query: string;
operationType: OperationTypeNode;
operationName: string;
variables: GraphQLVariables;
cookies: Record<string, string>;
};
log(args: {
request: Request;
response: Response;
parsedResult: GraphQLRequestParsedResult;
}): Promise<void>;
}
type DefaultRequestMultipartBody = Record<string, string | File | Array<string | File>>;
type DefaultBodyType = Record<string, any> | DefaultRequestMultipartBody | string | number | boolean | null | undefined;
type JsonBodyType = Record<string, any> | string | number | boolean | null | undefined;
interface RequestHandlerDefaultInfo {
header: string;
}
interface RequestHandlerInternalInfo {
callFrame?: string;
}
type ResponseResolverReturnType<ResponseBodyType extends DefaultBodyType = undefined> = ([ResponseBodyType] extends [undefined] ? Response : ResponseBodyType extends GraphQLRequestBody<any> ? HttpResponse<ResponseBodyType> | DefaultUnsafeFetchResponse : HttpResponse<ResponseBodyType>) | undefined | void;
type MaybeAsyncResponseResolverReturnType<ResponseBodyType extends DefaultBodyType> = MaybePromise<ResponseResolverReturnType<ResponseBodyType>>;
type AsyncResponseResolverReturnType<ResponseBodyType extends DefaultBodyType> = MaybePromise<ResponseResolverReturnType<ResponseBodyType> | Iterable<MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>> | AsyncIterable<MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>, MaybeAsyncResponseResolverReturnType<ResponseBodyType>>>;
type ResponseResolverInfo<ResolverExtraInfo extends Record<string, unknown>, RequestBodyType extends DefaultBodyType = DefaultBodyType> = {
request: StrictRequest<RequestBodyType>;
requestId: string;
} & ResolverExtraInfo;
type ResponseResolver<ResolverExtraInfo extends Record<string, unknown> = Record<string, unknown>, RequestBodyType extends DefaultBodyType = DefaultBodyType, ResponseBodyType extends DefaultBodyType = undefined> = (info: ResponseResolverInfo<ResolverExtraInfo, RequestBodyType>) => AsyncResponseResolverReturnType<ResponseBodyType>;
interface RequestHandlerArgs<HandlerInfo, HandlerOptions extends RequestHandlerOptions> {
info: HandlerInfo;
resolver: ResponseResolver<any>;
options?: HandlerOptions;
}
interface RequestHandlerOptions {
once?: boolean;
}
interface RequestHandlerExecutionResult<ParsedResult extends object | undefined> {
handler: RequestHandler;
parsedResult?: ParsedResult;
request: Request;
requestId: string;
response?: Response;
}
declare abstract class RequestHandler<HandlerInfo extends RequestHandlerDefaultInfo = RequestHandlerDefaultInfo, ParsedResult extends Record<string, any> | undefined = any, ResolverExtras extends Record<string, unknown> = any, HandlerOptions extends RequestHandlerOptions = RequestHandlerOptions> {
static cache: WeakMap<StrictRequest<DefaultBodyType>, StrictRequest<DefaultBodyType>>;
readonly kind: "request";
protected resolver: ResponseResolver<ResolverExtras, any, any>;
private resolverIterator?;
private resolverIteratorResult?;
private options?;
info: HandlerInfo & RequestHandlerInternalInfo;
/**
* Indicates whether this request handler has been used
* (its resolver has successfully executed).
*/
isUsed: boolean;
constructor(args: RequestHandlerArgs<HandlerInfo, HandlerOptions>);
/**
* Reset the runtime state accumulated during response resolution,
* such as generator iterator progress. Called when this handler is
* removed from the active handlers list so re-adding it later starts
* from a clean state.
*/
protected reset(): void;
/**
* Restore this handler so it can match requests again after being
* exhausted (e.g. via `{ once: true }`). Also clears any accumulated
* resolution state.
*/
protected restore(): void;
/**
* Determine if the intercepted request should be mocked.
*/
abstract predicate(args: {
request: Request;
parsedResult: ParsedResult;
resolutionContext?: ResponseResolutionContext;
}): boolean | Promise<boolean>;
/**
* Print out the successfully handled request.
*/
abstract log(args: {
request: Request;
response: Response;
parsedResult: ParsedResult;
}): void;
/**
* Parse the intercepted request to extract additional information from it.
* Parsed result is then exposed to other methods of this request handler.
*/
parse(_args: {
request: Request;
resolutionContext?: ResponseResolutionContext;
}): Promise<ParsedResult>;
/**
* Test if this handler matches the given request.
*
* This method is not used internally but is exposed
* as a convenience method for consumers writing custom
* handlers.
*/
test(args: {
request: Request;
resolutionContext?: ResponseResolutionContext;
}): Promise<boolean>;
protected extendResolverArgs(_args: {
request: Request;
parsedResult: ParsedResult;
}): ResolverExtras;
private cloneRequestOrGetFromCache;
/**
* Execute this request handler and produce a mocked response
* using the given resolver function.
*/
run(args: {
request: StrictRequest<any>;
requestId: string;
resolutionContext?: ResponseResolutionContext;
}): Promise<RequestHandlerExecutionResult<ParsedResult> | null>;
private wrapResolver;
private createExecutionResult;
}
/**
* Forwards the cookies from the given response to `document.cookie`.
*/
declare function forwardResponseCookies(response: Response): void;
interface HttpResponseInit extends ResponseInit {
type?: ResponseType;
}
declare const bodyType: unique symbol;
type DefaultUnsafeFetchResponse = Response & {
[bodyType]?: never;
};
interface StrictRequest<BodyType extends JsonBodyType> extends Request {
json(): Promise<BodyType>;
clone(): StrictRequest<BodyType>;
}
/**
* Opaque `Response` type that supports strict body type.
*
* @deprecated Please use {@link HttpResponse} instead.
*/
type StrictResponse<BodyType extends DefaultBodyType> = HttpResponse<BodyType>;
declare const kDefaultContentType: unique symbol;
/**
* A drop-in replacement for the standard `Response` class
* to allow additional features, like mocking the response `Set-Cookie` header.
*
* @example
* new HttpResponse('Hello world', { status: 201 })
* HttpResponse.json({ name: 'John' })
* HttpResponse.formData(form)
*
* @see {@link https://mswjs.io/docs/api/http-response `HttpResponse` API reference}
*/
declare class HttpResponse<BodyType extends DefaultBodyType> extends FetchResponse {
readonly [bodyType]: BodyType;
constructor(body?: NoInfer<BodyType> | null, init?: HttpResponseInit);
static error(): HttpResponse<any>;
/**
* Create a `Response` with a `Content-Type: "text/plain"` body.
* @example
* HttpResponse.text('hello world')
* HttpResponse.text('Error', { status: 500 })
*/
static text<BodyType extends string>(body?: NoInfer<BodyType> | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "application/json"` body.
* @example
* HttpResponse.json({ firstName: 'John' })
* HttpResponse.json({ error: 'Not Authorized' }, { status: 401 })
*/
static json<BodyType extends JsonBodyType>(body?: NoInfer<BodyType> | null | undefined, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "application/xml"` body.
* @example
* HttpResponse.xml(`<user name="John" />`)
* HttpResponse.xml(`<article id="abc-123" />`, { status: 201 })
*/
static xml<BodyType extends string>(body?: BodyType | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `Content-Type: "text/html"` body.
* @example
* HttpResponse.html(`<p class="author">Jane Doe</p>`)
* HttpResponse.html(`<main id="abc-123">Main text</main>`, { status: 201 })
*/
static html<BodyType extends string>(body?: BodyType | null, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with an `ArrayBuffer` body.
* @example
* const buffer = new ArrayBuffer(3)
* const view = new Uint8Array(buffer)
* view.set([1, 2, 3])
*
* HttpResponse.arrayBuffer(buffer)
*/
static arrayBuffer<BodyType extends ArrayBuffer | SharedArrayBuffer>(body?: BodyType, init?: HttpResponseInit): HttpResponse<BodyType>;
/**
* Create a `Response` with a `FormData` body.
* @example
* const data = new FormData()
* data.set('name', 'Alice')
*
* HttpResponse.formData(data)
*/
static formData(body?: FormData, init?: HttpResponseInit): HttpResponse<FormData>;
}
export { type AsyncResponseResolverReturnType as A, type GraphQLHandlerNameSelector as B, type GraphQLHandlerInfo as C, type DefaultBodyType as D, type GraphQLRequestParsedResult as E, type GraphQLCustomPredicateResult as F, GraphQLHandler as G, HttpResponse as H, isDocumentNode as I, type JsonBodyType as J, type RequestHandlerInternalInfo as K, type RequestHandlerArgs as L, type MaybeAsyncResponseResolverReturnType as M, type RequestHandlerExecutionResult as N, forwardResponseCookies as O, type ParsedGraphQLRequest as P, bodyType as Q, RequestHandler as R, type StrictRequest as S, type DefaultUnsafeFetchResponse as T, kDefaultContentType as U, type ResponseResolver as a, type ResponseResolverReturnType as b, type RequestHandlerOptions as c, type DefaultRequestMultipartBody as d, type ResponseResolverInfo as e, type GraphQLQuery as f, type GraphQLVariables as g, type GraphQLRequestBody as h, type GraphQLResponseBody as i, type GraphQLJsonRequestBody as j, type GraphQLOperationType as k, type GraphQLCustomPredicate as l, type ResponseResolutionContext as m, type HttpResponseInit as n, type StrictResponse as o, type GraphQLPredicate as p, type GraphQLResolverExtras as q, type RequestHandlerDefaultInfo as r, type HandlersExecutionResult as s, executeHandlers as t, type ParsedGraphQLQuery as u, parseDocumentNode as v, type GraphQLParsedOperationsMap as w, type GraphQLMultipartRequestBody as x, parseGraphQLRequest as y, type DocumentTypeDecoration as z };

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display