declare const addr_symbol: symbol;

/**
 * Bind an Addr
 */
export declare function bind(addr: socketAddr.v4.SocketAddrV4): TcpListener;

export declare type Enumerate<N extends number, Acc extends number[] = []> = Acc["length"] extends N ? Acc[number] : Enumerate<N, [...Acc, Acc["length"]]>;

declare namespace http {
    export {
        PullZoneHandlerOptions,
        OriginRequestContext,
        OriginResponseContext,
        PullZoneHandler,
        serve,
        ServeHandler,
        servePullZone,
        ServerHandler
    }
}
export { http }

export declare const internal_getPlatform: () => Platform;

export declare class InvalidAddr extends Error {
    _guard: typeof addr_symbol;
    constructor(message: string);
    toString(): string;
}

declare namespace ip {
    export {
        toString,
        tryParseFromString,
        Enumerate,
        Range,
        IPv4
    }
}
export { ip }

/**
 * Returns the IP address associated with this socket address.
 */
export declare function ip_alias_1(addr: SocketAddrV4): ip.IPv4;

/**
 * An IPv4 Address
 */
export declare type IPv4 = [Range<0, 255>, Range<0, 255>, Range<0, 255>, Range<0, 255>];

export declare function isTcpListener(value: unknown): value is TcpListener;

/**
 * Tell if it's a v4 [SocketAddr].
 */
export declare function isV4(value: SocketAddr): value is v4_2.SocketAddrV4;

declare namespace net {
    export {
        http,
        ip,
        socketAddr,
        tcp
    }
}
export { net }

export declare type NoAddr = {
    readonly _tag: "NoAddr";
};

export declare function node_serve(listener: tcp.TcpListener, handler: ServerHandler): ServeHandler;

export declare type OriginRequestContext = {
    request: Request;
};

export declare type OriginResponseContext = {
    request: Request;
    response: Response;
};

export declare type Platform = {
    /**
     * @internal
     */
    readonly _tag: "_Platform";
    name: PlatformName;
    version: string;
    runtime: "bunny" | "node" | "deno" | "unknown";
    runtime_version: string;
};

declare type PlatformName = "MacOS" | "Linux" | "Windows" | "FreeBSD" | "OpenBSD" | "iOS" | "Android" | `Other:${string}` | "Unknown";

/**
 * Returns the port number associated with this socket address.
 */
export declare function port(addr: SocketAddrV4): number;

export declare type PullZoneHandler = {
    /**
     * Add a Middleware for the requests being processed.
     */
    onOriginRequest: (middleware: (ctx: OriginRequestContext) => Promise<Request> | Promise<Response>) => PullZoneHandler;
    /**
     * Add a Middleware for the response being processed.
     */
    onOriginResponse: (middleware: (ctx: OriginResponseContext) => Promise<Response>) => PullZoneHandler;
};

export declare type PullZoneHandlerOptions = {
    url: string;
};

export declare type Range<F extends number, T extends number> = Exclude<Enumerate<T>, Enumerate<F>> | T;

/**
 * Serves HTTP requests with the provided handler.
 *
 * @example
 * ```ts
 * import * as BunnySDK from "https://esm.sh/@bunny.net/edgescript-sdk@0.11";
 *
 * console.log("Starting server...");
 * BunnySDK.net.http.serve(async (req) => {
 *   console.log(`[INFO]: ${req.method} - ${req.url}`);
 *   return new Response("Hello bunny!");
 * });
 * ```
 */
export declare function serve(handler: ServerHandler): ServeHandler;

export declare function serve(listener: {
    port: number;
    hostname: string;
}, handler: ServerHandler): ServeHandler;

export declare function serve(listener: TcpListener, handler: ServerHandler): ServeHandler;

export declare type ServeHandler = {} & unknown;

/**
 * Serves HTTP requests for a PullZone
 *
 * If you have an associated PullZone within Bunny, we'll use it on production
 * and for local development you can configure it with the `url` option.
 *
 * @example
 * ```ts
 * import BunnySDK from "https://esm.sh/@bunny.net/edgescript-sdk@0.11.2";
 *
 * console.log("Starting server...");
 *
 * BunnySDK.net.http.servePullZone({ url: "https://echo.free.beeceptor.com/" })
 *   .onOriginRequest(
 *     (ctx) => {
 *       const optFT = ctx.request.headers.get("feature-flags");
 *       const featureFlags = optFT
 *         ? optFT.split(",").map((v) => v.trimStart())
 *         : [];
 *
 *       // Route-based matching and feature flag check
 *       const path = new URL(ctx.request.url).pathname;
 *       if (path === "/d") {
 *         if (!featureFlags.includes("route-d-preview")) {
 *           return Promise.resolve(
 *             new Response("You cannot use this route.", { status: 400 }),
 *           );
 *         }
 *       }
 *
 *       return Promise.resolve(ctx.request);
 *     },
 *   ).onOriginResponse((ctx) => {
 *     const response = ctx.response;
 *     response.headers.append("Via", "Custom");
 *
 *     return Promise.resolve(response);
 *   });
 * ```
 */
export declare function servePullZone(options: PullZoneHandlerOptions): PullZoneHandler;

export declare function servePullZone(listener: {
    port: number;
    hostname: string;
}, options: PullZoneHandlerOptions): PullZoneHandler;

export declare function servePullZone(listener: TcpListener, options: PullZoneHandlerOptions): PullZoneHandler;

/**
 * A handler for HTTP Requests.
 * Consumes a request and return a response.
 */
export declare type ServerHandler = (request: Request) => Response | Promise<Response>;

/**
 * An internet socket address
 *
 * We have a special case where it's not a socket address but a socket provided
 * by Bunny. This type will be refined with the associated method to fix it.
 */
export declare type SocketAddr = v4_2.SocketAddrV4 | NoAddr;

declare namespace socketAddr {
    export {
        isV4,
        v4,
        NoAddr,
        SocketAddr,
        SocketAddrError,
        InvalidAddr
    }
}
export { socketAddr }

export declare type SocketAddrError = InvalidAddr;

export declare type SocketAddrV4 = {
    readonly _tag: "SocketAddrV4";
    port: number;
    ip: ip.IPv4;
};

declare namespace tcp {
    export {
        isTcpListener,
        unstable_local_addr,
        toString_alias_1 as toString,
        unstable_new,
        bind,
        TcpListener
    }
}
export { tcp }

export declare type TcpListener = {
    /**
     * Prevent the construction
     * @internal
     */
    readonly _tag: 'TcpListener';
    addr: socketAddr.SocketAddr;
};

export declare function toString(ip: IPv4): string;

/**
 * Format the associated [TcpListener] to a String
 */
export declare function toString_alias_1(tcp: TcpListener): string;

/**
 * Try to parse a SocketAddrV4
 */
export declare function tryFromString(value: string): SocketAddrV4 | SyntaxError;

/**
 * Try to parse na IP
 */
export declare function tryParseFromString(ip: string): IPv4 | SyntaxError;

/**
 * Returns the local socket address of this listener.
 */
export declare function unstable_local_addr(tcp: TcpListener): socketAddr.SocketAddr;

/**
 * Create a new [TcpListener].
 */
export declare function unstable_new(): TcpListener;

export declare namespace v4 {
    export {
        port,
        ip_alias_1 as ip,
        tryFromString,
        SocketAddrV4
    }
}

declare namespace v4_2 {
    export {
        port,
        ip_alias_1 as ip,
        tryFromString,
        SocketAddrV4
    }
}

export { }
