import { EventEmitter } from "node:events";
import { Gauge, Histogram } from "@lodestar/utils";
import { StrictEventEmitter } from "strict-event-emitter-types";
import { IJson, RpcPayload } from "../interface.js";
export declare enum JsonRpcHttpClientEvent {
    /**
     * When registered this event will be emitted before the client throws an error.
     * This is useful for defining the error behavior in a common place at the time of declaration of the client.
     */
    ERROR = "jsonRpcHttpClient:error",
    /**
     * When registered this event will be emitted before the client returns the valid response to the caller.
     * This is useful for defining some common behavior for each request/response cycle
     */
    RESPONSE = "jsonRpcHttpClient:response"
}
export type JsonRpcHttpClientEvents = {
    [JsonRpcHttpClientEvent.ERROR]: (event: {
        payload?: unknown;
        error: Error;
    }) => void;
    [JsonRpcHttpClientEvent.RESPONSE]: (event: {
        payload?: unknown;
        response: unknown;
    }) => void;
};
declare const JsonRpcHttpClientEventEmitter_base: {
    new (): StrictEventEmitter<EventEmitter, JsonRpcHttpClientEvents>;
};
export declare class JsonRpcHttpClientEventEmitter extends JsonRpcHttpClientEventEmitter_base {
}
interface RpcResponseError {
    jsonrpc: "2.0";
    id: number;
    error: {
        code: number;
        message: string;
    };
}
export type ReqOpts = {
    timeout?: number;
    routeId?: string;
    retries?: number;
    retryDelay?: number;
    shouldRetry?: (lastError: Error) => boolean;
};
export type JsonRpcHttpClientMetrics = {
    requestTime: Histogram<{
        routeId: string;
    }>;
    streamTime: Histogram<{
        routeId: string;
    }>;
    requestErrors: Gauge<{
        routeId: string;
    }>;
    requestUsedFallbackUrl: Gauge<{
        routeId: string;
    }>;
    activeRequests: Gauge<{
        routeId: string;
    }>;
    configUrlsCount: Gauge;
    retryCount: Gauge<{
        routeId: string;
    }>;
};
export interface IJsonRpcHttpClient {
    fetch<R, P = IJson[]>(payload: RpcPayload<P>, opts?: ReqOpts): Promise<R>;
    fetchWithRetries<R, P = IJson[]>(payload: RpcPayload<P>, opts?: ReqOpts): Promise<R>;
    fetchBatch<R>(rpcPayloadArr: RpcPayload[], opts?: ReqOpts): Promise<R[]>;
    emitter: JsonRpcHttpClientEventEmitter;
}
export declare class JsonRpcHttpClient implements IJsonRpcHttpClient {
    private readonly urls;
    private readonly opts?;
    private id;
    /**
     * Optional: If provided, use this jwt secret to HS256 encode and add a jwt token in the
     * request header which can be authenticated by the RPC server to provide access.
     * A fresh token is generated on each requests as EL spec mandates the ELs to check
     * the token freshness +-5 seconds (via `iat` property of the token claim)
     */
    private readonly jwtSecret?;
    private readonly jwtId?;
    private readonly jwtVersion?;
    private readonly metrics;
    readonly emitter: JsonRpcHttpClientEventEmitter;
    constructor(urls: string[], opts?: {
        signal?: AbortSignal;
        timeout?: number;
        /** If returns true, do not fallback to other urls and throw early */
        shouldNotFallback?: (error: Error) => boolean;
        /**
         * Optional: If provided, use this jwt secret to HS256 encode and add a jwt token in the
         * request header which can be authenticated by the RPC server to provide access.
         * A fresh token is generated on each requests as EL spec mandates the ELs to check
         * the token freshness +-5 seconds (via `iat` property of the token claim)
         *
         * Otherwise the requests to the RPC server will be unauthorized
         * and it might deny responses to the RPC requests.
         */
        jwtSecret?: Uint8Array;
        /** If jwtSecret and jwtId are provided, jwtId will be included in JwtClaim.id */
        jwtId?: string;
        /** If jwtSecret and jwtVersion are provided, jwtVersion will be included in JwtClaim.clv. */
        jwtVersion?: string;
        /** Number of retries per request */
        retries?: number;
        /** Retry delay, only relevant if retries > 0 */
        retryDelay?: number;
        /** Metrics for retry, could be expanded later */
        metrics?: JsonRpcHttpClientMetrics | null;
    } | undefined);
    /**
     * Perform RPC request
     */
    fetch<R, P = IJson[]>(payload: RpcPayload<P>, opts?: ReqOpts): Promise<R>;
    /**
     * Perform RPC request with retry
     */
    fetchWithRetries<R, P = IJson[]>(payload: RpcPayload<P>, opts?: ReqOpts): Promise<R>;
    /**
     * Perform RPC batched request
     * Type-wise assumes all requests results have the same type
     */
    fetchBatch<R>(rpcPayloadArr: RpcPayload[], opts?: ReqOpts): Promise<R[]>;
    private wrapWithEvents;
    private fetchJson;
    /**
     * Fetches JSON and throws detailed errors in case the HTTP request is not ok
     */
    private fetchJsonOneUrl;
}
export declare class ErrorParseJson extends Error {
    constructor(json: string, e: Error);
}
/** JSON RPC endpoint returned status code == 200, but with error property set */
export declare class ErrorJsonRpcResponse extends Error {
    response: RpcResponseError;
    constructor(res: RpcResponseError, payloadMethod: string);
}
/** JSON RPC endpoint returned status code != 200 */
export declare class HttpRpcError extends Error {
    readonly status: number;
    constructor(status: number, message: string);
}
/**
 * JSON RPC spec errors https://www.jsonrpc.org/specification#response_object
 */
export declare function parseJsonRpcErrorCode(code: number): string;
export {};
//# sourceMappingURL=jsonRpcHttpClient.d.ts.map