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 };
