/// <reference lib="es2023" preserve="true" />
/// <reference lib="dom" preserve="true" />
/// <reference lib="dom.iterable" preserve="true" />
import type { ReadableStream as WebReadableStream } from 'node:stream/web';
import { HttpRequestError } from '../error/error.util.js';
import type { ErrorDataTuple } from '../types.js';
import type { FetcherAfterResponseHook, FetcherBeforeRequestHook, FetcherBeforeRetryHook, FetcherCfg, FetcherGraphQLOptions, FetcherNormalizedCfg, FetcherOnErrorHook, FetcherOptions, FetcherResponse, FetchFunction, RequestInitNormalized } from './fetcher.model.js';
/**
 * Experimental wrapper around Fetch.
 * Works in both Browser and Node, using `globalThis.fetch`.
 */
export declare class Fetcher {
    /**
     * Included in UserAgent when run in Node.
     * In the browser it's not included, as we want "browser own" UserAgent to be included instead.
     *
     * Version is to be incremented every time a difference in behaviour (or a bugfix) is done.
     */
    static readonly VERSION = 4;
    /**
     * userAgent is statically exposed as Fetcher.userAgent.
     * It can be modified globally, and will be used (read) at the start of every request.
     */
    static userAgent: string | undefined;
    private constructor();
    /**
     * Add BeforeRequest hook at the end of the hooks list.
     */
    onBeforeRequest(hook: FetcherBeforeRequestHook): this;
    onAfterResponse(hook: FetcherAfterResponseHook): this;
    onBeforeRetry(hook: FetcherBeforeRetryHook): this;
    onError(hook: FetcherOnErrorHook): this;
    cfg: FetcherNormalizedCfg;
    static create(cfg?: FetcherCfg & FetcherOptions): Fetcher;
    get: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
    post: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
    put: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
    patch: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
    delete: <T = unknown>(url: string, opt?: FetcherOptions) => Promise<T>;
    getText: (url: string, opt?: FetcherOptions) => Promise<string>;
    postText: (url: string, opt?: FetcherOptions) => Promise<string>;
    putText: (url: string, opt?: FetcherOptions) => Promise<string>;
    patchText: (url: string, opt?: FetcherOptions) => Promise<string>;
    deleteText: (url: string, opt?: FetcherOptions) => Promise<string>;
    getVoid: (url: string, opt?: FetcherOptions) => Promise<void>;
    postVoid: (url: string, opt?: FetcherOptions) => Promise<void>;
    putVoid: (url: string, opt?: FetcherOptions) => Promise<void>;
    patchVoid: (url: string, opt?: FetcherOptions) => Promise<void>;
    deleteVoid: (url: string, opt?: FetcherOptions) => Promise<void>;
    headVoid: (url: string, opt?: FetcherOptions) => Promise<void>;
    /**
     * Small convenience wrapper that allows to issue GraphQL queries.
     * In practice, all it does is:
     * - Defines convenience `query` input option
     * - Unwraps `response.data`
     * - Unwraps `response.errors` and throws, if it's defined (as GQL famously returns http 200 even for errors)
     *
     * Currently it only unwraps and uses the first error from the `errors` array, for simplicity.
     *
     * @experimental
     */
    queryGraphQL<T = unknown>(opt: FetcherGraphQLOptions): Promise<T>;
    /**
     * Returns raw fetchResponse.body, which is a ReadableStream<Uint8Array>
     *
     * More on streams and Node interop:
     * https://css-tricks.com/web-streams-everywhere-and-fetch-for-node-js/
     */
    getReadableStream(url: string, opt?: FetcherOptions): Promise<WebReadableStream<Uint8Array>>;
    fetch<T = unknown>(opt: FetcherOptions): Promise<T>;
    /**
     * Execute fetch and expect/assert it to return an Error (which will be wrapped in
     * HttpRequestError as it normally would).
     * If fetch succeeds, which is unexpected, it'll throw an UnexpectedPass error.
     * Useful in unit testing.
     */
    expectError(opt: FetcherOptions): Promise<HttpRequestError>;
    /**
     * Like pTry - returns a [err, data] tuple (aka ErrorDataTuple).
     * err, if defined, is strictly HttpRequestError.
     * UPD: actually not, err is typed as Error, as it feels unsafe to guarantee error type.
     * UPD: actually yes - it will return HttpRequestError, and throw if there's an error
     * of any other type.
     */
    tryFetch<T = unknown>(opt: FetcherOptions): Promise<ErrorDataTuple<T, HttpRequestError>>;
    /**
     * Returns FetcherResponse.
     * Never throws, returns `err` property in the response instead.
     * Use this method instead of `throwHttpErrors: false` or try-catching.
     *
     * Note: responseType defaults to `void`, so, override it if you expect different.
     */
    doFetch<T = unknown>(opt: FetcherOptions): Promise<FetcherResponse<T>>;
    private onOkResponse;
    /**
     * This method exists to be able to easily mock it.
     * It is static, so mocking applies to ALL instances (even future ones) of Fetcher at once.
     */
    static callNativeFetch(url: string, init: RequestInitNormalized, fetchFn?: FetchFunction): Promise<Response>;
    private onNotOkResponse;
    private processRetry;
    private getRetryTimeout;
    /**
     * Default is yes,
     * unless there's reason not to (e.g method is POST).
     *
     * statusCode of 0 (or absense of it) will BE retried.
     */
    private shouldRetry;
    private getStatusFamily;
    /**
     * Returns url without baseUrl and before ?queryString
     */
    private getShortUrl;
    private normalizeCfg;
    private getFetcherName;
    private normalizeOptions;
}
export declare function getFetcher(cfg?: FetcherCfg & FetcherOptions): Fetcher;
