import * as dntShim from "../_dnt.shims.js";
import { Path } from "../deps/jsr.io/@david/path/0.3.2/mod.js";
import { type Delay, type WriteFileOptions } from "../deps/jsr.io/@david/shell/0.5.4/mod.js";
import { symbols } from "../deps/jsr.io/@david/shell/0.5.4/internal.js";
import type { ProgressBar } from "./console/mod.js";
interface RequestBuilderState {
    noThrow: boolean | number[];
    url: string | URL | undefined;
    body: dntShim.BodyInit | undefined;
    cache: dntShim.RequestCache | undefined;
    headers: Record<string, string | undefined>;
    integrity: string | undefined;
    keepalive: boolean | undefined;
    method: string | undefined;
    mode: dntShim.RequestMode | undefined;
    progressBarFactory: ((message: string) => ProgressBar) | undefined;
    redirect: dntShim.RequestRedirect | undefined;
    referrer: string | undefined;
    referrerPolicy: dntShim.ReferrerPolicy | undefined;
    progressOptions: {
        noClear: boolean;
    } | undefined;
    onProgress: ((event: ProgressEvent) => void)[];
    timeout: number | undefined;
    signal: AbortSignal | undefined;
    beforeRequest: BeforeRequestCallback[] | undefined;
}
/** Callback invoked before a request is sent.
 *
 * Receives the current builder and may return a (possibly modified) builder
 * to use for the request. Returning the builder unchanged — or returning
 * nothing — is a no-op.
 *
 * The builder passed to the callback is wrapped in a Proxy that hides its
 * `.then`, so it isn't detected as a thenable by the JavaScript Promise
 * machinery. That makes it safe to `return builder.header(...)` from an
 * `async` function without the runtime recursively unwrapping the thenable
 * and triggering a fetch. Methods like `.header(...)` that return a new
 * builder return another such wrapped Proxy.
 *
 * The return type is loose because TypeScript infers the async return type
 * by following `PromiseLike` (the same logic the runtime uses), so e.g.
 * `async b => b.header(...)` is inferred as `Promise<RequestResponse>`.
 */
export type BeforeRequestCallback = (builder: RequestBuilder) => RequestBuilder | Promise<RequestBuilder> | Promise<RequestResponse> | void | Promise<void>;
/** Event passed to an `onProgress` callback as bytes are received. */
export interface ProgressEvent {
    /** Cumulative number of bytes received so far. */
    loaded: number;
    /** Total number of bytes expected from the `content-length` header,
     * or `undefined` if not provided by the server.
     */
    total: number | undefined;
}
/** @internal */
export declare const withProgressBarFactorySymbol: unique symbol;
/**
 * Builder API for downloading files.
 */
