import * as http from "node:http";
import * as net from "node:net";
import { EventEmitter } from "node:events";
import type { Stream } from "node:stream";
export interface ProxyTargetDetailed {
    host: string;
    port: number;
    protocol?: string;
    hostname?: string;
    socketPath?: string;
    key?: string;
    passphrase?: string;
    pfx?: Buffer | string;
    cert?: string;
    ca?: string;
    ciphers?: string;
    secureProtocol?: string;
}
export type ProxyType = "ws" | "web";
export type ProxyTarget = ProxyTargetUrl | ProxyTargetDetailed;
export type ProxyTargetUrl = URL | string | {
    port: number;
    host: string;
    protocol?: string;
};
export type NormalizeProxyTarget<T extends ProxyTargetUrl> = Exclude<T, string> | URL;
export interface ServerOptions {
    /** URL string to be parsed with the url module. */
    target?: ProxyTarget;
    /** URL string to be parsed with the url module or a URL object. */
    forward?: ProxyTargetUrl;
    /** Object to be passed to http(s).request. */
    agent?: any;
    /** Object to be passed to https.createServer(). */
    ssl?: any;
    /** If you want to proxy websockets. */
    ws?: boolean;
    /** Adds x- forward headers. */
    xfwd?: boolean;
    /** Verify SSL certificate. */
    secure?: boolean;
    /** Explicitly specify if we are proxying to another proxy. */
    toProxy?: boolean;
    /** Specify whether you want to prepend the target's path to the proxy path. */
    prependPath?: boolean;
    /** Specify whether you want to ignore the proxy path of the incoming request. */
    ignorePath?: boolean;
    /** Local interface string to bind for outgoing connections. */
    localAddress?: string;
    /** Changes the origin of the host header to the target URL. */
    changeOrigin?: boolean;
    /** specify whether you want to keep letter case of response header key */
    preserveHeaderKeyCase?: boolean;
    /** Basic authentication i.e. 'user:password' to compute an Authorization header. */
    auth?: string;
    /** Rewrites the location hostname on (301 / 302 / 307 / 308) redirects, Default: null. */
    hostRewrite?: string;
    /** Rewrites the location host/ port on (301 / 302 / 307 / 308) redirects based on requested host/ port.Default: false. */
    autoRewrite?: boolean;
    /** Rewrites the location protocol on (301 / 302 / 307 / 308) redirects to 'http' or 'https'.Default: null. */
    protocolRewrite?: string;
    /** rewrites domain of set-cookie headers. */
    cookieDomainRewrite?: false | string | {
        [oldDomain: string]: string;
    };
    /** rewrites path of set-cookie headers. Default: false */
    cookiePathRewrite?: false | string | {
        [oldPath: string]: string;
    };
    /** object with extra headers to be added to target requests. */
    headers?: {
        [header: string]: string | string[] | undefined;
    };
    /** Timeout (in milliseconds) when proxy receives no response from target. Default: 120000 (2 minutes) */
    proxyTimeout?: number;
    /** Timeout (in milliseconds) for incoming requests */
    timeout?: number;
    /** Specify whether you want to follow redirects. Default: false */
    followRedirects?: boolean;
    /** If set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the proxyRes event */
    selfHandleResponse?: boolean;
    /** Buffer */
    buffer?: Stream;
    /** Explicitly set the method type of the ProxyReq */
    method?: string;
    /**
     * Optionally override the trusted CA certificates.
     * This is passed to https.request.
     */
    ca?: string;
    /** Optional fetch implementation to use instead of global fetch, use this to activate fetch-based proxying,
     * for example to proxy HTTP/2 requests
    */
    fetch?: typeof fetch;
    /** Optional configuration object for fetch-based proxy requests.
     * Use this to customize fetch request and response handling.
     * For custom fetch implementations, use the `fetch` property.*/
    fetchOptions?: FetchOptions;
}
export interface FetchOptions {
    /** Fetch request options */
    requestOptions?: RequestInit;
    /** Called before making the fetch request */
    onBeforeRequest?: (requestOptions: RequestInit, req: http.IncomingMessage, res: http.ServerResponse, options: NormalizedServerOptions) => void | Promise<void>;
    /** Called after receiving the fetch response */
    onAfterResponse?: (response: Response, req: http.IncomingMessage, res: http.ServerResponse, options: NormalizedServerOptions) => void | Promise<void>;
}
export interface NormalizedServerOptions extends ServerOptions {
    target?: NormalizeProxyTarget<ProxyTarget>;
    forward?: NormalizeProxyTarget<ProxyTargetUrl>;
}
export type ErrorCallback<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> = (err: TError, req: InstanceType<TIncomingMessage>, res: InstanceType<TServerResponse> | net.Socket, target?: ProxyTargetUrl) => void;
type ProxyServerEventMap<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> = {
    error: Parameters<ErrorCallback<TIncomingMessage, TServerResponse, TError>>;
    start: [
        req: InstanceType<TIncomingMessage>,
        res: InstanceType<TServerResponse>,
        target: ProxyTargetUrl
    ];
    open: [socket: net.Socket];
    proxyReq: [
        proxyReq: http.ClientRequest,
        req: InstanceType<TIncomingMessage>,
        res: InstanceType<TServerResponse>,
        options: ServerOptions,
        socket: net.Socket
    ];
    proxyRes: [
        proxyRes: InstanceType<TIncomingMessage>,
        req: InstanceType<TIncomingMessage>,
        res: InstanceType<TServerResponse>
    ];
    proxyReqWs: [
        proxyReq: http.ClientRequest,
        req: InstanceType<TIncomingMessage>,
        socket: net.Socket,
        options: ServerOptions,
        head: any
    ];
    econnreset: [
        err: Error,
        req: InstanceType<TIncomingMessage>,
        res: InstanceType<TServerResponse>,
        target: ProxyTargetUrl
    ];
    end: [
        req: InstanceType<TIncomingMessage>,
        res: InstanceType<TServerResponse>,
        proxyRes: InstanceType<TIncomingMessage>
    ];
    close: [
        proxyRes: InstanceType<TIncomingMessage>,
        proxySocket: net.Socket,
        proxyHead: any
    ];
};
type ProxyMethodArgs<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> = {
    ws: [
        req: InstanceType<TIncomingMessage>,
        socket: any,
        head: any,
        ...args: [
            options?: ServerOptions,
            callback?: ErrorCallback<TIncomingMessage, TServerResponse, TError>
        ] | [callback?: ErrorCallback<TIncomingMessage, TServerResponse, TError>]
    ];
    web: [
        req: InstanceType<TIncomingMessage>,
        res: InstanceType<TServerResponse>,
        ...args: [
            options: ServerOptions,
            callback?: ErrorCallback<TIncomingMessage, TServerResponse, TError>
        ] | [callback?: ErrorCallback<TIncomingMessage, TServerResponse, TError>]
    ];
};
type PassFunctions<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> = {
    ws: (req: InstanceType<TIncomingMessage>, socket: net.Socket, options: NormalizedServerOptions, head: Buffer | undefined, server: ProxyServer<TIncomingMessage, TServerResponse, TError>, cb?: ErrorCallback<TIncomingMessage, TServerResponse, TError>) => unknown;
    web: (req: InstanceType<TIncomingMessage>, res: InstanceType<TServerResponse>, options: NormalizedServerOptions, head: Buffer | undefined, server: ProxyServer<TIncomingMessage, TServerResponse, TError>, cb?: ErrorCallback<TIncomingMessage, TServerResponse, TError>) => unknown;
};
export declare class ProxyServer<TIncomingMessage extends typeof http.IncomingMessage = typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse = typeof http.ServerResponse, TError = Error> extends EventEmitter<ProxyServerEventMap<TIncomingMessage, TServerResponse, TError>> {
    /**
     * Used for proxying WS(S) requests
     * @param req - Client request.
     * @param socket - Client socket.
     * @param head - Client head.
     * @param options - Additional options.
     */
    readonly ws: (...args: ProxyMethodArgs<TIncomingMessage, TServerResponse, TError>["ws"]) => void;
    /**
     * Used for proxying regular HTTP(S) requests
     * @param req - Client request.
     * @param res - Client response.
     * @param options - Additional options.
     */
    readonly web: (...args: ProxyMethodArgs<TIncomingMessage, TServerResponse, TError>["web"]) => void;
    private options;
    private webPasses;
    private wsPasses;
    private _server?;
    /**
     * Creates the proxy server with specified options.
     * @param options - Config object passed to the proxy
     */
    constructor(options?: ServerOptions);
    /**
     * Creates the proxy server with specified options.
     * @param options Config object passed to the proxy
     * @returns Proxy object with handlers for `ws` and `web` requests
     */
    static createProxyServer<TIncomingMessage extends typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse, TError = Error>(options?: ServerOptions): ProxyServer<TIncomingMessage, TServerResponse, TError>;
    /**
     * Creates the proxy server with specified options.
     * @param options Config object passed to the proxy
     * @returns Proxy object with handlers for `ws` and `web` requests
     */
    static createServer<TIncomingMessage extends typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse, TError = Error>(options?: ServerOptions): ProxyServer<TIncomingMessage, TServerResponse, TError>;
    /**
     * Creates the proxy server with specified options.
     * @param options Config object passed to the proxy
     * @returns Proxy object with handlers for `ws` and `web` requests
     */
    static createProxy<TIncomingMessage extends typeof http.IncomingMessage, TServerResponse extends typeof http.ServerResponse, TError = Error>(options?: ServerOptions): ProxyServer<TIncomingMessage, TServerResponse, TError>;
    createRightProxy: <PT extends ProxyType>(type: PT) => Function;
    onError: (err: TError) => void;
    /**
     * A function that wraps the object in a webserver, for your convenience
     * @param port - Port to listen on
     * @param hostname - The hostname to listen on
     */
    listen: (port: number, hostname?: string) => this;
    address: () => string | net.AddressInfo | null | undefined;
    /**
     * A function that closes the inner webserver and stops listening on given port
     */
    close: (cb?: Function) => void;
    before: <PT extends ProxyType>(type: PT, passName: string, cb: PassFunctions<TIncomingMessage, TServerResponse, TError>[PT]) => void;
    after: <PT extends ProxyType>(type: PT, passName: string, cb: PassFunctions<TIncomingMessage, TServerResponse, TError>[PT]) => void;
}
export {};
