mockttp
Version:
Mock HTTP server for testing HTTP clients and stubbing webservices
407 lines • 13.2 kB
TypeScript
import type * as stream from 'stream';
import type * as http from 'http';
import type { EventEmitter } from 'events';
export declare const DEFAULT_ADMIN_SERVER_PORT = 45454;
export declare enum Method {
GET = 0,
POST = 1,
PUT = 2,
DELETE = 3,
PATCH = 4,
HEAD = 5,
OPTIONS = 6
}
export declare enum RulePriority {
FALLBACK = 0,
DEFAULT = 1
}
export interface Headers {
host?: string;
'content-length'?: string;
'content-type'?: string;
'user-agent'?: string;
cookie?: string;
':method'?: string;
':scheme'?: string;
':authority'?: string;
':path'?: string;
[key: string]: undefined | string | string[];
}
export interface Trailers {
[key: string]: undefined | string | string[];
}
export type RawHeaders = Array<[key: string, value: string]>;
export type RawTrailers = RawHeaders;
export interface Destination {
hostname: string;
port: number;
}
export interface Request {
id: string;
matchedRuleId?: string;
protocol: string;
httpVersion: string;
method: string;
url: string;
path: string;
remoteIpAddress?: string;
remotePort?: number;
/**
* The best guess at the target host + port of the request. This uses tunnelling metadata
* wherever possible, or the headers if not.
*/
destination: Destination;
headers: Headers;
rawHeaders: RawHeaders;
timingEvents: TimingEvents;
tags: string[];
}
export interface TlsConnectionEvent {
remoteIpAddress?: string;
remotePort?: number;
tags: string[];
timingEvents: TlsTimingEvents;
destination?: Destination;
tlsMetadata: TlsSocketMetadata;
}
export interface TlsSocketMetadata {
sniHostname?: string;
clientAlpn?: string[];
ja3Fingerprint?: string;
ja4Fingerprint?: string;
}
export interface TlsPassthroughEvent extends RawPassthroughEvent, TlsConnectionEvent {
destination: Destination;
remoteIpAddress: string;
remotePort: number;
timingEvents: TlsTimingEvents;
}
export interface TlsHandshakeFailure extends TlsConnectionEvent {
failureCause: 'closed' | 'reset' | 'cert-rejected' | 'no-shared-cipher' | 'handshake-timeout' | 'unknown';
timingEvents: TlsFailureTimingEvents;
}
export interface RawPassthroughEvent {
id: string;
destination: Destination;
/**
* The IP address of the remote client that initiated the connection.
*/
remoteIpAddress: string;
/**
* The port of the remote client that initiated the connection.
*/
remotePort: number;
tags: string[];
timingEvents: ConnectionTimingEvents;
}
export interface RawPassthroughDataEvent {
/**
* The id of the passthrough tunnel.
*/
id: string;
/**
* The direction of the message, from the downstream perspective (received from the client,
* or sent back to the client).
*/
direction: 'sent' | 'received';
/**
* The contents of the message as a raw buffer.
*/
content: Uint8Array;
/**
* A high-precision floating-point monotonically increasing timestamp.
* Comparable and precise, but not related to specific current time.
*
* To link this to the current time, compare it to `timingEvents.startTime`.
*/
eventTimestamp: number;
}
export interface ConnectionTimingEvents {
/**
* When the socket initially connected, in MS since the unix
* epoch.
*/
startTime: number;
/**
* When the socket initially connected, equivalent to startTime.
*
* High-precision floating-point monotonically increasing timestamps.
* Comparable and precise, but not related to specific current time.
*/
connectTimestamp: number;
/**
* When the outer tunnel (e.g. a preceeding CONNECT request/SOCKS
* connection) was created, if there was one.
*/
tunnelTimestamp?: number;
/**
* When the connection was closed, if it has been closed.
*/
disconnectTimestamp?: number;
}
export interface TlsTimingEvents extends ConnectionTimingEvents {
/**
* When Mockttp's handshake for this connection was completed (if there
* was one). This is not set for passed through connections.
*/
handshakeTimestamp?: number;
}
export interface TlsFailureTimingEvents extends TlsTimingEvents {
/**
* When the TLS connection failed. This may be due to a failed handshake
* (in which case `handshakeTimestamp` will be undefined) or due to a
* subsequent error which means the TLS connection was not usable (like
* an immediate closure due to an async certificate rejection).
*/
failureTimestamp: number;
}
export interface OngoingRequest extends Request, EventEmitter {
body: OngoingBody;
rawTrailers?: RawHeaders;
}
export interface OngoingBody {
asStream: () => stream.Readable;
asBuffer: () => Promise<Buffer>;
asDecodedBuffer: () => Promise<Buffer>;
asText: () => Promise<string>;
asJson: () => Promise<object>;
asFormData: () => Promise<{
[key: string]: string | string[] | undefined;
}>;
}
export interface CompletedBody {
/**
* The raw bytes of the response. If a content encoding was used, this is
* the raw encoded data.
*/
buffer: Buffer;
/**
* The decoded bytes of the response. If no encoding was used, this is the
* same as `.buffer`. The response is decoded and returned asynchronously
* as a Promise.
*/
getDecodedBuffer(): Promise<Buffer | undefined>;
/**
* The contents of the response, decoded and parsed as a UTF-8 string.
* The response is decoded and returned asynchronously as a Promise.
*/
getText(): Promise<string | undefined>;
/**
* The contents of the response, decoded, parsed as UTF-8 string, and
* then parsed a JSON. The response is decoded and returned asynchronously
* as a Promise.
*/
getJson(): Promise<object | undefined>;
/**
* The contents of the response, decoded, and then parsed automatically as
* either one of the form encoding types (either URL-encoded or multipart),
* determined automatically from the message content-type header.
*
* This method is convenient and offers a single mechanism to parse both
* formats, but you may want to consider parsing on format explicitly with
* the `getUrlEncodedFormData()` or `getMultipartFormData()` methods instead.
*
* After parsing & decoding, the result is returned asynchronously as a
* Promise for a key-value(s) object.
*/
getFormData(): Promise<{
[key: string]: string | string[] | undefined;
} | undefined>;
/**
* The contents of the response, decoded, parsed as UTF-8 string, and then
* parsed as URL-encoded form data. After parsing & decoding, the result is
* returned asynchronously as a Promise for a key-value(s) object.
*/
getUrlEncodedFormData(): Promise<{
[key: string]: string | string[] | undefined;
} | undefined>;
/**
* The contents of the response, decoded, and then parsed as multi-part
* form data. The response is result is returned asynchronously as a
* Promise for an array of parts with their names, data and metadata.
*/
getMultipartFormData(): Promise<Array<{
name?: string;
filename?: string;
type?: string;
data: Buffer;
}> | undefined>;
}
export type InitiatedRequest = Request;
export interface AbortedRequest extends InitiatedRequest {
error?: {
name?: string;
code?: string;
message?: string;
stack?: string;
};
}
export interface CompletedRequest extends Request {
body: CompletedBody;
rawTrailers: RawTrailers;
trailers: Trailers;
}
export interface TimingEvents {
startTime: number;
startTimestamp: number;
bodyReceivedTimestamp?: number;
headersSentTimestamp?: number;
responseSentTimestamp?: number;
wsAcceptedTimestamp?: number;
wsClosedTimestamp?: number;
abortedTimestamp?: number;
}
export interface OngoingResponse extends http.ServerResponse {
id: string;
getHeaders(): Headers;
getRawHeaders(): RawHeaders;
body: OngoingBody;
getRawTrailers(): RawTrailers;
timingEvents: TimingEvents;
tags: string[];
}
export interface CompletedResponse {
id: string;
statusCode: number;
statusMessage: string;
headers: Headers;
rawHeaders: RawHeaders;
body: CompletedBody;
rawTrailers: RawTrailers;
trailers: Trailers;
timingEvents: TimingEvents;
tags: string[];
}
export interface WebSocketMessage {
/**
* The id of this websocket stream. This will match the id of the request,
* the initial connection response, and any other WebSocket events for the
* same connection stream.
*/
streamId: string;
/**
* Whether the message was sent by Mockttp, or received from a Mockttp client.
*/
direction: 'sent' | 'received';
/**
* The contents of the message as a raw buffer. This is already decompressed,
* if the WebSocket uses compression.
*/
content: Uint8Array;
/**
* Whether this is a string message or a raw binary data message.
*/
isBinary: boolean;
/**
* A high-precision floating-point monotonically increasing timestamp.
* Comparable and precise, but not related to specific current time.
*
* To link this to the current time, compare it to `timingEvents.startTime`.
*/
eventTimestamp: number;
timingEvents: TimingEvents;
tags: string[];
}
export interface WebSocketClose {
/**
* The id of this websocket stream. This will match the id of the request,
* the initial connection response, and any other WebSocket events for the
* same connection stream.
*/
streamId: string;
/**
* The close code of the shutdown. This is the close code that was received
* from the remote client (either initiated remotely, or echoing our own sent
* close frame).
*
* This may be undefined only if a close frame was received but did not contain
* any close code. If no close frame was received before the connection was
* lost (i.e. the connection was not cleanly closed) this event will not
* fire at all, and an 'abort' event will fire instead.
*/
closeCode: number | undefined;
/**
* The close reason of the shutdown.
*/
closeReason: string;
timingEvents: TimingEvents;
tags: string[];
}
/**
* A client error event describes a request (or our best guess at parsing it),
* that wasn't correctly completed, and the error response it received, or
* 'aborted' if the connection was disconnected before we could respond.
*/
export interface ClientError {
errorCode?: string;
request: {
id: string;
timingEvents: TimingEvents;
tags: string[];
protocol?: string;
httpVersion: string;
method?: string;
url?: string;
path?: string;
destination?: Destination;
headers: Headers;
rawHeaders: RawHeaders;
remoteIpAddress?: string;
remotePort?: number;
};
response: CompletedResponse | 'aborted';
}
/**
* An event fired from an individual rule during request processing.
*/
export interface RuleEvent<T = unknown> {
requestId: string;
ruleId: string;
eventType: string;
eventData: T;
}
/**
* A mocked endpoint provides methods to see the current state of
* a mock rule.
*/
export interface MockedEndpoint {
id: string;
/**
* Get the requests that this endpoint has seen so far.
*
* This method returns a promise, which resolves with the requests seen
* up until now, once all ongoing requests have terminated. The returned
* lists are immutable, so won't change if more requests arrive in future.
* Call `getSeenRequests` again later to get an updated list.
*
* Requests are included here once the response is completed, even if the request
* itself failed, the responses failed or exceptions are thrown elsewhere. To
* watch for errors or detailed response info, look at the various server.on(event)
* methods.
*/
getSeenRequests(): Promise<CompletedRequest[]>;
/**
* Reports whether this endpoint is still pending: if it either hasn't seen the
* specified number of requests (if one was specified e.g. with .twice())
* or if it hasn't seen at least one request, by default.
*
* This method returns a promise, which resolves with the result once all
* ongoing requests have terminated.
*/
isPending(): Promise<boolean>;
}
export interface MockedEndpointData {
id: string;
explanation?: string;
seenRequests: CompletedRequest[];
isPending: boolean;
}
export interface Explainable {
explain(): string;
}
export interface ProxyEnvConfig {
HTTP_PROXY: string;
HTTPS_PROXY: string;
}
export type defaultMaxListeners = typeof EventEmitter.defaultMaxListeners;
//# sourceMappingURL=types.d.ts.map