export declare class RequestBuilder implements PromiseLike<RequestResponse> {
    #private;
    [symbols.readable]: () => dntShim.ReadableStream<Uint8Array>;
    then<TResult1 = RequestResponse, TResult2 = never>(onfulfilled?: ((value: RequestResponse) => TResult1 | PromiseLike<TResult1>) | null | undefined, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null | undefined): PromiseLike<TResult1 | TResult2>;
    /** Fetches and gets the response. */
    fetch(): Promise<RequestResponse>;
    /** Specifies the URL to send the request to. */
    url(value: string | URL | undefined): RequestBuilder;
    /** Sets multiple headers at the same time via an object literal. */
    header(items: Record<string, string | undefined>): RequestBuilder;
    /** Sets a header to send with the request. */
    header(name: string, value: string | undefined): RequestBuilder;
    /**
     * Do not throw if a non-2xx status code is received.
     *
     * By default the request builder will throw when
     * receiving a non-2xx status code. Specify this
     * to have it not throw.
     */
    noThrow(value?: boolean): RequestBuilder;
    /**
     * Do not throw if a non-2xx status code is received
     * except for these excluded provided status codes.
     *
     * This overload may be especially useful when wanting to ignore
     * 404 status codes and have it return undefined instead. For example:
     *
     * ```ts
     * const data = await $.request(`https://crates.io/api/v1/crates/${crateName}`)
     *   .noThrow(404)
     *   .json<CratesIoMetadata | undefined>();
     * ```
     *
     * Note, use multiple arguments to ignore multiple status codes (ex. `.noThrow(400, 404)`) as
     * multiple calls to `.noThrow()` will overwrite the previous.
     */
    noThrow(exclusionStatusCode: number, ...additional: number[]): RequestBuilder;
    body(value: dntShim.BodyInit | undefined): RequestBuilder;
    cache(value: dntShim.RequestCache | undefined): RequestBuilder;
    integrity(value: string | undefined): RequestBuilder;
    keepalive(value: boolean): RequestBuilder;
    method(value: string): RequestBuilder;
    mode(value: dntShim.RequestMode): RequestBuilder;
    /** @internal */
    [withProgressBarFactorySymbol](factory: (message: string) => ProgressBar): RequestBuilder;
    redirect(value: dntShim.RequestRedirect): RequestBuilder;
    referrer(value: string | undefined): RequestBuilder;
    referrerPolicy(value: dntShim.ReferrerPolicy | undefined): RequestBuilder;
    /** Shows a progress bar while downloading with the provided options. */
    showProgress(opts: {
        noClear?: boolean;
    }): RequestBuilder;
    /** Shows a progress bar while downloading. */
    showProgress(show?: boolean): RequestBuilder;
    /** Adds a callback that is invoked as bytes are received from the response body.
     *
     * The callback fires once per chunk read from the network with the cumulative
     * number of bytes received and the total expected size (from the `content-length`
     * header, or `undefined` if the server didn't provide one). Multiple callbacks
     * may be registered by calling this method repeatedly; each is invoked in the
     * order it was added.
     */
    onProgress(callback: (event: ProgressEvent) => void): RequestBuilder;
    /** Timeout the request after the specified delay throwing a `TimeoutError`. */
    timeout(delay: Delay | undefined): RequestBuilder;
    /** Sets an abort signal for the request. When the signal is
     * aborted, the request will be cancelled.
     */
    signal(signal: AbortSignal): RequestBuilder;
    /** Registers a callback that runs just before each request is sent.
     *
     * The callback receives the current builder and may return a (possibly
     * modified) builder to use for the request. Useful for asynchronously
     * resolving values such as auth tokens.
     *
     * ```ts
     * $.request(url).beforeRequest(async (builder) => {
     *   return builder.header("Authorization", `Bearer ${await getAccessToken()}`);
     * });
     * ```
     *
     * Multiple `.beforeRequest(...)` calls compose: each registered callback runs
     * in the order it was added, with the builder produced by the previous one.
     *
     * The builder passed to the callback is in a special "passthrough" mode so
     * its `.then(...)` resolves with the builder itself (instead of fetching) —
     * this is what makes `return builder.header(...)` from an `async` function
     * safe. If you construct a fresh `new RequestBuilder()` inside the callback,
     * return it as `{ requestBuilder: ... }` to avoid accidental fetching.
     */
    beforeRequest(callback: BeforeRequestCallback): RequestBuilder;
    /** Fetches and gets the response as an array buffer. */
    arrayBuffer(): Promise<ArrayBuffer>;
    /** Fetches and gets the response as a blob. */
    blob(): Promise<Blob>;
    /** Fetches and gets the response as form data. */
    formData(): Promise<FormData>;
    /** Fetches and gets the response as JSON additionally setting
     * a JSON accept header if not set. */
    json<TResult = any>(): Promise<TResult>;
    /** Fetches and gets the response as text. */
    text(): Promise<string>;
    /** Pipes the response body to the provided writable stream. */
    pipeTo(dest: dntShim.WritableStream<Uint8Array>, options?: dntShim.StreamPipeOptions): Promise<void>;
    /**
     * Pipes the response body to a file.
     *
     * @remarks The path will be derived from the request's url
     * and downloaded to the current working directory.
     *
     * @returns The path reference of the downloaded file.
     */
    pipeToPath(options?: WriteFileOptions): Promise<Path>;
    /**
     * Pipes the response body to a file.
     *
     * @remarks If no path is provided then it will be derived from the
     * request's url and downloaded to the current working directory.
     *
     * @returns The path reference of the downloaded file.
     */
    pipeToPath(path?: string | URL | Path | undefined, options?: WriteFileOptions): Promise<Path>;
    /** Pipes the response body through the provided transform. */
    pipeThrough<T>(transform: {
        writable: dntShim.WritableStream<Uint8Array>;
        readable: dntShim.ReadableStream<T>;
    }): Promise<dntShim.ReadableStream<T>>;
}
interface RequestAbortController {
    controller: AbortController;
    /** Clears the timeout that may be set if there's a delay */
    clearTimeout(): void;
}
/** Response of making a request where the body can be read. */
export declare class RequestResponse {
    #private;
    /** @internal */
    constructor(opts: {
        response: Response;
        originalUrl: string;
        progressBar: ProgressBar | undefined;
        onProgress: ((event: ProgressEvent) => void)[];
        contentLength: number | undefined;
        abortController: RequestAbortController;
    });
    /** Raw response. */
    get response(): Response;
    /** Response headers. */
    get headers(): Headers;
    /** If the response had a 2xx code. */
    get ok(): boolean;
    /** If the response is the result of a redirect. */
    get redirected(): boolean;
    /** The underlying `AbortSignal` used to abort the request body
     * when a timeout is reached or when the `.abort()` method is called. */
    get signal(): AbortSignal;
    /** Status code of the response. */
    get status(): number;
    /** Status text of the response. */
    get statusText(): string;
    /** URL of the response. */
    get url(): string;
    /** Aborts  */
    abort(reason?: unknown): void;
    /**
     * Throws if the response doesn't have a 2xx code.
     *
     * This might be useful if the request was built with `.noThrow()`, but
     * otherwise this is called automatically for any non-2xx response codes.
     *
     * Note: this does not consume the body. If you don't intend to read the
     * body, call `cancelBody()` first to release the underlying resources.
     */
    throwIfNotOk(): void;
    /**
     * Cancels the response body, releasing the underlying resources.
     *
     * Useful in conjunction with `.noThrow()` and `throwIfNotOk()` when you
     * don't intend to read the body.
     */
    cancelBody(): Promise<void>;
    /**
     * Respose body as an array buffer.
     *
     * Note: Returns `undefined` when `.noThrow(404)` and status code is 404.
     */
    arrayBuffer(): Promise<ArrayBuffer>;
    /**
     * Response body as a blog.
     *
     * Note: Returns `undefined` when `.noThrow(404)` and status code is 404.
     */
    blob(): Promise<Blob>;
    /**
     * Response body as a form data.
     *
     * Note: Returns `undefined` when `.noThrow(404)` and status code is 404.
     */
    formData(): Promise<FormData>;
    /**
     * Respose body as JSON.
     *
     * Note: Returns `undefined` when `.noThrow(404)` and status code is 404.
     */
    json<TResult = any>(): Promise<TResult>;
    /**
     * Respose body as text.
     *
     * Note: Returns `undefined` when `.noThrow(404)` and status code is 404.
     */
    text(): Promise<string>;
    /** Pipes the response body to the provided writable stream. */
    pipeTo(dest: dntShim.WritableStream<Uint8Array>, options?: dntShim.StreamPipeOptions): Promise<void>;
    /**
     * Pipes the response body to a file.
     *
     * @remarks The path will be derived from the request's url
     * and downloaded to the current working directory.
     *
     * @remarks  If the path is a directory, then the file name will be derived
     * from the request's url and the file will be downloaded to the provided directory
     *
     * @returns The path reference of the downloaded file
     */
    pipeToPath(options?: WriteFileOptions): Promise<Path>;
    /**
     * Pipes the response body to a file.
     *
     * @remarks If no path is provided then it will be derived from the
     * request's url and downloaded to the current working directory.
     *
     * @remarks  If the path is a directory, then the file name will be derived
     * from the request's url and the file will be downloaded to the provided directory
     *
     * @returns The path reference of the downloaded file
     */
    pipeToPath(path?: string | URL | Path | undefined, options?: WriteFileOptions): Promise<Path>;
    /** Pipes the response body through the provided transform. */
    pipeThrough<T>(transform: {
        writable: dntShim.WritableStream<Uint8Array>;
        readable: dntShim.ReadableStream<T>;
    }): dntShim.ReadableStream<T>;
    get readable(): dntShim.ReadableStream<Uint8Array>;
}
export declare function makeRequest(state: RequestBuilderState): Promise<RequestResponse>;
export {};
//# sourceMappingURL=request.d.ts.map