straightforward
Version:
A straightforward forward-proxy.
142 lines (135 loc) • 4.11 kB
TypeScript
import http from 'http';
import { EventEmitter } from 'events';
import internal from 'stream';
/**
* 'next' function, passed to a middleware
*/
type Next = () => void | Promise<void>;
/**
* A middleware
*/
type Middleware<T> = (context: T, next: Next) => Promise<void> | void;
/**
* A middleware container and invoker
*/
declare class MiddlewareDispatcher<T> {
middlewares: Middleware<T>[];
constructor();
/**
* Add a middleware function.
*/
use(...mw: Middleware<T>[]): void;
/**
* Execute the chain of middlewares, in the order they were added on a
* given Context.
*/
dispatch(context: T): Promise<void>;
}
interface StraightforwardOptions {
requestTimeout: number;
}
type Request = http.IncomingMessage & RequestAdditions;
interface RequestLocals {
isConnect: boolean;
urlParts: {
host: string;
port: number;
path: string;
};
}
interface RequestAdditions {
locals: RequestLocals;
}
type Response = http.ServerResponse<http.IncomingMessage> & {
req: http.IncomingMessage;
};
type ProxyResponse = http.IncomingMessage;
type RequestContext<Locals extends {
locals: Record<string, any>;
} = {
locals: {};
}> = {
req: Request & Locals;
res: Response;
};
type ResponseContext<Locals extends {
locals: Record<string, any>;
} = {
locals: {};
}> = {
req: Request;
res: Response;
proxyRes: ProxyResponse;
};
type ConnectContext<Locals extends {
locals: Record<string, any>;
} = {
locals: {};
}> = {
req: Request & Locals;
clientSocket: internal.Duplex;
head: Buffer;
};
/** Typeguard to check if a context belongs to a http request (rather than a connect request) */
declare function isRequest(ctx: any): ctx is RequestContext;
/** Typeguard to check if a context belongs to a connect request (rather than a http request) */
declare function isConnect(ctx: any): ctx is ConnectContext;
declare class Straightforward extends EventEmitter {
server: http.Server;
instanceId: number;
opts: StraightforwardOptions;
onRequest: MiddlewareDispatcher<RequestContext<any>>;
onResponse: MiddlewareDispatcher<ResponseContext<any>>;
onConnect: MiddlewareDispatcher<ConnectContext<any>>;
stats: {
onRequest: number;
onConnect: number;
};
constructor(opts?: Partial<StraightforwardOptions>);
cluster(port: number, count?: number): Promise<unknown>;
listen(port?: number): Promise<unknown>;
close(): void;
private _onRequest;
private _proxyRequest;
private _onResponse;
private _onConnect;
private _proxyConnect;
private _onUpgrade;
private _onRequestError;
private _onServerError;
private _onUncaughtException;
private _populateUrlParts;
}
interface AuthOpts {
user?: string;
pass?: string;
dynamic?: boolean;
}
interface RequestAdditionsAuth {
locals: {
proxyUser: string;
proxyPass: string;
};
}
/**
* Authenticate an incoming proxy request
* Supports static `user` and `pass` or `dynamic`,
* in which case `ctx.req.locals` will be populated with `proxyUser` and `proxyPass`
* This middleware supports both onRequest and onConnect
*/
declare const auth: ({ user, pass, dynamic, }: AuthOpts) => Middleware<RequestContext<RequestAdditionsAuth> | ConnectContext<RequestAdditionsAuth>>;
/** Echo an incoming proxy request by returning it's data */
declare const echo: Middleware<RequestContext>;
type index_AuthOpts = AuthOpts;
type index_RequestAdditionsAuth = RequestAdditionsAuth;
declare const index_auth: typeof auth;
declare const index_echo: typeof echo;
declare namespace index {
export {
index_AuthOpts as AuthOpts,
index_RequestAdditionsAuth as RequestAdditionsAuth,
index_auth as auth,
index_echo as echo,
};
}
export { ConnectContext, Middleware, MiddlewareDispatcher, Next, ProxyResponse, Request, RequestAdditions, RequestContext, RequestLocals, Response, ResponseContext, Straightforward, StraightforwardOptions, Straightforward as default, isConnect, isRequest, index as middleware };