diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 2da4b78b93..f30f4a39d8 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -5871,31 +5871,76 @@ declare module "bun" { 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 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 - * @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) + * For optimal performance with multiple small writes, consider batching multiple + * writes together into a single `socket.write()` call. * - * 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 - * 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. + * // Send binary data + * const buffer = new Uint8Array([0x01, 0x02, 0x03]); + * 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; /** - * 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; /** - * 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; @@ -5922,20 +5967,33 @@ declare module "bun" { timeout(seconds: number): void; /** - * Forcefully close the socket. The other end may not receive all data, and - * the socket will be closed immediately. + * Forcefully closes the socket connection immediately. This is an abrupt termination, unlike the graceful shutdown initiated by `end()`. + * 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 - * `0` and then calls `close(2)`. + * @example + * ```ts + * socket.terminate(); + * ``` */ 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; @@ -5961,6 +6019,11 @@ declare module "bun" { /** * 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; @@ -5982,17 +6045,31 @@ declare module "bun" { /** * Remote IP address connected to the socket + * @example "192.168.1.100" | "2001:db8::1" */ readonly remoteAddress: string; + /** + * Remote port connected to the socket + * @example 8080 + */ readonly remotePort: number; + /** + * IP protocol family used for the local endpoint of the socket + * @example "IPv4" | "IPv6" + */ readonly localFamily: "IPv4" | "IPv6"; + /** + * Local IP address connected to the socket + * @example "192.168.1.100" | "2001:db8::1" + */ readonly localAddress: string; /** * local port connected to the socket + * @example 8080 */ readonly localPort: number; @@ -6156,6 +6233,8 @@ declare module "bun" { /** * See `Session Resumption` for more information. * @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; @@ -6198,30 +6277,91 @@ declare module "bun" { 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; + /** + * 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; pause(): void; + /** + * If this is a TLS Socket + */ 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; getSession(): void; + /** + * Sets the session of the socket. + * + * @param session The session to set. + */ 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; + /** + * 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(options: TLSUpgradeOptions): [raw: Socket, tls: Socket]; + /** + * Closes the socket. + * + * This is a wrapper around `end()` and `shutdown()`. + * + * @see {@link end} + * @see {@link shutdown} + */ close(): void; + /** + * Returns the servername of the socket. + * + * @see {@link setServername} + */ getServername(): string; + /** + * Sets the servername of the socket. + * + * @see {@link getServername} + */ setServername(name: string): void; } diff --git a/packages/bun-types/test.d.ts b/packages/bun-types/test.d.ts index 9c0e7cac34..7692df3f77 100644 --- a/packages/bun-types/test.d.ts +++ b/packages/bun-types/test.d.ts @@ -88,18 +88,19 @@ declare module "bun:test" { */ export function setSystemTime(now?: Date | number): ThisType; - interface Jest { - restoreAllMocks(): void; - clearAllMocks(): void; - fn any>(func?: T): Mock; - setSystemTime(now?: number | Date): void; - setTimeout(milliseconds: number): void; - useFakeTimers(): void; - useRealTimers(): void; - spyOn: spyOn; - } - export const jest: Jest; export namespace jest { + function restoreAllMocks(): void; + function clearAllMocks(): void; + function fn any>(func?: T): Mock; + function setSystemTime(now?: number | Date): void; + function setTimeout(milliseconds: number): void; + function useFakeTimers(): void; + function useRealTimers(): void; + function spyOn( + obj: T, + methodOrPropertyValue: K, + ): Mock any>>; + /** * Constructs the type of a mock function, e.g. the return type of `jest.fn()`. */ diff --git a/test/integration/bun-types/fixture/test.ts b/test/integration/bun-types/fixture/test.ts index eb4f710b65..388d3705ee 100644 --- a/test/integration/bun-types/fixture/test.ts +++ b/test/integration/bun-types/fixture/test.ts @@ -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"; const hooks = [beforeAll, beforeEach, afterAll, afterEach]; @@ -141,3 +141,6 @@ expectType string>>(myNormalSpiedMethod); const spy = spyOn(console, "log"); expectType(spy.mock.calls).is<[message?: any, ...optionalParams: any[]][]>(); + +jest.spyOn(console, "log"); +jest.fn(() => 123 as const);