Files
Camilla Schoeser 6a71f91e2f ajout du site
2026-05-29 21:38:59 +02:00

323 lines
10 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Serve as BunServe, type Server as BunServer } from 'bun';
import type { Equal, MaybePromise } from '../types';
export interface ErrorLike extends Error {
code?: string;
errno?: number;
syscall?: string;
}
export interface GenericServeOptions {
/**
* 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"
*/
/**
* 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<Response> | undefined | Promise<undefined>;
/**
* 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;
}
export interface ServeOptions extends GenericServeOptions {
/**
* What port should the server listen on?
* @default process.env.PORT || "3000"
*/
port?: string | number;
/**
* If 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;
/**
* 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;
/**
* If set, the HTTP server will listen on a unix socket instead of a port.
* (Cannot be used with hostname+port)
*/
unix?: never;
/**
* Handle HTTP requests
*
* Respond to {@link Request} objects with a {@link Response} object.
*/
fetch(this: Server, request: Request, server: Server): Response | Promise<Response>;
routes: Record<string, Function | Response | Record<string, Function | Response>>;
}
export type Serve = Equal<BunServe.Options<unknown>, unknown> extends false ? BunServe.Options<unknown> : ServeOptions;
export type Server = Equal<BunServer<unknown>, unknown> extends false ? BunServer<unknown> : ServerOptions;
export type ServerWebSocketSendStatus = number;
export interface SocketAddress {
/**
* The IP address of the client.
*/
address: string;
/**
* The port of the client.
*/
port: number;
/**
* The IP family ("IPv4" or "IPv6").
*/
family: 'IPv4' | 'IPv6';
}
export interface ServerOptions 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): 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(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<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";
* 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<T = undefined>(request: Request, options?: {
/**
* Send any additional headers while upgrading, like cookies
*/
headers?: Bun.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;
/**
* 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;
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;
/**
* 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;
}
export type ListenCallback = (server: Server) => MaybePromise<void>;