strongly-typed-test
Version:
Library to help developers identify type mismatches
1,754 lines (1,642 loc) โข 165 kB
TypeScript
/**
* Bun.js runtime APIs
*
* @example
*
* ```js
* import {file} from 'bun';
*
* // Log the file to the console
* const input = await file('/path/to/file.txt').text();
* console.log(input);
* ```
*
* This module aliases `globalThis.Bun`.
*/
declare module "bun" {
import type { Encoding as CryptoEncoding } from "crypto";
import type {
CipherNameAndProtocol,
EphemeralKeyInfo,
PeerCertificate,
} from "tls";
interface Env {
NODE_ENV?: string;
/**
* Can be used to change the default timezone at runtime
*/
TZ?: string;
}
/**
* The environment variables of the process
*
* Defaults to `process.env` as it was when the current Bun process launched.
*
* Changes to `process.env` at runtime won't automatically be reflected in the default value. For that, you can pass `process.env` explicitly.
*/
const env: NodeJS.ProcessEnv;
/**
* The raw arguments passed to the process, including flags passed to Bun. If you want to easily read flags passed to your script, consider using `process.argv` instead.
*/
const argv: string[];
const origin: string;
/**
* Find the path to an executable, similar to typing which in your terminal. Reads the `PATH` environment variable unless overridden with `options.PATH`.
*
* @param {string} command The name of the executable or script
* @param {string} options.PATH Overrides the PATH environment variable
* @param {string} options.cwd When given a relative path, use this path to join it.
*/
function which(
command: string,
options?: { PATH?: string; cwd?: string },
): string | null;
/**
* Get the column count of a string as it would be displayed in a terminal.
* Supports ANSI escape codes, emoji, and wide characters.
*
* This is useful for:
* - Aligning text in a terminal
* - Quickly checking if a string contains ANSI escape codes
* - Measuring the width of a string in a terminal
*
* This API is designed to match the popular "string-width" package, so that
* existing code can be easily ported to Bun and vice versa.
*
* @returns The width of the string in columns
*
* ## Examples
* @example
* ```ts
* import { stringWidth } from "bun";
*
* console.log(stringWidth("abc")); // 3
* console.log(stringWidth("๐ฉโ๐ฉโ๐งโ๐ฆ")); // 1
* console.log(stringWidth("\u001b[31mhello\u001b[39m")); // 5
* console.log(stringWidth("\u001b[31mhello\u001b[39m", { countAnsiEscapeCodes: false })); // 5
* console.log(stringWidth("\u001b[31mhello\u001b[39m", { countAnsiEscapeCodes: true })); // 13
* ```
*
*/
function stringWidth(
/**
* The string to measure
*/
input: string,
options?: {
/**
* If `true`, count ANSI escape codes as part of the string width. If `false`, ANSI escape codes are ignored when calculating the string width.
*
* @default false
*/
countAnsiEscapeCodes?: boolean;
/**
* When it's ambiugous and `true`, count emoji as 1 characters wide. If `false`, emoji are counted as 2 character wide.
*
* @default true
*/
ambiguousIsNarrow?: boolean;
},
): number;
export type ShellFunction = (input: Uint8Array) => Uint8Array;
export type ShellExpression =
| { toString(): string }
| Array<ShellExpression>
| string
| { raw: string }
| Subprocess
| SpawnOptions.Readable
| SpawnOptions.Writable
| ReadableStream;
class ShellError extends Error implements ShellOutput {
readonly stdout: Buffer;
readonly stderr: Buffer;
readonly exitCode: number;
/**
* Read from stdout as a string
*
* @param encoding - The encoding to use when decoding the output
* @returns Stdout as a string with the given encoding
* @example
*
* ## Read as UTF-8 string
*
* ```ts
* const output = await $`echo hello`;
* console.log(output.text()); // "hello\n"
* ```
*
* ## Read as base64 string
*
* ```ts
* const output = await $`echo ${atob("hello")}`;
* console.log(output.text("base64")); // "hello\n"
* ```
*
*/
text(encoding?: BufferEncoding): string;
/**
* Read from stdout as a JSON object
*
* @returns Stdout as a JSON object
* @example
*
* ```ts
* const output = await $`echo '{"hello": 123}'`;
* console.log(output.json()); // { hello: 123 }
* ```
*
*/
json(): any;
/**
* Read from stdout as an ArrayBuffer
*
* @returns Stdout as an ArrayBuffer
* @example
*
* ```ts
* const output = await $`echo hello`;
* console.log(output.arrayBuffer()); // ArrayBuffer { byteLength: 6 }
* ```
*/
arrayBuffer(): ArrayBuffer;
/**
* Read from stdout as a Blob
*
* @returns Stdout as a blob
* @example
* ```ts
* const output = await $`echo hello`;
* console.log(output.blob()); // Blob { size: 6, type: "" }
* ```
*/
blob(): Blob;
}
class ShellPromise extends Promise<ShellOutput> {
get stdin(): WritableStream;
/**
* Change the current working directory of the shell.
* @param newCwd - The new working directory
*/
cwd(newCwd: string): this;
/**
* Set environment variables for the shell.
* @param newEnv - The new environment variables
*
* @example
* ```ts
* await $`echo $FOO`.env({ ...process.env, FOO: "LOL!" })
* expect(stdout.toString()).toBe("LOL!");
* ```
*/
env(newEnv: Record<string, string> | undefined): this;
/**
* By default, the shell will write to the current process's stdout and stderr, as well as buffering that output.
*
* This configures the shell to only buffer the output.
*/
quiet(): this;
/**
* Read from stdout as a string, line by line
*
* Automatically calls {@link quiet} to disable echoing to stdout.
*/
lines(): AsyncIterable<string>;
/**
* Read from stdout as a string
*
* Automatically calls {@link quiet} to disable echoing to stdout.
* @param encoding - The encoding to use when decoding the output
* @returns A promise that resolves with stdout as a string
* @example
*
* ## Read as UTF-8 string
*
* ```ts
* const output = await $`echo hello`.text();
* console.log(output); // "hello\n"
* ```
*
* ## Read as base64 string
*
* ```ts
* const output = await $`echo ${atob("hello")}`.text("base64");
* console.log(output); // "hello\n"
* ```
*
*/
text(encoding?: BufferEncoding): Promise<string>;
/**
* Read from stdout as a JSON object
*
* Automatically calls {@link quiet}
*
* @returns A promise that resolves with stdout as a JSON object
* @example
*
* ```ts
* const output = await $`echo '{"hello": 123}'`.json();
* console.log(output); // { hello: 123 }
* ```
*
*/
json(): Promise<any>;
/**
* Read from stdout as an ArrayBuffer
*
* Automatically calls {@link quiet}
* @returns A promise that resolves with stdout as an ArrayBuffer
* @example
*
* ```ts
* const output = await $`echo hello`.arrayBuffer();
* console.log(output); // ArrayBuffer { byteLength: 6 }
* ```
*/
arrayBuffer(): Promise<ArrayBuffer>;
/**
* Read from stdout as a Blob
*
* Automatically calls {@link quiet}
* @returns A promise that resolves with stdout as a Blob
* @example
* ```ts
* const output = await $`echo hello`.blob();
* console.log(output); // Blob { size: 6, type: "" }
* ```
*/
blob(): Promise<Blob>;
/**
* Configure the shell to not throw an exception on non-zero exit codes. Throwing can be re-enabled with `.throws(true)`.
*
* By default, the shell with throw an exception on commands which return non-zero exit codes.
*/
nothrow(): this;
/**
* Configure whether or not the shell should throw an exception on non-zero exit codes.
*
* By default, this is configured to `true`.
*/
throws(shouldThrow: boolean): this;
}
interface ShellConstructor {
new (): Shell;
}
export interface Shell {
(
strings: TemplateStringsArray,
...expressions: ShellExpression[]
): ShellPromise;
/**
* Perform bash-like brace expansion on the given pattern.
* @param pattern - Brace pattern to expand
*
* @example
* ```js
* const result = braces('index.{js,jsx,ts,tsx}');
* console.log(result) // ['index.js', 'index.jsx', 'index.ts', 'index.tsx']
* ```
*/
braces(pattern: string): string[];
/**
* Escape strings for input into shell commands.
* @param input
*/
escape(input: string): string;
/**
*
* Change the default environment variables for shells created by this instance.
*
* @param newEnv Default environment variables to use for shells created by this instance.
* @default process.env
*
* ## Example
*
* ```js
* import {$} from 'bun';
* $.env({ BUN: "bun" });
* await $`echo $BUN`;
* // "bun"
* ```
*/
env(newEnv?: Record<string, string | undefined>): this;
/**
*
* @param newCwd Default working directory to use for shells created by this instance.
*/
cwd(newCwd?: string): this;
/**
* Configure the shell to not throw an exception on non-zero exit codes.
*/
nothrow(): this;
/**
* Configure whether or not the shell should throw an exception on non-zero exit codes.
*/
throws(shouldThrow: boolean): this;
readonly ShellPromise: typeof ShellPromise;
readonly Shell: ShellConstructor;
}
export interface ShellOutput {
readonly stdout: Buffer;
readonly stderr: Buffer;
readonly exitCode: number;
/**
* Read from stdout as a string
*
* @param encoding - The encoding to use when decoding the output
* @returns Stdout as a string with the given encoding
* @example
*
* ## Read as UTF-8 string
*
* ```ts
* const output = await $`echo hello`;
* console.log(output.text()); // "hello\n"
* ```
*
* ## Read as base64 string
*
* ```ts
* const output = await $`echo ${atob("hello")}`;
* console.log(output.text("base64")); // "hello\n"
* ```
*
*/
text(encoding?: BufferEncoding): string;
/**
* Read from stdout as a JSON object
*
* @returns Stdout as a JSON object
* @example
*
* ```ts
* const output = await $`echo '{"hello": 123}'`;
* console.log(output.json()); // { hello: 123 }
* ```
*
*/
json(): any;
/**
* Read from stdout as an ArrayBuffer
*
* @returns Stdout as an ArrayBuffer
* @example
*
* ```ts
* const output = await $`echo hello`;
* console.log(output.arrayBuffer()); // ArrayBuffer { byteLength: 6 }
* ```
*/
arrayBuffer(): ArrayBuffer;
/**
* Read from stdout as an Uint8Array
*
* @returns Stdout as an Uint8Array
* @example
*
* ```ts
* const output = await $`echo hello`;
* console.log(output.bytes()); // Uint8Array { byteLength: 6 }
* ```
*/
bytes(): Uint8Array;
/**
* Read from stdout as a Blob
*
* @returns Stdout as a blob
* @example
* ```ts
* const output = await $`echo hello`;
* console.log(output.blob()); // Blob { size: 6, type: "" }
* ```
*/
blob(): Blob;
}
export const $: Shell;
interface TOML {
/**
* Parse a TOML string into a JavaScript object.
*
* @param {string} command The name of the executable or script
* @param {string} options.PATH Overrides the PATH environment variable
* @param {string} options.cwd Limits the search to a particular directory in which to searc
*/
parse(input: string): object;
}
const TOML: TOML;
type Serve<WebSocketDataType = undefined> =
| ServeOptions
| TLSServeOptions
| UnixServeOptions
| UnixTLSServeOptions
| WebSocketServeOptions<WebSocketDataType>
| TLSWebSocketServeOptions<WebSocketDataType>
| UnixWebSocketServeOptions<WebSocketDataType>
| UnixTLSWebSocketServeOptions<WebSocketDataType>;
/**
* Start a fast HTTP server.
*
* @param options Server options (port defaults to $PORT || 3000)
*
* -----
*
* @example
*
* ```ts
* Bun.serve({
* fetch(req: Request): Response | Promise<Response> {
* return new Response("Hello World!");
* },
*
* // Optional port number - the default value is 3000
* port: process.env.PORT || 3000,
* });
* ```
* -----
*
* @example
*
* Send a file
*
* ```ts
* Bun.serve({
* fetch(req: Request): Response | Promise<Response> {
* return new Response(Bun.file("./package.json"));
* },
*
* // Optional port number - the default value is 3000
* port: process.env.PORT || 3000,
* });
* ```
*/
// eslint-disable-next-line @definitelytyped/no-unnecessary-generics
function serve<T>(options: Serve<T>): Server;
/**
* Synchronously resolve a `moduleId` as though it were imported from `parent`
*
* On failure, throws a `ResolveMessage`
*/
// tslint:disable-next-line:unified-signatures
function resolveSync(moduleId: string, parent: string): string;
/**
* Resolve a `moduleId` as though it were imported from `parent`
*
* On failure, throws a `ResolveMessage`
*
* For now, use the sync version. There is zero performance benefit to using this async version. It exists for future-proofing.
*/
// tslint:disable-next-line:unified-signatures
function resolve(moduleId: string, parent: string): Promise<string>;
/**
* Use the fastest syscalls available to copy from `input` into `destination`.
*
* If `destination` exists, it must be a regular file or symlink to a file. If `destination`'s directory does not exist, it will be created by default.
*
* @param destination The file or file path to write to
* @param input The data to copy into `destination`.
* @returns A promise that resolves with the number of bytes written.
*/
// tslint:disable-next-line:unified-signatures
function write(
destination: BunFile | Bun.PathLike,
input: Blob | NodeJS.TypedArray | ArrayBufferLike | string | Bun.BlobPart[],
options?: {
/** If writing to a PathLike, set the permissions of the file. */
mode?: number;
/**
* If `true`, create the parent directory if it doesn't exist. By default, this is `true`.
*
* If `false`, this will throw an error if the directory doesn't exist.
*
* @default true
*/
createPath?: boolean;
},
): Promise<number>;
/**
* Persist a {@link Response} body to disk.
*
* @param destination The file to write to. If the file doesn't exist,
* it will be created and if the file does exist, it will be
* overwritten. If `input`'s size is less than `destination`'s size,
* `destination` will be truncated.
* @param input - `Response` object
* @returns A promise that resolves with the number of bytes written.
*/
function write(
destination: BunFile,
input: Response,
options?: {
/**
* If `true`, create the parent directory if it doesn't exist. By default, this is `true`.
*
* If `false`, this will throw an error if the directory doesn't exist.
*
* @default true
*/
createPath?: boolean;
},
): Promise<number>;
/**
* Persist a {@link Response} body to disk.
*
* @param destinationPath The file path to write to. If the file doesn't
* exist, it will be created and if the file does exist, it will be
* overwritten. If `input`'s size is less than `destination`'s size,
* `destination` will be truncated.
* @param input - `Response` object
* @returns A promise that resolves with the number of bytes written.
*/
// tslint:disable-next-line:unified-signatures
function write(
destinationPath: Bun.PathLike,
input: Response,
options?: {
/**
* If `true`, create the parent directory if it doesn't exist. By default, this is `true`.
*
* If `false`, this will throw an error if the directory doesn't exist.
*
* @default true
*/
createPath?: boolean;
},
): Promise<number>;
/**
* Use the fastest syscalls available to copy from `input` into `destination`.
*
* If `destination` exists, it must be a regular file or symlink to a file.
*
* On Linux, this uses `copy_file_range`.
*
* On macOS, when the destination doesn't already exist, this uses
* [`clonefile()`](https://www.manpagez.com/man/2/clonefile/) and falls
* back to [`fcopyfile()`](https://www.manpagez.com/man/2/fcopyfile/)
*
* @param destination The file to write to. If the file doesn't exist,
* it will be created and if the file does exist, it will be
* overwritten. If `input`'s size is less than `destination`'s size,
* `destination` will be truncated.
* @param input The file to copy from.
* @returns A promise that resolves with the number of bytes written.
*/
// tslint:disable-next-line:unified-signatures
function write(
destination: BunFile,
input: BunFile,
options?: {
/**
* If `true`, create the parent directory if it doesn't exist. By default, this is `true`.
*
* If `false`, this will throw an error if the directory doesn't exist.
*
* @default true
*/
createPath?: boolean;
},
): Promise<number>;
/**
* Use the fastest syscalls available to copy from `input` into `destination`.
*
* If `destination` exists, it must be a regular file or symlink to a file.
*
* On Linux, this uses `copy_file_range`.
*
* On macOS, when the destination doesn't already exist, this uses
* [`clonefile()`](https://www.manpagez.com/man/2/clonefile/) and falls
* back to [`fcopyfile()`](https://www.manpagez.com/man/2/fcopyfile/)
*
* @param destinationPath The file path to write to. If the file doesn't
* exist, it will be created and if the file does exist, it will be
* overwritten. If `input`'s size is less than `destination`'s size,
* `destination` will be truncated.
* @param input The file to copy from.
* @returns A promise that resolves with the number of bytes written.
*/
// tslint:disable-next-line:unified-signatures
function write(
destinationPath: Bun.PathLike,
input: BunFile,
options?: {
/**
* If `true`, create the parent directory if it doesn't exist. By default, this is `true`.
*
* If `false`, this will throw an error if the directory doesn't exist.
*
* @default true
*/
createPath?: boolean;
},
): Promise<number>;
interface SystemError extends Error {
errno?: number | undefined;
code?: string | undefined;
path?: string | undefined;
syscall?: string | undefined;
}
/**
* Concatenate an array of typed arrays into a single `ArrayBuffer`. This is a fast path.
*
* You can do this manually if you'd like, but this function will generally
* be a little faster.
*
* If you want a `Uint8Array` instead, consider `Buffer.concat`.
*
* @param buffers An array of typed arrays to concatenate.
* @returns An `ArrayBuffer` with the data from all the buffers.
*
* Here is similar code to do it manually, except about 30% slower:
* ```js
* var chunks = [...];
* var size = 0;
* for (const chunk of chunks) {
* size += chunk.byteLength;
* }
* var buffer = new ArrayBuffer(size);
* var view = new Uint8Array(buffer);
* var offset = 0;
* for (const chunk of chunks) {
* view.set(chunk, offset);
* offset += chunk.byteLength;
* }
* return buffer;
* ```
*
* This function is faster because it uses uninitialized memory when copying. Since the entire
* length of the buffer is known, it is safe to use uninitialized memory.
*/
function concatArrayBuffers(
buffers: Array<ArrayBufferView | ArrayBufferLike>,
maxLength?: number,
): ArrayBuffer;
function concatArrayBuffers(
buffers: Array<ArrayBufferView | ArrayBufferLike>,
maxLength: number,
asUint8Array: false,
): ArrayBuffer;
function concatArrayBuffers(
buffers: Array<ArrayBufferView | ArrayBufferLike>,
maxLength: number,
asUint8Array: true,
): Uint8Array;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single {@link ArrayBuffer}.
*
* Each chunk must be a TypedArray or an ArrayBuffer. If you need to support
* chunks of different types, consider {@link readableStreamToBlob}
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks or the concatenated chunks as an `ArrayBuffer`.
*/
function readableStreamToArrayBuffer(
stream: ReadableStream<ArrayBufferView | ArrayBufferLike>,
): Promise<ArrayBuffer> | ArrayBuffer;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single {@link ArrayBuffer}.
*
* Each chunk must be a TypedArray or an ArrayBuffer. If you need to support
* chunks of different types, consider {@link readableStreamToBlob}
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks or the concatenated chunks as a {@link Uint8Array}.
*/
function readableStreamToBytes(
stream: ReadableStream<ArrayBufferView | ArrayBufferLike>,
): Promise<Uint8Array> | Uint8Array;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single {@link Blob}.
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks as a {@link Blob}.
*/
function readableStreamToBlob(stream: ReadableStream): Promise<Blob>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Reads the multi-part or URL-encoded form data into a {@link FormData} object
*
* @param stream The stream to consume.
* @param multipartBoundaryExcludingDashes Optional boundary to use for multipart form data. If none is provided, assumes it is a URLEncoded form.
* @returns A promise that resolves with the data encoded into a {@link FormData} object.
*
* ## Multipart form data example
*
* ```ts
* // without dashes
* const boundary = "WebKitFormBoundary" + Math.random().toString(16).slice(2);
*
* const myStream = getStreamFromSomewhere() // ...
* const formData = await Bun.readableStreamToFormData(stream, boundary);
* formData.get("foo"); // "bar"
* ```
* ## URL-encoded form data example
*
* ```ts
* const stream = new Response("hello=123").body;
* const formData = await Bun.readableStreamToFormData(stream);
* formData.get("hello"); // "123"
* ```
*/
function readableStreamToFormData(
stream: ReadableStream<string | NodeJS.TypedArray | ArrayBufferView>,
multipartBoundaryExcludingDashes?:
| string
| NodeJS.TypedArray
| ArrayBufferView,
): Promise<FormData>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single string. Chunks must be a TypedArray or an ArrayBuffer. If you need to support chunks of different types, consider {@link readableStreamToBlob}.
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks as a {@link String}.
*/
function readableStreamToText(stream: ReadableStream): Promise<string>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* Concatenate the chunks into a single string and parse as JSON. Chunks must be a TypedArray or an ArrayBuffer. If you need to support chunks of different types, consider {@link readableStreamToBlob}.
*
* @param stream The stream to consume.
* @returns A promise that resolves with the concatenated chunks as a {@link String}.
*/
function readableStreamToJSON(stream: ReadableStream): Promise<any>;
/**
* Consume all data from a {@link ReadableStream} until it closes or errors.
*
* @param stream The stream to consume
* @returns A promise that resolves with the chunks as an array
*/
function readableStreamToArray<T>(
stream: ReadableStream<T>,
): Promise<T[]> | T[];
/**
* Escape the following characters in a string:
*
* - `"` becomes `"""`
* - `&` becomes `"&"`
* - `'` becomes `"'"`
* - `<` becomes `"<"`
* - `>` becomes `">"`
*
* This function is optimized for large input. On an M1X, it processes 480 MB/s -
* 20 GB/s, depending on how much data is being escaped and whether there is non-ascii
* text.
*
* Non-string types will be converted to a string before escaping.
*/
function escapeHTML(input: string | object | number | boolean): string;
/**
* Convert a filesystem path to a file:// URL.
*
* @param path The path to convert.
* @returns A {@link URL} with the file:// scheme.
*
* @example
* ```js
* const url = Bun.pathToFileURL("/foo/bar.txt");
* console.log(url.href); // "file:///foo/bar.txt"
* ```
*
* Internally, this function uses WebKit's URL API to
* convert the path to a file:// URL.
*/
function pathToFileURL(path: string): URL;
interface Peek {
<T = undefined>(promise: T | Promise<T>): Promise<T> | T;
status<T = undefined>(
promise: T | Promise<T>,
): "pending" | "fulfilled" | "rejected";
}
/**
* Extract the value from the Promise in the same tick of the event loop
*/
const peek: Peek;
/**
* Convert a {@link URL} to a filesystem path.
* @param url The URL to convert.
* @returns A filesystem path.
* @throws If the URL is not a URL.
* @example
* ```js
* const path = Bun.fileURLToPath(new URL("file:///foo/bar.txt"));
* console.log(path); // "/foo/bar.txt"
* ```
*/
function fileURLToPath(url: URL | string): string;
/**
* Fast incremental writer that becomes an `ArrayBuffer` on end().
*/
class ArrayBufferSink {
constructor();
start(options?: {
asUint8Array?: boolean;
/**
* Preallocate an internal buffer of this size
* This can significantly improve performance when the chunk size is small
*/
highWaterMark?: number;
/**
* On {@link ArrayBufferSink.flush}, return the written data as a `Uint8Array`.
* Writes will restart from the beginning of the buffer.
*/
stream?: boolean;
}): void;
write(
chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
): number;
/**
* Flush the internal buffer
*
* If {@link ArrayBufferSink.start} was passed a `stream` option, this will return a `ArrayBuffer`
* If {@link ArrayBufferSink.start} was passed a `stream` option and `asUint8Array`, this will return a `Uint8Array`
* Otherwise, this will return the number of bytes written since the last flush
*
* This API might change later to separate Uint8ArraySink and ArrayBufferSink
*/
flush(): number | Uint8Array | ArrayBuffer;
end(): ArrayBuffer | Uint8Array;
}
const dns: {
/**
* Lookup the IP address for a hostname
*
* Uses non-blocking APIs by default
*
* @param hostname The hostname to lookup
* @param options Options for the lookup
*
* ## Example
*
* ```js
* const [{ address }] = await Bun.dns.lookup('example.com');
* ```
*
* ### Filter results to IPv4:
*
* ```js
* import { dns } from 'bun';
* const [{ address }] = await dns.lookup('example.com', {family: 4});
* console.log(address); // "123.122.22.126"
* ```
*
* ### Filter results to IPv6:
*
* ```js
* import { dns } from 'bun';
* const [{ address }] = await dns.lookup('example.com', {family: 6});
* console.log(address); // "2001:db8::1"
* ```
*
* #### DNS resolver client
*
* Bun supports three DNS resolvers:
* - `c-ares` - Uses the c-ares library to perform DNS resolution. This is the default on Linux.
* - `system` - Uses the system's non-blocking DNS resolver API if available, falls back to `getaddrinfo`. This is the default on macOS and the same as `getaddrinfo` on Linux.
* - `getaddrinfo` - Uses the posix standard `getaddrinfo` function. Will cause performance issues under concurrent loads.
*
* To customize the DNS resolver, pass a `backend` option to `dns.lookup`:
* ```js
* import { dns } from 'bun';
* const [{ address }] = await dns.lookup('example.com', {backend: 'getaddrinfo'});
* console.log(address); // "19.42.52.62"
* ```
*/
lookup(
hostname: string,
options?: {
/**
* Limit results to either IPv4, IPv6, or both
*/
family?: 4 | 6 | 0 | "IPv4" | "IPv6" | "any";
/**
* Limit results to either UDP or TCP
*/
socketType?: "udp" | "tcp";
flags?: number;
port?: number;
/**
* The DNS resolver implementation to use
*
* Defaults to `"c-ares"` on Linux and `"system"` on macOS. This default
* may change in a future version of Bun if c-ares is not reliable
* enough.
*
* On macOS, `system` uses the builtin macOS [non-blocking DNS
* resolution
* API](https://opensource.apple.com/source/Libinfo/Libinfo-222.1/lookup.subproj/netdb_async.h.auto.html).
*
* On Linux, `system` is the same as `getaddrinfo`.
*
* `c-ares` is more performant on Linux in some high concurrency
* situations, but it lacks support support for mDNS (`*.local`,
* `*.localhost` domains) along with some other advanced features. If
* you run into issues using `c-ares`, you should try `system`. If the
* hostname ends with `.local` or `.localhost`, Bun will automatically
* use `system` instead of `c-ares`.
*
* [`getaddrinfo`](https://man7.org/linux/man-pages/man3/getaddrinfo.3.html)
* is the POSIX standard function for blocking DNS resolution. Bun runs
* it in Bun's thread pool, which is limited to `cpus / 2`. That means
* if you run a lot of concurrent DNS lookups, concurrent IO will
* potentially pause until the DNS lookups are done.
*
* On macOS, it shouldn't be necessary to use "`getaddrinfo`" because
* `"system"` uses the same API underneath (except non-blocking).
*
* On Windows, libuv's non-blocking DNS resolver is used by default, and
* when specifying backends "system", "libc", or "getaddrinfo". The c-ares
* backend isn't currently supported on Windows.
*/
backend?: "libc" | "c-ares" | "system" | "getaddrinfo";
},
): Promise<DNSLookup[]>;
/**
*
* **Experimental API**
*
* Prefetch a hostname.
*
* This will be used by fetch() and Bun.connect() to avoid DNS lookups.
*
* @param hostname The hostname to prefetch
*
* @example
* ```js
* import { dns } from 'bun';
* dns.prefetch('example.com');
* // ... something expensive
* await fetch('https://example.com');
* ```
*/
prefetch(hostname: string): void;
/**
* **Experimental API**
*/
getCacheStats(): {
/**
* The number of times a cached DNS entry that was already resolved was used.
*/
cacheHitsCompleted: number;
cacheHitsInflight: number;
cacheMisses: number;
size: number;
errors: number;
totalCount: number;
};
};
interface DNSLookup {
/**
* The IP address of the host as a string in IPv4 or IPv6 format.
*
* @example "127.0.0.1"
* @example "192.168.0.1"
* @example "2001:4860:4860::8888"
*/
address: string;
family: 4 | 6;
/**
* Time to live in seconds
*
* Only supported when using the `c-ares` DNS resolver via "backend" option
* to {@link dns.lookup}. Otherwise, it's 0.
*/
ttl: number;
}
/**
* Fast incremental writer for files and pipes.
*
* This uses the same interface as {@link ArrayBufferSink}, but writes to a file or pipe.
*/
interface FileSink {
/**
* Write a chunk of data to the file.
*
* If the file descriptor is not writable yet, the data is buffered.
*/
write(
chunk: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
): number;
/**
* Flush the internal buffer, committing the data to disk or the pipe.
*/
flush(): number | Promise<number>;
/**
* Close the file descriptor. This also flushes the internal buffer.
*/
end(error?: Error): number | Promise<number>;
start(options?: {
/**
* Preallocate an internal buffer of this size
* This can significantly improve performance when the chunk size is small
*/
highWaterMark?: number;
}): void;
/**
* For FIFOs & pipes, this lets you decide whether Bun's process should
* remain alive until the pipe is closed.
*
* By default, it is automatically managed. While the stream is open, the
* process remains alive and once the other end hangs up or the stream
* closes, the process exits.
*
* If you previously called {@link unref}, you can call this again to re-enable automatic management.
*
* Internally, it will reference count the number of times this is called. By default, that number is 1
*
* If the file is not a FIFO or pipe, {@link ref} and {@link unref} do
* nothing. If the pipe is already closed, this does nothing.
*/
ref(): void;
/**
* For FIFOs & pipes, this lets you decide whether Bun's process should
* remain alive until the pipe is closed.
*
* If you want to allow Bun's process to terminate while the stream is open,
* call this.
*
* If the file is not a FIFO or pipe, {@link ref} and {@link unref} do
* nothing. If the pipe is already closed, this does nothing.
*/
unref(): void;
}
interface FileBlob extends BunFile {}
/**
* [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) powered by the fastest system calls available for operating on files.
*
* This Blob is lazy. That means it won't do any work until you read from it.
*
* - `size` will not be valid until the contents of the file are read at least once.
* - `type` is auto-set based on the file extension when possible
*
* @example
* ```js
* const file = Bun.file("./hello.json");
* console.log(file.type); // "application/json"
* console.log(await file.text()); // '{"hello":"world"}'
* ```
*
* @example
* ```js
* await Bun.write(
* Bun.file("./hello.txt"),
* "Hello, world!"
* );
* ```
*/
interface BunFile extends Blob {
/**
* Offset any operation on the file starting at `begin` and ending at `end`. `end` is relative to 0
*
* Similar to [`TypedArray.subarray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray). Does not copy the file, open the file, or modify the file.
*
* If `begin` > 0, {@link Bun.write()} will be slower on macOS
*
* @param begin - start offset in bytes
* @param end - absolute offset in bytes (relative to 0)
* @param contentType - MIME type for the new BunFile
*/
slice(begin?: number, end?: number, contentType?: string): BunFile;
/** */
/**
* Offset any operation on the file starting at `begin`
*
* Similar to [`TypedArray.subarray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray). Does not copy the file, open the file, or modify the file.
*
* If `begin` > 0, {@link Bun.write()} will be slower on macOS
*
* @param begin - start offset in bytes
* @param contentType - MIME type for the new BunFile
*/
slice(begin?: number, contentType?: string): BunFile;
/**
* @param contentType - MIME type for the new BunFile
*/
slice(contentType?: string): BunFile;
/**
* Incremental writer for files and pipes.
*/
writer(options?: { highWaterMark?: number }): FileSink;
readonly readable: ReadableStream;
// TODO: writable: WritableStream;
/**
* A UNIX timestamp indicating when the file was last modified.
*/
lastModified: number;
/**
* The name or path of the file, as specified in the constructor.
*/
readonly name?: string;
/**
* Does the file exist?
*
* This returns true for regular files and FIFOs. It returns false for
* directories. Note that a race condition can occur where the file is
* deleted or renamed after this is called but before you open it.
*
* This does a system call to check if the file exists, which can be
* slow.
*
* If using this in an HTTP server, it's faster to instead use `return new
* Response(Bun.file(path))` and then an `error` handler to handle
* exceptions.
*
* Instead of checking for a file's existence and then performing the
* operation, it is faster to just perform the operation and handle the
* error.
*
* For empty Blob, this always returns true.
*/
exists(): Promise<boolean>;
}
/**
* This lets you use macros as regular imports
* @example
* ```
* {
* "react-relay": {
* "graphql": "bun-macro-relay/bun-macro-relay.tsx"
* }
* }
* ```
*/
type MacroMap = Record<string, Record<string, string>>;
/**
* Hash a string or array buffer using Wyhash
*
* This is not a cryptographic hash function.
* @param data The data to hash.
* @param seed The seed to use.
*/
const hash: ((
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
seed?: number | bigint,
) => number | bigint) &
Hash;
interface Hash {
wyhash: (
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
seed?: bigint,
) => bigint;
adler32: (
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
) => number;
crc32: (
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
) => number;
cityHash32: (
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
) => number;
cityHash64: (
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
seed?: bigint,
) => bigint;
murmur32v3: (
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
seed?: number,
) => number;
murmur32v2: (
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
seed?: number,
) => number;
murmur64v2: (
data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
seed?: bigint,
) => bigint;
}
type JavaScriptLoader = "jsx" | "js" | "ts" | "tsx";
/**
* Fast deep-equality check two objects.
*
* This also powers expect().toEqual in `bun:test`
*/
function deepEquals(
a: any,
b: any,
/** @default false */
strict?: boolean,
): boolean;
/**
* Returns true if all properties in the subset exist in the
* other and have equal values.
*
* This also powers expect().toMatchObject in `bun:test`
*/
function deepMatch(subset: unknown, a: unknown): boolean;
/**
* tsconfig.json options supported by Bun
*/
interface TSConfig {
extends?: string;
compilerOptions?: {
paths?: Record<string, string[]>;
baseUrl?: string;
/** "preserve" is not supported yet */
jsx?: "preserve" | "react" | "react-jsx" | "react-jsxdev";
jsxFactory?: string;
jsxFragmentFactory?: string;
jsxImportSource?: string;
useDefineForClassFields?: boolean;
importsNotUsedAsValues?: "remove" | "preserve" | "error";
/** moduleSuffixes is not supported yet */
moduleSuffixes?: any;
};
}
interface TranspilerOptions {
/**
* Replace key with value. Value must be a JSON string.
* @example
* ```
* { "process.env.NODE_ENV": "\"production\"" }
* ```
*/
define?: Record<string, string>;
/** What is the default loader used for this transpiler? */
loader?: JavaScriptLoader;
/** What platform are we targeting? This may affect how import and/or require is used */
/** @example "browser" */
target?: Target;
/**
* TSConfig.json file as stringified JSON or an object
* Use this to set a custom JSX factory, fragment, or import source
* For example, if you want to use Preact instead of React. Or if you want to use Emotion.
*/
tsconfig?: string | TSConfig;
/**
* Replace an import statement with a macro.
*
* This will remove the import statement from the final output
* and replace any function calls or template strings with the result returned by the macro
*
* @example
* ```json
* {
* "react-relay": {
* "graphql": "bun-macro-relay"
* }
* }
* ```
*
* Code that calls `graphql` will be replaced with the result of the macro.
*
* ```js
* import {graphql} from "react-relay";
*
* // Input:
* const query = graphql`
* query {
* ... on User {
* id
* }
* }
* }`;
* ```
*
* Will be replaced with:
*
* ```js
* import UserQuery from "./UserQuery.graphql";
* const query = UserQuery;
* ```
*/
macro?: MacroMap;
autoImportJSX?: boolean;
allowBunRuntime?: boolean;
exports?: {
eliminate?: string[];
replace?: Record<string, string>;
};
treeShaking?: boolean;
trimUnusedImports?: boolean;
jsxOptimizationInline?: boolean;
/**
* **Experimental**
*
* Minify whitespace and comments from the output.
*/
minifyWhitespace?: boolean;
/**
* **Experimental**
*
* Enabled by default, use this to disable dead code elimination.
*
* Some other transpiler options may still do some specific dead code elimination.
*/
deadCodeElimination?: boolean;
/**
* This does two things (and possibly more in the future):
* 1. `const` declarations to primitive types (excluding Object/Array) at the top of a scope before any `let` or `var` declarations will be inlined into their usages.
* 2. `let` and `const` declarations only used once are inlined into their usages.
*
* JavaScript engines typically do these optimizations internally, however
* it might only happen much later in the compilation pipeline, after code
* has been executed many many times.
*
* This will typically shrink the output size of code, but it might increase
* it in some cases. Do your own benchmarks!
*/
inline?: boolean;
/**
* @default "warn"
*/
logLevel?: "verbose" | "debug" | "info" | "warn" | "error";
}
/**
* Quickly transpile TypeScript, JSX, or JS to modern JavaScript.
*
* @example
* ```js
* const transpiler = new Bun.Transpiler();
* transpiler.transformSync(`
* const App = () => <div>Hello World</div>;
* export default App;
* `);
* // This outputs:
* const output = `
* const App = () => jsx("div", {
* children: "Hello World"
* }, undefined, false, undefined, this);
* export default App;
* `
* ```
*/
class Transpiler {
constructor(options?: TranspilerOptions);
/**
* Transpile code from TypeScript or JSX into valid JavaScript.
* This function does not resolve imports.
* @param code The code to transpile
*/
transform(
code: Bun.StringOrBuffer,
loader?: JavaScriptLoader,
): Promise<string>;
/**
* Transpile code from TypeScript or JSX into valid JavaScript.
* This function does not resolve imports.
* @param code The code to transpile
*/
transformSync(
code: Bun.StringOrBuffer,
loader: JavaScriptLoader,
ctx: object,
): string;
/**
* Transpile code from TypeScript or JSX into valid JavaScript.
* This function does not resolve imports.
* @param code The code to transpile
* @param ctx An object to pass to macros
*/
transformSync(code: Bun.StringOrBuffer, ctx: object): string;
/**
* Transpile code from TypeScript or JSX into valid JavaScript.
* This function does not resolve imports.
* @param code The code to transpile
*/
transformSync(code: Bun.StringOrBuffer, loader?: JavaScriptLoader): string;
/**
* Get a list of import paths and paths from a TypeScript, JSX, TSX, or JavaScript file.
* @param code The code to scan
* @example
* ```js
* const {imports, exports} = transpiler.scan(`
* import {foo} from "baz";
* export const hello = "hi!";
* `);
*
* console.log(imports); // ["baz"]
* console.log(exports); // ["hello"]
* ```
*/
scan(code: Bun.StringOrBuffer): { exports: string[]; imports: Import[] };
/**
* Get a list of import paths from a TypeScript, JSX, TSX, or JavaScript file.
* @param code The code to scan
* @example
* ```js
* const imports = transpiler.scanImports(`
* import {foo} from "baz";
* import type {FooType} from "bar";
* import type {DogeType} from "wolf";
* `);
*
* console.log(imports); // ["baz"]
* ```
* This is a fast path which performs less work than `scan`.
*/
scanImports(code: Bun.StringOrBuffer): Import[];
}
type ImportKind =
| "import-statement"
| "require-call"
| "require-resolve"
| "dynamic-import"
| "import-rule"
| "url-token"
| "internal"
| "entry-point";
interface Import {
path: string;
kind: ImportKind;
}
interface BuildConfig {
entrypoints: string[]; // list of file path
outdir?: string; // output directory
target?: Target; // default: "browser"
/**
* Output module format. Top-level await is only supported for `"esm"`.
*
* Can be:
* - `"esm"`
* - `"cjs"` (**experimental**)
* - `"iife"` (**experimental**)
*
* @default "esm"
*/
format?: /**
* ECMAScript Module format
*/
| "esm"
/**
* CommonJS format
* **Experimental**
*/
| "cjs"
/**
* IIFE format
* **Experimental**
*/
| "iife";
naming?:
| string
| {
chunk?: string;
entry?: string;
asset?: string;
}; // | string;
root?: string; // project root
splitting?: boolean; // default true, enable code splitting
plugins?: BunPlugin[];
// manifest?: boolean; // whether to return manifest
external?: string[];
packages?: "bundle" | "external";
publicPath?: string;
define?: Record<string, string>;
// origin?: string; // e.g. http://mydomain.com
loader?: { [k in string]: Loader };
sourcemap?: "none" | "linked" | "inline" | "external" | "linked"; // default: "none", true -> "inline"
/**
* package.json `exports` conditions used when resolving imports
*
* Equivalent to `--conditions` in `bun build` or `bun run`.
*
* https://nodejs.org/api/packages.html#exports
*/
conditions?: Array<string> | string;
minify?:
| boolean
| {
whitespace?: boolean;
syntax?: boolean;
identifiers?: boolean;
};
/**
* Ignore dead code elimination/tree-shaking annotations such as @__PURE__ and package.json
* "sideEffects" fields. This should only be used as a temporary workaround for incorrect
* annotations in libraries.
*/
ignoreDCEAnnotations?: boolean;
/**
* Force emitting @__PURE__ annotations even if minify.whitespace is true.
*/
emitDCEAnnotations?: boolean;
// treeshaking?: boolean;
// jsx?:
// | "automatic"
// | "classic"
// | /* later: "preserve" */ {
// runtime?: "automatic" | "classic"; // later: "preserve"
// /** Only works when runtime=classic */
// factory?: string; // default: "React.createElement"
// /** Only works when runtime=classic */
// fragment?: string; // default: "React.Fragment"
// /** Only works when runtime=automatic */
// importSource?: string; // default: "react"
// };
/**
* Generate bytecode for the output. This can dramatically improve cold
* start times, but will make the final output larger and slightly increase
* memory usage.
*
* Bytecode is currently only supported for CommonJS (`format: "cjs"`).
*
* Must be `target: "bun"`
* @default false
*/
bytecode?: boolean;
/**
* Add a banner to the bundled code such as "use client";
*/
banner?: string;
/**
* Add a footer to the bundled code such as a comment block like
*
* `// made with bun!`
*/
footer?: string;
/**
* **Experimental**
*
* Enable CSS support.
*/
experimentalCss?: boolean;
/**
* Drop function calls to matching property accesses.
*/
drop?: string[];
}
namespace Password {
type AlgorithmLabel = "bcrypt" | "argon2id" | "argon2d" | "argon2i";
interface Argon2Algorithm {
algorithm: "argon2id" | "argon2d" | "argon2i";
/**
* Memory cost, which defines the memory usage, given in kibibytes.
*/
memoryCost?: number;
/**
* Defines the amount of computation realized and therefore the execution
* time, given in number of iterations.
*/
timeCost?: number;
}
interface BCryptAlgorithm {
algorithm: "bcrypt";
/**
* A number between 4 and 31. The default is 10.
*/
cost?: number;
}
}
/**
* Hash and verify passwords using argon2 or bcrypt. The default is argon2.
* Password hashing functions are necessarily slow, and this object will
* automatically run in a worker thread.
*
* The underlying implementation of these functions are provided by the Zig
* Standard Library. Thanks to @jedisct1 and other Zig contributors for their
* work on this.
*
* ### Example with argon2
*
* ```ts
* import {password} from "bun";
*
* const hash = await password.hash("hello world");
* const verify = await password.verify("hello world", hash);
* console.log(verify); // true
* ```
*
* ### Example with bcrypt
* ```ts
* import {password} from "bun";
*
* const hash = await password.hash("hello world", "bcrypt");
* // algorithm is optional, will be inferred from the hash if not specified
* const verify = await password.verify("hello world", hash, "bcrypt");
*
* console.log(verify); // true
* ```
*/
const password: {
/**
* Verify a password against a previously hashed password.
*
* @returns true if the password matches, false otherwise
*
* @example
* ```ts
* import {password} from "bun";
* await password.verify("hey", "$argon2id$v=19$m=65536,t=2,p=1$ddbcyBcbAcagei7wSkZFiouX6TqnUQHmTyS5mxGCzeM$+3OIaFatZ3n6LtMhUlfWbgJyNp7h8/oIsLK+LzZO+WI");
* // true
* ```
*
* @throws If the algorithm is specified and does not match the hash
* @throws If the algorithm is invalid
* @throws if the hash is invalid
*/
verify(
/**
* The password to verify.
*
* If empty, always returns false
*/
password: Bun.StringOrBuffer,
/**
* Previously hashed pas