dax
Version:
Cross platform shell tools inspired by zx.
306 lines • 13.4 kB
TypeScript
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