UNPKG

bun-types

Version:

Type definitions and documentation for Bun, an incredibly fast JavaScript runtime

1,297 lines (1,211 loc) 38.3 kB
declare module "bun" { /** * 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 = number; /** * A state that represents if a WebSocket is connected. * * - `WebSocket.CONNECTING` is `0`, the connection is pending. * - `WebSocket.OPEN` is `1`, the connection is established and `send()` is possible. * - `WebSocket.CLOSING` is `2`, the connection is closing. * - `WebSocket.CLOSED` is `3`, the connection is closed or couldn't be opened. * * @link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/readyState */ type WebSocketReadyState = 0 | 1 | 2 | 3; /** * 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 * ```ts * 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); * }, * } * }); * ``` */ interface ServerWebSocket<T = undefined> { /** * 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; /** * Returns an array of all topics the client is currently subscribed to. * * @example * ws.subscribe("chat"); * ws.subscribe("notifications"); * console.log(ws.subscriptions); // ["chat", "notifications"] */ readonly subscriptions: string[]; /** * 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<T = unknown>(callback: (ws: ServerWebSocket<T>) => 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: { * data: {} as {accessToken: string | null}, * message(ws) { * console.log(ws.data.accessToken); * } * } * }); */ data: T; getBufferedAmount(): number; } /** * 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"); * }, * }); * ``` */ interface WebSocketHandler<T> { /** * Specify the type for the {@link ServerWebSocket.data} property on * connecting websocket clients. You can pass this value when you make a * call to {@link Server.upgrade}. * * This pattern exists in Bun due to a [TypeScript limitation (#26242)](https://github.com/microsoft/TypeScript/issues/26242) * * @example * ```ts * Bun.serve({ * websocket: { * data: {} as { name: string }, // ← Specify the type of `ws.data` like this * message: (ws, message) => console.log(ws.data.name, 'says:', message); * }, * // ... * }); * ``` */ data?: T; /** * 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<T>, message: string | Buffer<ArrayBuffer>): void | Promise<void>; /** * Called when a connection is opened. * * @param ws The websocket that was opened */ open?(ws: ServerWebSocket<T>): void | Promise<void>; /** * 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<T>): void | Promise<void>; /** * Called when a connection is closed. * * @param ws The websocket that was closed * @param code The close code * @param reason The close reason */ close?(ws: ServerWebSocket<T>, code: number, reason: string): void | Promise<void>; /** * 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<T>, data: Buffer): void | Promise<void>; /** * 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<T>, data: Buffer): void | Promise<void>; /** * 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 false */ closeOnBackpressureLimit?: boolean; /** * Sets the number of seconds to wait before timing out a connection * due to no messages or pings. * * @default 120 */ idleTimeout?: number; /** * Should `ws.publish()` also send a message to `ws` (itself), if it is subscribed? * * @default false */ publishToSelf?: boolean; /** * Should the server automatically send and respond to pings to clients? * * @default true */ sendPings?: boolean; /** * Sets the compression level for messages, for clients that supports it. By default, compression is disabled. * * @default false */ perMessageDeflate?: | boolean | { /** * Sets the compression level. */ compress?: WebSocketCompressor | boolean; /** * Sets the decompression level. */ decompress?: WebSocketCompressor | boolean; }; } namespace Serve { type ExtractRouteParams<T> = string extends T ? Record<string, string> : T extends `${string}:${infer Param}/${infer Rest}` ? { [K in Param]: string } & ExtractRouteParams<Rest> : T extends `${string}:${infer Param}` ? { [K in Param]: string } : T extends `${string}*` ? {} : {}; /** * Development configuration for {@link Bun.serve} */ type Development = | boolean | { /** * Enable Hot Module Replacement for routes (including React Fast Refresh, if React is in use) * * @default true if process.env.NODE_ENV !== 'production' * */ hmr?: boolean; /** * Enable console log streaming from browser to server * @default false */ console?: boolean; /** * Enable automatic workspace folders for Chrome DevTools * * This lets you persistently edit files in the browser. It works by adding the following route to the server: * `/.well-known/appspecific/com.chrome.devtools.json` * * The response is a JSON object with the following shape: * ```json * { * "workspace": { * "root": "<cwd>", * "uuid": "<uuid>" * } * } * ``` * * The `root` field is the current working directory of the server. * The `"uuid"` field is a hash of the file that started the server and a hash of the current working directory. * * For security reasons, if the remote socket address is not from localhost, 127.0.0.1, or ::1, the request is ignored. * @default true */ chromeDevToolsAutomaticWorkspaceFolders?: boolean; }; type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS"; type Handler<Req extends Request, S, Res> = (request: Req, server: S) => MaybePromise<Res>; type BaseRouteValue = Response | false | HTMLBundle | BunFile; type Routes<WebSocketData, R extends string> = { [Path in R]: | BaseRouteValue | Handler<BunRequest<Path>, Server<WebSocketData>, Response> | Partial<Record<HTTPMethod, Handler<BunRequest<Path>, Server<WebSocketData>, Response> | Response>>; }; type RoutesWithUpgrade<WebSocketData, R extends string> = { [Path in R]: | BaseRouteValue | Handler<BunRequest<Path>, Server<WebSocketData>, Response | undefined | void> | Partial< Record<HTTPMethod, Handler<BunRequest<Path>, Server<WebSocketData>, Response | undefined | void> | Response> >; }; type FetchOrRoutes<WebSocketData, R extends string> = | { /** * Handle HTTP requests * * Respond to {@link Request} objects with a {@link Response} object. */ fetch?(this: Server<WebSocketData>, req: Request, server: Server<WebSocketData>): MaybePromise<Response>; routes: Routes<WebSocketData, R>; } | { /** * Handle HTTP requests * * Respond to {@link Request} objects with a {@link Response} object. */ fetch(this: Server<WebSocketData>, req: Request, server: Server<WebSocketData>): MaybePromise<Response>; routes?: Routes<WebSocketData, R>; }; type FetchOrRoutesWithWebSocket<WebSocketData, R extends string> = { /** * Enable websockets with {@link Bun.serve} * * 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 * * @example * ```js * const server: Bun.Server = 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"); * }, * }); * ``` */ websocket: WebSocketHandler<WebSocketData>; } & ( | { /** * Handle HTTP requests, or call {@link Server.upgrade} and return early * * Respond to {@link Request} objects with a {@link Response} object. */ fetch?( this: Server<WebSocketData>, req: Request, server: Server<WebSocketData>, ): MaybePromise<Response | void | undefined>; routes: RoutesWithUpgrade<WebSocketData, R>; } | { /** * Handle HTTP requests, or call {@link Server.upgrade} and return early * * Respond to {@link Request} objects with a {@link Response} object. */ fetch( this: Server<WebSocketData>, req: Request, server: Server<WebSocketData>, ): MaybePromise<Response | void | undefined>; routes?: RoutesWithUpgrade<WebSocketData, R>; } ); interface BaseServeOptions<WebSocketData> { /** * Set options for using TLS with this server * * @example * ```ts * const server = Bun.serve({ * fetch: request => new Response("Welcome to Bun!"), * tls: { * cert: Bun.file("cert.pem"), * key: Bun.file("key.pem"), * ca: [Bun.file("ca1.pem"), Bun.file("ca2.pem")], * }, * }); * ``` */ tls?: TLSOptions | TLSOptions[]; /** * 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?: Development; /** * Callback called when an error is thrown during request handling * @param error The error that was thrown * @returns A response to send to the client * * @example * ```ts * error: (error) => { * return new Response("Internal Server Error", { status: 500 }); * } * ``` */ error?: (this: Server<WebSocketData>, error: ErrorLike) => Response | Promise<Response> | void | Promise<void>; /** * Uniquely identify a server instance with an ID * * --- * * **When bun is started with the `--hot` flag**: * * This string will be used to hot reload the server without interrupting * pending requests or websockets. If not provided, a value will be * generated. To disable hot reloading, set this value to `null`. * * **When bun is not started with the `--hot` flag**: * * This string will currently do nothing. But in the future it could be useful for logs or metrics. */ id?: string | null; } interface HostnamePortServeOptions<WebSocketData> extends BaseServeOptions<WebSocketData> { /** * 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?: "0.0.0.0" | "127.0.0.1" | "localhost" | (string & {}); /** * What port should the server listen on? * @default process.env.PORT || "3000" */ port?: string | number; /** * Whether the `SO_REUSEPORT` flag should be set. * * This allows multiple processes to bind to the same port, which is useful for load balancing. * * @default false */ reusePort?: boolean; /** * Whether the `IPV6_V6ONLY` flag should be set. * @default false */ ipv6Only?: boolean; /** * Sets the number of seconds to wait before timing out a connection * due to inactivity. * * @default 10 */ idleTimeout?: number; } interface UnixServeOptions<WebSocketData> extends BaseServeOptions<WebSocketData> { /** * If set, the HTTP server will listen on a unix socket instead of a port. * (Cannot be used with hostname+port) */ unix?: string; } /** * The type of options that can be passed to {@link serve}, with support for * `routes` and a safer requirement for `fetch` * * @example * ```ts * export default { * fetch: req => Response.json(req.url), * * websocket: { * message(ws) { * ws.data.name; // string * }, * }, * } satisfies Bun.Serve.Options<{ name: string }>; * ``` */ type Options<WebSocketData, R extends string = string> = Bun.__internal.XOR< HostnamePortServeOptions<WebSocketData>, UnixServeOptions<WebSocketData> > & Bun.__internal.XOR<FetchOrRoutes<WebSocketData, R>, FetchOrRoutesWithWebSocket<WebSocketData, R>>; } interface BunRequest<T extends string = string> extends Request { readonly params: { [Key in keyof Serve.ExtractRouteParams<T>]: Serve.ExtractRouteParams<T>[Key]; } & {}; readonly cookies: CookieMap; clone(): BunRequest<T>; } /** * 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. */ interface Server<WebSocketData> extends Disposable { /** * 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): Promise<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.reload({ * fetch(request) { * return new Response("Hello World v2") * } * }); * ``` * * Passing other options such as `port` or `hostname` won't do anything. */ reload<R extends string>(options: Serve.Options<WebSocketData, R>): Server<WebSocketData>; /** * 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<Response>; /** * 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"; * const server: Bun.Server<{ user: string }> = 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, { * data: {user: "John Doe"} * }); * 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: [WebSocketData] extends [undefined] ? [ options?: { /** */ headers?: HeadersInit; /** * Data to store on the WebSocket instance * * --- * * **Surprised this line is erroring?** * * Tell TypeScript about the WebSocket data by using `Bun.Server<MyWebSocketData>` * * ```ts * const server: Bun.Server<MyWebSocketData> = Bun.serve({ * fetch: (req, server) => { * const didUpgrade = server.upgrade(req, { * data: { ... }, // Works now! * }); * }, * }); * ``` */ data?: undefined; }, ] : [ options: { /** * Send any additional headers while upgrading, like cookies */ headers?: HeadersInit; /** * Data to store on the WebSocket instance */ data: WebSocketData; }, ] ): 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; /** * A count of connections subscribed to a given topic * * This operation will loop through each topic internally to get the count. * * @param topic the websocket topic to check how many subscribers are connected to * @returns the number of subscribers */ subscriberCount(topic: string): number; /** * Returns the client IP address and port of the given Request. If the request was closed or is a unix socket, returns null. * * @example * ```js * export default { * async fetch(request, server) { * return new Response(server.requestIP(request)); * } * } * ``` */ requestIP(request: Request): SocketAddress | null; /** * Reset the idleTimeout of the given Request to the number in seconds. 0 means no timeout. * * @example * ```js * export default { * async fetch(request, server) { * server.timeout(request, 60); * await Bun.sleep(30000); * return new Response("30 seconds have passed"); * } * } * ``` */ timeout(request: Request, seconds: number): void; /** * Undo a call to {@link Server.unref} * * If the Server has already been stopped, this does nothing. * * If {@link Server.ref} is called multiple times, this does nothing. Think of it as a boolean toggle. */ ref(): void; /** * Don't keep the process alive if this server is the only thing left. * Active connections may continue to keep the process alive. * * By default, the server is ref'd. * * To prevent new connections from being accepted, use {@link Server.stop} */ unref(): void; /** * 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 url: URL; /** * The port the server is listening on. * * This will be undefined when the server is listening on a unix socket. * * @example * ```js * 3000 * ``` */ readonly port: number | undefined; /** * The hostname the server is listening on. Does not include the port. * * This will be `undefined` when the server is listening on a unix socket. * * @example * ```js * "localhost" * ``` */ readonly hostname: string | undefined; /** * The protocol the server is listening on. * * - "http" for normal servers * - "https" when TLS is enabled * - null for unix sockets or when unavailable */ readonly protocol: "http" | "https" | null; /** * 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; /** * An identifier of the server instance * * When bun is started with the `--hot` flag, this ID is used to hot reload the server without interrupting pending requests or websockets. * * When bun is not started with the `--hot` flag, this ID is currently unused. */ readonly id: string; } /** * Bun.serve provides a high-performance HTTP server with built-in routing support. * It enables both function-based and object-based route handlers with type-safe * parameters and method-specific handling. * * @param options Server configuration options * * @example * **Basic Usage** * * ```ts * Bun.serve({ * port: 3000, * fetch(req) { * return new Response("Hello World"); * } * }); * ``` * * @example * **Route-based Handlers** * * ```ts * Bun.serve({ * routes: { * // Static responses * "/": new Response("Home page"), * * // Function handlers with type-safe parameters * "/users/:id": (req) => { * // req.params.id is typed as string * return new Response(`User ${req.params.id}`); * }, * * // Method-specific handlers * "/api/posts": { * GET: () => new Response("Get posts"), * POST: async (req) => { * const body = await req.json(); * return new Response("Created post"); * }, * DELETE: (req) => new Response("Deleted post") * }, * * // Wildcard routes * "/static/*": (req) => { * // Handle any path under /static/ * return new Response("Static file"); * }, * * // Disable route (fall through to fetch handler) * "/api/legacy": false * }, * * // Fallback handler for unmatched routes * fetch(req) { * return new Response("Not Found", { status: 404 }); * } * }); * ``` * * @example * **Path Parameters** * * ```ts * Bun.serve({ * routes: { * // Single parameter * "/users/:id": (req: BunRequest<"/users/:id">) => { * return new Response(`User ID: ${req.params.id}`); * }, * * // Multiple parameters * "/posts/:postId/comments/:commentId": ( * req: BunRequest<"/posts/:postId/comments/:commentId"> * ) => { * return new Response(JSON.stringify(req.params)); * // Output: {"postId": "123", "commentId": "456"} * } * } * }); * ``` * * @example * **Route Precedence** * * ```ts * // Routes are matched in the following order: * // 1. Exact static routes ("/about") * // 2. Parameter routes ("/users/:id") * // 3. Wildcard routes ("/api/*") * * Bun.serve({ * routes: { * "/api/users": () => new Response("Users list"), * "/api/users/:id": (req) => new Response(`User ${req.params.id}`), * "/api/*": () => new Response("API catchall"), * "/*": () => new Response("Root catchall") * } * }); * ``` * * @example * **Error Handling** * * ```ts * Bun.serve({ * routes: { * "/error": () => { * throw new Error("Something went wrong"); * } * }, * error(error) { * // Custom error handler * console.error(error); * return new Response(`Error: ${error.message}`, { * status: 500 * }); * } * }); * ``` * * @example * **Server Lifecycle** * * ```ts * const server = Bun.serve({ * // Server config... * }); * * // Update routes at runtime * server.reload({ * routes: { * "/": () => new Response("Updated route") * } * }); * * // Stop the server * server.stop(); * ``` * * @example * **Development Mode** * * ```ts * Bun.serve({ * development: true, // Enable hot reloading * routes: { * // Routes will auto-reload on changes * } * }); * ``` * * @example * **Type-Safe Request Handling** * * ```ts * type Post = { * id: string; * title: string; * }; * * Bun.serve({ * routes: { * "/api/posts/:id": async ( * req: BunRequest<"/api/posts/:id"> * ) => { * if (req.method === "POST") { * const body: Post = await req.json(); * return Response.json(body); * } * return new Response("Method not allowed", { * status: 405 * }); * } * } * }); * ``` */ function serve<WebSocketData = undefined, R extends string = never>( options: Serve.Options<WebSocketData, R>, ): Server<WebSocketData>; }