aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/bun-types-tests.yml3
-rw-r--r--Makefile1
-rw-r--r--packages/bun-types/buffer.d.ts3
-rw-r--r--packages/bun-types/bun.d.ts28
-rw-r--r--packages/bun-types/child_process.d.ts2
-rw-r--r--packages/bun-types/crypto.d.ts1
-rw-r--r--packages/bun-types/dns.d.ts895
-rw-r--r--packages/bun-types/dns/promises.d.ts402
-rw-r--r--packages/bun-types/fs.d.ts2
-rw-r--r--packages/bun-types/fs/promises.d.ts1
-rw-r--r--packages/bun-types/globals.d.ts4
-rw-r--r--packages/bun-types/net.d.ts1007
-rw-r--r--packages/bun-types/package.json2
-rw-r--r--packages/bun-types/string_decoder.d.ts5
-rw-r--r--packages/bun-types/tsconfig.json1
-rw-r--r--packages/bun-types/zlib.d.ts1
-rw-r--r--src/bun.js/api/bun.zig21
-rw-r--r--src/bun.js/api/bun/socket.zig71
-rw-r--r--src/bun.js/api/server.zig130
-rw-r--r--src/bun.js/bindings/ImportMetaObject.cpp26
-rw-r--r--src/bun.js/bindings/ImportMetaObject.h4
-rw-r--r--src/bun.js/bindings/JSBufferList.cpp22
-rw-r--r--src/bun.js/bindings/JSBufferList.h9
-rw-r--r--src/bun.js/bindings/JSStringDecoder.cpp23
-rw-r--r--src/bun.js/bindings/JSStringDecoder.h6
-rw-r--r--src/bun.js/bindings/bindings.zig16
-rw-r--r--src/bun.js/bindings/headers-cpp.h2
-rw-r--r--src/bun.js/bindings/headers.h2
-rw-r--r--src/bun.js/javascript.zig81
-rw-r--r--src/bun.js/modules/NodeModuleModule.cpp44
-rw-r--r--src/bun.js/net.exports.js21
-rw-r--r--src/bun.js/test/jest.zig49
-rw-r--r--src/bun.zig1
-rw-r--r--src/cli/test_command.zig8
-rw-r--r--src/deps/uws.zig6
-rw-r--r--src/js_parser.zig5
-rw-r--r--src/options.zig2
-rw-r--r--src/runtime.zig3
-rw-r--r--test/bun.js/bun-test/nested-describes.test.ts38
-rw-r--r--test/bun.js/bun-write.test.js40
-rw-r--r--test/bun.js/child_process-node.test.js34
-rw-r--r--test/bun.js/esbuild-child_process.test.ts63
-rw-r--r--test/bun.js/esbuild-test.js37
-rw-r--r--test/bun.js/fetch.test.js44
-rw-r--r--test/bun.js/inspect.test.js37
-rw-r--r--test/bun.js/process.test.js8
-rw-r--r--test/bun.js/socket/socket.test.ts7
-rw-r--r--test/bun.js/transpiler.test.js24
-rw-r--r--test/bun.js/websocket-server.test.ts52
49 files changed, 2980 insertions, 314 deletions
diff --git a/.github/workflows/bun-types-tests.yml b/.github/workflows/bun-types-tests.yml
index 152a89197..a0aca829f 100644
--- a/.github/workflows/bun-types-tests.yml
+++ b/.github/workflows/bun-types-tests.yml
@@ -3,6 +3,7 @@ on:
push:
paths:
- packages/bun-types/**/*
+ branches: [main]
pull_request:
paths:
- packages/bun-types/**/*
@@ -22,7 +23,7 @@ jobs:
- name: Install bun
uses: xhyrom/setup-bun@v0.1.8
with:
- bun-version: canary
+ bun-version: latest
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install node
diff --git a/Makefile b/Makefile
index f3db46a4d..74498f76b 100644
--- a/Makefile
+++ b/Makefile
@@ -1378,6 +1378,7 @@ clean: clean-bindings
(cd $(BUN_DEPS_DIR)/boringssl && make clean) || echo "";
(cd $(BUN_DEPS_DIR)/picohttp && make clean) || echo "";
(cd $(BUN_DEPS_DIR)/zlib && make clean) || echo "";
+ (cd $(BUN_DEPS_DIR)/c-ares && rm -rf build && make clean) || echo "";
.PHONY: release-bindings
release-bindings: $(OBJ_DIR) $(OBJ_FILES) $(WEBCORE_OBJ_FILES) $(SQLITE_OBJ_FILES) $(NODE_OS_OBJ_FILES) $(BUILTINS_OBJ_FILES) $(IO_FILES) $(MODULES_OBJ_FILES)
diff --git a/packages/bun-types/buffer.d.ts b/packages/bun-types/buffer.d.ts
index a7de0cfe4..5a0dd071a 100644
--- a/packages/bun-types/buffer.d.ts
+++ b/packages/bun-types/buffer.d.ts
@@ -44,6 +44,7 @@
* @see [source](https://github.com/nodejs/node/blob/v18.0.0/lib/buffer.js)
*/
declare module "buffer" {
+ import { ArrayBufferView } from "bun";
export const INSPECT_MAX_BYTES: number;
export const kMaxLength: number;
export type TranscodeEncoding =
@@ -244,7 +245,7 @@ declare module "buffer" {
* @return The number of bytes contained within `string`.
*/
byteLength(
- string: string | ArrayBufferView | ArrayBuffer | SharedArrayBuffer,
+ string: string | ArrayBufferView | ArrayBufferLike,
encoding?: BufferEncoding,
): number;
/**
diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts
index 8eb664ce1..41deb9410 100644
--- a/packages/bun-types/bun.d.ts
+++ b/packages/bun-types/bun.d.ts
@@ -1,5 +1,3 @@
-import { Encoding } from "crypto";
-
interface VoidFunction {
(): void;
}
@@ -28,6 +26,8 @@ declare namespace Bun {
*
*/
declare module "bun" {
+ type ArrayBufferView = TypedArray | DataView;
+ import { Encoding as CryptoEncoding } from "crypto";
/**
* The environment variables of the process
*
@@ -1374,6 +1374,21 @@ declare module "bun" {
* @see {@link ServerWebSocket.publish}
*/
closeOnBackpressureLimit?: boolean;
+
+ /**
+ * Control whether or not ws.publish() should include the ServerWebSocket
+ * that published the message. This is enabled by default, but it was an API
+ * design mistake. A future version of Bun will change this default to
+ * `false` and eventually remove this option entirely. The better way to publish to all is to use {@link Server.publish}.
+ *
+ * if `true` or `undefined`, {@link ServerWebSocket.publish} will publish to all subscribers, including the websocket publishing the message.
+ *
+ * if `false`, {@link ServerWebSocket.publish} will publish to all subscribers excluding the websocket publishing the message.
+ *
+ * @default true
+ *
+ */
+ publishToSelf?: boolean;
}
interface GenericServeOptions {
@@ -2085,7 +2100,7 @@ declare module "bun" {
*
* @param input
*/
- update(input: StringOrBuffer, inputEncoding?: Encoding): CryptoHasher;
+ update(input: StringOrBuffer, inputEncoding?: CryptoEncoding): CryptoHasher;
/**
* Finalize the hash
@@ -2753,6 +2768,12 @@ declare module "bun" {
drain?(socket: Socket<Data>): void | Promise<void>;
/**
+ * When the socket has been shutdown from the other end, this function is
+ * called. This is a TCP FIN packet.
+ */
+ end?(socket: Socket<Data>): void | Promise<void>;
+
+ /**
* When the socket fails to be created, this function is called.
*
* The promise returned by `Bun.connect` rejects **after** this function is
@@ -3225,6 +3246,7 @@ type TypedArray =
| Uint32Array
| Float32Array
| Float64Array;
+
type TimeLike = string | number | Date;
type StringOrBuffer = string | TypedArray | ArrayBufferLike;
type PathLike = string | TypedArray | ArrayBufferLike | URL;
diff --git a/packages/bun-types/child_process.d.ts b/packages/bun-types/child_process.d.ts
index c36a7dd0d..04389986f 100644
--- a/packages/bun-types/child_process.d.ts
+++ b/packages/bun-types/child_process.d.ts
@@ -66,7 +66,7 @@
* @see [source](https://github.com/nodejs/node/blob/v18.0.0/lib/child_process.js)
*/
declare module "child_process" {
- import { SpawnOptions } from "bun";
+ import { SpawnOptions, ArrayBufferView } from "bun";
import { ObjectEncodingOptions } from "node:fs";
import { EventEmitter, Abortable } from "node:events";
diff --git a/packages/bun-types/crypto.d.ts b/packages/bun-types/crypto.d.ts
index 288bfe916..411deebd5 100644
--- a/packages/bun-types/crypto.d.ts
+++ b/packages/bun-types/crypto.d.ts
@@ -16,6 +16,7 @@
* @see [source](https://github.com/nodejs/node/blob/v18.0.0/lib/crypto.js)
*/
declare module "crypto" {
+ import { ArrayBufferView } from "bun";
import * as stream from "node:stream";
/**
* SPKAC is a Certificate Signing Request mechanism originally implemented by
diff --git a/packages/bun-types/dns.d.ts b/packages/bun-types/dns.d.ts
new file mode 100644
index 000000000..b5c9a777b
--- /dev/null
+++ b/packages/bun-types/dns.d.ts
@@ -0,0 +1,895 @@
+/**
+ * The `dns` module enables name resolution. For example, use it to look up IP
+ * addresses of host names.
+ *
+ * Although named for the [Domain Name System (DNS)](https://en.wikipedia.org/wiki/Domain_Name_System), it does not always use the
+ * DNS protocol for lookups. {@link lookup} uses the operating system
+ * facilities to perform name resolution. It may not need to perform any network
+ * communication. To perform name resolution the way other applications on the same
+ * system do, use {@link lookup}.
+ *
+ * ```js
+ * const dns = require('dns');
+ *
+ * dns.lookup('example.org', (err, address, family) => {
+ * console.log('address: %j family: IPv%s', address, family);
+ * });
+ * // address: "93.184.216.34" family: IPv4
+ * ```
+ *
+ * All other functions in the `dns` module connect to an actual DNS server to
+ * perform name resolution. They will always use the network to perform DNS
+ * queries. These functions do not use the same set of configuration files used by {@link lookup} (e.g. `/etc/hosts`). Use these functions to always perform
+ * DNS queries, bypassing other name-resolution facilities.
+ *
+ * ```js
+ * const dns = require('dns');
+ *
+ * dns.resolve4('archive.org', (err, addresses) => {
+ * if (err) throw err;
+ *
+ * console.log(`addresses: ${JSON.stringify(addresses)}`);
+ *
+ * addresses.forEach((a) => {
+ * dns.reverse(a, (err, hostnames) => {
+ * if (err) {
+ * throw err;
+ * }
+ * console.log(`reverse for ${a}: ${JSON.stringify(hostnames)}`);
+ * });
+ * });
+ * });
+ * ```
+ *
+ * See the `Implementation considerations section` for more information.
+ * @see [source](https://github.com/nodejs/node/blob/v18.0.0/lib/dns.js)
+ */
+declare module "dns" {
+ import * as dnsPromises from "node:dns/promises";
+ // Supported getaddrinfo flags.
+ export const ADDRCONFIG: number;
+ export const V4MAPPED: number;
+ /**
+ * If `dns.V4MAPPED` is specified, return resolved IPv6 addresses as
+ * well as IPv4 mapped IPv6 addresses.
+ */
+ export const ALL: number;
+ export interface LookupOptions {
+ family?: number | undefined;
+ // hints?: number | undefined;
+ // all?: boolean | undefined;
+ /**
+ * @default true
+ */
+ // verbatim?: boolean | undefined;
+ }
+ export interface LookupOneOptions extends LookupOptions {
+ // all?: false | undefined;
+ }
+ export interface LookupAllOptions extends LookupOptions {
+ // all: true;
+ }
+ export interface LookupAddress {
+ address: string;
+ family: number;
+ }
+ /**
+ * Resolves a host name (e.g. `'nodejs.org'`) into the first found A (IPv4) or
+ * AAAA (IPv6) record. All `option` properties are optional. If `options` is an
+ * integer, then it must be `4` or `6` – if `options` is not provided, then IPv4
+ * and IPv6 addresses are both returned if found.
+ *
+ * With the `all` option set to `true`, the arguments for `callback` change to`(err, addresses)`, with `addresses` being an array of objects with the
+ * properties `address` and `family`.
+ *
+ * On error, `err` is an `Error` object, where `err.code` is the error code.
+ * Keep in mind that `err.code` will be set to `'ENOTFOUND'` not only when
+ * the host name does not exist but also when the lookup fails in other ways
+ * such as no available file descriptors.
+ *
+ * `dns.lookup()` does not necessarily have anything to do with the DNS protocol.
+ * The implementation uses an operating system facility that can associate names
+ * with addresses, and vice versa. This implementation can have subtle but
+ * important consequences on the behavior of any Node.js program. Please take some
+ * time to consult the `Implementation considerations section` before using`dns.lookup()`.
+ *
+ * Example usage:
+ *
+ * ```js
+ * const dns = require('dns');
+ * const options = {
+ * family: 6,
+ * hints: dns.ADDRCONFIG | dns.V4MAPPED,
+ * };
+ * dns.lookup('example.com', options, (err, address, family) =>
+ * console.log('address: %j family: IPv%s', address, family));
+ * // address: "2606:2800:220:1:248:1893:25c8:1946" family: IPv6
+ *
+ * // When options.all is true, the result will be an Array.
+ * options.all = true;
+ * dns.lookup('example.com', options, (err, addresses) =>
+ * console.log('addresses: %j', addresses));
+ * // addresses: [{"address":"2606:2800:220:1:248:1893:25c8:1946","family":6}]
+ * ```
+ *
+ * If this method is invoked as its `util.promisify()` ed version, and `all`is not set to `true`, it returns a `Promise` for an `Object` with `address` and`family` properties.
+ * @since v0.1.90
+ */
+ export function lookup(
+ hostname: string,
+ family: number,
+ callback: (
+ err: ErrnoException | null,
+ address: string,
+ family: number,
+ ) => void,
+ ): void;
+ // export function lookup(
+ // hostname: string,
+ // options: LookupOneOptions,
+ // callback: (
+ // err: ErrnoException | null,
+ // address: string,
+ // family: number,
+ // ) => void,
+ // ): void;
+ // export function lookup(
+ // hostname: string,
+ // options: LookupAllOptions,
+ // callback: (
+ // err: ErrnoException | null,
+ // addresses: LookupAddress[],
+ // ) => void,
+ // ): void;
+ export function lookup(
+ hostname: string,
+ options: LookupOptions,
+ callback: (
+ err: ErrnoException | null,
+ address: string | LookupAddress[],
+ family: number,
+ ) => void,
+ ): void;
+ export function lookup(
+ hostname: string,
+ callback: (
+ err: ErrnoException | null,
+ address: string,
+ family: number,
+ ) => void,
+ ): void;
+ // export namespace lookup {
+ // function __promisify__(
+ // hostname: string,
+ // options: LookupAllOptions,
+ // ): Promise<LookupAddress[]>;
+ // function __promisify__(
+ // hostname: string,
+ // options?: LookupOneOptions | number,
+ // ): Promise<LookupAddress>;
+ // function __promisify__(
+ // hostname: string,
+ // options: LookupOptions,
+ // ): Promise<LookupAddress | LookupAddress[]>;
+ // }
+ /**
+ * Resolves the given `address` and `port` into a host name and service using
+ * the operating system's underlying `getnameinfo` implementation.
+ *
+ * If `address` is not a valid IP address, a `TypeError` will be thrown.
+ * The `port` will be coerced to a number. If it is not a legal port, a `TypeError`will be thrown.
+ *
+ * On an error, `err` is an `Error` object, where `err.code` is the error code.
+ *
+ * ```js
+ * const dns = require('dns');
+ * dns.lookupService('127.0.0.1', 22, (err, hostname, service) => {
+ * console.log(hostname, service);
+ * // Prints: localhost ssh
+ * });
+ * ```
+ *
+ * If this method is invoked as its `util.promisify()` ed version, it returns a`Promise` for an `Object` with `hostname` and `service` properties.
+ * @since v0.11.14
+ */
+ export function lookupService(
+ address: string,
+ port: number,
+ callback: (
+ err: ErrnoException | null,
+ hostname: string,
+ service: string,
+ ) => void,
+ ): void;
+ // export namespace lookupService {
+ // function __promisify__(
+ // address: string,
+ // port: number,
+ // ): Promise<{
+ // hostname: string;
+ // service: string;
+ // }>;
+ // }
+ export interface ResolveOptions {
+ ttl: boolean;
+ }
+ export interface ResolveWithTtlOptions extends ResolveOptions {
+ ttl: true;
+ }
+ export interface RecordWithTtl {
+ address: string;
+ ttl: number;
+ }
+ /** @deprecated Use `AnyARecord` or `AnyAaaaRecord` instead. */
+ export type AnyRecordWithTtl = AnyARecord | AnyAaaaRecord;
+ export interface AnyARecord extends RecordWithTtl {
+ type: "A";
+ }
+ export interface AnyAaaaRecord extends RecordWithTtl {
+ type: "AAAA";
+ }
+ export interface CaaRecord {
+ critial: number;
+ issue?: string | undefined;
+ issuewild?: string | undefined;
+ iodef?: string | undefined;
+ contactemail?: string | undefined;
+ contactphone?: string | undefined;
+ }
+ export interface MxRecord {
+ priority: number;
+ exchange: string;
+ }
+ export interface AnyMxRecord extends MxRecord {
+ type: "MX";
+ }
+ export interface NaptrRecord {
+ flags: string;
+ service: string;
+ regexp: string;
+ replacement: string;
+ order: number;
+ preference: number;
+ }
+ export interface AnyNaptrRecord extends NaptrRecord {
+ type: "NAPTR";
+ }
+ export interface SoaRecord {
+ nsname: string;
+ hostmaster: string;
+ serial: number;
+ refresh: number;
+ retry: number;
+ expire: number;
+ minttl: number;
+ }
+ export interface AnySoaRecord extends SoaRecord {
+ type: "SOA";
+ }
+ export interface SrvRecord {
+ priority: number;
+ weight: number;
+ port: number;
+ name: string;
+ }
+ export interface AnySrvRecord extends SrvRecord {
+ type: "SRV";
+ }
+ export interface AnyTxtRecord {
+ type: "TXT";
+ entries: string[];
+ }
+ export interface AnyNsRecord {
+ type: "NS";
+ value: string;
+ }
+ export interface AnyPtrRecord {
+ type: "PTR";
+ value: string;
+ }
+ export interface AnyCnameRecord {
+ type: "CNAME";
+ value: string;
+ }
+ export type AnyRecord =
+ | AnyARecord
+ | AnyAaaaRecord
+ | AnyCnameRecord
+ | AnyMxRecord
+ | AnyNaptrRecord
+ | AnyNsRecord
+ | AnyPtrRecord
+ | AnySoaRecord
+ | AnySrvRecord
+ | AnyTxtRecord;
+ /**
+ * Uses the DNS protocol to resolve a host name (e.g. `'nodejs.org'`) into an array
+ * of the resource records. The `callback` function has arguments`(err, records)`. When successful, `records` will be an array of resource
+ * records. The type and structure of individual results varies based on `rrtype`:
+ *
+ * <omitted>
+ *
+ * On error, `err` is an `Error` object, where `err.code` is one of the `DNS error codes`.
+ * @since v0.1.27
+ * @param hostname Host name to resolve.
+ * @param [rrtype='A'] Resource record type.
+ */
+ export function resolve(
+ hostname: string,
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "A",
+ // callback: (err: ErrnoException | null, addresses: string[]) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "AAAA",
+ // callback: (err: ErrnoException | null, addresses: string[]) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "ANY",
+ // callback: (
+ // err: ErrnoException | null,
+ // addresses: AnyRecord[],
+ // ) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "CNAME",
+ // callback: (err: ErrnoException | null, addresses: string[]) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "MX",
+ // callback: (
+ // err: ErrnoException | null,
+ // addresses: MxRecord[],
+ // ) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "NAPTR",
+ // callback: (
+ // err: ErrnoException | null,
+ // addresses: NaptrRecord[],
+ // ) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "NS",
+ // callback: (err: ErrnoException | null, addresses: string[]) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "PTR",
+ // callback: (err: ErrnoException | null, addresses: string[]) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "SOA",
+ // callback: (err: ErrnoException | null, addresses: SoaRecord) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "SRV",
+ // callback: (
+ // err: ErrnoException | null,
+ // addresses: SrvRecord[],
+ // ) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: "TXT",
+ // callback: (
+ // err: ErrnoException | null,
+ // addresses: string[][],
+ // ) => void,
+ // ): void;
+ // export function resolve(
+ // hostname: string,
+ // rrtype: string,
+ // callback: (
+ // err: ErrnoException | null,
+ // addresses:
+ // | string[]
+ // | MxRecord[]
+ // | NaptrRecord[]
+ // | SoaRecord
+ // | SrvRecord[]
+ // | string[][]
+ // | AnyRecord[],
+ // ) => void,
+ // ): void;
+ // export namespace resolve {
+ // function __promisify__(
+ // hostname: string,
+ // rrtype?: "A" | "AAAA" | "CNAME" | "NS" | "PTR",
+ // ): Promise<string[]>;
+ // function __promisify__(
+ // hostname: string,
+ // rrtype: "ANY",
+ // ): Promise<AnyRecord[]>;
+ // function __promisify__(hostname: string, rrtype: "MX"): Promise<MxRecord[]>;
+ // function __promisify__(
+ // hostname: string,
+ // rrtype: "NAPTR",
+ // ): Promise<NaptrRecord[]>;
+ // function __promisify__(hostname: string, rrtype: "SOA"): Promise<SoaRecord>;
+ // function __promisify__(
+ // hostname: string,
+ // rrtype: "SRV",
+ // ): Promise<SrvRecord[]>;
+ // function __promisify__(
+ // hostname: string,
+ // rrtype: "TXT",
+ // ): Promise<string[][]>;
+ // function __promisify__(
+ // hostname: string,
+ // rrtype: string,
+ // ): Promise<
+ // | string[]
+ // | MxRecord[]
+ // | NaptrRecord[]
+ // | SoaRecord
+ // | SrvRecord[]
+ // | string[][]
+ // | AnyRecord[]
+ // >;
+ // }
+ /**
+ * Uses the DNS protocol to resolve a IPv4 addresses (`A` records) for the`hostname`. The `addresses` argument passed to the `callback` function
+ * will contain an array of IPv4 addresses (e.g.`['74.125.79.104', '74.125.79.105', '74.125.79.106']`).
+ * @since v0.1.16
+ * @param hostname Host name to resolve.
+ */
+ export function resolve4(
+ hostname: string,
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export function resolve4(
+ hostname: string,
+ options: ResolveWithTtlOptions,
+ callback: (err: ErrnoException | null, addresses: RecordWithTtl[]) => void,
+ ): void;
+ export function resolve4(
+ hostname: string,
+ options: ResolveOptions,
+ callback: (
+ err: ErrnoException | null,
+ addresses: string[] | RecordWithTtl[],
+ ) => void,
+ ): void;
+ // export namespace resolve4 {
+ // function __promisify__(hostname: string): Promise<string[]>;
+ // function __promisify__(
+ // hostname: string,
+ // options: ResolveWithTtlOptions,
+ // ): Promise<RecordWithTtl[]>;
+ // function __promisify__(
+ // hostname: string,
+ // options?: ResolveOptions,
+ // ): Promise<string[] | RecordWithTtl[]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve a IPv6 addresses (`AAAA` records) for the`hostname`. The `addresses` argument passed to the `callback` function
+ * will contain an array of IPv6 addresses.
+ * @since v0.1.16
+ * @param hostname Host name to resolve.
+ */
+ export function resolve6(
+ hostname: string,
+ callback: (err: ErrnoException | null, addresses: string[]) => void,
+ ): void;
+ export function resolve6(
+ hostname: string,
+ options: ResolveWithTtlOptions,
+ callback: (err: ErrnoException | null, addresses: RecordWithTtl[]) => void,
+ ): void;
+ export function resolve6(
+ hostname: string,
+ options: ResolveOptions,
+ callback: (
+ err: ErrnoException | null,
+ addresses: string[] | RecordWithTtl[],
+ ) => void,
+ ): void;
+ // export namespace resolve6 {
+ // function __promisify__(hostname: string): Promise<string[]>;
+ // function __promisify__(
+ // hostname: string,
+ // options: ResolveWithTtlOptions,
+ // ): Promise<RecordWithTtl[]>;
+ // function __promisify__(
+ // hostname: string,
+ // options?: ResolveOptions,
+ // ): Promise<string[] | RecordWithTtl[]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve `CNAME` records for the `hostname`. The`addresses` argument passed to the `callback` function
+ * will contain an array of canonical name records available for the `hostname`(e.g. `['bar.example.com']`).
+ * @since v0.3.2
+ */
+ // export function resolveCname(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, addresses: string[]) => void,
+ // ): void;
+ // export namespace resolveCname {
+ // function __promisify__(hostname: string): Promise<string[]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve `CAA` records for the `hostname`. The`addresses` argument passed to the `callback` function
+ * will contain an array of certification authority authorization records
+ * available for the `hostname` (e.g. `[{critical: 0, iodef: 'mailto:pki@example.com'}, {critical: 128, issue: 'pki.example.com'}]`).
+ * @since v15.0.0, v14.17.0
+ */
+ // export function resolveCaa(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, records: CaaRecord[]) => void,
+ // ): void;
+ // export namespace resolveCaa {
+ // function __promisify__(hostname: string): Promise<CaaRecord[]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve mail exchange records (`MX` records) for the`hostname`. The `addresses` argument passed to the `callback` function will
+ * contain an array of objects containing both a `priority` and `exchange`property (e.g. `[{priority: 10, exchange: 'mx.example.com'}, ...]`).
+ * @since v0.1.27
+ */
+ // export function resolveMx(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, addresses: MxRecord[]) => void,
+ // ): void;
+ // export namespace resolveMx {
+ // function __promisify__(hostname: string): Promise<MxRecord[]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve regular expression based records (`NAPTR`records) for the `hostname`. The `addresses` argument passed to the `callback`function will contain an array of
+ * objects with the following properties:
+ *
+ * * `flags`
+ * * `service`
+ * * `regexp`
+ * * `replacement`
+ * * `order`
+ * * `preference`
+ *
+ * ```js
+ * {
+ * flags: 's',
+ * service: 'SIP+D2U',
+ * regexp: '',
+ * replacement: '_sip._udp.example.com',
+ * order: 30,
+ * preference: 100
+ * }
+ * ```
+ * @since v0.9.12
+ */
+ // export function resolveNaptr(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, addresses: NaptrRecord[]) => void,
+ // ): void;
+ // export namespace resolveNaptr {
+ // function __promisify__(hostname: string): Promise<NaptrRecord[]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve name server records (`NS` records) for the`hostname`. The `addresses` argument passed to the `callback` function will
+ * contain an array of name server records available for `hostname`(e.g. `['ns1.example.com', 'ns2.example.com']`).
+ * @since v0.1.90
+ */
+ // export function resolveNs(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, addresses: string[]) => void,
+ // ): void;
+ // export namespace resolveNs {
+ // function __promisify__(hostname: string): Promise<string[]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve pointer records (`PTR` records) for the`hostname`. The `addresses` argument passed to the `callback` function will
+ * be an array of strings containing the reply records.
+ * @since v6.0.0
+ */
+ // export function resolvePtr(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, addresses: string[]) => void,
+ // ): void;
+ // export namespace resolvePtr {
+ // function __promisify__(hostname: string): Promise<string[]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve a start of authority record (`SOA` record) for
+ * the `hostname`. The `address` argument passed to the `callback` function will
+ * be an object with the following properties:
+ *
+ * * `nsname`
+ * * `hostmaster`
+ * * `serial`
+ * * `refresh`
+ * * `retry`
+ * * `expire`
+ * * `minttl`
+ *
+ * ```js
+ * {
+ * nsname: 'ns.example.com',
+ * hostmaster: 'root.example.com',
+ * serial: 2013101809,
+ * refresh: 10000,
+ * retry: 2400,
+ * expire: 604800,
+ * minttl: 3600
+ * }
+ * ```
+ * @since v0.11.10
+ */
+ // export function resolveSoa(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, address: SoaRecord) => void,
+ // ): void;
+ // export namespace resolveSoa {
+ // function __promisify__(hostname: string): Promise<SoaRecord>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve service records (`SRV` records) for the`hostname`. The `addresses` argument passed to the `callback` function will
+ * be an array of objects with the following properties:
+ *
+ * * `priority`
+ * * `weight`
+ * * `port`
+ * * `name`
+ *
+ * ```js
+ * {
+ * priority: 10,
+ * weight: 5,
+ * port: 21223,
+ * name: 'service.example.com'
+ * }
+ * ```
+ * @since v0.1.27
+ */
+ // export function resolveSrv(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, addresses: SrvRecord[]) => void,
+ // ): void;
+ // export namespace resolveSrv {
+ // function __promisify__(hostname: string): Promise<SrvRecord[]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve text queries (`TXT` records) for the`hostname`. The `records` argument passed to the `callback` function is a
+ * two-dimensional array of the text records available for `hostname` (e.g.`[ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ]`). Each sub-array contains TXT chunks of
+ * one record. Depending on the use case, these could be either joined together or
+ * treated separately.
+ * @since v0.1.27
+ */
+ // export function resolveTxt(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, addresses: string[][]) => void,
+ // ): void;
+ // export namespace resolveTxt {
+ // function __promisify__(hostname: string): Promise<string[][]>;
+ // }
+ /**
+ * Uses the DNS protocol to resolve all records (also known as `ANY` or `*` query).
+ * The `ret` argument passed to the `callback` function will be an array containing
+ * various types of records. Each object has a property `type` that indicates the
+ * type of the current record. And depending on the `type`, additional properties
+ * will be present on the object:
+ *
+ * <omitted>
+ *
+ * Here is an example of the `ret` object passed to the callback:
+ *
+ * ```js
+ * [ { type: 'A', address: '127.0.0.1', ttl: 299 },
+ * { type: 'CNAME', value: 'example.com' },
+ * { type: 'MX', exchange: 'alt4.aspmx.l.example.com', priority: 50 },
+ * { type: 'NS', value: 'ns1.example.com' },
+ * { type: 'TXT', entries: [ 'v=spf1 include:_spf.example.com ~all' ] },
+ * { type: 'SOA',
+ * nsname: 'ns1.example.com',
+ * hostmaster: 'admin.example.com',
+ * serial: 156696742,
+ * refresh: 900,
+ * retry: 900,
+ * expire: 1800,
+ * minttl: 60 } ]
+ * ```
+ *
+ * DNS server operators may choose not to respond to `ANY`queries. It may be better to call individual methods like {@link resolve4},{@link resolveMx}, and so on. For more details, see [RFC
+ * 8482](https://tools.ietf.org/html/rfc8482).
+ */
+ // export function resolveAny(
+ // hostname: string,
+ // callback: (err: ErrnoException | null, addresses: AnyRecord[]) => void,
+ // ): void;
+ // export namespace resolveAny {
+ // function __promisify__(hostname: string): Promise<AnyRecord[]>;
+ // }
+ /**
+ * Performs a reverse DNS query that resolves an IPv4 or IPv6 address to an
+ * array of host names.
+ *
+ * On error, `err` is an `Error` object, where `err.code` is
+ * one of the `DNS error codes`.
+ * @since v0.1.16
+ */
+ // export function reverse(
+ // ip: string,
+ // callback: (err: ErrnoException | null, hostnames: string[]) => void,
+ // ): void;
+ /**
+ * Sets the IP address and port of servers to be used when performing DNS
+ * resolution. The `servers` argument is an array of [RFC 5952](https://tools.ietf.org/html/rfc5952#section-6) formatted
+ * addresses. If the port is the IANA default DNS port (53) it can be omitted.
+ *
+ * ```js
+ * dns.setServers([
+ * '4.4.4.4',
+ * '[2001:4860:4860::8888]',
+ * '4.4.4.4:1053',
+ * '[2001:4860:4860::8888]:1053',
+ * ]);
+ * ```
+ *
+ * An error will be thrown if an invalid address is provided.
+ *
+ * The `dns.setServers()` method must not be called while a DNS query is in
+ * progress.
+ *
+ * The {@link setServers} method affects only {@link resolve},`dns.resolve*()` and {@link reverse} (and specifically _not_ {@link lookup}).
+ *
+ * This method works much like [resolve.conf](https://man7.org/linux/man-pages/man5/resolv.conf.5.html).
+ * That is, if attempting to resolve with the first server provided results in a`NOTFOUND` error, the `resolve()` method will _not_ attempt to resolve with
+ * subsequent servers provided. Fallback DNS servers will only be used if the
+ * earlier ones time out or result in some other error.
+ * @since v0.11.3
+ * @param servers array of `RFC 5952` formatted addresses
+ */
+ // export function setServers(servers: ReadonlyArray<string>): void;
+ /**
+ * Returns an array of IP address strings, formatted according to [RFC 5952](https://tools.ietf.org/html/rfc5952#section-6),
+ * that are currently configured for DNS resolution. A string will include a port
+ * section if a custom port is used.
+ *
+ * ```js
+ * [
+ * '4.4.4.4',
+ * '2001:4860:4860::8888',
+ * '4.4.4.4:1053',
+ * '[2001:4860:4860::8888]:1053',
+ * ]
+ * ```
+ * @since v0.11.3
+ */
+ // export function getServers(): string[];
+ /**
+ * Set the default value of `verbatim` in {@link lookup} and `dnsPromises.lookup()`. The value could be:
+ *
+ * * `ipv4first`: sets default `verbatim` `false`.
+ * * `verbatim`: sets default `verbatim` `true`.
+ *
+ * The default is `ipv4first` and {@link setDefaultResultOrder} have higher
+ * priority than `--dns-result-order`. When using `worker threads`,{@link setDefaultResultOrder} from the main thread won't affect the default
+ * dns orders in workers.
+ * @since v16.4.0, v14.18.0
+ * @param order must be `'ipv4first'` or `'verbatim'`.
+ */
+ // export function setDefaultResultOrder(order: "ipv4first" | "verbatim"): void;
+ // Error codes
+ export const NODATA: string;
+ export const FORMERR: string;
+ export const SERVFAIL: string;
+ export const NOTFOUND: string;
+ export const NOTIMP: string;
+ export const REFUSED: string;
+ export const BADQUERY: string;
+ export const BADNAME: string;
+ export const BADFAMILY: string;
+ export const BADRESP: string;
+ export const CONNREFUSED: string;
+ export const TIMEOUT: string;
+ export const EOF: string;
+ export const FILE: string;
+ export const NOMEM: string;
+ export const DESTRUCTION: string;
+ export const BADSTR: string;
+ export const BADFLAGS: string;
+ export const NONAME: string;
+ export const BADHINTS: string;
+ export const NOTINITIALIZED: string;
+ export const LOADIPHLPAPI: string;
+ export const ADDRGETNETWORKPARAMS: string;
+ export const CANCELLED: string;
+ export interface ResolverOptions {
+ timeout?: number | undefined;
+ /**
+ * @default 4
+ */
+ tries?: number;
+ }
+ /**
+ * An independent resolver for DNS requests.
+ *
+ * Creating a new resolver uses the default server settings. Setting
+ * the servers used for a resolver using `resolver.setServers()` does not affect
+ * other resolvers:
+ *
+ * ```js
+ * const { Resolver } = require('dns');
+ * const resolver = new Resolver();
+ * resolver.setServers(['4.4.4.4']);
+ *
+ * // This request will use the server at 4.4.4.4, independent of global settings.
+ * resolver.resolve4('example.org', (err, addresses) => {
+ * // ...
+ * });
+ * ```
+ *
+ * The following methods from the `dns` module are available:
+ *
+ * * `resolver.getServers()`
+ * * `resolver.resolve()`
+ * * `resolver.resolve4()`
+ * * `resolver.resolve6()`
+ * * `resolver.resolveAny()`
+ * * `resolver.resolveCaa()`
+ * * `resolver.resolveCname()`
+ * * `resolver.resolveMx()`
+ * * `resolver.resolveNaptr()`
+ * * `resolver.resolveNs()`
+ * * `resolver.resolvePtr()`
+ * * `resolver.resolveSoa()`
+ * * `resolver.resolveSrv()`
+ * * `resolver.resolveTxt()`
+ * * `resolver.reverse()`
+ * * `resolver.setServers()`
+ * @since v8.3.0
+ */
+ export class Resolver {
+ constructor(options?: ResolverOptions);
+ /**
+ * Cancel all outstanding DNS queries made by this resolver. The corresponding
+ * callbacks will be called with an error with code `ECANCELLED`.
+ * @since v8.3.0
+ */
+ cancel(): void;
+ // getServers: typeof getServers;
+ resolve: typeof resolve;
+ resolve4: typeof resolve4;
+ resolve6: typeof resolve6;
+ // resolveAny: typeof resolveAny;
+ // resolveCname: typeof resolveCname;
+ // resolveMx: typeof resolveMx;
+ // resolveNaptr: typeof resolveNaptr;
+ // resolveNs: typeof resolveNs;
+ // resolvePtr: typeof resolvePtr;
+ // resolveSoa: typeof resolveSoa;
+ // resolveSrv: typeof resolveSrv;
+ // resolveTxt: typeof resolveTxt;
+ // reverse: typeof reverse;
+ /**
+ * The resolver instance will send its requests from the specified IP address.
+ * This allows programs to specify outbound interfaces when used on multi-homed
+ * systems.
+ *
+ * If a v4 or v6 address is not specified, it is set to the default, and the
+ * operating system will choose a local address automatically.
+ *
+ * The resolver will use the v4 local address when making requests to IPv4 DNS
+ * servers, and the v6 local address when making requests to IPv6 DNS servers.
+ * The `rrtype` of resolution requests has no impact on the local address used.
+ * @since v15.1.0, v14.17.0
+ * @param [ipv4='0.0.0.0'] A string representation of an IPv4 address.
+ * @param [ipv6='::0'] A string representation of an IPv6 address.
+ */
+ // setLocalAddress(ipv4?: string, ipv6?: string): void;
+ // setServers: typeof setServers;
+ }
+ export { dnsPromises as promises };
+}
+declare module "node:dns" {
+ export * from "dns";
+}
diff --git a/packages/bun-types/dns/promises.d.ts b/packages/bun-types/dns/promises.d.ts
new file mode 100644
index 000000000..6460128b2
--- /dev/null
+++ b/packages/bun-types/dns/promises.d.ts
@@ -0,0 +1,402 @@
+/**
+ * The `dns.promises` API provides an alternative set of asynchronous DNS methods
+ * that return `Promise` objects rather than using callbacks. The API is accessible
+ * via `require('dns').promises` or `require('dns/promises')`.
+ * @since v10.6.0
+ */
+declare module "dns/promises" {
+ import {
+ LookupAddress,
+ LookupOneOptions,
+ LookupAllOptions,
+ LookupOptions,
+ // AnyRecord,
+ // CaaRecord,
+ // MxRecord,
+ // NaptrRecord,
+ // SoaRecord,
+ // SrvRecord,
+ ResolveWithTtlOptions,
+ RecordWithTtl,
+ ResolveOptions,
+ ResolverOptions,
+ } from "node:dns";
+ /**
+ * Returns an array of IP address strings, formatted according to [RFC 5952](https://tools.ietf.org/html/rfc5952#section-6),
+ * that are currently configured for DNS resolution. A string will include a port
+ * section if a custom port is used.
+ *
+ * ```js
+ * [
+ * '4.4.4.4',
+ * '2001:4860:4860::8888',
+ * '4.4.4.4:1053',
+ * '[2001:4860:4860::8888]:1053',
+ * ]
+ * ```
+ * @since v10.6.0
+ */
+ // function getServers(): string[];
+ /**
+ * Resolves a host name (e.g. `'nodejs.org'`) into the first found A (IPv4) or
+ * AAAA (IPv6) record. All `option` properties are optional. If `options` is an
+ * integer, then it must be `4` or `6` – if `options` is not provided, then IPv4
+ * and IPv6 addresses are both returned if found.
+ *
+ * With the `all` option set to `true`, the `Promise` is resolved with `addresses`being an array of objects with the properties `address` and `family`.
+ *
+ * On error, the `Promise` is rejected with an `Error` object, where `err.code`is the error code.
+ * Keep in mind that `err.code` will be set to `'ENOTFOUND'` not only when
+ * the host name does not exist but also when the lookup fails in other ways
+ * such as no available file descriptors.
+ *
+ * `dnsPromises.lookup()` does not necessarily have anything to do with the DNS
+ * protocol. The implementation uses an operating system facility that can
+ * associate names with addresses, and vice versa. This implementation can have
+ * subtle but important consequences on the behavior of any Node.js program. Please
+ * take some time to consult the `Implementation considerations section` before
+ * using `dnsPromises.lookup()`.
+ *
+ * Example usage:
+ *
+ * ```js
+ * const dns = require('dns');
+ * const dnsPromises = dns.promises;
+ * const options = {
+ * family: 6,
+ * hints: dns.ADDRCONFIG | dns.V4MAPPED,
+ * };
+ *
+ * dnsPromises.lookup('example.com', options).then((result) => {
+ * console.log('address: %j family: IPv%s', result.address, result.family);
+ * // address: "2606:2800:220:1:248:1893:25c8:1946" family: IPv6
+ * });
+ *
+ * // When options.all is true, the result will be an Array.
+ * options.all = true;
+ * dnsPromises.lookup('example.com', options).then((result) => {
+ * console.log('addresses: %j', result);
+ * // addresses: [{"address":"2606:2800:220:1:248:1893:25c8:1946","family":6}]
+ * });
+ * ```
+ * @since v10.6.0
+ */
+ function lookup(hostname: string, family: number): Promise<LookupAddress>;
+ function lookup(
+ hostname: string,
+ options: LookupOneOptions,
+ ): Promise<LookupAddress>;
+ function lookup(
+ hostname: string,
+ options: LookupAllOptions,
+ ): Promise<LookupAddress[]>;
+ function lookup(
+ hostname: string,
+ options: LookupOptions,
+ ): Promise<LookupAddress | LookupAddress[]>;
+ function lookup(hostname: string): Promise<LookupAddress>;
+ /**
+ * Resolves the given `address` and `port` into a host name and service using
+ * the operating system's underlying `getnameinfo` implementation.
+ *
+ * If `address` is not a valid IP address, a `TypeError` will be thrown.
+ * The `port` will be coerced to a number. If it is not a legal port, a `TypeError`will be thrown.
+ *
+ * On error, the `Promise` is rejected with an `Error` object, where `err.code`is the error code.
+ *
+ * ```js
+ * const dnsPromises = require('dns').promises;
+ * dnsPromises.lookupService('127.0.0.1', 22).then((result) => {
+ * console.log(result.hostname, result.service);
+ * // Prints: localhost ssh
+ * });
+ * ```
+ * @since v10.6.0
+ */
+ function lookupService(
+ address: string,
+ port: number,
+ ): Promise<{
+ hostname: string;
+ service: string;
+ }>;
+ /**
+ * Uses the DNS protocol to resolve a host name (e.g. `'nodejs.org'`) into an array
+ * of the resource records. When successful, the `Promise` is resolved with an
+ * array of resource records. The type and structure of individual results vary
+ * based on `rrtype`:
+ *
+ * <omitted>
+ *
+ * On error, the `Promise` is rejected with an `Error` object, where `err.code`is one of the `DNS error codes`.
+ * @since v10.6.0
+ * @param hostname Host name to resolve.
+ * @param [rrtype='A'] Resource record type.
+ */
+ function resolve(hostname: string): Promise<string[]>;
+ // function resolve(hostname: string, rrtype: "A"): Promise<string[]>;
+ // function resolve(hostname: string, rrtype: "AAAA"): Promise<string[]>;
+ // function resolve(hostname: string, rrtype: "ANY"): Promise<AnyRecord[]>;
+ // function resolve(hostname: string, rrtype: "CAA"): Promise<CaaRecord[]>;
+ // function resolve(hostname: string, rrtype: "CNAME"): Promise<string[]>;
+ // function resolve(hostname: string, rrtype: "MX"): Promise<MxRecord[]>;
+ // function resolve(hostname: string, rrtype: "NAPTR"): Promise<NaptrRecord[]>;
+ // function resolve(hostname: string, rrtype: "NS"): Promise<string[]>;
+ // function resolve(hostname: string, rrtype: "PTR"): Promise<string[]>;
+ // function resolve(hostname: string, rrtype: "SOA"): Promise<SoaRecord>;
+ // function resolve(hostname: string, rrtype: "SRV"): Promise<SrvRecord[]>;
+ // function resolve(hostname: string, rrtype: "TXT"): Promise<string[][]>;
+ // function resolve(
+ // hostname: string,
+ // rrtype: string,
+ // ): Promise<
+ // | string[]
+ // | MxRecord[]
+ // | NaptrRecord[]
+ // | SoaRecord
+ // | SrvRecord[]
+ // | string[][]
+ // | AnyRecord[]
+ // >;
+ /**
+ * Uses the DNS protocol to resolve IPv4 addresses (`A` records) for the`hostname`. On success, the `Promise` is resolved with an array of IPv4
+ * addresses (e.g. `['74.125.79.104', '74.125.79.105', '74.125.79.106']`).
+ * @since v10.6.0
+ * @param hostname Host name to resolve.
+ */
+ function resolve4(hostname: string): Promise<string[]>;
+ function resolve4(
+ hostname: string,
+ options: ResolveWithTtlOptions,
+ ): Promise<RecordWithTtl[]>;
+ function resolve4(
+ hostname: string,
+ options: ResolveOptions,
+ ): Promise<string[] | RecordWithTtl[]>;
+ /**
+ * Uses the DNS protocol to resolve IPv6 addresses (`AAAA` records) for the`hostname`. On success, the `Promise` is resolved with an array of IPv6
+ * addresses.
+ * @since v10.6.0
+ * @param hostname Host name to resolve.
+ */
+ function resolve6(hostname: string): Promise<string[]>;
+ function resolve6(
+ hostname: string,
+ options: ResolveWithTtlOptions,
+ ): Promise<RecordWithTtl[]>;
+ function resolve6(
+ hostname: string,
+ options: ResolveOptions,
+ ): Promise<string[] | RecordWithTtl[]>;
+ /**
+ * Uses the DNS protocol to resolve all records (also known as `ANY` or `*` query).
+ * On success, the `Promise` is resolved with an array containing various types of
+ * records. Each object has a property `type` that indicates the type of the
+ * current record. And depending on the `type`, additional properties will be
+ * present on the object:
+ *
+ * <omitted>
+ *
+ * Here is an example of the result object:
+ *
+ * ```js
+ * [ { type: 'A', address: '127.0.0.1', ttl: 299 },
+ * { type: 'CNAME', value: 'example.com' },
+ * { type: 'MX', exchange: 'alt4.aspmx.l.example.com', priority: 50 },
+ * { type: 'NS', value: 'ns1.example.com' },
+ * { type: 'TXT', entries: [ 'v=spf1 include:_spf.example.com ~all' ] },
+ * { type: 'SOA',
+ * nsname: 'ns1.example.com',
+ * hostmaster: 'admin.example.com',
+ * serial: 156696742,
+ * refresh: 900,
+ * retry: 900,
+ * expire: 1800,
+ * minttl: 60 } ]
+ * ```
+ * @since v10.6.0
+ */
+ // function resolveAny(hostname: string): Promise<AnyRecord[]>;
+ /**
+ * Uses the DNS protocol to resolve `CAA` records for the `hostname`. On success,
+ * the `Promise` is resolved with an array of objects containing available
+ * certification authority authorization records available for the `hostname`(e.g. `[{critical: 0, iodef: 'mailto:pki@example.com'},{critical: 128, issue: 'pki.example.com'}]`).
+ * @since v15.0.0, v14.17.0
+ */
+ // function resolveCaa(hostname: string): Promise<CaaRecord[]>;
+ /**
+ * Uses the DNS protocol to resolve `CNAME` records for the `hostname`. On success,
+ * the `Promise` is resolved with an array of canonical name records available for
+ * the `hostname` (e.g. `['bar.example.com']`).
+ * @since v10.6.0
+ */
+ // function resolveCname(hostname: string): Promise<string[]>;
+ /**
+ * Uses the DNS protocol to resolve mail exchange records (`MX` records) for the`hostname`. On success, the `Promise` is resolved with an array of objects
+ * containing both a `priority` and `exchange` property (e.g.`[{priority: 10, exchange: 'mx.example.com'}, ...]`).
+ * @since v10.6.0
+ */
+ // function resolveMx(hostname: string): Promise<MxRecord[]>;
+ /**
+ * Uses the DNS protocol to resolve regular expression based records (`NAPTR`records) for the `hostname`. On success, the `Promise` is resolved with an array
+ * of objects with the following properties:
+ *
+ * * `flags`
+ * * `service`
+ * * `regexp`
+ * * `replacement`
+ * * `order`
+ * * `preference`
+ *
+ * ```js
+ * {
+ * flags: 's',
+ * service: 'SIP+D2U',
+ * regexp: '',
+ * replacement: '_sip._udp.example.com',
+ * order: 30,
+ * preference: 100
+ * }
+ * ```
+ * @since v10.6.0
+ */
+ // function resolveNaptr(hostname: string): Promise<NaptrRecord[]>;
+ /**
+ * Uses the DNS protocol to resolve name server records (`NS` records) for the`hostname`. On success, the `Promise` is resolved with an array of name server
+ * records available for `hostname` (e.g.`['ns1.example.com', 'ns2.example.com']`).
+ * @since v10.6.0
+ */
+ // function resolveNs(hostname: string): Promise<string[]>;
+ /**
+ * Uses the DNS protocol to resolve pointer records (`PTR` records) for the`hostname`. On success, the `Promise` is resolved with an array of strings
+ * containing the reply records.
+ * @since v10.6.0
+ */
+ // function resolvePtr(hostname: string): Promise<string[]>;
+ /**
+ * Uses the DNS protocol to resolve a start of authority record (`SOA` record) for
+ * the `hostname`. On success, the `Promise` is resolved with an object with the
+ * following properties:
+ *
+ * * `nsname`
+ * * `hostmaster`
+ * * `serial`
+ * * `refresh`
+ * * `retry`
+ * * `expire`
+ * * `minttl`
+ *
+ * ```js
+ * {
+ * nsname: 'ns.example.com',
+ * hostmaster: 'root.example.com',
+ * serial: 2013101809,
+ * refresh: 10000,
+ * retry: 2400,
+ * expire: 604800,
+ * minttl: 3600
+ * }
+ * ```
+ * @since v10.6.0
+ */
+ // function resolveSoa(hostname: string): Promise<SoaRecord>;
+ /**
+ * Uses the DNS protocol to resolve service records (`SRV` records) for the`hostname`. On success, the `Promise` is resolved with an array of objects with
+ * the following properties:
+ *
+ * * `priority`
+ * * `weight`
+ * * `port`
+ * * `name`
+ *
+ * ```js
+ * {
+ * priority: 10,
+ * weight: 5,
+ * port: 21223,
+ * name: 'service.example.com'
+ * }
+ * ```
+ * @since v10.6.0
+ */
+ // function resolveSrv(hostname: string): Promise<SrvRecord[]>;
+ /**
+ * Uses the DNS protocol to resolve text queries (`TXT` records) for the`hostname`. On success, the `Promise` is resolved with a two-dimensional array
+ * of the text records available for `hostname` (e.g.`[ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ]`). Each sub-array contains TXT chunks of
+ * one record. Depending on the use case, these could be either joined together or
+ * treated separately.
+ * @since v10.6.0
+ */
+ // function resolveTxt(hostname: string): Promise<string[][]>;
+ /**
+ * Performs a reverse DNS query that resolves an IPv4 or IPv6 address to an
+ * array of host names.
+ *
+ * On error, the `Promise` is rejected with an `Error` object, where `err.code`is one of the `DNS error codes`.
+ * @since v10.6.0
+ */
+ // function reverse(ip: string): Promise<string[]>;
+ /**
+ * Sets the IP address and port of servers to be used when performing DNS
+ * resolution. The `servers` argument is an array of [RFC 5952](https://tools.ietf.org/html/rfc5952#section-6) formatted
+ * addresses. If the port is the IANA default DNS port (53) it can be omitted.
+ *
+ * ```js
+ * dnsPromises.setServers([
+ * '4.4.4.4',
+ * '[2001:4860:4860::8888]',
+ * '4.4.4.4:1053',
+ * '[2001:4860:4860::8888]:1053',
+ * ]);
+ * ```
+ *
+ * An error will be thrown if an invalid address is provided.
+ *
+ * The `dnsPromises.setServers()` method must not be called while a DNS query is in
+ * progress.
+ *
+ * This method works much like [resolve.conf](https://man7.org/linux/man-pages/man5/resolv.conf.5.html).
+ * That is, if attempting to resolve with the first server provided results in a`NOTFOUND` error, the `resolve()` method will _not_ attempt to resolve with
+ * subsequent servers provided. Fallback DNS servers will only be used if the
+ * earlier ones time out or result in some other error.
+ * @since v10.6.0
+ * @param servers array of `RFC 5952` formatted addresses
+ */
+ // function setServers(servers: ReadonlyArray<string>): void;
+ /**
+ * Set the default value of `verbatim` in `dns.lookup()` and `dnsPromises.lookup()`. The value could be:
+ *
+ * * `ipv4first`: sets default `verbatim` `false`.
+ * * `verbatim`: sets default `verbatim` `true`.
+ *
+ * The default is `ipv4first` and `dnsPromises.setDefaultResultOrder()` have
+ * higher priority than `--dns-result-order`. When using `worker threads`,`dnsPromises.setDefaultResultOrder()` from the main thread won't affect the
+ * default dns orders in workers.
+ * @since v16.4.0, v14.18.0
+ * @param order must be `'ipv4first'` or `'verbatim'`.
+ */
+ // function setDefaultResultOrder(order: "ipv4first" | "verbatim"): void;
+ class Resolver {
+ constructor(options?: ResolverOptions);
+ cancel(): void;
+ // getServers: typeof getServers;
+ resolve: typeof resolve;
+ resolve4: typeof resolve4;
+ resolve6: typeof resolve6;
+ // resolveAny: typeof resolveAny;
+ // resolveCname: typeof resolveCname;
+ // resolveMx: typeof resolveMx;
+ // resolveNaptr: typeof resolveNaptr;
+ // resolveNs: typeof resolveNs;
+ // resolvePtr: typeof resolvePtr;
+ // resolveSoa: typeof resolveSoa;
+ // resolveSrv: typeof resolveSrv;
+ // resolveTxt: typeof resolveTxt;
+ // reverse: typeof reverse;
+ // setLocalAddress(ipv4?: string, ipv6?: string): void;
+ // setServers: typeof setServers;
+ }
+}
+declare module "node:dns/promises" {
+ export * from "dns/promises";
+}
diff --git a/packages/bun-types/fs.d.ts b/packages/bun-types/fs.d.ts
index c4fc1f99c..7e34d5873 100644
--- a/packages/bun-types/fs.d.ts
+++ b/packages/bun-types/fs.d.ts
@@ -19,7 +19,7 @@
*/
declare module "fs" {
import * as stream from "stream";
- import type { SystemError } from "bun";
+ import type { SystemError, ArrayBufferView } from "bun";
interface ObjectEncodingOptions {
encoding?: BufferEncoding | null | undefined;
diff --git a/packages/bun-types/fs/promises.d.ts b/packages/bun-types/fs/promises.d.ts
index 3749ca058..c4356da5c 100644
--- a/packages/bun-types/fs/promises.d.ts
+++ b/packages/bun-types/fs/promises.d.ts
@@ -8,6 +8,7 @@
* concurrent modifications on the same file or data corruption may occur.
*/
declare module "fs/promises" {
+ import { ArrayBufferView } from "bun";
import {
Stats,
BigIntStats,
diff --git a/packages/bun-types/globals.d.ts b/packages/bun-types/globals.d.ts
index a27ee2b92..8cf57b05a 100644
--- a/packages/bun-types/globals.d.ts
+++ b/packages/bun-types/globals.d.ts
@@ -351,7 +351,7 @@ interface Process {
revision: string;
chdir(directory: string): void;
cwd(): string;
- exit(code?: number): void;
+ exit(code?: number): never;
getgid(): number;
setgid(id: number | string): void;
getuid(): number;
@@ -1854,7 +1854,7 @@ declare var AbortSignal: {
// type AlgorithmIdentifier = Algorithm | string;
// type BodyInit = ReadableStream | XMLHttpRequestBodyInit;
-type BufferSource = ArrayBufferView | ArrayBuffer | SharedArrayBuffer;
+type BufferSource = TypedArray | DataView | ArrayBufferLike;
// type COSEAlgorithmIdentifier = number;
// type CSSNumberish = number;
// type CanvasImageSource =
diff --git a/packages/bun-types/net.d.ts b/packages/bun-types/net.d.ts
new file mode 100644
index 000000000..1e373f4ba
--- /dev/null
+++ b/packages/bun-types/net.d.ts
@@ -0,0 +1,1007 @@
+/**
+ * > Stability: 2 - Stable
+ *
+ * The `net` module provides an asynchronous network API for creating stream-based
+ * TCP or `IPC` servers ({@link createServer}) and clients
+ * ({@link createConnection}).
+ *
+ * It can be accessed using:
+ *
+ * ```js
+ * const net = require('net');
+ * ```
+ * @see [source](https://github.com/nodejs/node/blob/v18.0.0/lib/net.js)
+ */
+declare module "net" {
+ import * as stream from "node:stream";
+ import {
+ Abortable,
+ // EventEmitter
+ } from "node:events";
+ // import * as dns from "node:dns";
+ // type LookupFunction = (
+ // hostname: string,
+ // options: dns.LookupOneOptions,
+ // callback: (
+ // err: NodeJS.ErrnoException | null,
+ // address: string,
+ // family: number,
+ // ) => void,
+ // ) => void;
+ interface AddressInfo {
+ address: string;
+ family: string;
+ port: number;
+ }
+ interface SocketConstructorOpts {
+ // fd?: number | undefined;
+ allowHalfOpen?: boolean | undefined;
+ readable?: boolean | undefined;
+ writable?: boolean | undefined;
+ signal?: AbortSignal;
+ }
+ interface OnReadOpts {
+ buffer: Uint8Array | (() => Uint8Array);
+ /**
+ * This function is called for every chunk of incoming data.
+ * Two arguments are passed to it: the number of bytes written to buffer and a reference to buffer.
+ * Return false from this function to implicitly pause() the socket.
+ */
+ callback(bytesWritten: number, buf: Uint8Array): boolean;
+ }
+ interface ConnectOpts {
+ /**
+ * If specified, incoming data is stored in a single buffer and passed to the supplied callback when data arrives on the socket.
+ * Note: this will cause the streaming functionality to not provide any data, however events like 'error', 'end', and 'close' will
+ * still be emitted as normal and methods like pause() and resume() will also behave as expected.
+ */
+ onread?: OnReadOpts | undefined;
+ }
+ interface TcpSocketConnectOpts extends ConnectOpts {
+ port: number;
+ host?: string | undefined;
+ // localAddress?: string | undefined;
+ // localPort?: number | undefined;
+ // hints?: number | undefined;
+ // family?: number | undefined;
+ // lookup?: LookupFunction | undefined;
+ // noDelay?: boolean | undefined;
+ // keepAlive?: boolean | undefined;
+ // keepAliveInitialDelay?: number | undefined;
+ }
+ // interface IpcSocketConnectOpts extends ConnectOpts {
+ // path: string;
+ // }
+ type SocketConnectOpts = TcpSocketConnectOpts; // | IpcSocketConnectOpts;
+ type SocketReadyState =
+ | "opening"
+ | "open"
+ | "readOnly"
+ | "writeOnly"
+ | "closed";
+ /**
+ * This class is an abstraction of a TCP socket or a streaming `IPC` endpoint
+ * (uses named pipes on Windows, and Unix domain sockets otherwise). It is also
+ * an `EventEmitter`.
+ *
+ * A `net.Socket` can be created by the user and used directly to interact with
+ * a server. For example, it is returned by {@link createConnection},
+ * so the user can use it to talk to the server.
+ *
+ * It can also be created by Node.js and passed to the user when a connection
+ * is received. For example, it is passed to the listeners of a `'connection'` event emitted on a {@link Server}, so the user can use
+ * it to interact with the client.
+ * @since v0.3.4
+ */
+ class Socket extends stream.Duplex {
+ constructor(options?: SocketConstructorOpts);
+ /**
+ * Sends data on the socket. The second parameter specifies the encoding in the
+ * case of a string. It defaults to UTF8 encoding.
+ *
+ * Returns `true` if the entire data was flushed successfully to the kernel
+ * buffer. Returns `false` if all or part of the data was queued in user memory.`'drain'` will be emitted when the buffer is again free.
+ *
+ * The optional `callback` parameter will be executed when the data is finally
+ * written out, which may not be immediately.
+ *
+ * See `Writable` stream `write()` method for more
+ * information.
+ * @since v0.1.90
+ * @param [encoding='utf8'] Only used when data is `string`.
+ */
+ write(buffer: Uint8Array | string, cb?: (err?: Error) => void): boolean;
+ write(
+ str: Uint8Array | string,
+ encoding?: BufferEncoding,
+ cb?: (err?: Error) => void,
+ ): boolean;
+ /**
+ * Initiate a connection on a given socket.
+ *
+ * Possible signatures:
+ *
+ * * `socket.connect(options[, connectListener])`
+ * * `socket.connect(path[, connectListener])` for `IPC` connections.
+ * * `socket.connect(port[, host][, connectListener])` for TCP connections.
+ * * Returns: `net.Socket` The socket itself.
+ *
+ * This function is asynchronous. When the connection is established, the `'connect'` event will be emitted. If there is a problem connecting,
+ * instead of a `'connect'` event, an `'error'` event will be emitted with
+ * the error passed to the `'error'` listener.
+ * The last parameter `connectListener`, if supplied, will be added as a listener
+ * for the `'connect'` event **once**.
+ *
+ * This function should only be used for reconnecting a socket after`'close'` has been emitted or otherwise it may lead to undefined
+ * behavior.
+ */
+ connect(options: SocketConnectOpts, connectionListener?: () => void): this;
+ connect(port: number, host: string, connectionListener?: () => void): this;
+ connect(port: number, connectionListener?: () => void): this;
+ connect(path: string, connectionListener?: () => void): this;
+ /**
+ * Set the encoding for the socket as a `Readable Stream`. See `readable.setEncoding()` for more information.
+ * @since v0.1.90
+ * @return The socket itself.
+ */
+ setEncoding(encoding?: BufferEncoding): this;
+ /**
+ * Pauses the reading of data. That is, `'data'` events will not be emitted.
+ * Useful to throttle back an upload.
+ * @return The socket itself.
+ */
+ pause(): this;
+ /**
+ * Close the TCP connection by sending an RST packet and destroy the stream.
+ * If this TCP socket is in connecting status, it will send an RST packet
+ * and destroy this TCP socket once it is connected. Otherwise, it will call
+ * `socket.destroy` with an `ERR_SOCKET_CLOSED` Error. If this is not a TCP socket
+ * (for example, a pipe), calling this method will immediately throw
+ * an `ERR_INVALID_HANDLE_TYPE` Error.
+ * @since v18.3.0
+ * @return The socket itself.
+ */
+ resetAndDestroy(): this;
+ /**
+ * Resumes reading after a call to `socket.pause()`.
+ * @return The socket itself.
+ */
+ resume(): this;
+ /**
+ * Sets the socket to timeout after `timeout` milliseconds of inactivity on
+ * the socket. By default `net.Socket` do not have a timeout.
+ *
+ * When an idle timeout is triggered the socket will receive a `'timeout'` event but the connection will not be severed. The user must manually call `socket.end()` or `socket.destroy()` to
+ * end the connection.
+ *
+ * ```js
+ * socket.setTimeout(3000);
+ * socket.on('timeout', () => {
+ * console.log('socket timeout');
+ * socket.end();
+ * });
+ * ```
+ *
+ * If `timeout` is 0, then the existing idle timeout is disabled.
+ *
+ * The optional `callback` parameter will be added as a one-time listener for the `'timeout'` event.
+ * @since v0.1.90
+ * @return The socket itself.
+ */
+ setTimeout(timeout: number, callback?: () => void): this;
+ /**
+ * Enable/disable the use of Nagle's algorithm.
+ *
+ * When a TCP connection is created, it will have Nagle's algorithm enabled.
+ *
+ * Nagle's algorithm delays data before it is sent via the network. It attempts
+ * to optimize throughput at the expense of latency.
+ *
+ * Passing `true` for `noDelay` or not passing an argument will disable Nagle's
+ * algorithm for the socket. Passing `false` for `noDelay` will enable Nagle's
+ * algorithm.
+ * @since v0.1.90
+ * @param [noDelay=true]
+ * @return The socket itself.
+ */
+ setNoDelay(noDelay?: boolean): this;
+ /**
+ * Enable/disable keep-alive functionality, and optionally set the initial
+ * delay before the first keepalive probe is sent on an idle socket.
+ *
+ * Set `initialDelay` (in milliseconds) to set the delay between the last
+ * data packet received and the first keepalive probe. Setting `0` for`initialDelay` will leave the value unchanged from the default
+ * (or previous) setting.
+ *
+ * Enabling the keep-alive functionality will set the following socket options:
+ *
+ * * `SO_KEEPALIVE=1`
+ * * `TCP_KEEPIDLE=initialDelay`
+ * * `TCP_KEEPCNT=10`
+ * * `TCP_KEEPINTVL=1`
+ * @since v0.1.92
+ * @param [enable=false]
+ * @param [initialDelay=0]
+ * @return The socket itself.
+ */
+ setKeepAlive(enable?: boolean, initialDelay?: number): this;
+ /**
+ * Returns the bound `address`, the address `family` name and `port` of the
+ * socket as reported by the operating system:`{ port: 12346, family: 'IPv4', address: '127.0.0.1' }`
+ * @since v0.1.90
+ */
+ address(): AddressInfo | {};
+ /**
+ * Calling `unref()` on a socket will allow the program to exit if this is the only
+ * active socket in the event system. If the socket is already `unref`ed calling`unref()` again will have no effect.
+ * @since v0.9.1
+ * @return The socket itself.
+ */
+ unref(): this;
+ /**
+ * Opposite of `unref()`, calling `ref()` on a previously `unref`ed socket will _not_ let the program exit if it's the only socket left (the default behavior).
+ * If the socket is `ref`ed calling `ref` again will have no effect.
+ * @since v0.9.1
+ * @return The socket itself.
+ */
+ ref(): this;
+ /**
+ * This property shows the number of characters buffered for writing. The buffer
+ * may contain strings whose length after encoding is not yet known. So this number
+ * is only an approximation of the number of bytes in the buffer.
+ *
+ * `net.Socket` has the property that `socket.write()` always works. This is to
+ * help users get up and running quickly. The computer cannot always keep up
+ * with the amount of data that is written to a socket. The network connection
+ * simply might be too slow. Node.js will internally queue up the data written to a
+ * socket and send it out over the wire when it is possible.
+ *
+ * The consequence of this internal buffering is that memory may grow.
+ * Users who experience large or growing `bufferSize` should attempt to
+ * "throttle" the data flows in their program with `socket.pause()` and `socket.resume()`.
+ * @since v0.3.8
+ * @deprecated Since v14.6.0 - Use `writableLength` instead.
+ */
+ readonly bufferSize: number;
+ /**
+ * The amount of received bytes.
+ * @since v0.5.3
+ */
+ readonly bytesRead: number;
+ /**
+ * The amount of bytes sent.
+ * @since v0.5.3
+ */
+ readonly bytesWritten: number;
+ /**
+ * If `true`,`socket.connect(options[, connectListener])` was
+ * called and has not yet finished. It will stay `true` until the socket becomes
+ * connected, then it is set to `false` and the `'connect'` event is emitted. Note
+ * that the `socket.connect(options[, connectListener])` callback is a listener for the `'connect'` event.
+ * @since v6.1.0
+ */
+ readonly connecting: boolean;
+ /**
+ * See `writable.destroyed` for further details.
+ */
+ // readonly destroyed: boolean;
+ /**
+ * The string representation of the local IP address the remote client is
+ * connecting on. For example, in a server listening on `'0.0.0.0'`, if a client
+ * connects on `'192.168.1.1'`, the value of `socket.localAddress` would be`'192.168.1.1'`.
+ * @since v0.9.6
+ */
+ readonly localAddress?: string;
+ /**
+ * The numeric representation of the local port. For example, `80` or `21`.
+ * @since v0.9.6
+ */
+ readonly localPort?: number;
+ /**
+ * The string representation of the local IP family. `'IPv4'` or `'IPv6'`.
+ * @since v18.8.0
+ */
+ readonly localFamily?: string;
+ /**
+ * This property represents the state of the connection as a string.
+ * @see {https://nodejs.org/api/net.html#socketreadystate}
+ * @since v0.5.0
+ */
+ readonly readyState: SocketReadyState;
+ /**
+ * The string representation of the remote IP address. For example,`'74.125.127.100'` or `'2001:4860:a005::68'`. Value may be `undefined` if
+ * the socket is destroyed (for example, if the client disconnected).
+ * @since v0.5.10
+ */
+ readonly remoteAddress?: string | undefined;
+ /**
+ * The string representation of the remote IP family. `'IPv4'` or `'IPv6'`.
+ * @since v0.11.14
+ */
+ readonly remoteFamily?: string | undefined;
+ /**
+ * The numeric representation of the remote port. For example, `80` or `21`.
+ * @since v0.5.10
+ */
+ readonly remotePort?: number | undefined;
+ /**
+ * The socket timeout in milliseconds as set by socket.setTimeout(). It is undefined if a timeout has not been set.
+ * @since v10.7.0
+ */
+ readonly timeout?: number | undefined;
+ /**
+ * Half-closes the socket. i.e., it sends a FIN packet. It is possible the
+ * server will still send some data.
+ *
+ * See `writable.end()` for further details.
+ * @since v0.1.90
+ * @param [encoding='utf8'] Only used when data is `string`.
+ * @param callback Optional callback for when the socket is finished.
+ * @return The socket itself.
+ */
+ end(callback?: () => void): this;
+ end(buffer: Uint8Array | string, callback?: () => void): this;
+ end(
+ str: Uint8Array | string,
+ encoding?: BufferEncoding,
+ callback?: () => void,
+ ): this;
+ /**
+ * events.EventEmitter
+ * 1. close
+ * 2. connect
+ * 3. data
+ * 4. drain
+ * 5. end
+ * 6. error
+ * 7. lookup
+ * 8. ready
+ * 9. timeout
+ */
+ addListener(event: string, listener: (...args: any[]) => void): this;
+ addListener(event: "close", listener: (hadError: boolean) => void): this;
+ addListener(event: "connect", listener: () => void): this;
+ addListener(event: "data", listener: (data: Buffer) => void): this;
+ addListener(event: "drain", listener: () => void): this;
+ addListener(event: "end", listener: () => void): this;
+ addListener(event: "error", listener: (err: Error) => void): this;
+ addListener(
+ event: "lookup",
+ listener: (
+ err: Error,
+ address: string,
+ family: string | number,
+ host: string,
+ ) => void,
+ ): this;
+ addListener(event: "ready", listener: () => void): this;
+ addListener(event: "timeout", listener: () => void): this;
+ emit(event: string | symbol, ...args: any[]): boolean;
+ emit(event: "close", hadError: boolean): boolean;
+ emit(event: "connect"): boolean;
+ emit(event: "data", data: Buffer): boolean;
+ emit(event: "drain"): boolean;
+ emit(event: "end"): boolean;
+ emit(event: "error", err: Error): boolean;
+ emit(
+ event: "lookup",
+ err: Error,
+ address: string,
+ family: string | number,
+ host: string,
+ ): boolean;
+ emit(event: "ready"): boolean;
+ emit(event: "timeout"): boolean;
+ on(event: string, listener: (...args: any[]) => void): this;
+ on(event: "close", listener: (hadError: boolean) => void): this;
+ on(event: "connect", listener: () => void): this;
+ on(event: "data", listener: (data: Buffer) => void): this;
+ on(event: "drain", listener: () => void): this;
+ on(event: "end", listener: () => void): this;
+ on(event: "error", listener: (err: Error) => void): this;
+ on(
+ event: "lookup",
+ listener: (
+ err: Error,
+ address: string,
+ family: string | number,
+ host: string,
+ ) => void,
+ ): this;
+ on(event: "ready", listener: () => void): this;
+ on(event: "timeout", listener: () => void): this;
+ once(event: string, listener: (...args: any[]) => void): this;
+ once(event: "close", listener: (hadError: boolean) => void): this;
+ once(event: "connect", listener: () => void): this;
+ once(event: "data", listener: (data: Buffer) => void): this;
+ once(event: "drain", listener: () => void): this;
+ once(event: "end", listener: () => void): this;
+ once(event: "error", listener: (err: Error) => void): this;
+ once(
+ event: "lookup",
+ listener: (
+ err: Error,
+ address: string,
+ family: string | number,
+ host: string,
+ ) => void,
+ ): this;
+ once(event: "ready", listener: () => void): this;
+ once(event: "timeout", listener: () => void): this;
+ prependListener(event: string, listener: (...args: any[]) => void): this;
+ prependListener(
+ event: "close",
+ listener: (hadError: boolean) => void,
+ ): this;
+ prependListener(event: "connect", listener: () => void): this;
+ prependListener(event: "data", listener: (data: Buffer) => void): this;
+ prependListener(event: "drain", listener: () => void): this;
+ prependListener(event: "end", listener: () => void): this;
+ prependListener(event: "error", listener: (err: Error) => void): this;
+ prependListener(
+ event: "lookup",
+ listener: (
+ err: Error,
+ address: string,
+ family: string | number,
+ host: string,
+ ) => void,
+ ): this;
+ prependListener(event: "ready", listener: () => void): this;
+ prependListener(event: "timeout", listener: () => void): this;
+ prependOnceListener(
+ event: string,
+ listener: (...args: any[]) => void,
+ ): this;
+ prependOnceListener(
+ event: "close",
+ listener: (hadError: boolean) => void,
+ ): this;
+ prependOnceListener(event: "connect", listener: () => void): this;
+ prependOnceListener(event: "data", listener: (data: Buffer) => void): this;
+ prependOnceListener(event: "drain", listener: () => void): this;
+ prependOnceListener(event: "end", listener: () => void): this;
+ prependOnceListener(event: "error", listener: (err: Error) => void): this;
+ prependOnceListener(
+ event: "lookup",
+ listener: (
+ err: Error,
+ address: string,
+ family: string | number,
+ host: string,
+ ) => void,
+ ): this;
+ prependOnceListener(event: "ready", listener: () => void): this;
+ prependOnceListener(event: "timeout", listener: () => void): this;
+ }
+ interface ListenOptions extends Abortable {
+ port?: number | undefined;
+ host?: string | undefined;
+ backlog?: number | undefined;
+ path?: string | undefined;
+ exclusive?: boolean | undefined;
+ readableAll?: boolean | undefined;
+ writableAll?: boolean | undefined;
+ /**
+ * @default false
+ */
+ ipv6Only?: boolean | undefined;
+ }
+ interface ServerOpts {
+ /**
+ * Indicates whether half-opened TCP connections are allowed.
+ * @default false
+ */
+ allowHalfOpen?: boolean | undefined;
+ /**
+ * Indicates whether the socket should be paused on incoming connections.
+ * @default false
+ */
+ pauseOnConnect?: boolean | undefined;
+ /**
+ * If set to `true`, it disables the use of Nagle's algorithm immediately after a new incoming connection is received.
+ * @default false
+ * @since v16.5.0
+ */
+ noDelay?: boolean | undefined;
+ /**
+ * If set to `true`, it enables keep-alive functionality on the socket immediately after a new incoming connection is received,
+ * similarly on what is done in `socket.setKeepAlive([enable][, initialDelay])`.
+ * @default false
+ * @since v16.5.0
+ */
+ keepAlive?: boolean | undefined;
+ /**
+ * If set to a positive number, it sets the initial delay before the first keepalive probe is sent on an idle socket.
+ * @default 0
+ * @since v16.5.0
+ */
+ keepAliveInitialDelay?: number | undefined;
+ }
+ interface DropArgument {
+ localAddress?: string;
+ localPort?: number;
+ localFamily?: string;
+ remoteAddress?: string;
+ remotePort?: number;
+ remoteFamily?: string;
+ }
+ /**
+ * This class is used to create a TCP or `IPC` server.
+ * @since v0.1.90
+ */
+ // class Server extends EventEmitter {
+ // constructor(connectionListener?: (socket: Socket) => void);
+ // constructor(
+ // options?: ServerOpts,
+ // connectionListener?: (socket: Socket) => void,
+ // );
+ // /**
+ // * Start a server listening for connections. A `net.Server` can be a TCP or
+ // * an `IPC` server depending on what it listens to.
+ // *
+ // * Possible signatures:
+ // *
+ // * * `server.listen(handle[, backlog][, callback])`
+ // * * `server.listen(options[, callback])`
+ // * * `server.listen(path[, backlog][, callback])` for `IPC` servers
+ // * * `server.listen([port[, host[, backlog]]][, callback])` for TCP servers
+ // *
+ // * This function is asynchronous. When the server starts listening, the `'listening'` event will be emitted. The last parameter `callback`will be added as a listener for the `'listening'`
+ // * event.
+ // *
+ // * All `listen()` methods can take a `backlog` parameter to specify the maximum
+ // * length of the queue of pending connections. The actual length will be determined
+ // * by the OS through sysctl settings such as `tcp_max_syn_backlog` and `somaxconn`on Linux. The default value of this parameter is 511 (not 512).
+ // *
+ // * All {@link Socket} are set to `SO_REUSEADDR` (see [`socket(7)`](https://man7.org/linux/man-pages/man7/socket.7.html) for
+ // * details).
+ // *
+ // * The `server.listen()` method can be called again if and only if there was an
+ // * error during the first `server.listen()` call or `server.close()` has been
+ // * called. Otherwise, an `ERR_SERVER_ALREADY_LISTEN` error will be thrown.
+ // *
+ // * One of the most common errors raised when listening is `EADDRINUSE`.
+ // * This happens when another server is already listening on the requested`port`/`path`/`handle`. One way to handle this would be to retry
+ // * after a certain amount of time:
+ // *
+ // * ```js
+ // * server.on('error', (e) => {
+ // * if (e.code === 'EADDRINUSE') {
+ // * console.log('Address in use, retrying...');
+ // * setTimeout(() => {
+ // * server.close();
+ // * server.listen(PORT, HOST);
+ // * }, 1000);
+ // * }
+ // * });
+ // * ```
+ // */
+ // listen(
+ // port?: number,
+ // hostname?: string,
+ // backlog?: number,
+ // listeningListener?: () => void,
+ // ): this;
+ // listen(
+ // port?: number,
+ // hostname?: string,
+ // listeningListener?: () => void,
+ // ): this;
+ // listen(
+ // port?: number,
+ // backlog?: number,
+ // listeningListener?: () => void,
+ // ): this;
+ // listen(port?: number, listeningListener?: () => void): this;
+ // listen(
+ // path: string,
+ // backlog?: number,
+ // listeningListener?: () => void,
+ // ): this;
+ // listen(path: string, listeningListener?: () => void): this;
+ // listen(options: ListenOptions, listeningListener?: () => void): this;
+ // listen(handle: any, backlog?: number, listeningListener?: () => void): this;
+ // listen(handle: any, listeningListener?: () => void): this;
+ // /**
+ // * Stops the server from accepting new connections and keeps existing
+ // * connections. This function is asynchronous, the server is finally closed
+ // * when all connections are ended and the server emits a `'close'` event.
+ // * The optional `callback` will be called once the `'close'` event occurs. Unlike
+ // * that event, it will be called with an `Error` as its only argument if the server
+ // * was not open when it was closed.
+ // * @since v0.1.90
+ // * @param callback Called when the server is closed.
+ // */
+ // close(callback?: (err?: Error) => void): this;
+ // /**
+ // * Returns the bound `address`, the address `family` name, and `port` of the server
+ // * as reported by the operating system if listening on an IP socket
+ // * (useful to find which port was assigned when getting an OS-assigned address):`{ port: 12346, family: 'IPv4', address: '127.0.0.1' }`.
+ // *
+ // * For a server listening on a pipe or Unix domain socket, the name is returned
+ // * as a string.
+ // *
+ // * ```js
+ // * const server = net.createServer((socket) => {
+ // * socket.end('goodbye\n');
+ // * }).on('error', (err) => {
+ // * // Handle errors here.
+ // * throw err;
+ // * });
+ // *
+ // * // Grab an arbitrary unused port.
+ // * server.listen(() => {
+ // * console.log('opened server on', server.address());
+ // * });
+ // * ```
+ // *
+ // * `server.address()` returns `null` before the `'listening'` event has been
+ // * emitted or after calling `server.close()`.
+ // * @since v0.1.90
+ // */
+ // address(): AddressInfo | string | null;
+ // /**
+ // * Asynchronously get the number of concurrent connections on the server. Works
+ // * when sockets were sent to forks.
+ // *
+ // * Callback should take two arguments `err` and `count`.
+ // * @since v0.9.7
+ // */
+ // getConnections(cb: (error: Error | null, count: number) => void): void;
+ // /**
+ // * Opposite of `unref()`, calling `ref()` on a previously `unref`ed server will _not_ let the program exit if it's the only server left (the default behavior).
+ // * If the server is `ref`ed calling `ref()` again will have no effect.
+ // * @since v0.9.1
+ // */
+ // ref(): this;
+ // /**
+ // * Calling `unref()` on a server will allow the program to exit if this is the only
+ // * active server in the event system. If the server is already `unref`ed calling`unref()` again will have no effect.
+ // * @since v0.9.1
+ // */
+ // unref(): this;
+ // /**
+ // * Set this property to reject connections when the server's connection count gets
+ // * high.
+ // *
+ // * It is not recommended to use this option once a socket has been sent to a child
+ // * with `child_process.fork()`.
+ // * @since v0.2.0
+ // */
+ // maxConnections: number;
+ // connections: number;
+ // /**
+ // * Indicates whether or not the server is listening for connections.
+ // * @since v5.7.0
+ // */
+ // listening: boolean;
+ // /**
+ // * events.EventEmitter
+ // * 1. close
+ // * 2. connection
+ // * 3. error
+ // * 4. listening
+ // * 5. drop
+ // */
+ // addListener(event: string, listener: (...args: any[]) => void): this;
+ // addListener(event: "close", listener: () => void): this;
+ // addListener(event: "connection", listener: (socket: Socket) => void): this;
+ // addListener(event: "error", listener: (err: Error) => void): this;
+ // addListener(event: "listening", listener: () => void): this;
+ // addListener(event: "drop", listener: (data?: DropArgument) => void): this;
+ // emit(event: string | symbol, ...args: any[]): boolean;
+ // emit(event: "close"): boolean;
+ // emit(event: "connection", socket: Socket): boolean;
+ // emit(event: "error", err: Error): boolean;
+ // emit(event: "listening"): boolean;
+ // emit(event: "drop", data?: DropArgument): boolean;
+ // on(event: string, listener: (...args: any[]) => void): this;
+ // on(event: "close", listener: () => void): this;
+ // on(event: "connection", listener: (socket: Socket) => void): this;
+ // on(event: "error", listener: (err: Error) => void): this;
+ // on(event: "listening", listener: () => void): this;
+ // on(event: "drop", listener: (data?: DropArgument) => void): this;
+ // once(event: string, listener: (...args: any[]) => void): this;
+ // once(event: "close", listener: () => void): this;
+ // once(event: "connection", listener: (socket: Socket) => void): this;
+ // once(event: "error", listener: (err: Error) => void): this;
+ // once(event: "listening", listener: () => void): this;
+ // once(event: "drop", listener: (data?: DropArgument) => void): this;
+ // prependListener(event: string, listener: (...args: any[]) => void): this;
+ // prependListener(event: "close", listener: () => void): this;
+ // prependListener(
+ // event: "connection",
+ // listener: (socket: Socket) => void,
+ // ): this;
+ // prependListener(event: "error", listener: (err: Error) => void): this;
+ // prependListener(event: "listening", listener: () => void): this;
+ // prependListener(
+ // event: "drop",
+ // listener: (data?: DropArgument) => void,
+ // ): this;
+ // prependOnceListener(
+ // event: string,
+ // listener: (...args: any[]) => void,
+ // ): this;
+ // prependOnceListener(event: "close", listener: () => void): this;
+ // prependOnceListener(
+ // event: "connection",
+ // listener: (socket: Socket) => void,
+ // ): this;
+ // prependOnceListener(event: "error", listener: (err: Error) => void): this;
+ // prependOnceListener(event: "listening", listener: () => void): this;
+ // prependOnceListener(
+ // event: "drop",
+ // listener: (data?: DropArgument) => void,
+ // ): this;
+ // }
+ type IPVersion = "ipv4" | "ipv6";
+ /**
+ * The `BlockList` object can be used with some network APIs to specify rules for
+ * disabling inbound or outbound access to specific IP addresses, IP ranges, or
+ * IP subnets.
+ * @since v15.0.0, v14.18.0
+ */
+ // class BlockList {
+ // /**
+ // * Adds a rule to block the given IP address.
+ // * @since v15.0.0, v14.18.0
+ // * @param address An IPv4 or IPv6 address.
+ // * @param [type='ipv4'] Either `'ipv4'` or `'ipv6'`.
+ // */
+ // addAddress(address: string, type?: IPVersion): void;
+ // addAddress(address: SocketAddress): void;
+ // /**
+ // * Adds a rule to block a range of IP addresses from `start` (inclusive) to`end` (inclusive).
+ // * @since v15.0.0, v14.18.0
+ // * @param start The starting IPv4 or IPv6 address in the range.
+ // * @param end The ending IPv4 or IPv6 address in the range.
+ // * @param [type='ipv4'] Either `'ipv4'` or `'ipv6'`.
+ // */
+ // addRange(start: string, end: string, type?: IPVersion): void;
+ // addRange(start: SocketAddress, end: SocketAddress): void;
+ // /**
+ // * Adds a rule to block a range of IP addresses specified as a subnet mask.
+ // * @since v15.0.0, v14.18.0
+ // * @param net The network IPv4 or IPv6 address.
+ // * @param prefix The number of CIDR prefix bits. For IPv4, this must be a value between `0` and `32`. For IPv6, this must be between `0` and `128`.
+ // * @param [type='ipv4'] Either `'ipv4'` or `'ipv6'`.
+ // */
+ // addSubnet(net: SocketAddress, prefix: number): void;
+ // addSubnet(net: string, prefix: number, type?: IPVersion): void;
+ // /**
+ // * Returns `true` if the given IP address matches any of the rules added to the`BlockList`.
+ // *
+ // * ```js
+ // * const blockList = new net.BlockList();
+ // * blockList.addAddress('123.123.123.123');
+ // * blockList.addRange('10.0.0.1', '10.0.0.10');
+ // * blockList.addSubnet('8592:757c:efae:4e45::', 64, 'ipv6');
+ // *
+ // * console.log(blockList.check('123.123.123.123')); // Prints: true
+ // * console.log(blockList.check('10.0.0.3')); // Prints: true
+ // * console.log(blockList.check('222.111.111.222')); // Prints: false
+ // *
+ // * // IPv6 notation for IPv4 addresses works:
+ // * console.log(blockList.check('::ffff:7b7b:7b7b', 'ipv6')); // Prints: true
+ // * console.log(blockList.check('::ffff:123.123.123.123', 'ipv6')); // Prints: true
+ // * ```
+ // * @since v15.0.0, v14.18.0
+ // * @param address The IP address to check
+ // * @param [type='ipv4'] Either `'ipv4'` or `'ipv6'`.
+ // */
+ // check(address: SocketAddress): boolean;
+ // check(address: string, type?: IPVersion): boolean;
+ // }
+ interface TcpNetConnectOpts
+ extends TcpSocketConnectOpts,
+ SocketConstructorOpts {
+ timeout?: number | undefined;
+ }
+ // interface IpcNetConnectOpts
+ // extends IpcSocketConnectOpts,
+ // SocketConstructorOpts {
+ // timeout?: number | undefined;
+ // }
+ type NetConnectOpts = TcpNetConnectOpts; //| IpcNetConnectOpts;
+ /**
+ * Creates a new TCP or `IPC` server.
+ *
+ * If `allowHalfOpen` is set to `true`, when the other end of the socket
+ * signals the end of transmission, the server will only send back the end of
+ * transmission when `socket.end()` is explicitly called. For example, in the
+ * context of TCP, when a FIN packed is received, a FIN packed is sent
+ * back only when `socket.end()` is explicitly called. Until then the
+ * connection is half-closed (non-readable but still writable). See `'end'` event and [RFC 1122](https://tools.ietf.org/html/rfc1122) (section 4.2.2.13) for more information.
+ *
+ * If `pauseOnConnect` is set to `true`, then the socket associated with each
+ * incoming connection will be paused, and no data will be read from its handle.
+ * This allows connections to be passed between processes without any data being
+ * read by the original process. To begin reading data from a paused socket, call `socket.resume()`.
+ *
+ * The server can be a TCP server or an `IPC` server, depending on what it `listen()` to.
+ *
+ * Here is an example of a TCP echo server which listens for connections
+ * on port 8124:
+ *
+ * ```js
+ * const net = require('net');
+ * const server = net.createServer((c) => {
+ * // 'connection' listener.
+ * console.log('client connected');
+ * c.on('end', () => {
+ * console.log('client disconnected');
+ * });
+ * c.write('hello\r\n');
+ * c.pipe(c);
+ * });
+ * server.on('error', (err) => {
+ * throw err;
+ * });
+ * server.listen(8124, () => {
+ * console.log('server bound');
+ * });
+ * ```
+ *
+ * Test this by using `telnet`:
+ *
+ * ```console
+ * $ telnet localhost 8124
+ * ```
+ *
+ * To listen on the socket `/tmp/echo.sock`:
+ *
+ * ```js
+ * server.listen('/tmp/echo.sock', () => {
+ * console.log('server bound');
+ * });
+ * ```
+ *
+ * Use `nc` to connect to a Unix domain socket server:
+ *
+ * ```console
+ * $ nc -U /tmp/echo.sock
+ * ```
+ * @since v0.5.0
+ * @param connectionListener Automatically set as a listener for the {@link 'connection'} event.
+ */
+ // function createServer(connectionListener?: (socket: Socket) => void): Server;
+ // function createServer(
+ // options?: ServerOpts,
+ // connectionListener?: (socket: Socket) => void,
+ // ): Server;
+ /**
+ * Aliases to {@link createConnection}.
+ *
+ * Possible signatures:
+ *
+ * * {@link connect}
+ * * {@link connect} for `IPC` connections.
+ * * {@link connect} for TCP connections.
+ */
+ function connect(
+ options: NetConnectOpts,
+ connectionListener?: () => void,
+ ): Socket;
+ function connect(
+ port: number,
+ host?: string,
+ connectionListener?: () => void,
+ ): Socket;
+ function connect(path: string, connectionListener?: () => void): Socket;
+ /**
+ * A factory function, which creates a new {@link Socket},
+ * immediately initiates connection with `socket.connect()`,
+ * then returns the `net.Socket` that starts the connection.
+ *
+ * When the connection is established, a `'connect'` event will be emitted
+ * on the returned socket. The last parameter `connectListener`, if supplied,
+ * will be added as a listener for the `'connect'` event **once**.
+ *
+ * Possible signatures:
+ *
+ * * {@link createConnection}
+ * * {@link createConnection} for `IPC` connections.
+ * * {@link createConnection} for TCP connections.
+ *
+ * The {@link connect} function is an alias to this function.
+ */
+ function createConnection(
+ options: NetConnectOpts,
+ connectionListener?: () => void,
+ ): Socket;
+ function createConnection(
+ port: number,
+ host?: string,
+ connectionListener?: () => void,
+ ): Socket;
+ function createConnection(
+ path: string,
+ connectionListener?: () => void,
+ ): Socket;
+ /**
+ * Returns `6` if `input` is an IPv6 address. Returns `4` if `input` is an IPv4
+ * address in [dot-decimal notation](https://en.wikipedia.org/wiki/Dot-decimal_notation) with no leading zeroes. Otherwise, returns`0`.
+ *
+ * ```js
+ * net.isIP('::1'); // returns 6
+ * net.isIP('127.0.0.1'); // returns 4
+ * net.isIP('127.000.000.001'); // returns 0
+ * net.isIP('127.0.0.1/24'); // returns 0
+ * net.isIP('fhqwhgads'); // returns 0
+ * ```
+ * @since v0.3.0
+ */
+ function isIP(input: string): number;
+ /**
+ * Returns `true` if `input` is an IPv4 address in [dot-decimal notation](https://en.wikipedia.org/wiki/Dot-decimal_notation) with no
+ * leading zeroes. Otherwise, returns `false`.
+ *
+ * ```js
+ * net.isIPv4('127.0.0.1'); // returns true
+ * net.isIPv4('127.000.000.001'); // returns false
+ * net.isIPv4('127.0.0.1/24'); // returns false
+ * net.isIPv4('fhqwhgads'); // returns false
+ * ```
+ * @since v0.3.0
+ */
+ function isIPv4(input: string): boolean;
+ /**
+ * Returns `true` if `input` is an IPv6 address. Otherwise, returns `false`.
+ *
+ * ```js
+ * net.isIPv6('::1'); // returns true
+ * net.isIPv6('fhqwhgads'); // returns false
+ * ```
+ * @since v0.3.0
+ */
+ function isIPv6(input: string): boolean;
+ // interface SocketAddressInitOptions {
+ // /**
+ // * The network address as either an IPv4 or IPv6 string.
+ // * @default 127.0.0.1
+ // */
+ // address?: string | undefined;
+ // /**
+ // * @default `'ipv4'`
+ // */
+ // family?: IPVersion | undefined;
+ // /**
+ // * An IPv6 flow-label used only if `family` is `'ipv6'`.
+ // * @default 0
+ // */
+ // flowlabel?: number | undefined;
+ // /**
+ // * An IP port.
+ // * @default 0
+ // */
+ // port?: number | undefined;
+ // }
+ /**
+ * @since v15.14.0, v14.18.0
+ */
+ // class SocketAddress {
+ // constructor(options: SocketAddressInitOptions);
+ // /**
+ // * @since v15.14.0, v14.18.0
+ // */
+ // readonly address: string;
+ // /**
+ // * Either \`'ipv4'\` or \`'ipv6'\`.
+ // * @since v15.14.0, v14.18.0
+ // */
+ // readonly family: IPVersion;
+ // /**
+ // * @since v15.14.0, v14.18.0
+ // */
+ // readonly port: number;
+ // /**
+ // * @since v15.14.0, v14.18.0
+ // */
+ // readonly flowlabel: number;
+ // }
+}
+declare module "node:net" {
+ export * from "net";
+}
diff --git a/packages/bun-types/package.json b/packages/bun-types/package.json
index b8c8a2e2a..b7eea6ea5 100644
--- a/packages/bun-types/package.json
+++ b/packages/bun-types/package.json
@@ -6,13 +6,11 @@
"scripts": {
"build": "rm -rf ./dist && bun run bundle && bun run fmt",
"bundle": "bun scripts/bundle.ts ./dist",
- "docs": "bun run build && typedoc",
"test": "tsd",
"fmt": "prettier --write './**/*.{ts,tsx,js,jsx}'"
},
"devDependencies": {
"tsd": "^0.22.0",
- "typedoc": "^0.23.9",
"prettier": "^2.4.1"
},
"tsd": {
diff --git a/packages/bun-types/string_decoder.d.ts b/packages/bun-types/string_decoder.d.ts
index aee1680dc..b4d507fac 100644
--- a/packages/bun-types/string_decoder.d.ts
+++ b/packages/bun-types/string_decoder.d.ts
@@ -39,6 +39,7 @@
* @see [source](https://github.com/nodejs/node/blob/v18.0.0/lib/string_decoder.js)
*/
declare module "string_decoder" {
+ import { ArrayBufferView } from "bun";
class StringDecoder {
constructor(encoding?: BufferEncoding);
/**
@@ -47,7 +48,7 @@ declare module "string_decoder" {
* returned string and stored in an internal buffer for the next call to`stringDecoder.write()` or `stringDecoder.end()`.
* @param buffer A `Buffer`, or `TypedArray`, or `DataView` containing the bytes to decode.
*/
- write(buffer: Buffer | ArrayBufferView): string;
+ write(buffer: ArrayBufferView): string;
/**
* Returns any remaining input stored in the internal buffer as a string. Bytes
* representing incomplete UTF-8 and UTF-16 characters will be replaced with
@@ -57,7 +58,7 @@ declare module "string_decoder" {
* After `end()` is called, the `stringDecoder` object can be reused for new input.
* @param buffer A `Buffer`, or `TypedArray`, or `DataView` containing the bytes to decode.
*/
- end(buffer?: Buffer | ArrayBufferView): string;
+ end(buffer?: ArrayBufferView): string;
}
}
declare module "node:string_decoder" {
diff --git a/packages/bun-types/tsconfig.json b/packages/bun-types/tsconfig.json
index 709470196..644fb4587 100644
--- a/packages/bun-types/tsconfig.json
+++ b/packages/bun-types/tsconfig.json
@@ -10,6 +10,7 @@
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"disableSolutionSearching": true,
+ "noUnusedLocals": true
},
"exclude": [
"dist",
diff --git a/packages/bun-types/zlib.d.ts b/packages/bun-types/zlib.d.ts
index 877350b93..ce1e581b0 100644
--- a/packages/bun-types/zlib.d.ts
+++ b/packages/bun-types/zlib.d.ts
@@ -90,6 +90,7 @@
* @see [source](https://github.com/nodejs/node/blob/v18.0.0/lib/zlib.js)
*/
declare module "zlib" {
+ import { ArrayBufferView } from "bun";
import * as stream from "node:stream";
interface ZlibOptions {
/**
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index e9b760de5..32bd0a9ec 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -942,7 +942,17 @@ fn doResolve(
return null;
}
- return doResolveWithArgs(ctx, specifier.getZigString(ctx.ptr()), from.getZigString(ctx.ptr()), exception, false);
+ var is_esm = true;
+ if (args.nextEat()) |next| {
+ if (next.isBoolean()) {
+ is_esm = next.toBoolean();
+ } else {
+ JSC.throwInvalidArguments("esm must be a boolean", .{}, ctx, exception);
+ return null;
+ }
+ }
+
+ return doResolveWithArgs(ctx, specifier.getZigString(ctx.ptr()), from.getZigString(ctx.ptr()), exception, is_esm, false);
}
fn doResolveWithArgs(
@@ -950,6 +960,7 @@ fn doResolveWithArgs(
specifier: ZigString,
from: ZigString,
exception: js.ExceptionRef,
+ is_esm: bool,
comptime is_file_path: bool,
) ?JSC.JSValue {
var errorable: ErrorableZigString = undefined;
@@ -960,6 +971,7 @@ fn doResolveWithArgs(
ctx.ptr(),
specifier,
from,
+ is_esm,
);
} else {
VirtualMachine.resolveForAPI(
@@ -967,6 +979,7 @@ fn doResolveWithArgs(
ctx.ptr(),
specifier,
from,
+ is_esm,
);
}
@@ -1010,10 +1023,11 @@ export fn Bun__resolve(
global: *JSGlobalObject,
specifier: JSValue,
source: JSValue,
+ is_esm: bool,
) JSC.JSValue {
var exception_ = [1]JSC.JSValueRef{null};
var exception = &exception_;
- const value = doResolveWithArgs(global, specifier.getZigString(global), source.getZigString(global), exception, true) orelse {
+ const value = doResolveWithArgs(global, specifier.getZigString(global), source.getZigString(global), exception, is_esm, true) orelse {
return JSC.JSPromise.rejectedPromiseValue(global, JSC.JSValue.fromRef(exception[0]));
};
return JSC.JSPromise.resolvedPromiseValue(global, value);
@@ -1023,10 +1037,11 @@ export fn Bun__resolveSync(
global: *JSGlobalObject,
specifier: JSValue,
source: JSValue,
+ is_esm: bool,
) JSC.JSValue {
var exception_ = [1]JSC.JSValueRef{null};
var exception = &exception_;
- return doResolveWithArgs(global, specifier.getZigString(global), source.getZigString(global), exception, true) orelse {
+ return doResolveWithArgs(global, specifier.getZigString(global), source.getZigString(global), exception, is_esm, true) orelse {
return JSC.JSValue.fromRef(exception[0]);
};
}
diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig
index f4dcfb01c..911dc9e89 100644
--- a/src/bun.js/api/bun/socket.zig
+++ b/src/bun.js/api/bun/socket.zig
@@ -232,38 +232,65 @@ pub const SocketConfig = struct {
}
}
- if (opts.getTruthy(globalObject, "hostname")) |hostname| {
- if (hostname.isEmptyOrUndefinedOrNull() or !hostname.isString()) {
- exception.* = JSC.toInvalidArguments("Expected \"hostname\" to be a string", .{}, globalObject).asObjectRef();
- return null;
- }
+ hostname_or_unix: {
+ if (opts.getTruthy(globalObject, "unix")) |unix_socket| {
+ if (!unix_socket.isString()) {
+ exception.* = JSC.toInvalidArguments("Expected \"unix\" to be a string", .{}, globalObject).asObjectRef();
+ return null;
+ }
- const port_value = opts.get(globalObject, "port") orelse JSValue.zero;
- if (port_value.isEmptyOrUndefinedOrNull() or !port_value.isNumber() or port_value.toInt64() > std.math.maxInt(u16) or port_value.toInt64() < 0) {
- exception.* = JSC.toInvalidArguments("Expected \"port\" to be a number between 0 and 65535", .{}, globalObject).asObjectRef();
- return null;
- }
+ hostname_or_unix = unix_socket.getZigString(globalObject).toSlice(bun.default_allocator);
- hostname_or_unix = hostname.getZigString(globalObject).toSlice(bun.default_allocator);
- port = port_value.toU16();
+ if (strings.hasPrefixComptime(hostname_or_unix.slice(), "file://") or strings.hasPrefixComptime(hostname_or_unix.slice(), "unix://") or strings.hasPrefixComptime(hostname_or_unix.slice(), "sock://")) {
+ hostname_or_unix.ptr += 7;
+ hostname_or_unix.len -|= 7;
+ }
- if (hostname_or_unix.len == 0) {
- exception.* = JSC.toInvalidArguments("Expected \"hostname\" to be a non-empty string", .{}, globalObject).asObjectRef();
- return null;
- }
- } else if (opts.getTruthy(globalObject, "unix")) |unix_socket| {
- if (unix_socket.isEmptyOrUndefinedOrNull() or !unix_socket.isString()) {
- exception.* = JSC.toInvalidArguments("Expected \"unix\" to be a string", .{}, globalObject).asObjectRef();
- return null;
+ if (hostname_or_unix.len > 0) {
+ break :hostname_or_unix;
+ }
}
- hostname_or_unix = unix_socket.getZigString(globalObject).toSlice(bun.default_allocator);
+ if (opts.getTruthy(globalObject, "hostname")) |hostname| {
+ if (!hostname.isString()) {
+ exception.* = JSC.toInvalidArguments("Expected \"hostname\" to be a string", .{}, globalObject).asObjectRef();
+ return null;
+ }
+
+ var port_value = opts.get(globalObject, "port") orelse JSValue.zero;
+ hostname_or_unix = hostname.getZigString(globalObject).toSlice(bun.default_allocator);
+
+ if (port_value.isEmptyOrUndefinedOrNull() and hostname_or_unix.len > 0) {
+ const parsed_url = bun.URL.parse(hostname_or_unix.slice());
+ if (parsed_url.getPort()) |port_num| {
+ port_value = JSValue.jsNumber(port_num);
+ hostname_or_unix.ptr = parsed_url.hostname.ptr;
+ hostname_or_unix.len = @truncate(u32, parsed_url.hostname.len);
+ }
+ }
+
+ if (port_value.isEmptyOrUndefinedOrNull() or !port_value.isNumber() or port_value.toInt64() > std.math.maxInt(u16) or port_value.toInt64() < 0) {
+ exception.* = JSC.toInvalidArguments("Expected \"port\" to be a number between 0 and 65535", .{}, globalObject).asObjectRef();
+ return null;
+ }
+
+ port = port_value.toU16();
+
+ if (hostname_or_unix.len == 0) {
+ exception.* = JSC.toInvalidArguments("Expected \"hostname\" to be a non-empty string", .{}, globalObject).asObjectRef();
+ return null;
+ }
+
+ if (hostname_or_unix.len > 0) {
+ break :hostname_or_unix;
+ }
+ }
if (hostname_or_unix.len == 0) {
exception.* = JSC.toInvalidArguments("Expected \"unix\" to be a non-empty string", .{}, globalObject).asObjectRef();
return null;
}
- } else {
+
exception.* = JSC.toInvalidArguments("Expected either \"hostname\" or \"unix\"", .{}, globalObject).asObjectRef();
return null;
}
diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig
index f47ee9fc0..137d164f0 100644
--- a/src/bun.js/api/server.zig
+++ b/src/bun.js/api/server.zig
@@ -2135,8 +2135,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp
const result = JSC.C.JSObjectCallAsFunctionReturnValue(this.server.globalThis, this.server.config.onError.asObjectRef(), this.server.thisObject.asObjectRef(), 1, &args);
if (!result.isEmptyOrUndefinedOrNull()) {
- if (result.isError() or result.isAggregateError(this.server.globalThis)) {
- this.finishRunningErrorHandler(result, status);
+ if (result.toError()) |err| {
+ this.finishRunningErrorHandler(err, status);
return;
} else if (result.as(Response)) |response| {
this.render(response);
@@ -2514,7 +2514,10 @@ pub const WebSocketServer = struct {
active_connections: usize = 0,
/// used by publish()
- ssl: bool = false,
+ flags: packed struct(u2) {
+ ssl: bool = false,
+ publish_to_self: bool = true,
+ } = .{},
pub fn fromJS(globalObject: *JSC.JSGlobalObject, object: JSC.JSValue) ?Handler {
var handler = Handler{ .globalObject = globalObject };
@@ -2752,6 +2755,17 @@ pub const WebSocketServer = struct {
}
}
+ if (object.get(globalObject, "publishToSelf")) |value| {
+ if (!value.isUndefinedOrNull()) {
+ if (!value.isBoolean()) {
+ globalObject.throwInvalidArguments("websocket expects publishToSelf to be a boolean", .{});
+ return null;
+ }
+
+ server.handler.flags.publish_to_self = value.toBoolean();
+ }
+ }
+
server.protect();
return server;
}
@@ -3025,7 +3039,9 @@ pub const ServerWebSocket = struct {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
- const ssl = this.handler.ssl;
+ const flags = this.handler.flags;
+ const ssl = flags.ssl;
+ const publish_to_self = flags.publish_to_self;
const topic_value = args.ptr[0];
const message_value = args.ptr[1];
@@ -3051,16 +3067,23 @@ pub const ServerWebSocket = struct {
return .zero;
}
- if (message_value.asArrayBuffer(globalThis)) |buffer| {
+ if (message_value.asArrayBuffer(globalThis)) |array_buffer| {
+ const buffer = array_buffer.slice();
+
if (buffer.len == 0) {
globalThis.throw("publish requires a non-empty message", .{});
return .zero;
}
+ const result = if (!publish_to_self)
+ this.websocket.publish(topic_slice.slice(), buffer, .binary, compress)
+ else
+ uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer, .binary, compress);
+
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
- @as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ if (result) @intCast(i32, @truncate(u31, buffer.len)) else @as(i32, 0),
);
}
@@ -3072,10 +3095,16 @@ pub const ServerWebSocket = struct {
}
const buffer = string_slice.slice();
+
+ const result = if (!publish_to_self)
+ this.websocket.publish(topic_slice.slice(), buffer, .text, compress)
+ else
+ uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer, .text, compress);
+
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
- @as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ if (result) @intCast(i32, @truncate(u31, buffer.len)) else @as(i32, 0),
);
}
@@ -3099,7 +3128,9 @@ pub const ServerWebSocket = struct {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
- const ssl = this.handler.ssl;
+ const flags = this.handler.flags;
+ const ssl = flags.ssl;
+ const publish_to_self = flags.publish_to_self;
const topic_value = args.ptr[0];
const message_value = args.ptr[1];
@@ -3132,10 +3163,16 @@ pub const ServerWebSocket = struct {
}
const buffer = string_slice.slice();
+
+ const result = if (!publish_to_self)
+ this.websocket.publish(topic_slice.slice(), buffer, .text, compress)
+ else
+ uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer, .text, compress);
+
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
- @as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer, .text, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ if (result) @intCast(i32, @truncate(u31, buffer.len)) else @as(i32, 0),
);
}
@@ -3156,7 +3193,9 @@ pub const ServerWebSocket = struct {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
- const ssl = this.handler.ssl;
+ const flags = this.handler.flags;
+ const ssl = flags.ssl;
+ const publish_to_self = flags.publish_to_self;
const topic_value = args.ptr[0];
const message_value = args.ptr[1];
const compress_value = args.ptr[2];
@@ -3180,19 +3219,25 @@ pub const ServerWebSocket = struct {
globalThis.throw("publishBinary requires a non-empty message", .{});
return .zero;
}
- const buffer = message_value.asArrayBuffer(globalThis) orelse {
+ const array_buffer = message_value.asArrayBuffer(globalThis) orelse {
globalThis.throw("publishBinary expects an ArrayBufferView", .{});
return .zero;
};
+ const buffer = array_buffer.slice();
if (buffer.len == 0) {
return JSC.JSValue.jsNumber(0);
}
+ const result = if (!publish_to_self)
+ this.websocket.publish(topic_slice.slice(), buffer, .binary, compress)
+ else
+ uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer, .binary, compress);
+
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
- @as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer.slice(), .binary, compress))) * @intCast(i32, @truncate(u31, buffer.len)),
+ if (result) @intCast(i32, @truncate(u31, buffer.len)) else @as(i32, 0),
);
}
@@ -3200,13 +3245,15 @@ pub const ServerWebSocket = struct {
this: *ServerWebSocket,
globalThis: *JSC.JSGlobalObject,
topic_str: *JSC.JSString,
- buffer: *JSC.JSUint8Array,
+ array: *JSC.JSUint8Array,
) callconv(.C) JSC.JSValue {
var app = this.handler.app orelse {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
- const ssl = this.handler.ssl;
+ const flags = this.handler.flags;
+ const ssl = flags.ssl;
+ const publish_to_self = flags.publish_to_self;
var topic_slice = topic_str.toSlice(globalThis, bun.default_allocator);
defer topic_slice.deinit();
@@ -3217,30 +3264,20 @@ pub const ServerWebSocket = struct {
const compress = true;
- const slice = buffer.slice();
- if (slice.len == 0) {
+ const buffer = array.slice();
+ if (buffer.len == 0) {
return JSC.JSValue.jsNumber(0);
}
+ const result = if (!publish_to_self)
+ this.websocket.publish(topic_slice.slice(), buffer, .binary, compress)
+ else
+ uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer, .binary, compress);
+
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
- @as(
- i32,
- @boolToInt(
- uws.AnyWebSocket.publishWithOptions(
- ssl,
- app,
- topic_slice.slice(),
- slice,
- .binary,
- compress,
- ),
- ),
- ) * @intCast(
- i32,
- @truncate(u31, slice.len),
- ),
+ if (result) @intCast(i32, @truncate(u31, buffer.len)) else @as(i32, 0),
);
}
@@ -3254,7 +3291,9 @@ pub const ServerWebSocket = struct {
log("publish() closed", .{});
return JSValue.jsNumber(0);
};
- const ssl = this.handler.ssl;
+ const flags = this.handler.flags;
+ const ssl = flags.ssl;
+ const publish_to_self = flags.publish_to_self;
var topic_slice = topic_str.toSlice(globalThis, bun.default_allocator);
defer topic_slice.deinit();
@@ -3266,24 +3305,21 @@ pub const ServerWebSocket = struct {
const compress = true;
const slice = str.toSlice(globalThis, bun.default_allocator);
- if (slice.len == 0) {
+ defer slice.deinit();
+ const buffer = slice.slice();
+
+ if (buffer.len == 0) {
return JSC.JSValue.jsNumber(0);
}
+ const result = if (!publish_to_self)
+ this.websocket.publish(topic_slice.slice(), buffer, .text, compress)
+ else
+ uws.AnyWebSocket.publishWithOptions(ssl, app, topic_slice.slice(), buffer, .text, compress);
return JSValue.jsNumber(
// if 0, return 0
// else return number of bytes sent
- @as(i32, @boolToInt(uws.AnyWebSocket.publishWithOptions(
- ssl,
- app,
- topic_slice.slice(),
- slice.slice(),
- .text,
- compress,
- ))) * @intCast(
- i32,
- @truncate(u31, slice.len),
- ),
+ if (result) @intCast(i32, @truncate(u31, buffer.len)) else @as(i32, 0),
);
}
@@ -4107,7 +4143,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
}
if (new_config.websocket) |*ws| {
- ws.handler.ssl = ssl_enabled;
+ ws.handler.flags.ssl = ssl_enabled;
if (ws.handler.onMessage != .zero or ws.handler.onOpen != .zero) {
if (this.config.websocket) |old_ws| {
old_ws.unprotect();
@@ -4671,7 +4707,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type {
if (this.config.websocket) |*websocket| {
websocket.globalObject = this.globalThis;
websocket.handler.app = this.app;
- websocket.handler.ssl = ssl_enabled;
+ websocket.handler.flags.ssl = ssl_enabled;
this.app.ws(
"/*",
this,
diff --git a/src/bun.js/bindings/ImportMetaObject.cpp b/src/bun.js/bindings/ImportMetaObject.cpp
index 5838bde04..0247b5140 100644
--- a/src/bun.js/bindings/ImportMetaObject.cpp
+++ b/src/bun.js/bindings/ImportMetaObject.cpp
@@ -80,7 +80,7 @@ static EncodedJSValue functionRequireResolve(JSC::JSGlobalObject* globalObject,
}
}
- auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from);
+ auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, false);
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
if (!JSC::JSValue::decode(result).isString()) {
@@ -156,17 +156,18 @@ JSObject* Zig::ImportMetaObject::createRequireFunction(VM& vm, JSGlobalObject* g
JSFunction* requireFunction = JSFunction::create(vm, importMetaObjectRequireCodeGenerator(vm), globalObject);
auto clientData = WebCore::clientData(vm);
requireFunction->putDirectCustomAccessor(vm, clientData->builtinNames().resolvePublicName(), JSC::CustomGetterSetter::create(vm, functionRequireResolveLazyGetter, functionRequireResolveLazySetter), 0);
- requireFunction->putDirect(vm, clientData->builtinNames().pathPrivateName(), jsOwnedString(vm, pathString), JSC::PropertyAttribute::DontEnum | 0);
+ requireFunction->putDirect(vm, clientData->builtinNames().pathPublicName(), jsString(vm, pathString), JSC::PropertyAttribute::DontEnum | 0);
return requireFunction;
}
extern "C" EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame)
{
JSC::VM& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
switch (callFrame->argumentCount()) {
case 0: {
- auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
+
// not "requires" because "require" could be confusing
JSC::throwTypeError(globalObject, scope, "import.meta.resolveSync needs 1 argument (a string)"_s);
scope.release();
@@ -176,13 +177,13 @@ extern "C" EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObject* g
JSC::JSValue moduleName = callFrame->argument(0);
if (moduleName.isUndefinedOrNull()) {
- auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
JSC::throwTypeError(globalObject, scope, "import.meta.resolveSync expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
JSC__JSValue from;
+ bool isESM = true;
if (callFrame->argumentCount() > 1) {
JSC::JSValue fromValue = callFrame->argument(1);
@@ -195,8 +196,20 @@ extern "C" EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObject* g
fromValue = array->getIndex(globalObject, 0);
}
}
+
+ if (callFrame->argumentCount() > 2) {
+ JSC::JSValue isESMValue = callFrame->argument(2);
+ if (isESMValue.isBoolean()) {
+ isESM = isESMValue.toBoolean(globalObject);
+ RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
+ }
+ }
+ } else if (fromValue.isBoolean()) {
+ isESM = fromValue.toBoolean(globalObject);
+ RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
}
from = JSC::JSValue::encode(fromValue);
+
} else {
JSC::JSObject* thisObject = JSC::jsDynamicCast<JSC::JSObject*>(callFrame->thisValue());
if (UNLIKELY(!thisObject)) {
@@ -210,8 +223,7 @@ extern "C" EncodedJSValue functionImportMeta__resolveSync(JSC::JSGlobalObject* g
from = JSC::JSValue::encode(thisObject->get(globalObject, clientData->builtinNames().pathPublicName()));
}
- auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from);
- auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
+ auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, isESM);
if (!JSC::JSValue::decode(result).isString()) {
JSC::throwException(globalObject, scope, JSC::JSValue::decode(result));
@@ -266,7 +278,7 @@ JSC_DEFINE_HOST_FUNCTION(functionImportMeta__resolve,
from = JSC::JSValue::encode(thisObject->get(globalObject, clientData->builtinNames().pathPublicName()));
}
- return Bun__resolve(globalObject, JSC::JSValue::encode(moduleName), from);
+ return Bun__resolve(globalObject, JSC::JSValue::encode(moduleName), from, true);
}
}
}
diff --git a/src/bun.js/bindings/ImportMetaObject.h b/src/bun.js/bindings/ImportMetaObject.h
index 3ce50ebbb..ff32c85d4 100644
--- a/src/bun.js/bindings/ImportMetaObject.h
+++ b/src/bun.js/bindings/ImportMetaObject.h
@@ -9,8 +9,8 @@
#include "JSDOMWrapperCache.h"
extern "C" JSC_DECLARE_HOST_FUNCTION(functionImportMeta__resolveSync);
-extern "C" EncodedJSValue Bun__resolve(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from);
-extern "C" EncodedJSValue Bun__resolveSync(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from);
+extern "C" EncodedJSValue Bun__resolve(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from, bool is_esm);
+extern "C" EncodedJSValue Bun__resolveSync(JSC::JSGlobalObject* global, JSC::EncodedJSValue specifier, JSC::EncodedJSValue from, bool is_esm);
namespace Zig {
diff --git a/src/bun.js/bindings/JSBufferList.cpp b/src/bun.js/bindings/JSBufferList.cpp
index e54b433e5..9b9990598 100644
--- a/src/bun.js/bindings/JSBufferList.cpp
+++ b/src/bun.js/bindings/JSBufferList.cpp
@@ -32,7 +32,7 @@ void JSBufferList::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject
JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly);
}
-JSC::JSValue JSBufferList::concat(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t n)
+JSC::JSValue JSBufferList::concat(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, size_t n)
{
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* subclassStructure = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject)->JSBufferSubclassStructure();
@@ -75,6 +75,8 @@ JSC::JSValue JSBufferList::concat(JSC::VM& vm, JSC::JSGlobalObject* lexicalGloba
i += length;
}
+ memset(uint8Array->typedVector() + i, 0, n - i);
+
RELEASE_AND_RETURN(throwScope, uint8Array);
}
@@ -100,7 +102,7 @@ JSC::JSValue JSBufferList::join(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalO
RELEASE_AND_RETURN(throwScope, ropeBuilder.release());
}
-JSC::JSValue JSBufferList::consume(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t n, bool hasString)
+JSC::JSValue JSBufferList::consume(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, size_t n, bool hasString)
{
if (hasString)
return _getString(vm, lexicalGlobalObject, n);
@@ -108,7 +110,7 @@ JSC::JSValue JSBufferList::consume(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlob
return _getBuffer(vm, lexicalGlobalObject, n);
}
-JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t total)
+JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, size_t total)
{
auto throwScope = DECLARE_THROW_SCOPE(vm);
if (total <= 0 || length() == 0) {
@@ -150,13 +152,14 @@ JSC::JSValue JSBufferList::_getString(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
if (!ropeBuilder.append(str))
return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
m_deque.removeFirst();
- if (n == len) break;
+ if (n == len)
+ break;
n -= len;
}
RELEASE_AND_RETURN(throwScope, ropeBuilder.release());
}
-JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, int32_t total)
+JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, size_t total)
{
auto throwScope = DECLARE_THROW_SCOPE(vm);
auto* subclassStructure = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject)->JSBufferSubclassStructure();
@@ -205,16 +208,23 @@ JSC::JSValue JSBufferList::_getBuffer(JSC::VM& vm, JSC::JSGlobalObject* lexicalG
auto buffer = array->possiblySharedBuffer();
JSC::JSUint8Array* newArray = JSC::JSUint8Array::create(lexicalGlobalObject, subclassStructure, buffer, n, len - n);
iter->set(vm, this, newArray);
+ offset += n;
break;
}
if (UNLIKELY(!uint8Array->setFromTypedArray(lexicalGlobalObject, offset, array, 0, len, JSC::CopyType::Unobservable))) {
return throwOutOfMemoryError(lexicalGlobalObject, throwScope);
}
m_deque.removeFirst();
- if (n == len) break;
+ if (n == len) {
+ offset += len;
+ break;
+ }
n -= len;
offset += len;
}
+
+ memset(uint8Array->typedVector() + offset, 0, total - offset);
+
RELEASE_AND_RETURN(throwScope, uint8Array);
}
diff --git a/src/bun.js/bindings/JSBufferList.h b/src/bun.js/bindings/JSBufferList.h
index a9227e981..94a69c8d1 100644
--- a/src/bun.js/bindings/JSBufferList.h
+++ b/src/bun.js/bindings/JSBufferList.h
@@ -76,11 +76,11 @@ public:
return JSC::JSValue(m_deque.first().get());
}
- JSC::JSValue concat(JSC::VM&, JSC::JSGlobalObject*, int32_t);
+ JSC::JSValue concat(JSC::VM&, JSC::JSGlobalObject*, size_t);
JSC::JSValue join(JSC::VM&, JSC::JSGlobalObject*, JSString*);
- JSC::JSValue consume(JSC::VM&, JSC::JSGlobalObject*, int32_t, bool);
- JSC::JSValue _getBuffer(JSC::VM&, JSC::JSGlobalObject*, int32_t);
- JSC::JSValue _getString(JSC::VM&, JSC::JSGlobalObject*, int32_t);
+ JSC::JSValue consume(JSC::VM&, JSC::JSGlobalObject*, size_t, bool);
+ JSC::JSValue _getBuffer(JSC::VM&, JSC::JSGlobalObject*, size_t);
+ JSC::JSValue _getString(JSC::VM&, JSC::JSGlobalObject*, size_t);
private:
Deque<WriteBarrier<Unknown>> m_deque;
@@ -134,6 +134,7 @@ public:
// Must be defined for each specialization class.
static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
DECLARE_EXPORT_INFO;
+
private:
JSBufferListConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
: Base(vm, structure, nativeFunction, nativeFunction)
diff --git a/src/bun.js/bindings/JSStringDecoder.cpp b/src/bun.js/bindings/JSStringDecoder.cpp
index 66f9cb654..ca79e9e1c 100644
--- a/src/bun.js/bindings/JSStringDecoder.cpp
+++ b/src/bun.js/bindings/JSStringDecoder.cpp
@@ -206,9 +206,30 @@ JSC::JSValue JSStringDecoder::write(JSC::VM& vm, JSC::JSGlobalObject* globalObje
}
}
-JSC::JSValue JSStringDecoder::end(JSC::VM& vm, JSC::JSGlobalObject* globalObject, uint8_t* bufPtr, uint32_t length)
+class ResetScope final {
+public:
+ ResetScope(JSStringDecoder* decoder);
+ ~ResetScope();
+ JSStringDecoder* m_decoder;
+};
+
+ResetScope::ResetScope(JSStringDecoder* decoder)
+{
+ m_decoder = decoder;
+}
+
+ResetScope::~ResetScope()
+{
+ m_decoder->m_lastTotal = 0;
+ m_decoder->m_lastNeed = 0;
+ memset(m_decoder->m_lastChar, 0, 4);
+}
+
+JSC::JSValue
+JSStringDecoder::end(JSC::VM& vm, JSC::JSGlobalObject* globalObject, uint8_t* bufPtr, uint32_t length)
{
auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto resetScope = ResetScope(this);
switch (m_encoding) {
case BufferEncodingType::ucs2:
case BufferEncodingType::utf16le: {
diff --git a/src/bun.js/bindings/JSStringDecoder.h b/src/bun.js/bindings/JSStringDecoder.h
index 299c2fb96..bce1ae05d 100644
--- a/src/bun.js/bindings/JSStringDecoder.h
+++ b/src/bun.js/bindings/JSStringDecoder.h
@@ -11,7 +11,10 @@ class JSStringDecoder : public JSC::JSDestructibleObject {
public:
JSStringDecoder(JSC::VM& vm, JSC::Structure* structure, BufferEncodingType encoding)
- : Base(vm, structure), m_lastNeed(0), m_lastTotal(0), m_encoding(encoding)
+ : Base(vm, structure)
+ , m_lastNeed(0)
+ , m_lastTotal(0)
+ , m_encoding(encoding)
{
}
@@ -108,6 +111,7 @@ public:
// Must be defined for each specialization class.
static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
DECLARE_EXPORT_INFO;
+
private:
JSStringDecoderConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
: Base(vm, structure, nativeFunction, nativeFunction)
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 41a52956d..1bee13fc0 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -1339,7 +1339,7 @@ pub fn NewGlobalObject(comptime Type: type) type {
}
pub fn resolve(res: *ErrorableZigString, global: *JSGlobalObject, specifier: *ZigString, source: *ZigString) callconv(.C) void {
if (comptime @hasDecl(Type, "resolve")) {
- @call(.always_inline, Type.resolve, .{ res, global, specifier.*, source.* });
+ @call(.always_inline, Type.resolve, .{ res, global, specifier.*, source.*, true });
return;
}
res.* = ErrorableZigString.err(error.ResolveFailed, ZigString.init(resolveNotImpl).toErrorInstance(global).asVoid());
@@ -1506,7 +1506,7 @@ pub const JSPromise = extern struct {
) JSValue {
if (value.isEmpty()) {
return resolvedPromiseValue(globalObject, JSValue.jsUndefined());
- } else if (value.isUndefinedOrNull() or !value.isCell()) {
+ } else if (value.isEmptyOrUndefinedOrNull() or !value.isCell()) {
return resolvedPromiseValue(globalObject, value);
}
@@ -2484,10 +2484,8 @@ pub const JSValue = enum(JSValueReprInt) {
}
pub fn isObject(this: JSType) bool {
- return switch (this) {
- .Object, .FinalObject => true,
- else => false,
- };
+ // inline constexpr bool isObjectType(JSType type) { return type >= ObjectType; }
+ return @enumToInt(this) >= @enumToInt(JSType.Object);
}
pub fn isFunction(this: JSType) bool {
@@ -2663,7 +2661,7 @@ pub const JSValue = enum(JSValueReprInt) {
}
pub fn isInstanceOf(this: JSValue, global: *JSGlobalObject, constructor: JSValue) bool {
- if (this.isEmptyOrUndefinedOrNull())
+ if (!this.isCell())
return false;
return JSC.C.JSValueIsInstanceOfConstructor(global, this.asObjectRef(), constructor.asObjectRef(), null);
@@ -3112,8 +3110,8 @@ pub const JSValue = enum(JSValueReprInt) {
pub fn isCustomGetterSetter(this: JSValue) bool {
return cppFn("isCustomGetterSetter", .{this});
}
- pub fn isObject(this: JSValue) bool {
- return cppFn("isObject", .{this});
+ pub inline fn isObject(this: JSValue) bool {
+ return this.isCell() and this.jsType().isObject();
}
pub fn isClass(this: JSValue, global: *JSGlobalObject) bool {
diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h
index 065fd8caa..a05007fff 100644
--- a/src/bun.js/bindings/headers-cpp.h
+++ b/src/bun.js/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1673374722
+//-- AUTOGENERATED FILE -- 1673376494
// clang-format off
#pragma once
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index 4e5dabe4e..71a8d1034 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format off
-//-- AUTOGENERATED FILE -- 1673374722
+//-- AUTOGENERATED FILE -- 1673376494
#pragma once
#include <stddef.h>
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index fd2ded108..c2c43cf81 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -429,7 +429,7 @@ pub const VirtualMachine = struct {
auto_install_dependencies: bool = false,
load_builtins_from_path: []const u8 = "",
- onUnhandledRejection: *const fn (*VirtualMachine, globalObject: *JSC.JSGlobalObject, JSC.JSValue) void = defaultOnUnhandledRejection,
+ onUnhandledRejection: *const OnUnhandledRejection = defaultOnUnhandledRejection,
onUnhandledRejectionCtx: ?*anyopaque = null,
unhandled_error_counter: usize = 0,
@@ -438,6 +438,8 @@ pub const VirtualMachine = struct {
gc_controller: JSC.GarbageCollectionController = .{},
+ pub const OnUnhandledRejection = fn (*VirtualMachine, globalObject: *JSC.JSGlobalObject, JSC.JSValue) void;
+
const VMHolder = struct {
pub threadlocal var vm: ?*VirtualMachine = null;
};
@@ -454,6 +456,30 @@ pub const VirtualMachine = struct {
pub threadlocal var is_main_thread_vm: bool = false;
+ pub const UnhandledRejectionScope = struct {
+ ctx: ?*anyopaque = null,
+ onUnhandledRejection: *const OnUnhandledRejection = undefined,
+ count: usize = 0,
+
+ pub fn apply(this: *UnhandledRejectionScope, vm: *JSC.VirtualMachine) void {
+ vm.onUnhandledRejection = this.onUnhandledRejection;
+ vm.onUnhandledRejectionCtx = this.ctx;
+ vm.unhandled_error_counter = this.count;
+ }
+ };
+
+ pub fn onQuietUnhandledRejectionHandler(this: *VirtualMachine, _: *JSC.JSGlobalObject, _: JSC.JSValue) void {
+ this.unhandled_error_counter += 1;
+ }
+
+ pub fn unhandledRejectionScope(this: *VirtualMachine) UnhandledRejectionScope {
+ return .{
+ .onUnhandledRejection = this.onUnhandledRejection,
+ .ctx = this.onUnhandledRejectionCtx,
+ .count = this.unhandled_error_counter,
+ };
+ }
+
pub fn resetUnhandledRejection(this: *VirtualMachine) void {
this.onUnhandledRejection = defaultOnUnhandledRejection;
}
@@ -891,6 +917,7 @@ pub const VirtualMachine = struct {
_: *JSGlobalObject,
specifier: string,
source: string,
+ is_esm: bool,
comptime is_a_file_path: bool,
comptime realpath: bool,
) !void {
@@ -936,7 +963,7 @@ pub const VirtualMachine = struct {
jsc_vm.bundler.fs.top_level_dir,
// TODO: do we need to handle things like query string params?
if (strings.hasPrefixComptime(specifier, "file://")) specifier["file://".len..] else specifier,
- .stmt,
+ if (is_esm) .stmt else .require,
.read_only,
)) {
.success => |r| r,
@@ -1012,19 +1039,53 @@ pub const VirtualMachine = struct {
}
}
- pub fn resolveForAPI(res: *ErrorableZigString, global: *JSGlobalObject, specifier: ZigString, source: ZigString) void {
- resolveMaybeNeedsTrailingSlash(res, global, specifier, source, false, true);
+ pub fn resolveForAPI(
+ res: *ErrorableZigString,
+ global: *JSGlobalObject,
+ specifier: ZigString,
+ source: ZigString,
+ is_esm: bool,
+ ) void {
+ resolveMaybeNeedsTrailingSlash(res, global, specifier, source, is_esm, false, true);
}
- pub fn resolveFilePathForAPI(res: *ErrorableZigString, global: *JSGlobalObject, specifier: ZigString, source: ZigString) void {
- resolveMaybeNeedsTrailingSlash(res, global, specifier, source, true, true);
+ pub fn resolveFilePathForAPI(
+ res: *ErrorableZigString,
+ global: *JSGlobalObject,
+ specifier: ZigString,
+ source: ZigString,
+ is_esm: bool,
+ ) void {
+ resolveMaybeNeedsTrailingSlash(res, global, specifier, source, is_esm, true, true);
+ }
+
+ pub fn resolve(
+ res: *ErrorableZigString,
+ global: *JSGlobalObject,
+ specifier: ZigString,
+ source: ZigString,
+ is_esm: bool,
+ ) void {
+ resolveMaybeNeedsTrailingSlash(res, global, specifier, source, is_esm, true, false);
}
- pub fn resolve(res: *ErrorableZigString, global: *JSGlobalObject, specifier: ZigString, source: ZigString) void {
- resolveMaybeNeedsTrailingSlash(res, global, specifier, source, true, false);
+ fn normalizeSource(source: []const u8) []const u8 {
+ if (strings.hasPrefixComptime(source, "file://")) {
+ return source["file://".len..];
+ }
+
+ return source;
}
- pub fn resolveMaybeNeedsTrailingSlash(res: *ErrorableZigString, global: *JSGlobalObject, specifier: ZigString, source: ZigString, comptime is_a_file_path: bool, comptime realpath: bool) void {
+ pub fn resolveMaybeNeedsTrailingSlash(
+ res: *ErrorableZigString,
+ global: *JSGlobalObject,
+ specifier: ZigString,
+ source: ZigString,
+ is_esm: bool,
+ comptime is_a_file_path: bool,
+ comptime realpath: bool,
+ ) void {
var result = ResolveFunctionResult{ .path = "", .result = null };
var jsc_vm = VirtualMachine.get();
if (jsc_vm.plugin_runner) |plugin_runner| {
@@ -1057,7 +1118,7 @@ pub const VirtualMachine = struct {
jsc_vm.bundler.linker.log = old_log;
jsc_vm.bundler.resolver.log = old_log;
}
- _resolve(&result, global, specifier.slice(), source.slice(), is_a_file_path, realpath) catch |err_| {
+ _resolve(&result, global, specifier.slice(), normalizeSource(source.slice()), is_esm, is_a_file_path, realpath) catch |err_| {
var err = err_;
const msg: logger.Msg = brk: {
var msgs: []logger.Msg = log.msgs.items;
diff --git a/src/bun.js/modules/NodeModuleModule.cpp b/src/bun.js/modules/NodeModuleModule.cpp
index 02e4e3849..01e061499 100644
--- a/src/bun.js/modules/NodeModuleModule.cpp
+++ b/src/bun.js/modules/NodeModuleModule.cpp
@@ -19,36 +19,24 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleCreateRequire,
return JSC::JSValue::encode(JSC::jsUndefined());
}
- Zig::ImportMetaObject *importMetaObject = Zig::ImportMetaObject::create(
- globalObject, callFrame->uncheckedArgument(0));
+ auto str = callFrame->uncheckedArgument(0).toStringOrNull(globalObject);
+ RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::jsUndefined()));
+ WTF::String val = str->value(globalObject);
+ auto *meta = Zig::ImportMetaObject::create(globalObject, str);
auto clientData = WebCore::clientData(vm);
-
- RETURN_IF_EXCEPTION(scope, {});
-
- if (!importMetaObject) {
- throwTypeError(globalObject, scope, "Invalid path"_s);
- return JSC::JSValue::encode(JSC::jsUndefined());
- }
-
- auto requireFunctionValue = importMetaObject->get(
- globalObject, clientData->builtinNames().requirePublicName());
- RETURN_IF_EXCEPTION(scope, {});
-
- JSC::JSBoundFunction *boundRequireFunction = JSC::JSBoundFunction::create(
- vm, globalObject, requireFunctionValue.getObject(), importMetaObject,
- nullptr, 1, jsString(vm, String("require"_s)));
- RETURN_IF_EXCEPTION(scope, {});
- auto resolveFunction = importMetaObject->get(
- globalObject, clientData->builtinNames().resolveSyncPublicName());
-
- JSC::JSBoundFunction *boundResolveFunction = JSC::JSBoundFunction::create(
- vm, globalObject, resolveFunction.getObject(), importMetaObject, nullptr,
- 1, jsString(vm, String("resolve"_s)));
+ auto requireFunction =
+ Zig::ImportMetaObject::createRequireFunction(vm, globalObject, val);
+ auto nameStr = jsCast<JSFunction *>(requireFunction)->name(vm);
+ JSC::JSBoundFunction *boundRequireFunction =
+ JSC::JSBoundFunction::create(vm, globalObject, requireFunction, meta,
+ nullptr, 0, jsString(vm, nameStr));
boundRequireFunction->putDirect(
- vm, clientData->builtinNames().resolvePublicName(), boundResolveFunction,
- JSC::PropertyAttribute::Function | 0);
+ vm, clientData->builtinNames().resolvePublicName(),
+ requireFunction->getDirect(
+ vm, clientData->builtinNames().resolvePublicName()),
+ 0);
- RELEASE_AND_RETURN(scope, JSC::JSValue::encode(boundRequireFunction));
+ RELEASE_AND_RETURN(scope, JSValue::encode(boundRequireFunction));
}
JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModulePaths,
(JSC::JSGlobalObject * globalObject,
@@ -113,7 +101,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionResolveFileName,
auto result =
Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName),
- JSValue::encode(callFrame->argument(1)));
+ JSValue::encode(callFrame->argument(1)), false);
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
if (!JSC::JSValue::decode(result).isString()) {
diff --git a/src/bun.js/net.exports.js b/src/bun.js/net.exports.js
index 8d283dd1e..f894cd5fa 100644
--- a/src/bun.js/net.exports.js
+++ b/src/bun.js/net.exports.js
@@ -86,11 +86,10 @@ export const Socket = (function (InternalSocket) {
self.emit("error", error);
},
- data(socket, buffer) {
- const self = socket.data;
- self.bytesRead += buffer.length;
+ data({ data: self }, { length, buffer }) {
+ self.bytesRead += length;
const queue = self.#readQueue;
- const ret = new Buffer(buffer.buffer);
+ const ret = new Buffer(buffer);
if (queue.isEmpty()) {
if (self.push(ret)) return;
}
@@ -197,7 +196,10 @@ export const Socket = (function (InternalSocket) {
connect(port, host, connectListener) {
// TODO support IPC sockets
var path;
- if (typeof host == "function") {
+ if (arguments.length === 1 && typeof port === "string") {
+ path = port;
+ port = undefined;
+ } else if (typeof host == "function") {
if (typeof port === "string") {
path = port;
port = undefined;
@@ -336,7 +338,14 @@ export const Socket = (function (InternalSocket) {
} else if (this.#writeCallback) {
callback(new Error("overlapping _write()"));
} else {
- if (written > 0) chunk = chunk.slice(written);
+ if (written > 0) {
+ if (typeof chunk == "string") {
+ chunk = chunk.slice(written);
+ } else {
+ chunk = chunk.subarray(written);
+ }
+ }
+
this.#writeCallback = callback;
this.#writeChunk = chunk;
}
diff --git a/src/bun.js/test/jest.zig b/src/bun.js/test/jest.zig
index 00c8148b2..4b31f7309 100644
--- a/src/bun.js/test/jest.zig
+++ b/src/bun.js/test/jest.zig
@@ -1124,12 +1124,38 @@ pub const Expect = struct {
}
const not = this.op.contains(.not);
- const result_ = value.call(globalObject, &.{}).toError();
+
+ const result_: ?JSValue = brk: {
+ var vm = globalObject.bunVM();
+ var scope = vm.unhandledRejectionScope();
+ vm.onUnhandledRejection = &VirtualMachine.onQuietUnhandledRejectionHandler;
+ const return_value: JSValue = value.call(globalObject, &.{});
+
+ if (return_value.asAnyPromise()) |promise| {
+ globalObject.bunVM().waitForPromise(promise);
+ scope.apply(vm);
+ const promise_result = promise.result(globalObject.vm());
+
+ switch (promise.status(globalObject.vm())) {
+ .Fulfilled => {
+ break :brk null;
+ },
+ .Rejected => {
+ // since we know for sure it rejected, we should always return the error
+ break :brk promise_result.toError() orelse promise_result;
+ },
+ .Pending => unreachable,
+ }
+ }
+ scope.apply(vm);
+
+ break :brk return_value.toError();
+ };
+
const did_throw = result_ != null;
const matched_expectation = did_throw == !not;
- if (matched_expectation) return thisValue;
- if (expected_value.isEmptyOrUndefinedOrNull()) {
+ if (!matched_expectation) {
if (!not)
globalObject.throw("Expected function to throw", .{})
else {
@@ -1139,7 +1165,14 @@ pub const Expect = struct {
return .zero;
}
- const result = result_.?;
+
+ // If you throw a string, it's treated as the message of an Error
+ // If you are expected not to throw and you didn't throw, then you pass
+ // If you are expected to throw a specific message and you throw a different one, then you fail.
+ if (matched_expectation and (!expected_value.isCell() or not))
+ return thisValue;
+
+ const result = result_ orelse JSC.JSValue.jsUndefined();
const expected_error = expected_value.toError();
@@ -1148,7 +1181,10 @@ pub const Expect = struct {
if (expected_value.isString()) break :brk expected_value;
break :brk expected_error.?.get(globalObject, "message");
};
- const actual = result.get(globalObject, "message");
+ const actual: ?JSValue = if (result.isObject())
+ result.get(globalObject, "message")
+ else
+ null;
// TODO support partial match
const pass = brk: {
if (expected) |expected_message|
@@ -1460,7 +1496,6 @@ pub const TestScope = struct {
.Internal => vm.waitForPromise(promise),
else => {},
}
-
switch (promise.status(vm.global.vm())) {
.Rejected => {
vm.runErrorHandler(promise.result(vm.global.vm()), null);
@@ -1737,7 +1772,7 @@ pub const DescribeScope = struct {
var scope = allocator.create(DescribeScope) catch unreachable;
scope.* = .{
.label = (label.toSlice(allocator).cloneIfNeeded(allocator) catch unreachable).slice(),
- .parent = this,
+ .parent = active,
.file_id = this.file_id,
};
var new_this = DescribeScope.Class.make(ctx, scope);
diff --git a/src/bun.zig b/src/bun.zig
index 00bceeea4..732862e8f 100644
--- a/src/bun.zig
+++ b/src/bun.zig
@@ -765,3 +765,4 @@ pub fn zero(comptime Type: type) Type {
return @bitCast(Type, out);
}
pub const c_ares = @import("./deps/c_ares.zig");
+pub const URL = @import("./url.zig").URL;
diff --git a/src/cli/test_command.zig b/src/cli/test_command.zig
index a36561be0..8fb8bf01b 100644
--- a/src/cli/test_command.zig
+++ b/src/cli/test_command.zig
@@ -113,7 +113,9 @@ pub const CommandLineReporter = struct {
const color_code = comptime if (skip) "<yellow>" else "";
if (Output.enable_ansi_colors_stderr) {
- for (scopes) |scope| {
+ for (scopes) |_, i| {
+ const index = (scopes.len - 1) - i;
+ const scope = scopes[index];
if (scope.label.len == 0) continue;
writer.writeAll(" ") catch unreachable;
@@ -123,7 +125,9 @@ pub const CommandLineReporter = struct {
writer.writeAll(" >") catch unreachable;
}
} else {
- for (scopes) |scope| {
+ for (scopes) |_, i| {
+ const index = (scopes.len - 1) - i;
+ const scope = scopes[index];
if (scope.label.len == 0) continue;
writer.writeAll(" ") catch unreachable;
writer.writeAll(scope.label) catch unreachable;
diff --git a/src/deps/uws.zig b/src/deps/uws.zig
index 62821c85c..bfcd00e7a 100644
--- a/src/deps/uws.zig
+++ b/src/deps/uws.zig
@@ -756,10 +756,10 @@ pub const AnyWebSocket = union(enum) {
// pub fn iterateTopics(this: AnyWebSocket) {
// return uws_ws_iterate_topics(ssl_flag, this.raw(), callback: ?*const fn ([*c]const u8, usize, ?*anyopaque) callconv(.C) void, user_data: ?*anyopaque) void;
// }
- pub fn publish(this: AnyWebSocket, topic: []const u8, message: []const u8) bool {
+ pub fn publish(this: AnyWebSocket, topic: []const u8, message: []const u8, opcode: Opcode, compress: bool) bool {
return switch (this) {
- .ssl => uws_ws_publish(1, this.ssl.raw(), topic.ptr, topic.len, message.ptr, message.len),
- .tcp => uws_ws_publish(0, this.tcp.raw(), topic.ptr, topic.len, message.ptr, message.len),
+ .ssl => uws_ws_publish_with_options(1, this.ssl.raw(), topic.ptr, topic.len, message.ptr, message.len, opcode, compress),
+ .tcp => uws_ws_publish_with_options(0, this.tcp.raw(), topic.ptr, topic.len, message.ptr, message.len, opcode, compress),
};
}
pub fn publishWithOptions(ssl: bool, app: *anyopaque, topic: []const u8, message: []const u8, opcode: Opcode, compress: bool) bool {
diff --git a/src/js_parser.zig b/src/js_parser.zig
index 1fa86041f..1dbf1ebf9 100644
--- a/src/js_parser.zig
+++ b/src/js_parser.zig
@@ -117,8 +117,9 @@ fn foldStringAddition(lhs: Expr, rhs: Expr) ?Expr {
switch (lhs.data) {
.e_string => |left| {
if (rhs.data == .e_string and left.isUTF8() and rhs.data.e_string.isUTF8()) {
- lhs.data.e_string.push(rhs.data.e_string);
- return lhs;
+ var orig = lhs.data.e_string.*;
+ orig.push(rhs.data.e_string);
+ return Expr.init(E.String, orig, lhs.loc);
}
},
.e_binary => |bin| {
diff --git a/src/options.zig b/src/options.zig
index 024ff188a..b9268f400 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -597,6 +597,7 @@ pub const Platform = enum {
default_conditions_strings.bun,
default_conditions_strings.worker,
default_conditions_strings.module,
+ default_conditions_strings.node,
default_conditions_strings.browser,
},
);
@@ -606,6 +607,7 @@ pub const Platform = enum {
default_conditions_strings.bun,
default_conditions_strings.worker,
default_conditions_strings.module,
+ default_conditions_strings.node,
default_conditions_strings.browser,
},
);
diff --git a/src/runtime.zig b/src/runtime.zig
index c942afb13..197dc4264 100644
--- a/src/runtime.zig
+++ b/src/runtime.zig
@@ -116,7 +116,6 @@ pub const Fallback = struct {
};
pub inline fn scriptContent() string {
- if (true) return;
if (comptime Environment.isDebug) {
var dirpath = comptime bun.Environment.base_path ++ std.fs.path.dirname(@src().file).?;
var env = std.process.getEnvMap(default_allocator) catch unreachable;
@@ -166,7 +165,6 @@ pub const Fallback = struct {
fallback: string,
entry_point: string,
};
- if (true) return;
try writer.print(HTMLTemplate, PrintArgs{
.blob = Base64FallbackMessage{ .msg = msg, .allocator = allocator },
.preload = preload,
@@ -188,7 +186,6 @@ pub const Fallback = struct {
fallback: string,
bun_error_page_css: string,
};
- if (true) return;
try writer.print(HTMLBackendTemplate, PrintArgs{
.blob = Base64FallbackMessage{ .msg = msg, .allocator = allocator },
.bun_error_css = ErrorCSS.sourceContent(),
diff --git a/test/bun.js/bun-test/nested-describes.test.ts b/test/bun.js/bun-test/nested-describes.test.ts
new file mode 100644
index 000000000..de7ba194e
--- /dev/null
+++ b/test/bun.js/bun-test/nested-describes.test.ts
@@ -0,0 +1,38 @@
+import {
+describe,
+expect,
+test,
+} from "bun:test";
+
+/*
+In this test we want the tests to print out the following on a success.
+Each success / fail should show the path of describe and test scopes
+
+✓ outer most describe > mid describe 1 > inner most describe 1 > first
+✓ outer most describe > mid describe 1 > inner most describe 2 > second
+✓ outer most describe > mid describe 2 > inner most describe 3 > first
+
+@TODO add testing for this, would require to read the test console output
+*/
+
+describe("outer most describe", () => {
+ describe("mid describe 1", () => {
+ describe("inner most describe 1", () => {
+ test("first", () => {
+ expect(5).toEqual(5);
+ })
+ })
+ describe("inner most describe 2", () => {
+ test("second", () => {
+ expect(5).toEqual(5);
+ })
+ })
+ })
+ describe("mid describe 2", () => {
+ describe("inner most describe 3", () => {
+ test("third", () => {
+ expect(5).toEqual(5);
+ })
+ })
+ })
+})
diff --git a/test/bun.js/bun-write.test.js b/test/bun.js/bun-write.test.js
index fdf31679f..864333ca6 100644
--- a/test/bun.js/bun-write.test.js
+++ b/test/bun.js/bun-write.test.js
@@ -281,27 +281,21 @@ it("Bun.write(Bun.stderr, 'new TextEncoder().encode(Bun.write STDERR TEST'))", a
// FLAKY TEST
// Since Bun.file is resolved lazily, this needs to specifically be checked
-// it("Bun.write('output.html', HTMLRewriter.transform(Bun.file)))", async (done) => {
-// var rewriter = new HTMLRewriter();
+it("Bun.write('output.html', HTMLRewriter.transform(Bun.file)))", async (done) => {
+ var rewriter = new HTMLRewriter();
-// rewriter.on("div", {
-// element(element) {
-// element.setInnerContent("<blink>it worked!</blink>", { html: true });
-// },
-// });
-// globalThis["HTMLRewriter.a"] = Bun.write(
-// "/tmp/html-rewriter.txt.js",
-// "<div>hello</div>",
-// );
-// await globalThis["HTMLRewriter.a"];
-// var input = new Response(Bun.file("/tmp/html-rewriter.txt.js"));
-// var output = rewriter.transform(input);
-// const outpath = `/tmp/html-rewriter.${Date.now()}.html`;
-// globalThis["HTMLRewriter.a"] = Bun.write(outpath, output);
-// await globalThis["HTMLRewriter.a"];
-// console.log("HIERE");
-// expect(await Bun.file(outpath).text()).toBe(
-// "<div><blink>it worked!</blink></div>",
-// );
-// done();
-// });
+ rewriter.on("div", {
+ element(element) {
+ element.setInnerContent("<blink>it worked!</blink>", { html: true });
+ },
+ });
+ await Bun.write("/tmp/html-rewriter.txt.js", "<div>hello</div>");
+ var input = new Response(Bun.file("/tmp/html-rewriter.txt.js"));
+ var output = rewriter.transform(input);
+ const outpath = `/tmp/html-rewriter.${Date.now()}.html`;
+ await Bun.write(outpath, output);
+ expect(await Bun.file(outpath).text()).toBe(
+ "<div><blink>it worked!</blink></div>",
+ );
+ done();
+});
diff --git a/test/bun.js/child_process-node.test.js b/test/bun.js/child_process-node.test.js
index 3cb8cd9e1..41e3e6afc 100644
--- a/test/bun.js/child_process-node.test.js
+++ b/test/bun.js/child_process-node.test.js
@@ -1,7 +1,6 @@
-import { beforeAll, describe, it as it_ } from "bun:test";
+import { beforeAll, describe, expect, it } from "bun:test";
import { ChildProcess, spawn, exec } from "node:child_process";
import {
- strictEqual,
throws,
assert,
createCallCheckCtx,
@@ -9,36 +8,7 @@ import {
} from "node-test-helpers";
import { tmpdir } from "node:os";
import { gcTick } from "gc";
-
-const it = (label, fn) => {
- const hasDone = fn.length === 1;
- if (fn.constructor.name === "AsyncFunction" && hasDone) {
- return it_(label, async (done) => {
- gcTick();
- await fn(done);
- gcTick();
- });
- } else if (hasDone) {
- return it_(label, (done) => {
- gcTick();
- fn(done);
- gcTick();
- });
- } else if (fn.constructor.name === "AsyncFunction") {
- return it_(label, async () => {
- gcTick();
- await fn();
- gcTick();
- });
- } else {
- return it_(label, () => {
- gcTick();
- fn();
- gcTick();
- });
- }
-};
-
+const strictEqual = (a, b) => expect(a).toStrictEqual(b);
const debug = process.env.DEBUG ? console.log : () => {};
const platformTmpDir = require("fs").realpathSync(tmpdir());
diff --git a/test/bun.js/esbuild-child_process.test.ts b/test/bun.js/esbuild-child_process.test.ts
index 511779d9f..d64786602 100644
--- a/test/bun.js/esbuild-child_process.test.ts
+++ b/test/bun.js/esbuild-child_process.test.ts
@@ -1,49 +1,20 @@
-import { transform, transformSync } from "esbuild";
-import { describe, it, expect } from "bun:test";
+import { spawnSync } from "bun";
+import { describe, it, expect, test } from "bun:test";
+import { bunExe } from "bunExe";
-describe("child_process.spawn - esbuild", () => {
- it("should transform successfully", async () => {
- const result = await transform("console.log('hello world')", {
- loader: "js",
- target: "node12",
- });
- expect(result.code).toBe('console.log("hello world");\n');
- });
+test("esbuild", () => {
+ const { exitCode, stderr, stdout } = spawnSync(
+ [bunExe(), import.meta.dir + "/esbuild-test.js"],
+ {
+ env: {
+ BUN_DEBUG_QUIET_LOGS: "1",
+ },
+ },
+ );
+ const out = "" + stderr?.toString() + stdout?.toString();
+ if (exitCode !== 0 && out?.length) {
+ throw new Error(out);
+ }
- it("works for input exceeding the pipe capacity", async () => {
- const hugeString = `console.log(${JSON.stringify("a".repeat(1000000))});`;
-
- for (let i = 0; i < 2; i++) {
- const result = await transform(hugeString, {
- loader: "js",
- target: "node12",
- });
- expect(result.code).toBe(hugeString + "\n");
- }
- });
-});
-
-describe("child_process.spawnSync - esbuild", () => {
- it("should transform successfully", () => {
- const result = transformSync("console.log('hello world')", {
- loader: "js",
- target: "node12",
- });
- expect(result.code).toBe('console.log("hello world");\n');
- });
-
- // This test is failing with the following error:
- // error: Error
- // path: "/Users/jarred/Code/bun/test/bun.js/node_modules/esbuild-darwin-arm64/bin/esbuild"
- // code: "13"
- // syscall: "spawnSync"
- // errno: -1
- // it("works for input exceeding the pipe capacity", () => {
- // const hugeString = `console.log(${JSON.stringify("a".repeat(100000))});`;
- // const result = transformSync(hugeString, {
- // loader: "js",
- // target: "node12",
- // });
- // expect(result.code).toBe(hugeString + "\n");
- // });
+ expect(exitCode).toBe(0);
});
diff --git a/test/bun.js/esbuild-test.js b/test/bun.js/esbuild-test.js
new file mode 100644
index 000000000..beb34b283
--- /dev/null
+++ b/test/bun.js/esbuild-test.js
@@ -0,0 +1,37 @@
+import { transform, transformSync } from "esbuild";
+
+{
+ const result = await transform("console.log('hello world')", {
+ loader: "js",
+ target: "node12",
+ });
+ if (result.code !== 'console.log("hello world");\n') {
+ throw new Error("Test failed.");
+ }
+}
+
+{
+ const hugeString = `console.log(${JSON.stringify("a".repeat(1000000))});`;
+
+ for (let i = 0; i < 2; i++) {
+ const result = await transform(hugeString, {
+ loader: "js",
+ target: "node12",
+ });
+ if (result.code !== hugeString + "\n") {
+ throw new Error("Test failed.");
+ }
+ }
+}
+
+{
+ const result = transformSync("console.log('hello world')", {
+ loader: "js",
+ target: "node12",
+ });
+ if (result.code !== 'console.log("hello world");\n') {
+ throw new Error("Test failed.");
+ }
+}
+
+process.exit(0);
diff --git a/test/bun.js/fetch.test.js b/test/bun.js/fetch.test.js
index ca8e387bf..5d0ca4854 100644
--- a/test/bun.js/fetch.test.js
+++ b/test/bun.js/fetch.test.js
@@ -1,5 +1,5 @@
-import { it, describe, expect } from "bun:test";
-import fs, { unlinkSync } from "fs";
+import { afterAll, beforeAll, describe, expect, it, test } from "bun:test";
+import fs, { chmodSync, unlinkSync } from "fs";
import { mkfifo } from "mkfifo";
import { gc, withoutAggressiveGC } from "./gc";
@@ -393,6 +393,46 @@ describe("Bun.file", () => {
const { size } = Bun.file("/tmp/test-fifo");
expect(size).toBe(Infinity);
});
+
+ function forEachMethod(fn) {
+ const method = ["arrayBuffer", "text", "json"];
+ for (const m of method) {
+ test(m, fn(m));
+ }
+ }
+
+ describe("bad permissions throws", () => {
+ beforeAll(async () => {
+ try {
+ unlinkSync("/tmp/my-new-file");
+ } catch {}
+ await Bun.write("/tmp/my-new-file", "hey");
+ chmodSync("/tmp/my-new-file", 0o000);
+ });
+ afterAll(() => {
+ try {
+ unlinkSync("/tmp/my-new-file");
+ } catch {}
+ });
+
+ forEachMethod((m) => () => {
+ const file = Bun.file("/tmp/my-new-file");
+ expect(async () => await file[m]()).toThrow("Permission denied");
+ });
+ });
+
+ describe("non-existent file throws", () => {
+ beforeAll(() => {
+ try {
+ unlinkSync("/tmp/does-not-exist");
+ } catch {}
+ });
+
+ forEachMethod((m) => async () => {
+ const file = Bun.file("/tmp/does-not-exist");
+ expect(async () => await file[m]()).toThrow("No such file or directory");
+ });
+ });
});
describe("Blob", () => {
diff --git a/test/bun.js/inspect.test.js b/test/bun.js/inspect.test.js
index 8789b7aba..738442211 100644
--- a/test/bun.js/inspect.test.js
+++ b/test/bun.js/inspect.test.js
@@ -2,7 +2,7 @@ import { it, expect, describe } from "bun:test";
it("Blob inspect", () => {
expect(Bun.inspect(new Blob(["123"]))).toBe(`Blob (3 bytes)`);
- expect(Bun.inspect(new Blob(["123".repeat(900)]))).toBe(`Blob (3 KB)`);
+ expect(Bun.inspect(new Blob(["123".repeat(900)]))).toBe(`Blob (2.70 KB)`);
expect(Bun.inspect(Bun.file("/tmp/file.txt")))
.toBe(`FileRef ("/tmp/file.txt") {
type: "text/plain;charset=utf-8"
@@ -30,26 +30,25 @@ it("Blob inspect", () => {
}`);
});
-// this test is currently failing!
-// it("utf16 property name", () => {
-// var { Database } = require("bun:sqlite");
-// const db = Database.open(":memory:");
-// expect("笑".codePointAt(0)).toBe(31505);
+it.skip("utf16 property name", () => {
+ var { Database } = require("bun:sqlite");
+ const db = Database.open(":memory:");
+ expect("笑".codePointAt(0)).toBe(31505);
-// // latin1 escaping identifier issue
-// expect(Object.keys({ 笑: "hey" })[0].codePointAt(0)).toBe(31505);
+ // latin1 escaping identifier issue
+ expect(Object.keys({ 笑: "hey" })[0].codePointAt(0)).toBe(31505);
-// const output = JSON.stringify(
-// [
-// {
-// 笑: "😀",
-// },
-// ],
-// null,
-// 2,
-// );
-// expect(Bun.inspect(db.prepare("select '😀' as 笑").all())).toBe(output);
-// });
+ const output = JSON.stringify(
+ [
+ {
+ 笑: "😀",
+ },
+ ],
+ null,
+ 2,
+ );
+ expect(Bun.inspect(db.prepare("select '😀' as 笑").all())).toBe(output);
+});
it("latin1", () => {
expect(Bun.inspect("English")).toBe("English");
diff --git a/test/bun.js/process.test.js b/test/bun.js/process.test.js
index be627b61c..8ea57a28b 100644
--- a/test/bun.js/process.test.js
+++ b/test/bun.js/process.test.js
@@ -1,6 +1,7 @@
-import { resolveSync } from "bun";
+import { resolveSync, which } from "bun";
import { describe, expect, it } from "bun:test";
import { readFileSync, realpathSync } from "fs";
+import { basename } from "path";
it("process", () => {
// this property isn't implemented yet but it should at least return a string
@@ -106,11 +107,12 @@ it("process.version starts with v", () => {
});
it("process.argv0", () => {
- expect(process.argv0).toBe(process.argv[0]);
+ expect(basename(process.argv0)).toBe(basename(process.argv[0]));
});
it("process.execPath", () => {
- expect(process.execPath).toBe(realpathSync(process.argv0));
+ expect(process.execPath).not.toBe(basename(process.argv0));
+ expect(which(process.execPath)).not.toBeNull();
});
it("process.uptime()", () => {
diff --git a/test/bun.js/socket/socket.test.ts b/test/bun.js/socket/socket.test.ts
index 200f9528c..3c41c96f7 100644
--- a/test/bun.js/socket/socket.test.ts
+++ b/test/bun.js/socket/socket.test.ts
@@ -25,12 +25,7 @@ it("should keep process alive only when active", async () => {
lines.filter(function (line) {
return line.startsWith("[Client]");
}),
- ).toEqual([
- "[Client] OPENED",
- "[Client] GOT response",
- "[Client] ENDED",
- "[Client] CLOSED",
- ]);
+ ).toEqual(["[Client] OPENED", "[Client] GOT response", "[Client] CLOSED"]);
});
it("listen() should throw connection error for invalid host", () => {
diff --git a/test/bun.js/transpiler.test.js b/test/bun.js/transpiler.test.js
index bc7102b95..94c3d52d2 100644
--- a/test/bun.js/transpiler.test.js
+++ b/test/bun.js/transpiler.test.js
@@ -915,6 +915,19 @@ export var ComponentThatHasSpreadCausesDeopt = $jsx(Hello, {
it("fold string addition", () => {
expectPrinted_(
+ `
+const a = "[^aeiou]";
+const b = a + "[^aeiouy]*";
+console.log(a);
+ `,
+ `
+const a = "[^aeiou]";
+const b = a + "[^aeiouy]*";
+console.log(a)
+ `.trim(),
+ );
+
+ expectPrinted_(
`export const foo = "a" + "b";`,
`export const foo = "ab"`,
);
@@ -1734,6 +1747,17 @@ class Foo {
`return "foobar";`,
);
+ check(
+ `
+const a = "[^aeiou]";
+const b = a + "[^aeiouy]*";
+console.log(a, b);
+ `,
+ `
+console.log("[^aeiou]", "[^aeiou][^aeiouy]*");
+ `.trim(),
+ );
+
// check that it doesn't inline after "var"
check(
`
diff --git a/test/bun.js/websocket-server.test.ts b/test/bun.js/websocket-server.test.ts
index 1d9c15341..0dc421eb6 100644
--- a/test/bun.js/websocket-server.test.ts
+++ b/test/bun.js/websocket-server.test.ts
@@ -1,6 +1,6 @@
-import { serve } from "bun";
import { describe, expect, it } from "bun:test";
import { gcTick } from "./gc";
+import { serve } from "bun";
var port = 4321;
function getPort() {
@@ -49,6 +49,44 @@ describe("websocket server", () => {
done();
});
+ it("can do publish() with publishToSelf: false", async (done) => {
+ var server = serve({
+ port: getPort(),
+ websocket: {
+ open(ws) {
+ ws.subscribe("all");
+ ws.publish("all", "hey");
+ server.publish("all", "hello");
+ },
+ message(ws, msg) {
+ if (new TextDecoder().decode(msg) !== "hello") {
+ done(new Error("unexpected message"));
+ }
+ },
+ close(ws) {},
+ publishToSelf: false,
+ },
+ fetch(req, server) {
+ if (server.upgrade(req)) {
+ return;
+ }
+
+ return new Response("success");
+ },
+ });
+
+ await new Promise<void>((resolve2, reject2) => {
+ var socket = new WebSocket(`ws://${server.hostname}:${server.port}`);
+
+ socket.onmessage = (e) => {
+ expect(e.data).toBe("hello");
+ resolve2();
+ };
+ });
+ server.stop();
+ done();
+ });
+
for (let method of ["publish", "publishText", "publishBinary"]) {
describe(method, () => {
it("in close() should work", async () => {
@@ -463,7 +501,9 @@ describe("websocket server", () => {
server.stop();
expect(() => {
server.upgrade(req);
- }).toThrow('To enable websocket support, set the "websocket" object in Bun.serve({})');
+ }).toThrow(
+ 'To enable websocket support, set the "websocket" object in Bun.serve({})',
+ );
return new Response("success");
},
});
@@ -826,9 +866,11 @@ describe("websocket server", () => {
fetch(req) {
gcTick();
server.stop();
- if (server.upgrade(req, {
- data: { count: 0 },
- }))
+ if (
+ server.upgrade(req, {
+ data: { count: 0 },
+ })
+ )
return;
return new Response("noooooo hello world");
},