UNPKG

elysia

Version:

Ergonomic Framework for Human

420 lines (419 loc) 13.8 kB
type TypedArray = Uint8Array | Uint8ClampedArray | Uint16Array | Uint32Array | Int8Array | Int16Array | Int32Array | BigUint64Array | BigInt64Array | Float32Array | Float64Array; export type BufferSource = TypedArray | DataView | ArrayBufferLike; /** * 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`); * } * ``` */ export 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 */ export 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 * 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<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: { * open(ws) { * console.log(ws.data.accessToken); * } * } * }); */ data: T; } /** * Compression options for WebSocket messages. */ export 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 interface WebSocketHandler<in out T = undefined> { /** * 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): 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 message The close message */ 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 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; }; } export {};