interface VoidFunction { (): void; } /** * * 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" { type ArrayBufferView = TypedArray | DataView; import { Encoding as CryptoEncoding } from "crypto"; export interface Env extends Dict, NodeJS.ProcessEnv { NODE_ENV?: string; /** * The timezone used by Intl, Date, etc. * * To change the timezone, set `Bun.env.TZ` or `process.env.TZ` to the time zone you want to use. * * You can view the current timezone with `Intl.DateTimeFormat().resolvedOptions().timeZone` * * @example * ```js * Bun.env.TZ = "America/Los_Angeles"; * console.log(Intl.DateTimeFormat().resolvedOptions().timeZone); // "America/Los_Angeles" * ``` */ 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. * */ export const env: Env; /** * 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. */ export const argv: string[]; export 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 Limits the search to a particular directory in which to searc * */ export function which( command: string, options?: { PATH?: string; cwd?: string }, ): string | null; export type Serve = | ServeOptions | TLSServeOptions | WebSocketServeOptions | TLSWebSocketServeOptions; /** * Start a fast HTTP server. * * @param options Server options (port defaults to $PORT || 3000) * * ----- * * @example * * ```ts * Bun.serve({ * fetch(req: Request): Response | Promise { * 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 { * return new Response(Bun.file("./package.json")); * }, * * // Optional port number - the default value is 3000 * port: process.env.PORT || 3000, * }); * ``` */ export function serve( options: | ServeOptions | TLSServeOptions | WebSocketServeOptions | TLSWebSocketServeOptions, ): Server; /** * Synchronously resolve a `moduleId` as though it were imported from `parent` * * On failure, throws a `ResolveMessage` */ // tslint:disable-next-line:unified-signatures export 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 export function resolve(moduleId: string, parent: string): Promise; /** * * 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. * * @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 export function write( destination: BunFile | PathLike, input: Blob | TypedArray | ArrayBufferLike | string | BlobPart[], ): Promise; /** * * 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. */ export function write(destination: BunFile, input: Response): Promise; /** * * 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 export function write( destinationPath: PathLike, input: Response, ): Promise; /** * * 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 export function write(destination: BunFile, input: BunFile): Promise; /** * * 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 export function write( destinationPath: PathLike, input: BunFile, ): Promise; export 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. */ export function concatArrayBuffers( buffers: Array, ): 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 an `ArrayBuffer`. */ export function readableStreamToArrayBuffer( stream: ReadableStream, ): Promise | ArrayBuffer; /** * 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}. */ export function readableStreamToBlob(stream: ReadableStream): Promise; /** * 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. * @params 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" * ``` */ export function readableStreamToFormData( stream: ReadableStream, multipartBoundaryExcludingDashes?: string | TypedArray | ArrayBufferView, ): Promise; /** * 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}. */ export function readableStreamToText(stream: ReadableStream): Promise; /** * 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}. */ export function readableStreamToJSON(stream: ReadableStream): Promise; /** * 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 * */ export function readableStreamToArray( stream: ReadableStream, ): Promise | 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. */ export 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. */ export function pathToFileURL(path: string): URL; export interface Peek { (promise: T | Promise): Promise | T; status( promise: T | Promise, ): "pending" | "fulfilled" | "rejected"; } /** * Extract the value from the Promise in the same tick of the event loop */ export 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" * ``` */ export function fileURLToPath(url: URL): string; /** * Fast incremental writer that becomes an `ArrayBuffer` on end(). */ export 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; } export 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). * */ backend?: "libc" | "c-ares" | "system" | "getaddrinfo"; }, ): Promise; }; 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. */ export 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; /** * Close the file descriptor. This also flushes the internal buffer. */ end(error?: Error): number | Promise; 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; } export 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!" * ); * ``` * */ export 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; } /** * This lets you use macros as regular imports * @example * ``` * { * "react-relay": { * "graphql": "bun-macro-relay/bun-macro-relay.tsx" * } * } * ``` */ export type MacroMap = Record>; /** * 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. */ export 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; } export type JavaScriptLoader = "jsx" | "js" | "ts" | "tsx"; /** * Fast deep-equality check two objects. * * This also powers expect().toEqual in `bun:test` * */ export 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` */ export function deepMatch(subset: unknown, a: unknown): boolean; /** * tsconfig.json options supported by Bun */ interface TSConfig { extends?: string; compilerOptions?: { paths?: Record; 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; }; } export interface TranspilerOptions { /** * Replace key with value. Value must be a JSON string. * @example * ``` * { "process.env.NODE_ENV": "\"production\"" } * ``` */ define?: Record; /** 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; }; treeShaking?: boolean; trimUnusedImports?: boolean; jsxOptimizationInline?: boolean; /** * **Experimental** * * Minify whitespace and comments from the output. */ minifyWhitespace?: 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; } /** * Quickly transpile TypeScript, JSX, or JS to modern JavaScript. * * @example * ```js * const transpiler = new Bun.Transpiler(); * transpiler.transformSync(` * const App = () =>
Hello World
; *export default App; * `); * // This outputs: * const output = ` * const App = () => jsx("div", { * children: "Hello World" * }, undefined, false, undefined, this); *export default App; * ` * ``` * */ export 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: StringOrBuffer, loader?: JavaScriptLoader): Promise; /** * Transpile code from TypeScript or JSX into valid JavaScript. * This function does not resolve imports. * @param code The code to transpile * */ transformSync( code: 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: 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: 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"; * const hello = "hi!"; * `); * * console.log(imports); // ["baz"] * console.log(exports); // ["hello"] * ``` */ scan(code: 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: StringOrBuffer): Import[]; } export type ImportKind = | "import-statement" | "require-call" | "require-resolve" | "dynamic-import" | "import-rule" | "url-token" | "internal" | "entry-point"; export interface Import { path: string; kind: ImportKind; } type ModuleFormat = "esm"; // later: "cjs", "iife" interface BuildConfig { entrypoints: string[]; // list of file path outdir?: string; // output directory target?: Target; // default: "browser" format?: ModuleFormat; // later: "cjs", "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?: Array; publicPath?: string; define?: Record; // origin?: string; // e.g. http://mydomain.com loader?: { [k in string]: Loader }; sourcemap?: "none" | "inline" | "external"; // default: "none" minify?: | boolean | { whitespace?: boolean; syntax?: boolean; identifiers?: 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" // }; } namespace Password { export type AlgorithmLabel = "bcrypt" | "argon2id" | "argon2d" | "argon2i"; export 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; } export 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 constributors 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 * ``` */ export 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: StringOrBuffer, /** * Previously hashed password. * If empty, always returns false */ hash: StringOrBuffer, /** * If not specified, the algorithm will be inferred from the hash. * * If specified and the algorithm does not match the hash, this function * throws an error. */ algorithm?: Password.AlgorithmLabel, ): Promise; /** * Asynchronously hash a password using argon2 or bcrypt. The default is argon2. * * @returns A promise that resolves to the hashed password * * ## Example with argon2 * ```ts * import {password} from "bun"; * const hash = await password.hash("hello world"); * console.log(hash); // $argon2id$v=1... * const verify = await password.verify("hello world", hash); * ``` * ## Example with bcrypt * ```ts * import {password} from "bun"; * const hash = await password.hash("hello world", "bcrypt"); * console.log(hash); // $2b$10$... * const verify = await password.verify("hello world", hash); * ``` */ hash( /** * The password to hash * * If empty, this function throws an error. It is usually a programming * mistake to hash an empty password. */ password: StringOrBuffer, /** * @default "argon2id" * * When using bcrypt, passwords exceeding 72 characters will be SHA512'd before */ algorithm?: | Password.AlgorithmLabel | Password.Argon2Algorithm | Password.BCryptAlgorithm, ): Promise; /** * Synchronously hash and verify passwords using argon2 or bcrypt. The default is argon2. * Warning: password hashing is slow, consider using {@link Bun.password.verify} * instead which runs in a worker thread. * * The underlying implementation of these functions are provided by the Zig * Standard Library. Thanks to @jedisct1 and other Zig constributors for their * work on this. * * ### Example with argon2 * * ```ts * import {password} from "bun"; * * const hash = await password.hashSync("hello world"); * const verify = await password.verifySync("hello world", hash); * console.log(verify); // true * ``` * * ### Example with bcrypt * ```ts * import {password} from "bun"; * * const hash = await password.hashSync("hello world", "bcrypt"); * // algorithm is optional, will be inferred from the hash if not specified * const verify = await password.verifySync("hello world", hash, "bcrypt"); * * console.log(verify); // true * ``` */ verifySync( password: StringOrBuffer, hash: StringOrBuffer, /** * If not specified, the algorithm will be inferred from the hash. */ algorithm?: Password.AlgorithmLabel, ): boolean; /** * Synchronously hash and verify passwords using argon2 or bcrypt. The default is argon2. * Warning: password hashing is slow, consider using {@link Bun.password.hash} * instead which runs in a worker thread. * * The underlying implementation of these functions are provided by the Zig * Standard Library. Thanks to @jedisct1 and other Zig constributors for their * work on this. * * ### Example with argon2 * * ```ts * import {password} from "bun"; * * const hash = await password.hashSync("hello world"); * const verify = await password.verifySync("hello world", hash); * console.log(verify); // true * ``` * * ### Example with bcrypt * ```ts * import {password} from "bun"; * * const hash = await password.hashSync("hello world", "bcrypt"); * // algorithm is optional, will be inferred from the hash if not specified * const verify = await password.verifySync("hello world", hash, "bcrypt"); * * console.log(verify); // true * ``` */ hashSync( /** * The password to hash * * If empty, this function throws an error. It is usually a programming * mistake to hash an empty password. */ password: StringOrBuffer, /** * @default "argon2id" * * When using bcrypt, passwords exceeding 72 characters will be SHA256'd before */ algorithm?: | Password.AlgorithmLabel | Password.Argon2Algorithm | Password.BCryptAlgorithm, ): string; }; interface BuildArtifact extends Blob { path: string; loader: Loader; hash: string | null; kind: "entry-point" | "chunk" | "asset" | "sourcemap"; sourcemap: BuildArtifact | null; } interface BuildOutput { outputs: Array; success: boolean; logs: Array; } function build(config: BuildConfig): Promise; /** * A status that represents the outcome of a sent message. * * - if **0**, the message was **dropped**. * - if **-1**, there is **backpressure** of messages. * - if **>0**, it represents the **number of bytes sent**. * * @example * ```js * const status = ws.send("Hello!"); * if (status === 0) { * console.log("Message was dropped"); * } else if (status === -1) { * console.log("Backpressure was applied"); * } else { * console.log(`Success! Sent ${status} bytes`); * } * ``` */ type ServerWebSocketSendStatus = 0 | -1 | number; /** * A fast WebSocket designed for servers. * * Features: * - **Message compression** - Messages can be compressed * - **Backpressure** - If the client is not ready to receive data, the server will tell you. * - **Dropped messages** - If the client cannot receive data, the server will tell you. * - **Topics** - Messages can be {@link ServerWebSocket.publish}ed to a specific topic and the client can {@link ServerWebSocket.subscribe} to topics * * This is slightly different than the browser {@link WebSocket} which Bun supports for clients. * * Powered by [uWebSockets](https://github.com/uNetworking/uWebSockets). * * @example * import { serve } from "bun"; * * serve({ * websocket: { * open(ws) { * console.log("Connected", ws.remoteAddress); * }, * message(ws, data) { * console.log("Received", data); * ws.send(data); * }, * close(ws, code, reason) { * console.log("Disconnected", code, reason); * }, * } * }); */ export interface ServerWebSocket { /** * Sends a message to the client. * * @param data The data to send. * @param compress Should the data be compressed? If the client does not support compression, this is ignored. * @example * ws.send("Hello!"); * ws.send("Compress this.", true); * ws.send(new Uint8Array([1, 2, 3, 4])); */ send( data: string | BufferSource, compress?: boolean, ): ServerWebSocketSendStatus; /** * Sends a text message to the client. * * @param data The data to send. * @param compress Should the data be compressed? If the client does not support compression, this is ignored. * @example * ws.send("Hello!"); * ws.send("Compress this.", true); */ sendText(data: string, compress?: boolean): ServerWebSocketSendStatus; /** * Sends a binary message to the client. * * @param data The data to send. * @param compress Should the data be compressed? If the client does not support compression, this is ignored. * @example * ws.send(new TextEncoder().encode("Hello!")); * ws.send(new Uint8Array([1, 2, 3, 4]), true); */ sendBinary( data: BufferSource, compress?: boolean, ): ServerWebSocketSendStatus; /** * Closes the connection. * * Here is a list of close codes: * - `1000` means "normal closure" **(default)** * - `1009` means a message was too big and was rejected * - `1011` means the server encountered an error * - `1012` means the server is restarting * - `1013` means the server is too busy or the client is rate-limited * - `4000` through `4999` are reserved for applications (you can use it!) * * To close the connection abruptly, use `terminate()`. * * @param code The close code to send * @param reason The close reason to send */ close(code?: number, reason?: string): void; /** * Abruptly close the connection. * * To gracefully close the connection, use `close()`. */ terminate(): void; /** * Sends a ping. * * @param data The data to send */ ping(data?: string | BufferSource): ServerWebSocketSendStatus; /** * Sends a pong. * * @param data The data to send */ pong(data?: string | BufferSource): ServerWebSocketSendStatus; /** * Sends a message to subscribers of the topic. * * @param topic The topic name. * @param data The data to send. * @param compress Should the data be compressed? If the client does not support compression, this is ignored. * @example * ws.publish("chat", "Hello!"); * ws.publish("chat", "Compress this.", true); * ws.publish("chat", new Uint8Array([1, 2, 3, 4])); */ publish( topic: string, data: string | BufferSource, compress?: boolean, ): ServerWebSocketSendStatus; /** * Sends a text message to subscribers of the topic. * * @param topic The topic name. * @param data The data to send. * @param compress Should the data be compressed? If the client does not support compression, this is ignored. * @example * ws.publish("chat", "Hello!"); * ws.publish("chat", "Compress this.", true); */ publishText( topic: string, data: string, compress?: boolean, ): ServerWebSocketSendStatus; /** * Sends a binary message to subscribers of the topic. * * @param topic The topic name. * @param data The data to send. * @param compress Should the data be compressed? If the client does not support compression, this is ignored. * @example * ws.publish("chat", new TextEncoder().encode("Hello!")); * ws.publish("chat", new Uint8Array([1, 2, 3, 4]), true); */ publishBinary( topic: string, data: BufferSource, compress?: boolean, ): ServerWebSocketSendStatus; /** * Subscribes a client to the topic. * * @param topic The topic name. * @example * ws.subscribe("chat"); */ subscribe(topic: string): void; /** * Unsubscribes a client to the topic. * * @param topic The topic name. * @example * ws.unsubscribe("chat"); */ unsubscribe(topic: string): void; /** * Is the client subscribed to a topic? * * @param topic The topic name. * @example * ws.subscribe("chat"); * console.log(ws.isSubscribed("chat")); // true */ isSubscribed(topic: string): boolean; /** * Batches `send()` and `publish()` operations, which makes it faster to send data. * * The `message`, `open`, and `drain` callbacks are automatically corked, so * you only need to call this if you are sending messages outside of those * callbacks or in async functions. * * @param callback The callback to run. * @example * ws.cork((ctx) => { * ctx.send("These messages"); * ctx.sendText("are sent"); * ctx.sendBinary(new TextEncoder().encode("together!")); * }); */ cork(callback: (ws: ServerWebSocket) => T): T; /** * The IP address of the client. * * @example * console.log(socket.remoteAddress); // "127.0.0.1" */ readonly remoteAddress: string; /** * The ready state of the client. * * - if `0`, the client is connecting. * - if `1`, the client is connected. * - if `2`, the client is closing. * - if `3`, the client is closed. * * @example * console.log(socket.readyState); // 1 */ readonly readyState: WebSocketReadyState; /** * Sets how binary data is returned in events. * * - if `nodebuffer`, binary data is returned as `Buffer` objects. **(default)** * - if `arraybuffer`, binary data is returned as `ArrayBuffer` objects. * - if `uint8array`, binary data is returned as `Uint8Array` objects. * * @example * let ws: WebSocket; * ws.binaryType = "uint8array"; * ws.addEventListener("message", ({ data }) => { * console.log(data instanceof Uint8Array); // true * }); */ binaryType?: "nodebuffer" | "arraybuffer" | "uint8array"; /** * Custom data that you can assign to a client, can be read and written at any time. * * @example * import { serve } from "bun"; * * serve({ * fetch(request, server) { * const data = { * accessToken: request.headers.get("Authorization"), * }; * if (server.upgrade(request, { data })) { * return; * } * return new Response(); * }, * websocket: { * open(ws) { * console.log(ws.data.accessToken); * } * } * }); */ data: T; } /** * Compression options for WebSocket messages. */ type WebSocketCompressor = | "disable" | "shared" | "dedicated" | "3KB" | "4KB" | "8KB" | "16KB" | "32KB" | "64KB" | "128KB" | "256KB"; /** * Create a server-side {@link ServerWebSocket} handler for use with {@link Bun.serve} * * @example * ```ts * import { websocket, serve } from "bun"; * * serve<{name: string}>({ * port: 3000, * websocket: { * open: (ws) => { * console.log("Client connected"); * }, * message: (ws, message) => { * console.log(`${ws.data.name}: ${message}`); * }, * close: (ws) => { * console.log("Client disconnected"); * }, * }, * * fetch(req, server) { * const url = new URL(req.url); * if (url.pathname === "/chat") { * const upgraded = server.upgrade(req, { * data: { * name: new URL(req.url).searchParams.get("name"), * }, * }); * if (!upgraded) { * return new Response("Upgrade failed", { status: 400 }); * } * return; * } * return new Response("Hello World"); * }, * }); */ export type WebSocketHandler = { /** * Called when the server receives an incoming message. * * If the message is not a `string`, its type is based on the value of `binaryType`. * - if `nodebuffer`, then the message is a `Buffer`. * - if `arraybuffer`, then the message is an `ArrayBuffer`. * - if `uint8array`, then the message is a `Uint8Array`. * * @param ws The websocket that sent the message * @param message The message received */ message( ws: ServerWebSocket, message: string | Buffer, ): void | Promise; /** * Called when a connection is opened. * * @param ws The websocket that was opened */ open?(ws: ServerWebSocket): void | Promise; /** * Called when a connection was previously under backpressure, * meaning it had too many queued messages, but is now ready to receive more data. * * @param ws The websocket that is ready for more data */ drain?(ws: ServerWebSocket): void | Promise; /** * Called when a connection is closed. * * @param ws The websocket that was closed * @param code The close code * @param message The close message */ close?( ws: ServerWebSocket, code: number, reason: string, ): void | Promise; /** * Called when a ping is sent. * * @param ws The websocket that received the ping * @param data The data sent with the ping */ ping?(ws: ServerWebSocket, data: Buffer): void | Promise; /** * Called when a pong is received. * * @param ws The websocket that received the ping * @param data The data sent with the ping */ pong?(ws: ServerWebSocket, data: Buffer): void | Promise; /** * Sets the maximum size of messages in bytes. * * Default is 16 MB, or `1024 * 1024 * 16` in bytes. */ maxPayloadLength?: number; /** * Sets the maximum number of bytes that can be buffered on a single connection. * * Default is 16 MB, or `1024 * 1024 * 16` in bytes. */ backpressureLimit?: number; /** * Sets if the connection should be closed if `backpressureLimit` is reached. * * Default is `false`. */ closeOnBackpressureLimit?: boolean; /** * Sets the the number of seconds to wait before timing out a connection * due to no messages or pings. * * Default is 2 minutes, or `120` in seconds. */ idleTimeout?: number; /** * Should `ws.publish()` also send a message to `ws` (itself), if it is subscribed? * * Default is `false`. */ publishToSelf?: boolean; /** * Should the server automatically send and respond to pings to clients? * * Default is `true`. */ sendPings?: boolean; /** * Sets the compression level for messages, for clients that supports it. By default, compression is disabled. * * Default is `false`. */ perMessageDeflate?: | boolean | { /** * Sets the compression level. */ compress?: WebSocketCompressor | boolean; /** * Sets the decompression level. */ decompress?: WebSocketCompressor | boolean; }; }; interface GenericServeOptions { /** * What port should the server listen on? * @default process.env.PORT || "3000" */ port?: string | number; /** * What hostname should the server listen on? * * @default * ```js * "0.0.0.0" // listen on all interfaces * ``` * @example * ```js * "127.0.0.1" // Only listen locally * ``` * @example * ```js * "remix.run" // Only listen on remix.run * ```` * * note: hostname should not include a {@link port} */ hostname?: string; /** * What URI should be used to make {@link Request.url} absolute? * * By default, looks at {@link hostname}, {@link port}, and whether or not SSL is enabled to generate one * * @example *```js * "http://my-app.com" * ``` * * @example *```js * "https://wongmjane.com/" * ``` * * This should be the public, absolute URL – include the protocol and {@link hostname}. If the port isn't 80 or 443, then include the {@link port} too. * * @example * "http://localhost:3000" * */ // baseURI?: string; /** * What is the maximum size of a request body? (in bytes) * @default 1024 * 1024 * 128 // 128MB */ maxRequestBodySize?: number; /** * Render contextual errors? This enables bun's error page * @default process.env.NODE_ENV !== 'production' */ development?: boolean; error?: ( this: Server, request: Errorlike, ) => Response | Promise | undefined | void | Promise; } export type AnyFunction = (..._: any[]) => any; export interface ServeOptions extends GenericServeOptions { /** * Handle HTTP requests * * Respond to {@link Request} objects with a {@link Response} object. * */ fetch( this: Server, request: Request, server: Server, ): Response | Promise; } export interface WebSocketServeOptions extends GenericServeOptions { /** * Enable websockets with {@link Bun.serve} * * For simpler type safety, see {@link Bun.websocket} * * @example * ```js *import { serve } from "bun"; *serve({ * websocket: { * open: (ws) => { * console.log("Client connected"); * }, * message: (ws, message) => { * console.log("Client sent message", message); * }, * close: (ws) => { * console.log("Client disconnected"); * }, * }, * fetch(req, server) { * const url = new URL(req.url); * if (url.pathname === "/chat") { * const upgraded = server.upgrade(req); * if (!upgraded) { * return new Response("Upgrade failed", { status: 400 }); * } * } * return new Response("Hello World"); * }, *}); *``` * Upgrade a {@link Request} to a {@link ServerWebSocket} via {@link Server.upgrade} * * Pass `data` in @{link Server.upgrade} to attach data to the {@link ServerWebSocket.data} property * * */ websocket: WebSocketHandler; /** * Handle HTTP requests or upgrade them to a {@link ServerWebSocket} * * Respond to {@link Request} objects with a {@link Response} object. * */ fetch( this: Server, request: Request, server: Server, ): Response | undefined | Promise; } export interface TLSWebSocketServeOptions extends WebSocketServeOptions, TLSOptions { tls?: TLSOptions; } export interface Errorlike extends Error { code?: string; errno?: number; syscall?: string; } interface TLSOptions { /** * File path to a TLS key * * To enable TLS, this option is required. * * @deprecated since v0.6.3 - Use `key: Bun.file(path)` instead. */ keyFile?: string; /** * File path to a TLS certificate * * To enable TLS, this option is required. * * @deprecated since v0.6.3 - Use `cert: Bun.file(path)` instead. */ certFile?: string; /** * Passphrase for the TLS key */ passphrase?: string; /** * File path to a .pem file for a custom root CA * * @deprecated since v0.6.3 - Use `ca: Bun.file(path)` instead. */ caFile?: string; /** * File path to a .pem file custom Diffie Helman parameters */ dhParamsFile?: string; /** * Explicitly set a server name */ serverName?: string; /** * This sets `OPENSSL_RELEASE_BUFFERS` to 1. * It reduces overall performance but saves some memory. * @default false */ lowMemoryMode?: boolean; /** * Optionally override the trusted CA certificates. Default is to trust * the well-known CAs curated by Mozilla. Mozilla's CAs are completely * replaced when CAs are explicitly specified using this option. */ ca?: | string | Buffer | BunFile | Array | undefined; /** * Cert chains in PEM format. One cert chain should be provided per * private key. Each cert chain should consist of the PEM formatted * certificate for a provided private key, followed by the PEM * formatted intermediate certificates (if any), in order, and not * including the root CA (the root CA must be pre-known to the peer, * see ca). When providing multiple cert chains, they do not have to * be in the same order as their private keys in key. If the * intermediate certificates are not provided, the peer will not be * able to validate the certificate, and the handshake will fail. */ cert?: | string | Buffer | BunFile | Array | undefined; /** * Private keys in PEM format. PEM allows the option of private keys * being encrypted. Encrypted keys will be decrypted with * options.passphrase. Multiple keys using different algorithms can be * provided either as an array of unencrypted key strings or buffers, * or an array of objects in the form {pem: [, * passphrase: ]}. The object form can only occur in an array. * object.passphrase is optional. Encrypted keys will be decrypted with * object.passphrase if provided, or options.passphrase if it is not. */ key?: | string | Buffer | BunFile | Array | undefined; /** * Optionally affect the OpenSSL protocol behavior, which is not * usually necessary. This should be used carefully if at all! Value is * a numeric bitmask of the SSL_OP_* options from OpenSSL Options */ secureOptions?: number | undefined; // Value is a numeric bitmask of the `SSL_OP_*` options } export interface TLSServeOptions extends ServeOptions, TLSOptions { /** * The keys are [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) hostnames. * The values are SSL options objects. */ serverNames?: Record; tls?: TLSOptions; } /** * HTTP & HTTPS Server * * To start the server, see {@link serve} * * For performance, Bun pre-allocates most of the data for 2048 concurrent requests. * That means starting a new server allocates about 500 KB of memory. Try to * avoid starting and stopping the server often (unless it's a new instance of bun). * * Powered by a fork of [uWebSockets](https://github.com/uNetworking/uWebSockets). Thank you @alexhultman. * */ export interface Server { /** * Stop listening to prevent new connections from being accepted. * * By default, it does not cancel in-flight requests or websockets. That means it may take some time before all network activity stops. * * @param closeActiveConnections Immediately terminate in-flight requests, websockets, and stop accepting new connections. * @default false */ stop(closeActiveConnections?: boolean): void; /** * Update the `fetch` and `error` handlers without restarting the server. * * This is useful if you want to change the behavior of your server without * restarting it or for hot reloading. * * @example * * ```js * // create the server * const server = Bun.serve({ * fetch(request) { * return new Response("Hello World v1") * } * }); * * // Update the server to return a different response * server.update({ * fetch(request) { * return new Response("Hello World v2") * } * }); * ``` * * Passing other options such as `port` or `hostname` won't do anything. */ reload(options: Serve): void; /** * Mock the fetch handler for a running server. * * This feature is not fully implemented yet. It doesn't normalize URLs * consistently in all cases and it doesn't yet call the `error` handler * consistently. This needs to be fixed */ fetch(request: Request | string): Response | Promise; /** * Upgrade a {@link Request} to a {@link ServerWebSocket} * * @param request The {@link Request} to upgrade * @param options Pass headers or attach data to the {@link ServerWebSocket} * * @returns `true` if the upgrade was successful and `false` if it failed * * @example * ```js * import { serve } from "bun"; * serve({ * websocket: { * open: (ws) => { * console.log("Client connected"); * }, * message: (ws, message) => { * console.log("Client sent message", message); * }, * close: (ws) => { * console.log("Client disconnected"); * }, * }, * fetch(req, server) { * const url = new URL(req.url); * if (url.pathname === "/chat") { * const upgraded = server.upgrade(req); * if (!upgraded) { * return new Response("Upgrade failed", { status: 400 }); * } * } * return new Response("Hello World"); * }, * }); * ``` * What you pass to `data` is available on the {@link ServerWebSocket.data} property * */ upgrade( request: Request, options?: { /** * Send any additional headers while upgrading, like cookies */ headers?: HeadersInit; /** * This value is passed to the {@link ServerWebSocket.data} property */ data?: T; }, ): boolean; /** * Send a message to all connected {@link ServerWebSocket} subscribed to a topic * * @param topic The topic to publish to * @param data The data to send * @param compress Should the data be compressed? Ignored if the client does not support compression. * * @returns 0 if the message was dropped, -1 if backpressure was applied, or the number of bytes sent. * * @example * * ```js * server.publish("chat", "Hello World"); * ``` * * @example * ```js * server.publish("chat", new Uint8Array([1, 2, 3, 4])); * ``` * * @example * ```js * server.publish("chat", new ArrayBuffer(4), true); * ``` * * @example * ```js * server.publish("chat", new DataView(new ArrayBuffer(4))); * ``` */ publish( topic: string, data: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer, compress?: boolean, ): ServerWebSocketSendStatus; /** * How many requests are in-flight right now? */ readonly pendingRequests: number; /** * How many {@link ServerWebSocket}s are in-flight right now? */ readonly pendingWebSockets: number; readonly port: number; /** * The hostname the server is listening on. Does not include the port * @example * ```js * "localhost" * ``` */ readonly hostname: string; /** * Is the server running in development mode? * * In development mode, `Bun.serve()` returns rendered error messages with * stack traces instead of a generic 500 error. This makes debugging easier, * but development mode shouldn't be used in production or you will risk * leaking sensitive information. * */ readonly development: boolean; } /** * [`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.json()); // { hello: "world" } * ``` * * @example * ```js * await Bun.write( * Bun.file("./hello.txt"), * "Hello, world!" * ); * ``` * @param path The path to the file (lazily loaded) * */ // tslint:disable-next-line:unified-signatures export function file(path: string | URL, options?: BlobPropertyBag): BunFile; /** * `Blob` that leverages the fastest system calls available to operate on files. * * This Blob is lazy. It won't do any work until you read from it. Errors propagate as promise rejections. * * `Blob.size` will not be valid until the contents of the file are read at least once. * `Blob.type` will have a default set based on the file extension * * @example * ```js * const file = Bun.file(new TextEncoder.encode("./hello.json")); * console.log(file.type); // "application/json" * ``` * * @param path The path to the file as a byte buffer (the buffer is copied) */ // tslint:disable-next-line:unified-signatures export function file( path: ArrayBufferLike | Uint8Array, options?: BlobPropertyBag, ): 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. * * @example * ```js * const file = Bun.file(fd); * ``` * * @param fileDescriptor The file descriptor of the file */ // tslint:disable-next-line:unified-signatures export function file( fileDescriptor: number, options?: BlobPropertyBag, ): BunFile; /** * Allocate a new [`Uint8Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) without zeroing the bytes. * * This can be 3.5x faster than `new Uint8Array(size)`, but if you send uninitialized memory to your users (even unintentionally), it can potentially leak anything recently in memory. */ export function allocUnsafe(size: number): Uint8Array; export interface BunInspectOptions { colors?: boolean; depth?: number; sorted?: boolean; } /** * Pretty-print an object the same as {@link console.log} to a `string` * * Supports JSX * * @param args */ export function inspect(arg: any, options?: BunInspectOptions): string; export namespace inspect { /** * That can be used to declare custom inspect functions. */ const custom: typeof import("util").inspect.custom; } interface MMapOptions { /** * Sets MAP_SYNC flag on Linux. Ignored on macOS due to lack of support. */ sync?: boolean; /** * Allow other processes to see results instantly? * This enables MAP_SHARED. If false, it enables MAP_PRIVATE. * @default true */ shared?: boolean; } /** * Open a file as a live-updating `Uint8Array` without copying memory * - Writing to the array writes to the file. * - Reading from the array reads from the file. * * This uses the [`mmap()`](https://man7.org/linux/man-pages/man2/mmap.2.html) syscall under the hood. * * --- * * This API inherently has some rough edges: * - It does not support empty files. It will throw a `SystemError` with `EINVAL` * - Usage on shared/networked filesystems is discouraged. It will be very slow. * - If you delete or truncate the file, that will crash bun. This is called a segmentation fault. * * --- * * To close the file, set the array to `null` and it will be garbage collected eventually. * */ export function mmap(path: PathLike, opts?: MMapOptions): Uint8Array; /** Write to stdout */ const stdout: BunFile; /** Write to stderr */ const stderr: BunFile; /** * Read from stdin * * This is read-only */ const stdin: BunFile; interface unsafe { /** * Cast bytes to a `String` without copying. This is the fastest way to get a `String` from a `Uint8Array` or `ArrayBuffer`. * * **Only use this for ASCII strings**. If there are non-ascii characters, your application may crash and/or very confusing bugs will happen such as `"foo" !== "foo"`. * * **The input buffer must not be garbage collected**. That means you will need to hold on to it for the duration of the string's lifetime. * */ arrayBufferToString(buffer: Uint8Array | ArrayBufferLike): string; /** * Cast bytes to a `String` without copying. This is the fastest way to get a `String` from a `Uint16Array` * * **The input must be a UTF-16 encoded string**. This API does no validation whatsoever. * * **The input buffer must not be garbage collected**. That means you will need to hold on to it for the duration of the string's lifetime. * */ // tslint:disable-next-line:unified-signatures arrayBufferToString(buffer: Uint16Array): string; /** Mock bun's segfault handler. You probably don't want to use this */ segfault(): void; /** * Force the garbage collector to run extremely often, * especially inside `bun:test`. * * - `0`: default, disable * - `1`: asynchronously call the garbage collector more often * - `2`: synchronously call the garbage collector more often. * * This is a global setting. It's useful for debugging seemingly random crashes. * * `BUN_GARBAGE_COLLECTOR_LEVEL` environment variable is also supported. * * @param level * @returns The previous level */ gcAggressionLevel(level?: 0 | 1 | 2): 0 | 1 | 2; } export const unsafe: unsafe; type DigestEncoding = "hex" | "base64"; /** * Are ANSI colors enabled for stdin and stdout? * * Used for {@link console.log} */ export const enableANSIColors: boolean; /** * What script launched bun? * * Absolute file path * * @example "/never-gonna-give-you-up.js" */ export const main: string; /** * Manually trigger the garbage collector * * This does two things: * 1. It tells JavaScriptCore to run the garbage collector * 2. It tells [mimalloc](https://github.com/microsoft/mimalloc) to clean up fragmented memory. Mimalloc manages the heap not used in JavaScriptCore. * * @param force Synchronously run the garbage collector */ export function gc(force: boolean): void; /** * JavaScriptCore engine's internal heap snapshot * * I don't know how to make this something Chrome or Safari can read. * * If you have any ideas, please file an issue https://github.com/oven-sh/bun */ interface HeapSnapshot { /** 2 */ version: number; /** "Inspector" */ type: string; nodes: number[]; nodeClassNames: string[]; edges: number[]; edgeTypes: string[]; edgeNames: string[]; } /** * Nanoseconds since Bun.js was started as an integer. * * This uses a high-resolution monotonic system timer. * * After 14 weeks of consecutive uptime, this function * wraps */ export function nanoseconds(): number; /** * Generate a heap snapshot for seeing where the heap is being used */ export function generateHeapSnapshot(): HeapSnapshot; /** * The next time JavaScriptCore is idle, clear unused memory and attempt to reduce the heap size. */ export function shrink(): void; /** * Open a file in your local editor. Auto-detects via `$VISUAL` || `$EDITOR` * * @param path path to open */ export function openInEditor(path: string, options?: EditorOptions): void; interface EditorOptions { editor?: "vscode" | "subl"; line?: number; column?: number; } /** * This class only exists in types */ abstract class CryptoHashInterface { /** * Update the hash with data * * @param data */ update(data: StringOrBuffer): T; /** * Finalize the hash * * @param encoding `DigestEncoding` to return the hash in. If none is provided, it will return a `Uint8Array`. */ digest(encoding: DigestEncoding): string; /** * Finalize the hash * * @param hashInto `TypedArray` to write the hash into. Faster than creating a new one each time */ digest(hashInto?: TypedArray): TypedArray; /** * Run the hash over the given data * * @param input `string`, `Uint8Array`, or `ArrayBuffer` to hash. `Uint8Array` or `ArrayBuffer` is faster. * * @param hashInto `TypedArray` to write the hash into. Faster than creating a new one each time */ static hash(input: StringOrBuffer, hashInto?: TypedArray): TypedArray; /** * Run the hash over the given data * * @param input `string`, `Uint8Array`, or `ArrayBuffer` to hash. `Uint8Array` or `ArrayBuffer` is faster. * * @param encoding `DigestEncoding` to return the hash in */ static hash(input: StringOrBuffer, encoding: DigestEncoding): string; } type SupportedCryptoAlgorithms = | "blake2b256" | "md4" | "md5" | "ripemd160" | "sha1" | "sha224" | "sha256" | "sha384" | "sha512" | "sha512-256"; /** * Hardware-accelerated cryptographic hash functions * * Used for `crypto.createHash()` */ export class CryptoHasher { /** * The algorithm chosen to hash the data * */ readonly algorithm: SupportedCryptoAlgorithms; /** * The length of the output hash in bytes */ readonly byteLength: number; /** * Create a new hasher * * @param algorithm The algorithm to use. See {@link algorithms} for a list of supported algorithms */ constructor(algorithm: SupportedCryptoAlgorithms); /** * Update the hash with data * * @param input */ update(input: StringOrBuffer, inputEncoding?: CryptoEncoding): CryptoHasher; /** * Perform a deep copy of the hasher */ copy(): CryptoHasher; /** * Finalize the hash. Resets the CryptoHasher so it can be reused. * * @param encoding `DigestEncoding` to return the hash in. If none is provided, it will return a `Uint8Array`. */ digest(encoding: DigestEncoding): string; /** * Finalize the hash * * @param hashInto `TypedArray` to write the hash into. Faster than creating a new one each time */ digest(hashInto?: TypedArray): TypedArray; /** * Run the hash over the given data * * @param input `string`, `Uint8Array`, or `ArrayBuffer` to hash. `Uint8Array` or `ArrayBuffer` is faster. * * @param hashInto `TypedArray` to write the hash into. Faster than creating a new one each time */ static hash( algorithm: SupportedCryptoAlgorithms, input: StringOrBuffer, hashInto?: TypedArray, ): TypedArray; /** * Run the hash over the given data * * @param input `string`, `Uint8Array`, or `ArrayBuffer` to hash. `Uint8Array` or `ArrayBuffer` is faster. * * @param encoding `DigestEncoding` to return the hash in */ static hash( algorithm: SupportedCryptoAlgorithms, input: StringOrBuffer, encoding: DigestEncoding, ): string; /** * List of supported hash algorithms * * These are hardware accelerated with BoringSSL */ static readonly algorithms: SupportedCryptoAlgorithms[]; } /** * Resolve a `Promise` after milliseconds. This is like * {@link setTimeout} except it returns a `Promise`. * * @param ms milliseconds to delay resolving the promise. This is a minimum * number. It may take longer. If a {@link Date} is passed, it will sleep until the * {@link Date} is reached. * * @example * ## Sleep for 1 second * ```ts * import { sleep } from "bun"; * * await sleep(1000); * ``` * ## Sleep for 10 milliseconds * ```ts * await Bun.sleep(10); * ``` * ## Sleep until `Date` * * ```ts * const target = new Date(); * target.setSeconds(target.getSeconds() + 1); * await Bun.sleep(target); * ``` * Internally, `Bun.sleep` is the equivalent of * ```ts * await new Promise((resolve) => setTimeout(resolve, ms)); * ``` * As always, you can use `Bun.sleep` or the imported `sleep` function interchangeably. */ export function sleep(ms: number | Date): Promise; /** * Sleep the thread for a given number of milliseconds * * This is a blocking function. * * Internally, it calls [nanosleep(2)](https://man7.org/linux/man-pages/man2/nanosleep.2.html) */ export function sleepSync(ms: number): void; /** * * Hash `input` using [SHA-2 512/256](https://en.wikipedia.org/wiki/SHA-2#Comparison_of_SHA_functions) * * @param input `string`, `Uint8Array`, or `ArrayBuffer` to hash. `Uint8Array` or `ArrayBuffer` will be faster * @param hashInto optional `Uint8Array` to write the hash to. 32 bytes minimum. * * This hashing function balances speed with cryptographic strength. This does not encrypt or decrypt data. * * The implementation uses [BoringSSL](https://boringssl.googlesource.com/boringssl) (used in Chromium & Go) * * The equivalent `openssl` command is: * * ```bash * # You will need OpenSSL 3 or later * openssl sha512-256 /path/to/file *``` */ export function sha(input: StringOrBuffer, hashInto?: TypedArray): TypedArray; /** * * Hash `input` using [SHA-2 512/256](https://en.wikipedia.org/wiki/SHA-2#Comparison_of_SHA_functions) * * @param input `string`, `Uint8Array`, or `ArrayBuffer` to hash. `Uint8Array` or `ArrayBuffer` will be faster * @param encoding `DigestEncoding` to return the hash in * * This hashing function balances speed with cryptographic strength. This does not encrypt or decrypt data. * * The implementation uses [BoringSSL](https://boringssl.googlesource.com/boringssl) (used in Chromium & Go) * * The equivalent `openssl` command is: * * ```bash * # You will need OpenSSL 3 or later * openssl sha512-256 /path/to/file *``` */ export function sha(input: StringOrBuffer, encoding: DigestEncoding): string; /** * This is not the default because it's not cryptographically secure and it's slower than {@link SHA512} * * Consider using the ugly-named {@link SHA512_256} instead */ export class SHA1 extends CryptoHashInterface { constructor(); /** * The number of bytes the hash will produce */ static readonly byteLength: 20; } export class MD5 extends CryptoHashInterface { constructor(); /** * The number of bytes the hash will produce */ static readonly byteLength: 16; } export class MD4 extends CryptoHashInterface { constructor(); /** * The number of bytes the hash will produce */ static readonly byteLength: 16; } export class SHA224 extends CryptoHashInterface { constructor(); /** * The number of bytes the hash will produce */ static readonly byteLength: 28; } export class SHA512 extends CryptoHashInterface { constructor(); /** * The number of bytes the hash will produce */ static readonly byteLength: 64; } export class SHA384 extends CryptoHashInterface { constructor(); /** * The number of bytes the hash will produce */ static readonly byteLength: 48; } export class SHA256 extends CryptoHashInterface { constructor(); /** * The number of bytes the hash will produce */ static readonly byteLength: 32; } /** * See also {@link sha} */ export class SHA512_256 extends CryptoHashInterface { constructor(); /** * The number of bytes the hash will produce */ static readonly byteLength: 32; } /** Compression options for `Bun.deflateSync` and `Bun.gzipSync` */ export type ZlibCompressionOptions = { /** * The compression level to use. Must be between `-1` and `9`. * - A value of `-1` uses the default compression level (Currently `6`) * - A value of `0` gives no compression * - A value of `1` gives least compression, fastest speed * - A value of `9` gives best compression, slowest speed */ level?: -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; /** * How much memory should be allocated for the internal compression state. * * A value of `1` uses minimum memory but is slow and reduces compression ratio. * * A value of `9` uses maximum memory for optimal speed. The default is `8`. */ memLevel?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; /** * The base 2 logarithm of the window size (the size of the history buffer). * * Larger values of this parameter result in better compression at the expense of memory usage. * * The following value ranges are supported: * - `9..15`: The output will have a zlib header and footer (Deflate) * - `-9..-15`: The output will **not** have a zlib header or footer (Raw Deflate) * - `25..31` (16+`9..15`): The output will have a gzip header and footer (gzip) * * The gzip header will have no file name, no extra data, no comment, no modification time (set to zero) and no header CRC. */ windowBits?: | -9 | -10 | -11 | -12 | -13 | -14 | -15 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 25 | 26 | 27 | 28 | 29 | 30 | 31; /** * Tunes the compression algorithm. * * - `Z_DEFAULT_STRATEGY`: For normal data **(Default)** * - `Z_FILTERED`: For data produced by a filter or predictor * - `Z_HUFFMAN_ONLY`: Force Huffman encoding only (no string match) * - `Z_RLE`: Limit match distances to one (run-length encoding) * - `Z_FIXED` prevents the use of dynamic Huffman codes * * `Z_RLE` is designed to be almost as fast as `Z_HUFFMAN_ONLY`, but give better compression for PNG image data. * * `Z_FILTERED` forces more Huffman coding and less string matching, it is * somewhat intermediate between `Z_DEFAULT_STRATEGY` and `Z_HUFFMAN_ONLY`. * Filtered data consists mostly of small values with a somewhat random distribution. */ strategy?: number; }; /** * Compresses a chunk of data with `zlib` DEFLATE algorithm. * @param data The buffer of data to compress * @param options Compression options to use * @returns The output buffer with the compressed data */ export function deflateSync( data: Uint8Array, options?: ZlibCompressionOptions, ): Uint8Array; /** * Compresses a chunk of data with `zlib` GZIP algorithm. * @param data The buffer of data to compress * @param options Compression options to use * @returns The output buffer with the compressed data */ export function gzipSync( data: Uint8Array, options?: ZlibCompressionOptions, ): Uint8Array; /** * Decompresses a chunk of data with `zlib` INFLATE algorithm. * @param data The buffer of data to decompress * @returns The output buffer with the decompressed data */ export function inflateSync(data: Uint8Array): Uint8Array; /** * Decompresses a chunk of data with `zlib` GUNZIP algorithm. * @param data The buffer of data to decompress * @returns The output buffer with the decompressed data */ export function gunzipSync(data: Uint8Array): Uint8Array; export type Target = /** * For generating bundles that are intended to be run by the Bun runtime. In many cases, * it isn't necessary to bundle server-side code; you can directly execute the source code * without modification. However, bundling your server code can reduce startup times and * improve running performance. * * All bundles generated with `target: "bun"` are marked with a special `// @bun` pragma, which * indicates to the Bun runtime that there's no need to re-transpile the file before execution. */ | "bun" /** * The plugin will be applied to Node.js builds */ | "node" /** * The plugin will be applied to browser builds */ | "browser"; /** https://bun.sh/docs/bundler/loaders */ type Loader = | "js" | "jsx" | "ts" | "tsx" | "json" | "toml" | "file" | "napi" | "wasm" | "text"; interface PluginConstraints { /** * Only apply the plugin when the import specifier matches this regular expression * * @example * ```ts * // Only apply the plugin when the import specifier matches the regex * Bun.plugin({ * setup(builder) { * builder.onLoad({ filter: /node_modules\/underscore/ }, (args) => { * return { contents: "throw new Error('Please use lodash instead of underscore.')" }; * }); * } * }) * ``` */ filter: RegExp; /** * Only apply the plugin when the import specifier has a namespace matching * this string * * Namespaces are prefixes in import specifiers. For example, `"bun:ffi"` * has the namespace `"bun"`. * * The default namespace is `"file"` and it can be omitted from import * specifiers. */ namespace?: string; } interface OnLoadResultSourceCode { /** * The source code of the module */ contents: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer; /** * The loader to use for this file * * "css" will be added in a future version of Bun. */ loader?: Loader; } interface OnLoadResultObject { /** * The object to use as the module * @example * ```ts * // In your loader * builder.onLoad({ filter: /^hello:world$/ }, (args) => { * return { exports: { foo: "bar" }, loader: "object" }; * }); * * // In your script * import {foo} from "hello:world"; * console.log(foo); // "bar" * ``` */ exports: Record; /** * The loader to use for this file */ loader: "object"; } interface OnLoadArgs { /** * The resolved import specifier of the module being loaded * @example * ```ts * builder.onLoad({ filter: /^hello:world$/ }, (args) => { * console.log(args.path); // "hello:world" * return { exports: { foo: "bar" }, loader: "object" }; * }); * ``` */ path: string; /** * The namespace of the module being loaded */ namespace: string; /** * The default loader for this file extension */ loader: Loader; } type OnLoadResult = OnLoadResultSourceCode | OnLoadResultObject; type OnLoadCallback = ( args: OnLoadArgs, ) => OnLoadResult | Promise; interface OnResolveArgs { /** * The import specifier of the module being loaded */ path: string; /** * The module that imported the module being resolved */ importer: string; /** * The namespace of the importer. */ namespace: string; /** * The kind of import this resolve is for. */ kind: ImportKind; // resolveDir: string; // pluginData: any; } interface OnResolveResult { /** * The destination of the import */ path: string; /** * The namespace of the destination * It will be concatenated with `path` to form the final import specifier * @example * ```ts * "foo" // "foo:bar" * ``` */ namespace?: string; external?: boolean; } type OnResolveCallback = ( args: OnResolveArgs, ) => | OnResolveResult | Promise | void | undefined | null; interface PluginBuilder { /** * Register a callback to load imports with a specific import specifier * @param constraints The constraints to apply the plugin to * @param callback The callback to handle the import * @example * ```ts * Bun.plugin({ * setup(builder) { * builder.onLoad({ filter: /^hello:world$/ }, (args) => { * return { exports: { foo: "bar" }, loader: "object" }; * }); * }, * }); * ``` */ onLoad(constraints: PluginConstraints, callback: OnLoadCallback): void; /** * Register a callback to resolve imports matching a filter and/or namespace * @param constraints The constraints to apply the plugin to * @param callback The callback to handle the import * @example * ```ts * Bun.plugin({ * setup(builder) { * builder.onResolve({ filter: /^wat$/ }, (args) => { * return { path: "/tmp/woah.js" }; * }); * }, * }); * ``` */ onResolve( constraints: PluginConstraints, callback: OnResolveCallback, ): void; /** * The config object passed to `Bun.build` as is. Can be mutated. */ config: BuildConfig & { plugins: BunPlugin[] }; } interface BunPlugin { /** * Human-readable name of the plugin * * In a future version of Bun, this will be used in error messages. */ name?: string; /** * The target JavaScript environment the plugin should be applied to. * - `bun`: The default environment when using `bun run` or `bun` to load a script * - `browser`: The plugin will be applied to browser builds * - `node`: The plugin will be applied to Node.js builds * * If in Bun's runtime, the default target is `bun`. * * If unspecified, it is assumed that the plugin is compatible with the default target. */ target?: Target; /** * A function that will be called when the plugin is loaded. * * This function may be called in the same tick that it is registered, or it may be called later. It could potentially be called multiple times for different targets. */ setup( /** * A builder object that can be used to register plugin hooks * @example * ```ts * builder.onLoad({ filter: /\.yaml$/ }, ({ path }) => ({ * loader: "object", * exports: require("js-yaml").load(fs.readFileSync(path, "utf8")), * })); * ``` */ build: PluginBuilder, ): void | Promise; } /** * Extend Bun's module resolution and loading behavior * * Plugins are applied in the order they are defined. * * Today, there are two kinds of hooks: * - `onLoad` lets you return source code or an object that will become the module's exports * - `onResolve` lets you redirect a module specifier to another module specifier. It does not chain. * * Plugin hooks must define a `filter` RegExp and will only be matched if the * import specifier contains a "." or a ":". * * ES Module resolution semantics mean that plugins may be initialized _after_ * a module is resolved. You might need to load plugins at the very beginning * of the application and then use a dynamic import to load the rest of the * application. A future version of Bun may also support specifying plugins * via `bunfig.toml`. * * * @example * A YAML loader plugin * * ```js *Bun.plugin({ * setup(builder) { * builder.onLoad({ filter: /\.yaml$/ }, ({path}) => ({ * loader: "object", * exports: require("js-yaml").load(fs.readFileSync(path, "utf8")) * })); *}); * * // You can use require() * const {foo} = require("./file.yaml"); * * // Or import * await import("./file.yaml"); * * ``` */ interface BunRegisterPlugin { (options: T): ReturnType; /** * Deactivate all plugins * * This prevents registered plugins from being applied to future builds. */ clearAll(): void; } const plugin: BunRegisterPlugin; /** * Is the current global scope the main thread? */ const isMainThread: boolean; interface Socket { /** * Write `data` to the socket * * @param data The data to write to the socket * @param byteOffset The offset in the buffer to start writing from (defaults to 0) * @param byteLength The number of bytes to write (defaults to the length of the buffer) * * When passed a string, `byteOffset` and `byteLength` refer to the UTF-8 offset, not the string character offset. * * This is unbuffered as of Bun v0.2.2. That means individual write() calls * will be slow. In the future, Bun will buffer writes and flush them at the * end of the tick, when the event loop is idle, or sooner if the buffer is full. */ write( data: string | BufferSource, byteOffset?: number, byteLength?: number, ): number; /** * The data context for the socket. */ data: Data; /** * Like {@link Socket.write} except it includes a TCP FIN packet * * Use it to send your last message and close the connection. */ end( data?: string | BufferSource, byteOffset?: number, byteLength?: number, ): number; /** * Close the socket immediately */ end(): void; /** * Keep Bun's process alive at least until this socket is closed * * After the socket has closed, the socket is unref'd, the process may exit, * and this becomes a no-op */ ref(): void; /** * Set a timeout until the socket automatically closes. * * To reset the timeout, call this function again. * * When a timeout happens, the `timeout` callback is called and the socket is closed. */ timeout(seconds: number): void; /** * Shutdown writes to a socket * * This makes the socket a half-closed socket. It can still receive data. * * This calls [shutdown(2)](https://man7.org/linux/man-pages/man2/shutdown.2.html) internally */ shutdown(halfClose?: boolean): void; readonly readyState: "open" | "closing" | "closed"; /** * Allow Bun's process to exit even if this socket is still open * * After the socket has closed, this function does nothing. */ unref(): void; /** * Flush any buffered data to the socket */ flush(): void; /** * Reset the socket's callbacks. This is useful with `bun --hot` to facilitate hot reloading. * * This will apply to all sockets from the same {@link Listener}. it is per socket only for {@link Bun.connect}. */ reload(handler: SocketHandler): void; /** * Get the server that created this socket * * This will return undefined if the socket was created by {@link Bun.connect} or if the listener has already closed. */ readonly listener?: SocketListener; /** * Remote IP address connected to the socket */ readonly remoteAddress: string; /** * local port connected to the socket */ readonly localPort: number; } interface SocketListener { stop(closeActiveConnections?: boolean): void; ref(): void; unref(): void; reload(options: Pick, "socket">): void; data: Data; } interface TCPSocketListener extends SocketListener { readonly port: number; readonly hostname: string; } interface UnixSocketListener extends SocketListener { readonly unix: string; } interface TCPSocket extends Socket {} interface TLSSocket extends Socket {} type BinaryTypeList = { arraybuffer: ArrayBuffer; buffer: Buffer; uint8array: Uint8Array; // TODO: DataView // dataview: DataView; }; type BinaryType = keyof BinaryTypeList; interface SocketHandler< Data = unknown, DataBinaryType extends BinaryType = "buffer", > { /** * Is called when the socket connects, or in case of TLS if no handshake is provided * this will be called only after handshake * @param socket */ open?(socket: Socket): void | Promise; close?(socket: Socket): void | Promise; error?(socket: Socket, error: Error): void | Promise; data?( socket: Socket, data: BinaryTypeList[DataBinaryType], ): void | Promise; drain?(socket: Socket): void | Promise; /** * When handshake is completed, this functions is called. * @param socket * @param success Indicates if the server authorized despite the authorizationError. * @param authorizationError Certificate Authorization Error or null. */ handshake?( socket: Socket, success: boolean, authorizationError: Error | null, ): void; /** * When the socket has been shutdown from the other end, this function is * called. This is a TCP FIN packet. */ end?(socket: Socket): void | Promise; /** * When the socket fails to be created, this function is called. * * The promise returned by `Bun.connect` rejects **after** this function is * called. * * When `connectError` is specified, the rejected promise will not be * added to the promise rejection queue (so it won't be reported as an * unhandled promise rejection, since connectError handles it). * * When `connectError` is not specified, the rejected promise will be added * to the promise rejection queue. */ connectError?(socket: Socket, error: Error): void | Promise; /** * Called when a message times out. */ timeout?(socket: Socket): void | Promise; /** * Choose what `ArrayBufferView` is returned in the {@link SocketHandler.data} callback. * * @default "buffer" * * @remarks * This lets you select the desired binary type for the `data` callback. * It's a small performance optimization to let you avoid creating extra * ArrayBufferView objects when possible. * * Bun originally defaulted to `Uint8Array` but when dealing with network * data, it's more useful to be able to directly read from the bytes which * `Buffer` allows. * */ binaryType?: BinaryType; } interface SocketOptions { socket: SocketHandler; data?: Data; } // interface TCPSocketOptions extends SocketOptions { // hostname: string; // port: number; // } interface TCPSocketListenOptions extends SocketOptions { hostname: string; port: number; tls?: TLSOptions; } interface TCPSocketConnectOptions extends SocketOptions { hostname: string; port: number; tls?: boolean; } interface UnixSocketOptions extends SocketOptions { unix: string; } /** * * Create a TCP client that connects to a server * * @param options The options to use when creating the client * @param options.socket The socket handler to use * @param options.data The per-instance data context * @param options.hostname The hostname to connect to * @param options.port The port to connect to * @param options.tls The TLS configuration object * @param options.unix The unix socket to connect to * */ export function connect( options: TCPSocketConnectOptions, ): Promise>; export function connect( options: UnixSocketOptions, ): Promise>; /** * * Create a TCP server that listens on a port * * @param options The options to use when creating the server * @param options.socket The socket handler to use * @param options.data The per-instance data context * @param options.hostname The hostname to connect to * @param options.port The port to connect to * @param options.tls The TLS configuration object * @param options.unix The unix socket to connect to * */ export function listen( options: TCPSocketListenOptions, ): TCPSocketListener; export function listen( options: UnixSocketOptions, ): UnixSocketListener; namespace SpawnOptions { /** * Option for stdout/stderr */ type Readable = | "pipe" | "inherit" | "ignore" | null // equivalent to "ignore" | undefined // to use default | BunFile | ArrayBufferView | number; /** * Option for stdin */ type Writable = | "pipe" | "inherit" | "ignore" | null // equivalent to "ignore" | undefined // to use default | BunFile | ArrayBufferView | number | ReadableStream | Blob | Response | Request; interface OptionsObject< In extends Writable = Writable, Out extends Readable = Readable, Err extends Readable = Readable, > { /** * The current working directory of the process * * Defaults to `process.cwd()` */ cwd?: 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. * */ env?: Record; /** * The standard file descriptors of the process, in the form [stdin, stdout, stderr]. * This overrides the `stdin`, `stdout`, and `stderr` properties. * * For stdin you may pass: * * - `"ignore"`, `null`, `undefined`: The process will have no standard input (default) * - `"pipe"`: The process will have a new {@link FileSink} for standard input * - `"inherit"`: The process will inherit the standard input of the current process * - `ArrayBufferView`, `Blob`, `Bun.file()`, `Response`, `Request`: The process will read from buffer/stream. * - `number`: The process will read from the file descriptor * * For stdout and stdin you may pass: * * - `"pipe"`, `undefined`: The process will have a {@link ReadableStream} for standard output/error * - `"ignore"`, `null`: The process will have no standard output/error * - `"inherit"`: The process will inherit the standard output/error of the current process * - `ArrayBufferView`: The process write to the preallocated buffer. Not implemented. * - `number`: The process will write to the file descriptor * * @default ["ignore", "pipe", "inherit"] for `spawn` * ["ignore", "pipe", "pipe"] for `spawnSync` */ stdio?: [In, Out, Err]; /** * The file descriptor for the standard input. It may be: * * - `"ignore"`, `null`, `undefined`: The process will have no standard input * - `"pipe"`: The process will have a new {@link FileSink} for standard input * - `"inherit"`: The process will inherit the standard input of the current process * - `ArrayBufferView`, `Blob`: The process will read from the buffer * - `number`: The process will read from the file descriptor * * @default "ignore" */ stdin?: In; /** * The file descriptor for the standard output. It may be: * * - `"pipe"`, `undefined`: The process will have a {@link ReadableStream} for standard output/error * - `"ignore"`, `null`: The process will have no standard output/error * - `"inherit"`: The process will inherit the standard output/error of the current process * - `ArrayBufferView`: The process write to the preallocated buffer. Not implemented. * - `number`: The process will write to the file descriptor * * @default "pipe" */ stdout?: Out; /** * The file descriptor for the standard error. It may be: * * - `"pipe"`, `undefined`: The process will have a {@link ReadableStream} for standard output/error * - `"ignore"`, `null`: The process will have no standard output/error * - `"inherit"`: The process will inherit the standard output/error of the current process * - `ArrayBufferView`: The process write to the preallocated buffer. Not implemented. * - `number`: The process will write to the file descriptor * * @default "inherit" for `spawn` * "pipe" for `spawnSync` */ stderr?: Err; /** * Callback that runs when the {@link Subprocess} exits * * This is called even if the process exits with a non-zero exit code. * * Warning: this may run before the `Bun.spawn` function returns. * * A simple alternative is `await subprocess.exited`. * * @example * * ```ts * const subprocess = spawn({ * cmd: ["echo", "hello"], * onExit: (subprocess, code) => { * console.log(`Process exited with code ${code}`); * }, * }); * ``` */ onExit?( subprocess: Subprocess, exitCode: number | null, signalCode: number | null, /** * If an error occurred in the call to waitpid2, this will be the error. */ error?: Errorlike, ): void | Promise; } type OptionsToSubprocess = Opts extends OptionsObject ? Subprocess< // "Writable extends In" means "if In === Writable", // aka if true that means the user didn't specify anything Writable extends In ? "ignore" : In, Readable extends Out ? "pipe" : Out, Readable extends Err ? "inherit" : Err > : Subprocess; type OptionsToSyncSubprocess = Opts extends OptionsObject ? SyncSubprocess< Readable extends Out ? "pipe" : Out, Readable extends Err ? "pipe" : Err > : SyncSubprocess; type ReadableIO = ReadableStream | number | undefined; type ReadableToIO = X extends "pipe" | undefined ? ReadableStream : X extends BunFile | ArrayBufferView | number ? number : undefined; type ReadableToSyncIO = X extends "pipe" | undefined ? Uint8Array : undefined; type WritableIO = FileSink | number | undefined; type WritableToIO = X extends "pipe" ? FileSink : X extends BunFile | ArrayBufferView | Blob | Request | Response | number ? number : undefined; } /** * A process created by {@link Bun.spawn}. * * This type accepts 3 optional type parameters which correspond to the `stdio` array from the options object. Instead of specifying these, you should use one of the following utility types instead: * - {@link ReadableSubprocess} (any, pipe, pipe) * - {@link WritableSubprocess} (pipe, any, any) * - {@link PipedSubprocess} (pipe, pipe, pipe) * - {@link NullSubprocess} (ignore, ignore, ignore) */ interface Subprocess< In extends SpawnOptions.Writable = SpawnOptions.Writable, Out extends SpawnOptions.Readable = SpawnOptions.Readable, Err extends SpawnOptions.Readable = SpawnOptions.Readable, > { readonly stdin: SpawnOptions.WritableToIO; readonly stdout: SpawnOptions.ReadableToIO; readonly stderr: SpawnOptions.ReadableToIO; /** * This returns the same value as {@link Subprocess.stdout} * * It exists for compatibility with {@link ReadableStream.pipeThrough} */ readonly readable: SpawnOptions.ReadableToIO; /** * The process ID of the child process * @example * ```ts * const { pid } = Bun.spawn({ cmd: ["echo", "hello"] }); * console.log(pid); // 1234 * ``` */ readonly pid: number; /** * The exit code of the process * * The promise will resolve when the process exits */ readonly exited: Promise; /** * Synchronously get the exit code of the process * * If the process hasn't exited yet, this will return `null` */ readonly exitCode: number | null; /** * Synchronously get the signal code of the process * * If the process never sent a signal code, this will return `null` * * To receive signal code changes, use the `onExit` callback. * * If the signal code is unknown, it will return the original signal code * number, but that case should essentially never happen. */ readonly signalCode: Signals | null; /** * Has the process exited? */ readonly killed: boolean; /** * Kill the process * @param exitCode The exitCode to send to the process */ kill(exitCode?: number): void; /** * This method will tell Bun to wait for this process to exit after you already * called `unref()`. * * Before shutting down, Bun will wait for all subprocesses to exit by default */ ref(): void; /** * Before shutting down, Bun will wait for all subprocesses to exit by default * * This method will tell Bun to not wait for this process to exit before shutting down. */ unref(): void; } /** * A process created by {@link Bun.spawnSync}. * * This type accepts 2 optional type parameters which correspond to the `stdout` and `stderr` options. Instead of specifying these, you should use one of the following utility types instead: * - {@link ReadableSyncSubprocess} (pipe, pipe) * - {@link NullSyncSubprocess} (ignore, ignore) */ interface SyncSubprocess< Out extends SpawnOptions.Readable = SpawnOptions.Readable, Err extends SpawnOptions.Readable = SpawnOptions.Readable, > { stdout: SpawnOptions.ReadableToSyncIO; stderr: SpawnOptions.ReadableToSyncIO; exitCode: number; success: boolean; } /** * Spawn a new process * * ```js * const subprocess = Bun.spawn({ * cmd: ["echo", "hello"], * stdout: "pipe", * }); * const text = await readableStreamToText(subprocess.stdout); * console.log(text); // "hello\n" * ``` * * Internally, this uses [posix_spawn(2)](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/posix_spawn.2.html) */ function spawn( options: Opts & { /** * The command to run * * The first argument will be resolved to an absolute executable path. It must be a file, not a directory. * * If you explicitly set `PATH` in `env`, that `PATH` will be used to resolve the executable instead of the default `PATH`. * * To check if the command exists before running it, use `Bun.which(bin)`. * * @example * ```ts * const subprocess = Bun.spawn(["echo", "hello"]); * ``` */ cmd: string[]; // to support dynamically constructed commands }, ): SpawnOptions.OptionsToSubprocess; /** * Spawn a new process * * ```js * const {stdout} = Bun.spawn(["echo", "hello"])); * const text = await readableStreamToText(stdout); * console.log(text); // "hello\n" * ``` * * Internally, this uses [posix_spawn(2)](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/posix_spawn.2.html) */ function spawn( /** * The command to run * * The first argument will be resolved to an absolute executable path. It must be a file, not a directory. * * If you explicitly set `PATH` in `env`, that `PATH` will be used to resolve the executable instead of the default `PATH`. * * To check if the command exists before running it, use `Bun.which(bin)`. * * @example * ```ts * const subprocess = Bun.spawn(["echo", "hello"]); * ``` */ cmds: string[], options?: Opts, ): SpawnOptions.OptionsToSubprocess; /** * Spawn a new process * * ```js * const {stdout} = Bun.spawnSync({ * cmd: ["echo", "hello"], * }); * console.log(stdout.toString()); // "hello\n" * ``` * * Internally, this uses [posix_spawn(2)](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/posix_spawn.2.html) */ function spawnSync( options: Opts & { /** * The command to run * * The first argument will be resolved to an absolute executable path. It must be a file, not a directory. * * If you explicitly set `PATH` in `env`, that `PATH` will be used to resolve the executable instead of the default `PATH`. * * To check if the command exists before running it, use `Bun.which(bin)`. * * @example * ```ts * const subprocess = Bun.spawnSync({ cmd: ["echo", "hello"] }); * ``` */ cmd: string[]; }, ): SpawnOptions.OptionsToSyncSubprocess; /** * Synchronously spawn a new process * * ```js * const {stdout} = Bun.spawnSync(["echo", "hello"])); * console.log(stdout.toString()); // "hello\n" * ``` * * Internally, this uses [posix_spawn(2)](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/posix_spawn.2.html) */ function spawnSync( /** * The command to run * * The first argument will be resolved to an absolute executable path. It must be a file, not a directory. * * If you explicitly set `PATH` in `env`, that `PATH` will be used to resolve the executable instead of the default `PATH`. * * To check if the command exists before running it, use `Bun.which(bin)`. * * @example * ```ts * const subprocess = Bun.spawnSync(["echo", "hello"]); * ``` */ cmds: string[], options?: Opts, ): SpawnOptions.OptionsToSyncSubprocess; /** Utility type for any process from {@link Bun.spawn()} with both stdout and stderr set to `"pipe"` */ type ReadableSubprocess = Subprocess; /** Utility type for any process from {@link Bun.spawn()} with stdin set to `"pipe"` */ type WritableSubprocess = Subprocess<"pipe", any, any>; /** Utility type for any process from {@link Bun.spawn()} with stdin, stdout, stderr all set to `"pipe"`. A combination of {@link ReadableSubprocess} and {@link WritableSubprocess} */ type PipedSubprocess = Subprocess<"pipe", "pipe", "pipe">; /** Utility type for any process from {@link Bun.spawn()} with stdin, stdout, stderr all set to `null` or similar. */ type NullSubprocess = Subprocess< "ignore" | "inherit" | null | undefined, "ignore" | "inherit" | null | undefined, "ignore" | "inherit" | null | undefined >; /** Utility type for any process from {@link Bun.spawnSync()} with both stdout and stderr set to `"pipe"` */ type ReadableSyncSubprocess = SyncSubprocess<"pipe", "pipe">; /** Utility type for any process from {@link Bun.spawnSync()} with both stdout and stderr set to `null` or similar */ type NullSyncSubprocess = SyncSubprocess< "ignore" | "inherit" | null | undefined, "ignore" | "inherit" | null | undefined >; export class FileSystemRouter { /** * Create a new {@link FileSystemRouter}. * * @example * ```ts *const router = new FileSystemRouter({ * dir: process.cwd() + "/pages", * style: "nextjs", *}); * * const {params} = router.match("/blog/2020/01/01/hello-world"); * console.log(params); // {year: "2020", month: "01", day: "01", slug: "hello-world"} * ``` * @param options The options to use when creating the router * @param options.dir The root directory containing the files to route * @param options.style The style of router to use (only "nextjs" supported * for now) */ constructor(options: { /** * The root directory containing the files to route * * There is no default value for this option. * * @example * ```ts * const router = new FileSystemRouter({ * dir: */ dir: string; style: "nextjs"; /** The base path to use when routing */ assetPrefix?: string; origin?: string; /** Limit the pages to those with particular file extensions. */ fileExtensions?: string[]; }); // todo: URL match(input: string | Request | Response): MatchedRoute | null; readonly assetPrefix: string; readonly origin: string; readonly style: string; readonly routes: Record; reload(): void; } export interface MatchedRoute { /** * A map of the parameters from the route * * @example * ```ts * const router = new FileSystemRouter({ * dir: "/path/to/files", * style: "nextjs", * }); * const {params} = router.match("/blog/2020/01/01/hello-world"); * console.log(params.year); // "2020" * console.log(params.month); // "01" * console.log(params.day); // "01" * console.log(params.slug); // "hello-world" * ``` */ readonly params: Record; readonly filePath: string; readonly pathname: string; readonly query: Record; readonly name: string; readonly kind: "exact" | "catch-all" | "optional-catch-all" | "dynamic"; readonly src: string; } /** * The current version of Bun * @example * "0.2.0" */ export const version: string; /** * The git sha at the time the currently-running version of Bun was compiled * @example * "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2" */ export const revision: string; /** * Find the index of a newline character in potentially ill-formed UTF-8 text. * * This is sort of like readline() except without the IO. */ export function indexOfLine( buffer: ArrayBufferView | ArrayBufferLike, offset?: number, ): number; } type TypedArray = | Uint8Array | Int8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array; type TimeLike = string | number | Date; type StringOrBuffer = string | TypedArray | ArrayBufferLike; type PathLike = string | TypedArray | ArrayBufferLike | URL; type PathOrFileDescriptor = PathLike | number; type NoParamCallback = (err: ErrnoException | null) => void; type BufferEncoding = | "buffer" | "utf8" | "utf-8" | "ascii" | "utf16le" | "ucs2" | "ucs-2" | "latin1" | "binary" | "hex" | "base64" | "base64url"; interface BufferEncodingOption { encoding?: BufferEncoding; } declare var Bun: typeof import("bun");