More comments in the socket type definition (#19410)

Co-authored-by: Alistair Smith <hi@alistair.sh>
This commit is contained in:
Jarred Sumner
2025-05-30 19:12:30 -07:00
committed by GitHub
parent 4d77cd53f1
commit 010ef4d119
3 changed files with 175 additions and 31 deletions

View File

@@ -5871,31 +5871,76 @@ declare module "bun" {
index: string; index: string;
} }
/**
* Represents a TCP or TLS socket connection used for network communication.
* This interface provides methods for reading, writing, managing the connection state,
* and handling TLS-specific features if applicable.
*
* Sockets are created using `Bun.connect()` or accepted by a `Bun.listen()` server.
*
* @category HTTP & Networking
*/
interface Socket<Data = undefined> extends Disposable { interface Socket<Data = undefined> extends Disposable {
/** /**
* Write `data` to the socket * Writes `data` to the socket. This method is unbuffered and non-blocking. This uses the `sendto(2)` syscall internally.
* *
* @param data The data to write to the socket * For optimal performance with multiple small writes, consider batching multiple
* @param byteOffset The offset in the buffer to start writing from (defaults to 0) * writes together into a single `socket.write()` call.
* @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. * @param data The data to write. Can be a string (encoded as UTF-8), `ArrayBuffer`, `TypedArray`, or `DataView`.
* @param byteOffset The offset in bytes within the buffer to start writing from. Defaults to 0. Ignored for strings.
* @param byteLength The number of bytes to write from the buffer. Defaults to the remaining length of the buffer from the offset. Ignored for strings.
* @returns The number of bytes written. Returns `-1` if the socket is closed or shutting down. Can return less than the input size if the socket's buffer is full (backpressure).
* @example
* ```ts
* // Send a string
* const bytesWritten = socket.write("Hello, world!\n");
* *
* This is unbuffered as of Bun v0.2.2. That means individual write() calls * // Send binary data
* will be slow. In the future, Bun will buffer writes and flush them at the * const buffer = new Uint8Array([0x01, 0x02, 0x03]);
* end of the tick, when the event loop is idle, or sooner if the buffer is full. * socket.write(buffer);
*
* // Send part of a buffer
* const largeBuffer = new Uint8Array(1024);
* // ... fill largeBuffer ...
* socket.write(largeBuffer, 100, 50); // Write 50 bytes starting from index 100
* ```
*/ */
write(data: string | BufferSource, byteOffset?: number, byteLength?: number): number; write(data: string | BufferSource, byteOffset?: number, byteLength?: number): number;
/** /**
* The data context for the socket. * The user-defined data associated with this socket instance.
* This can be set when the socket is created via `Bun.connect({ data: ... })`.
* It can be read or updated at any time.
*
* @example
* ```ts
* // In a socket handler
* function open(socket: Socket<{ userId: string }>) {
* console.log(`Socket opened for user: ${socket.data.userId}`);
* socket.data.lastActivity = Date.now(); // Update data
* }
* ```
*/ */
data: Data; data: Data;
/** /**
* Like {@link Socket.write} except it includes a TCP FIN packet * Sends the final data chunk and initiates a graceful shutdown of the socket's write side.
* After calling `end()`, no more data can be written using `write()` or `end()`.
* The socket remains readable until the remote end also closes its write side or the connection is terminated.
* This sends a TCP FIN packet after writing the data.
* *
* Use it to send your last message and close the connection. * @param data Optional final data to write before closing. Same types as `write()`.
* @param byteOffset Optional offset for buffer data.
* @param byteLength Optional length for buffer data.
* @returns The number of bytes written for the final chunk. Returns `-1` if the socket was already closed or shutting down.
* @example
* ```ts
* // send some data and close the write side
* socket.end("Goodbye!");
* // or close write side without sending final data
* socket.end();
* ```
*/ */
end(data?: string | BufferSource, byteOffset?: number, byteLength?: number): number; end(data?: string | BufferSource, byteOffset?: number, byteLength?: number): number;
@@ -5922,20 +5967,33 @@ declare module "bun" {
timeout(seconds: number): void; timeout(seconds: number): void;
/** /**
* Forcefully close the socket. The other end may not receive all data, and * Forcefully closes the socket connection immediately. This is an abrupt termination, unlike the graceful shutdown initiated by `end()`.
* the socket will be closed immediately. * It uses `SO_LINGER` with `l_onoff=1` and `l_linger=0` before calling `close(2)`.
* Consider using {@link close close()} or {@link end end()} for graceful shutdowns.
* *
* This passes `SO_LINGER` with `l_onoff` set to `1` and `l_linger` set to * @example
* `0` and then calls `close(2)`. * ```ts
* socket.terminate();
* ```
*/ */
terminate(): void; terminate(): void;
/** /**
* Shutdown writes to a socket * Shuts down the write-half or both halves of the connection.
* This allows the socket to enter a half-closed state where it can still receive data
* but can no longer send data (`halfClose = true`), or close both read and write
* (`halfClose = false`, similar to `end()` but potentially more immediate depending on OS).
* Calls `shutdown(2)` syscall internally.
* *
* This makes the socket a half-closed socket. It can still receive data. * @param halfClose If `true`, only shuts down the write side (allows receiving). If `false` or omitted, shuts down both read and write. Defaults to `false`.
* @example
* ```ts
* // Stop sending data, but allow receiving
* socket.shutdown(true);
* *
* This calls [shutdown(2)](https://man7.org/linux/man-pages/man2/shutdown.2.html) internally * // Shutdown both reading and writing
* socket.shutdown();
* ```
*/ */
shutdown(halfClose?: boolean): void; shutdown(halfClose?: boolean): void;
@@ -5961,6 +6019,11 @@ declare module "bun" {
/** /**
* Flush any buffered data to the socket * Flush any buffered data to the socket
* This attempts to send the data immediately, but success depends on the network conditions
* and the receiving end.
* It might be necessary after several `write` calls if immediate sending is critical,
* though often the OS handles flushing efficiently. Note that `write` calls outside
* `open`/`data`/`drain` might benefit from manual `cork`/`flush`.
*/ */
flush(): void; flush(): void;
@@ -5982,17 +6045,31 @@ declare module "bun" {
/** /**
* Remote IP address connected to the socket * Remote IP address connected to the socket
* @example "192.168.1.100" | "2001:db8::1"
*/ */
readonly remoteAddress: string; readonly remoteAddress: string;
/**
* Remote port connected to the socket
* @example 8080
*/
readonly remotePort: number; readonly remotePort: number;
/**
* IP protocol family used for the local endpoint of the socket
* @example "IPv4" | "IPv6"
*/
readonly localFamily: "IPv4" | "IPv6"; readonly localFamily: "IPv4" | "IPv6";
/**
* Local IP address connected to the socket
* @example "192.168.1.100" | "2001:db8::1"
*/
readonly localAddress: string; readonly localAddress: string;
/** /**
* local port connected to the socket * local port connected to the socket
* @example 8080
*/ */
readonly localPort: number; readonly localPort: number;
@@ -6156,6 +6233,8 @@ declare module "bun" {
/** /**
* See `Session Resumption` for more information. * See `Session Resumption` for more information.
* @return `true` if the session was reused, `false` otherwise. * @return `true` if the session was reused, `false` otherwise.
* **TLS Only:** Checks if the current TLS session was resumed from a previous session.
* Returns `true` if the session was resumed, `false` otherwise.
*/ */
isSessionReused(): boolean; isSessionReused(): boolean;
@@ -6198,30 +6277,91 @@ declare module "bun" {
setKeepAlive(enable?: boolean, initialDelay?: number): boolean; setKeepAlive(enable?: boolean, initialDelay?: number): boolean;
/** /**
* The number of bytes written to the socket. * The total number of bytes successfully written to the socket since it was established.
* This includes data currently buffered by the OS but not yet acknowledged by the remote peer.
*/ */
readonly bytesWritten: number; readonly bytesWritten: number;
/**
* Alias for `socket.end()`. Allows the socket to be used with `using` declarations
* for automatic resource management.
* @example
* ```ts
* async function processSocket() {
* using socket = await Bun.connect({ ... });
* socket.write("Data");
* // socket.end() is called automatically when exiting the scope
* }
* ```
*/
[Symbol.dispose](): void;
resume(): void; resume(): void;
pause(): void; pause(): void;
/**
* If this is a TLS Socket
*/
renegotiate(): void; renegotiate(): void;
/**
* Sets the verify mode of the socket.
*
* @param requestCert Whether to request a certificate.
* @param rejectUnauthorized Whether to reject unauthorized certificates.
*/
setVerifyMode(requestCert: boolean, rejectUnauthorized: boolean): void; setVerifyMode(requestCert: boolean, rejectUnauthorized: boolean): void;
getSession(): void; getSession(): void;
/**
* Sets the session of the socket.
*
* @param session The session to set.
*/
setSession(session: string | Buffer | BufferSource): void; setSession(session: string | Buffer | BufferSource): void;
/**
* Exports the keying material of the socket.
*
* @param length The length of the keying material to export.
* @param label The label of the keying material to export.
* @param context The context of the keying material to export.
*/
exportKeyingMaterial(length: number, label: string, context?: string | BufferSource): void; exportKeyingMaterial(length: number, label: string, context?: string | BufferSource): void;
/**
* Upgrades the socket to a TLS socket.
*
* @param options The options for the upgrade.
* @returns A tuple containing the raw socket and the TLS socket.
* @see {@link TLSUpgradeOptions}
*/
upgradeTLS<Data>(options: TLSUpgradeOptions<Data>): [raw: Socket<Data>, tls: Socket<Data>]; upgradeTLS<Data>(options: TLSUpgradeOptions<Data>): [raw: Socket<Data>, tls: Socket<Data>];
/**
* Closes the socket.
*
* This is a wrapper around `end()` and `shutdown()`.
*
* @see {@link end}
* @see {@link shutdown}
*/
close(): void; close(): void;
/**
* Returns the servername of the socket.
*
* @see {@link setServername}
*/
getServername(): string; getServername(): string;
/**
* Sets the servername of the socket.
*
* @see {@link getServername}
*/
setServername(name: string): void; setServername(name: string): void;
} }

View File

@@ -88,18 +88,19 @@ declare module "bun:test" {
*/ */
export function setSystemTime(now?: Date | number): ThisType<void>; export function setSystemTime(now?: Date | number): ThisType<void>;
interface Jest {
restoreAllMocks(): void;
clearAllMocks(): void;
fn<T extends (...args: any[]) => any>(func?: T): Mock<T>;
setSystemTime(now?: number | Date): void;
setTimeout(milliseconds: number): void;
useFakeTimers(): void;
useRealTimers(): void;
spyOn: spyOn;
}
export const jest: Jest;
export namespace jest { export namespace jest {
function restoreAllMocks(): void;
function clearAllMocks(): void;
function fn<T extends (...args: any[]) => any>(func?: T): Mock<T>;
function setSystemTime(now?: number | Date): void;
function setTimeout(milliseconds: number): void;
function useFakeTimers(): void;
function useRealTimers(): void;
function spyOn<T extends object, K extends keyof T>(
obj: T,
methodOrPropertyValue: K,
): Mock<Extract<T[K], (...args: any[]) => any>>;
/** /**
* Constructs the type of a mock function, e.g. the return type of `jest.fn()`. * Constructs the type of a mock function, e.g. the return type of `jest.fn()`.
*/ */

View File

@@ -1,4 +1,4 @@
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, type Mock, spyOn, test } from "bun:test"; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, jest, type Mock, spyOn, test } from "bun:test";
import { expectType } from "./utilities"; import { expectType } from "./utilities";
const hooks = [beforeAll, beforeEach, afterAll, afterEach]; const hooks = [beforeAll, beforeEach, afterAll, afterEach];
@@ -141,3 +141,6 @@ expectType<Mock<(name: string) => string>>(myNormalSpiedMethod);
const spy = spyOn(console, "log"); const spy = spyOn(console, "log");
expectType(spy.mock.calls).is<[message?: any, ...optionalParams: any[]][]>(); expectType(spy.mock.calls).is<[message?: any, ...optionalParams: any[]][]>();
jest.spyOn(console, "log");
jest.fn(() => 123 as const);