aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-10-25 00:44:25 -0700
committerGravatar GitHub <noreply@github.com> 2022-10-25 00:44:25 -0700
commit02c920f4fd09ddc1a32cb2e92c6f391875415949 (patch)
tree4f524f5ce9d672fadb8740c68cc9b1a8410a714f
parent1b50ecc52b55df0c00f991c8206d4ced84ad89b8 (diff)
downloadbun-02c920f4fd09ddc1a32cb2e92c6f391875415949.tar.gz
bun-02c920f4fd09ddc1a32cb2e92c6f391875415949.tar.zst
bun-02c920f4fd09ddc1a32cb2e92c6f391875415949.zip
TCP & TLS Socket API (#1374)
* TCP Socket API * Wip * Add snippet for StringDecoder * Rename `close` to `stop`, replace `close` with `end` * Add a tcp echo server test * Some docs * Update README.md * Fix build * Update README.md Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r--.vscode/settings.json8
-rw-r--r--README.md177
-rw-r--r--bench/snippets/string-decoder.mjs28
-rw-r--r--bench/snippets/tcp-echo.bun.ts49
-rw-r--r--bench/snippets/tcp-echo.node.mjs52
-rw-r--r--build-id2
-rwxr-xr-xbun.lockbbin11525 -> 31158 bytes
-rw-r--r--examples/tcp.ts49
-rw-r--r--package.json3
-rw-r--r--src/bun.js/api/bun.zig8
-rw-r--r--src/bun.js/api/bun/socket.zig1438
-rw-r--r--src/bun.js/api/sockets.classes.ts130
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h5
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h5
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h18
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h21
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.cpp1366
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.h375
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp4
-rw-r--r--src/bun.js/bindings/bindings.zig2
-rw-r--r--src/bun.js/bindings/generated_classes.zig362
-rw-r--r--src/bun.js/bindings/generated_classes_list.zig3
-rw-r--r--src/bun.js/bindings/headers-cpp.h2
-rw-r--r--src/bun.js/bindings/headers.h2
-rw-r--r--src/deps/uws.zig146
-rw-r--r--src/http/websocket_http_client.zig2
-rw-r--r--src/http_client_async.zig1
-rw-r--r--src/jsc.zig5
-rw-r--r--test/bun.js/tcp-server.test.ts114
29 files changed, 4337 insertions, 40 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json
index c866e2f0c..c3541749a 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -8,8 +8,8 @@
"search.useIgnoreFiles": true,
"zig.buildOnSave": false,
"[zig]": {
- "editor.tabSize": 4,
- "editor.useTabStops": false,
+ "editor.tabSize": 4,
+ "editor.useTabStops": false,
"editor.defaultFormatter": "AugusteRame.zls-vscode",
"editor.formatOnSave": true
},
@@ -87,6 +87,7 @@
"editor.defaultFormatter": "xaver.clang-format"
},
"files.associations": {
+ "*.lock": "yarnlock",
"*.idl": "cpp",
"memory": "cpp",
"iostream": "cpp",
@@ -178,7 +179,8 @@
"ctype.h": "c",
"ethernet.h": "c",
"inet.h": "c",
- "packet.h": "c"
+ "packet.h": "c",
+ "queue": "cpp"
},
"cmake.configureOnOpen": false
}
diff --git a/README.md b/README.md
index 3063170d3..d2422c483 100644
--- a/README.md
+++ b/README.md
@@ -2574,6 +2574,183 @@ const ls = Bun.which("ls", {
console.log(ls); // null
```
+## `Bun.listen` & `Bun.connect` - TCP/TLS sockets
+
+`Bun.listen` and `Bun.connect` is bun's native TCP & TLS socket API. Use it to implement database clients, game servers – anything that needs to communicate over TCP (instead of HTTP). This is a low-level API intended for library others and for advanced use cases.
+
+Start a TCP server with `Bun.listen`:
+
+```ts
+// The server
+Bun.listen({
+ hostname: "localhost",
+ port: 8080,
+ socket: {
+ open(socket) {
+ socket.write("hello world");
+ },
+ data(socket, data) {
+ console.log(data instanceof Uint8Array); // true
+ },
+ drain(socket) {
+ console.log("gimme more data");
+ },
+ close(socket) {
+ console.log("goodbye!");
+ },
+ },
+ // This is a TLS socket
+ // certFile: "/path/to/cert.pem",
+ // keyFile: "/path/to/key.pem",
+});
+```
+
+`Bun.connect` lets you create a TCP client:
+
+```ts
+// The client
+Bun.connect({
+ hostname: "localhost",
+ port: 8080,
+
+ socket: {
+ open(socket) {
+ socket.write("hello server, i'm the client!");
+ },
+ data(socket, message) {
+ socket.write("thanks for the message! Sincerely, " + socket.data.name);
+ },
+ drain(socket) {
+ console.log("my socket is ready for more data");
+ },
+ close(socket) {
+ console.log("");
+ },
+ timeout(socket) {
+ console.log("socket timed out");
+ },
+ },
+
+ data: {
+ name: "Clienty McClientface",
+ },
+});
+```
+
+#### Benchmark-driven API design
+
+Bun's TCP socket API is designed to go as fast as we can.
+
+Instead of using promises or assigning callbacks per socket instance (like Node.js' `EventEmitter` or the web-standard `WebSocket` API), assign all callbacks one time
+
+This design decision was made after benchmarking. For performance-sensitive servers, promise-heavy APIs or assigning callbacks per socket instance can cause significant garbage collector pressure and increase memory usage. If you're using a TCP server API, you probably care more about performance.
+
+```ts
+Bun.listen({
+ socket: {
+ open(socket) {},
+ data(socket, data) {},
+ drain(socket) {},
+ close(socket) {},
+ error(socket, error) {},
+ },
+ hostname: "localhost",
+ port: 8080,
+});
+```
+
+Instead of having to allocate unique functions for each instance of a socket, we can use each callback once for all sockets. This is a small optimization, but it adds up.
+
+How do you pass per-socket data to each socket object?
+
+`**data**` is a property on the `TCPSocket` & `TLSSocket` object that you can use to store per-socket data.
+
+```ts
+socket.data = { name: "Clienty McClientface" };
+```
+
+You can assign a default value to `data` in the `connect` or `listen` options.
+
+```ts
+Bun.listen({
+ socket: {
+ open(socket) {
+ console.log(socket.data); // { name: "Servery McServerface" }
+ },
+ },
+ data: {
+ name: "Servery McServerface",
+ },
+});
+```
+
+#### Hot-reloading TCP servers & clients
+
+`TCPSocket` (returned by `Bun.connect` and passed through callbacks in `Bun.listen`) has a `reload` method that lets you reload the callbacks for all related sockets (either just the one for `Bun.connect` or all sockets for `Bun.listen`):
+
+```ts
+const socket = Bun.connect({
+ hostname: "localhost",
+ port: 8080,
+ socket: {
+ data(socket, msg) {
+ console.log("wow i got a message!");
+
+ // this will be called the next time the server sends a message
+ socket.reload({
+ data(socket) {
+ console.log("okay, not so surprising this time");
+ },
+ });
+ },
+ },
+});
+```
+
+#### No buffering
+
+Currently, `TCPSocket` & `TLSSocket` in Bun do not buffer data. Adding support for corking (similar to `ServerWebSocket`) is planned, but it means you will need to handle backpressure yourself using the `drain` callback.
+
+Your TCP client/server will have abysmal performance if you don't consider buffering carefully.
+
+For example, this:
+
+```ts
+socket.write("h");
+socket.write("e");
+socket.write("l");
+socket.write("l");
+socket.write("o");
+```
+
+Performs significantly worse than:
+
+```ts
+socket.write("hello");
+```
+
+To simplify this for now, consider using `ArrayBufferSink` with the `{stream: true}` option:
+
+```ts
+const sink = new ArrayBufferSink({ stream: true, highWaterMark: 1024 });
+
+sink.write("h");
+sink.write("e");
+sink.write("l");
+sink.write("l");
+sink.write("o");
+
+queueMicrotask(() => {
+ var data = sink.flush();
+ if (!socket.write(data)) {
+ // put it back in the sink if the socket is full
+ sink.write(data);
+ }
+});
+```
+
+Builtin buffering is planned in a future version of Bun.
+
## `Bun.peek` - read a promise without resolving it
`Bun.peek` is a utility function that lets you read a promise's result without `await` or `.then`, but only if the promise has already fulfilled or rejected.
diff --git a/bench/snippets/string-decoder.mjs b/bench/snippets/string-decoder.mjs
new file mode 100644
index 000000000..8f7cb31fb
--- /dev/null
+++ b/bench/snippets/string-decoder.mjs
@@ -0,0 +1,28 @@
+import { bench, run } from "mitata";
+import { StringDecoder } from "string_decoder";
+
+var short = Buffer.from("Hello World!");
+var shortUTF16 = Buffer.from("Hello World 💕💕💕");
+var long = Buffer.from("Hello World!".repeat(1024));
+var longUTF16 = Buffer.from("Hello World 💕💕💕".repeat(1024));
+bench(`${short.length} ascii`, () => {
+ var decoder = new StringDecoder();
+ decoder.write(short);
+});
+
+bench(`${short.length} utf8`, () => {
+ var decoder = new StringDecoder();
+ decoder.write(shortUTF16);
+});
+
+bench(`${long.length} ascii`, () => {
+ var decoder = new StringDecoder();
+ decoder.write(long);
+});
+
+bench(`${longUTF16.length} utf8`, () => {
+ var decoder = new StringDecoder();
+ decoder.write(longUTF16);
+});
+
+await run();
diff --git a/bench/snippets/tcp-echo.bun.ts b/bench/snippets/tcp-echo.bun.ts
new file mode 100644
index 000000000..34250d65c
--- /dev/null
+++ b/bench/snippets/tcp-echo.bun.ts
@@ -0,0 +1,49 @@
+import { listen, connect } from "bun";
+
+var counter = 0;
+const msg = "Hello World!";
+
+const handlers = {
+ open(socket) {
+ if (!socket.data?.isServer) {
+ if (!socket.write(msg)) {
+ socket.data = { pending: msg };
+ }
+ }
+ },
+ data(socket, buffer) {
+ if (!socket.write(buffer)) {
+ socket.data = { pending: buffer };
+ return;
+ }
+ counter++;
+ },
+ drain(socket) {
+ const pending = socket.data?.pending;
+ if (!pending) return;
+ if (socket.write(pending)) {
+ socket.data = undefined;
+ counter++;
+ return;
+ }
+ },
+};
+
+setInterval(() => {
+ console.log("Wrote", counter, "messages");
+ counter = 0;
+}, 1000);
+
+const server = listen({
+ socket: handlers,
+ hostname: "localhost",
+ port: 8080,
+ data: {
+ isServer: true,
+ },
+});
+const connection = await connect({
+ socket: handlers,
+ hostname: "localhost",
+ port: 8080,
+});
diff --git a/bench/snippets/tcp-echo.node.mjs b/bench/snippets/tcp-echo.node.mjs
new file mode 100644
index 000000000..3362b5a3c
--- /dev/null
+++ b/bench/snippets/tcp-echo.node.mjs
@@ -0,0 +1,52 @@
+import { createRequire } from "node:module";
+const net = createRequire(import.meta.url)("net");
+
+const buffer = Buffer.from("Hello World!");
+var counter = 0;
+const handlers = {
+ open() {
+ if (!socket.data?.isServer) {
+ if (!this.write(buffer)) {
+ socket.data = { pending: buffer };
+ }
+ }
+ },
+ data(buffer) {
+ if (!this.write(buffer)) {
+ this.data = { pending: buffer.slice() };
+ return;
+ }
+ counter++;
+ },
+ drain() {
+ const pending = this.data?.pending;
+ if (!pending) return;
+ if (this.write(pending)) {
+ this.data = undefined;
+ counter++;
+ return;
+ }
+ },
+};
+
+const server = net.createServer(function (socket) {
+ socket.data = { isServer: true };
+ socket.on("connection", handlers.open.bind(socket));
+ socket.on("data", handlers.data.bind(socket));
+ socket.on("drain", handlers.drain.bind(socket));
+ socket.setEncoding("binary");
+});
+
+setInterval(() => {
+ console.log("Wrote", counter, "messages");
+ counter = 0;
+}, 1000);
+
+server.listen(8000);
+
+const socket = net.connect({ host: "localhost", port: 8000 }, () => {});
+socket.on("connection", handlers.open.bind(socket));
+socket.on("data", handlers.data.bind(socket));
+socket.on("drain", handlers.drain.bind(socket));
+socket.setEncoding("binary");
+socket.write(buffer);
diff --git a/build-id b/build-id
index 56a6051ca..d8263ee98 100644
--- a/build-id
+++ b/build-id
@@ -1 +1 @@
-1 \ No newline at end of file
+2 \ No newline at end of file
diff --git a/bun.lockb b/bun.lockb
index 662133860..9878e5e3b 100755
--- a/bun.lockb
+++ b/bun.lockb
Binary files differ
diff --git a/examples/tcp.ts b/examples/tcp.ts
new file mode 100644
index 000000000..b392febd1
--- /dev/null
+++ b/examples/tcp.ts
@@ -0,0 +1,49 @@
+import { listen, connect } from "bun";
+
+var counter = 0;
+const msg = Buffer.from("Hello World!");
+
+const handlers = {
+ open(socket) {
+ if (!socket.data?.isServer) {
+ if (!socket.write(msg)) {
+ socket.data = { pending: msg };
+ }
+ }
+ },
+ data(socket, buffer) {
+ if (!socket.write(buffer)) {
+ socket.data = { pending: buffer };
+ return;
+ }
+ counter++;
+ },
+ drain(socket) {
+ const pending = socket.data?.pending;
+ if (!pending) return;
+ if (socket.write(pending)) {
+ socket.data = undefined;
+ counter++;
+ return;
+ }
+ },
+};
+
+setInterval(() => {
+ console.log("Wrote", counter, "messages");
+ counter = 0;
+}, 1000);
+
+const server = listen({
+ socket: handlers,
+ hostname: "localhost",
+ port: 8080,
+ data: {
+ isServer: true,
+ },
+});
+const connection = await connect({
+ socket: handlers,
+ hostname: "localhost",
+ port: 8080,
+});
diff --git a/package.json b/package.json
index e3b365483..7c2d22894 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,7 @@
{
"dependencies": {
- "bun-types": "^0.1.5",
+ "bun-types": "latest",
+ "express": "^4.18.2",
"mitata": "^0.1.3",
"peechy": "0.4.32",
"react": "^18.2.0",
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index ca84bbad0..a343730f8 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -1201,6 +1201,14 @@ pub const Class = NewClass(
.spawnSync = .{
.rfn = JSC.wrapWithHasContainer(JSC.Subprocess, "spawnSync", false, false, false),
},
+
+ .listen = .{
+ .rfn = JSC.wrapWithHasContainer(JSC.API.Listener, "listen", false, false, false),
+ },
+
+ .connect = .{
+ .rfn = JSC.wrapWithHasContainer(JSC.API.Listener, "connect", false, false, false),
+ },
},
.{
.main = .{
diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig
new file mode 100644
index 000000000..8a4eca03b
--- /dev/null
+++ b/src/bun.js/api/bun/socket.zig
@@ -0,0 +1,1438 @@
+const default_allocator = @import("../../../global.zig").default_allocator;
+const bun = @import("../../../global.zig");
+const Environment = bun.Environment;
+const NetworkThread = @import("http").NetworkThread;
+const Global = bun.Global;
+const strings = bun.strings;
+const string = bun.string;
+const Output = @import("../../../global.zig").Output;
+const MutableString = @import("../../../global.zig").MutableString;
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const JSC = @import("javascript_core");
+const JSValue = JSC.JSValue;
+const JSGlobalObject = JSC.JSGlobalObject;
+const Which = @import("../../../which.zig");
+const uws = @import("uws");
+const ZigString = JSC.ZigString;
+// const Corker = struct {
+// ptr: ?*[16384]u8 = null,
+// holder: ?*anyopaque = null,
+// list: bun.ByteList = .{},
+
+// pub fn write(this: *Corker, owner: *anyopaque, bytes: []const u8) usize {
+// if (this.holder != null and this.holder.? != owner) {
+// return 0;
+// }
+
+// this.holder = owner;
+// if (this.ptr == null) {
+// this.ptr = bun.default_allocator.alloc(u8, 16384) catch @panic("Out of memory allocating corker");
+// std.debug.assert(this.list.cap == 0);
+// std.debug.assert(this.list.len == 0);
+// this.list.cap = 16384;
+// this.list.ptr = this.ptr.?;
+// this.list.len = 0;
+// }
+// }
+
+// pub fn flushIfNecessary(this: *Corker, comptime ssl: bool, socket: uws.NewSocketHandler(ssl), owner: *anyopaque) void {
+// if (this.holder == null or this.holder.? != owner) {
+// return;
+// }
+
+// if (this.ptr == null) {
+// return;
+// }
+
+// if (this.list.len == 0) {
+// return;
+// }
+
+// const bytes = ths.list.slice();
+
+// this.list.len = 0;
+// }
+// };
+
+const Handlers = struct {
+ onOpen: JSC.JSValue = .zero,
+ onClose: JSC.JSValue = .zero,
+ onData: JSC.JSValue = .zero,
+ onWritable: JSC.JSValue = .zero,
+ onTimeout: JSC.JSValue = .zero,
+ onConnectError: JSC.JSValue = .zero,
+ onEnd: JSC.JSValue = .zero,
+ onError: JSC.JSValue = .zero,
+
+ encoding: JSC.Node.Encoding = .utf8,
+
+ vm: *JSC.VirtualMachine,
+ globalObject: *JSC.JSGlobalObject,
+ active_connections: u32 = 0,
+ is_server: bool = false,
+ promise: JSC.Strong = .{},
+
+ // corker: Corker = .{},
+
+ pub fn resolvePromise(this: *Handlers, value: JSValue) void {
+ var promise = this.promise.get() orelse return;
+ this.promise.deinit();
+ promise.asPromise().?.resolve(this.globalObject, value);
+ }
+
+ pub fn rejectPromise(this: *Handlers, value: JSValue) bool {
+ var promise = this.promise.get() orelse return false;
+ this.promise.deinit();
+ promise.asPromise().?.reject(this.globalObject, value);
+ return true;
+ }
+
+ pub fn markInactive(this: *Handlers, ssl: bool, ctx: *uws.SocketContext) void {
+ this.active_connections -= 1;
+ if (this.active_connections == 0 and this.is_server) {
+ var listen_socket: *Listener = @fieldParentPtr(Listener, "handlers", this);
+ // allow it to be GC'd once the last connection is closed and it's not listening anymore
+ if (listen_socket.listener == null) {
+ listen_socket.strong_self.clear();
+ }
+ } else if (this.active_connections == 0 and !this.is_server) {
+ this.unprotect();
+ ctx.deinit(ssl);
+ bun.default_allocator.destroy(this);
+ }
+ }
+
+ pub fn callErrorHandler(this: *Handlers, thisValue: JSValue, err: []const JSValue) bool {
+ const onError = this.onError;
+ if (onError == .zero) {
+ return false;
+ }
+
+ const result = onError.callWithThis(this.globalObject, thisValue, err);
+ if (!result.isEmptyOrUndefinedOrNull() and result.isAnyError(this.globalObject)) {
+ this.vm.runErrorHandler(result, null);
+ }
+
+ return true;
+ }
+
+ pub fn fromJS(globalObject: *JSC.JSGlobalObject, opts: JSC.JSValue, exception: JSC.C.ExceptionRef) ?Handlers {
+ var handlers = Handlers{
+ .vm = globalObject.bunVM(),
+ .globalObject = globalObject,
+ };
+
+ if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) {
+ exception.* = JSC.toInvalidArguments("Expected socket object", .{}, globalObject).asObjectRef();
+ return null;
+ }
+
+ const pairs = .{
+ .{ "onData", "data" },
+ .{ "onWritable", "drain" },
+ .{ "onOpen", "open" },
+ .{ "onClose", "close" },
+ .{ "onData", "data" },
+ .{ "onTimeout", "timeout" },
+ .{ "onConnectError", "connectError" },
+ .{ "onEnd", "end" },
+ .{ "onError", "error" },
+ };
+ inline for (pairs) |pair| {
+ if (opts.getTruthy(globalObject, pair.@"1")) |callback_value| {
+ if (!callback_value.isCell() or !callback_value.isCallable(globalObject.vm())) {
+ exception.* = JSC.toInvalidArguments(comptime std.fmt.comptimePrint("Expected \"{s}\" callback to be a function", .{pair.@"1"}), .{}, globalObject).asObjectRef();
+ return null;
+ }
+
+ @field(handlers, pair.@"0") = callback_value;
+ }
+ }
+
+ if (handlers.onData == .zero and handlers.onWritable == .zero) {
+ exception.* = JSC.toInvalidArguments("Expected at least \"data\" or \"drain\" callback", .{}, globalObject).asObjectRef();
+ return null;
+ }
+
+ return handlers;
+ }
+
+ pub fn unprotect(this: *Handlers) void {
+ this.onOpen.unprotect();
+ this.onClose.unprotect();
+ this.onData.unprotect();
+ this.onWritable.unprotect();
+ this.onTimeout.unprotect();
+ this.onConnectError.unprotect();
+ this.onEnd.unprotect();
+ this.onError.unprotect();
+ }
+
+ pub fn protect(this: *Handlers) void {
+ this.onOpen.protect();
+ this.onClose.protect();
+ this.onData.protect();
+ this.onWritable.protect();
+ this.onTimeout.protect();
+ this.onConnectError.protect();
+ this.onEnd.protect();
+ this.onError.protect();
+ }
+};
+
+pub const SocketConfig = struct {
+ hostname_or_unix: JSC.ZigString.Slice,
+ port: ?u16 = null,
+ ssl: ?JSC.API.ServerConfig.SSLConfig = null,
+ handlers: Handlers,
+ default_data: JSC.JSValue = .zero,
+
+ pub fn fromJS(
+ opts: JSC.JSValue,
+ globalObject: *JSC.JSGlobalObject,
+ exception: JSC.C.ExceptionRef,
+ ) ?SocketConfig {
+ var hostname_or_unix: JSC.ZigString.Slice = JSC.ZigString.Slice.empty;
+ var port: ?u16 = null;
+
+ var ssl: ?JSC.API.ServerConfig.SSLConfig = null;
+ var default_data = JSValue.zero;
+
+ if (JSC.API.ServerConfig.SSLConfig.inJS(globalObject, opts, exception)) |ssl_config| {
+ ssl = ssl_config;
+ } else if (exception.* != null) {
+ return null;
+ }
+
+ if (opts.getTruthy(globalObject, "hostname") orelse opts.getTruthy(globalObject, "host")) |hostname| {
+ if (hostname.isEmptyOrUndefinedOrNull() or !hostname.isString()) {
+ exception.* = JSC.toInvalidArguments("Expected \"hostname\" 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 65432", .{}, globalObject).asObjectRef();
+ return null;
+ }
+
+ hostname_or_unix = hostname.getZigString(globalObject).toSlice(bun.default_allocator);
+ 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;
+ }
+ } 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;
+ }
+
+ hostname_or_unix = unix_socket.getZigString(globalObject).toSlice(bun.default_allocator);
+
+ 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;
+ }
+
+ const handlers = Handlers.fromJS(globalObject, opts.get(globalObject, "socket") orelse JSValue.zero, exception) orelse {
+ hostname_or_unix.deinit();
+ return null;
+ };
+
+ if (opts.getTruthy(globalObject, "data")) |default_data_value| {
+ default_data = default_data_value;
+ }
+
+ return SocketConfig{
+ .hostname_or_unix = hostname_or_unix,
+ .port = port,
+ .ssl = ssl,
+ .handlers = handlers,
+ .default_data = default_data,
+ };
+ }
+};
+
+pub const Listener = struct {
+ const log = Output.scoped(.Listener, false);
+
+ handlers: Handlers,
+ listener: ?*uws.ListenSocket = null,
+ poll_ref: JSC.PollRef = JSC.PollRef.init(),
+ connection: UnixOrHost,
+ socket_context: ?*uws.SocketContext = null,
+ ssl: bool = false,
+
+ strong_data: JSC.Strong = .{},
+ strong_self: JSC.Strong = .{},
+
+ pub usingnamespace JSC.Codegen.JSListener;
+
+ pub fn getData(
+ this: *Listener,
+ _: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ log("getData()", .{});
+ return this.strong_data.get() orelse JSValue.jsUndefined();
+ }
+
+ pub fn setData(
+ this: *Listener,
+ globalObject: *JSC.JSGlobalObject,
+ value: JSC.JSValue,
+ ) callconv(.C) bool {
+ log("setData()", .{});
+ this.strong_data.set(globalObject, value);
+ return true;
+ }
+
+ const UnixOrHost = union(enum) {
+ unix: []const u8,
+ host: struct {
+ host: []const u8,
+ port: u16,
+ },
+
+ pub fn deinit(this: UnixOrHost) void {
+ switch (this) {
+ .unix => |u| {
+ bun.default_allocator.destroy(@intToPtr([*]u8, @ptrToInt(u.ptr)));
+ },
+ .host => |h| {
+ bun.default_allocator.destroy(@intToPtr([*]u8, @ptrToInt(h.host.ptr)));
+ },
+ }
+ }
+ };
+
+ pub fn reload(this: *Listener, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ const args = callframe.arguments(1);
+
+ if (args.len < 1 or (this.listener == null and this.handlers.active_connections == 0)) {
+ globalObject.throw("Expected 1 argument", .{});
+ return .zero;
+ }
+
+ const opts = args.ptr[0];
+ if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) {
+ globalObject.throwValue(JSC.toInvalidArguments("Expected options object", .{}, globalObject));
+ return .zero;
+ }
+
+ var exception: JSC.C.JSValueRef = null;
+
+ var socket_obj = opts.get(globalObject, "socket") orelse {
+ globalObject.throw("Expected \"socket\" object", .{});
+ return .zero;
+ };
+
+ const handlers = Handlers.fromJS(globalObject, socket_obj, &exception) orelse {
+ globalObject.throwValue(exception.?.value());
+ return .zero;
+ };
+
+ var prev_handlers = this.handlers;
+ prev_handlers.unprotect();
+ this.handlers = handlers; // TODO: this is a memory leak
+ this.handlers.protect();
+
+ return JSValue.jsUndefined();
+ }
+
+ pub fn listen(
+ globalObject: *JSC.JSGlobalObject,
+ opts: JSValue,
+ exception: JSC.C.ExceptionRef,
+ ) JSValue {
+ log("listen", .{});
+ if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) {
+ exception.* = JSC.toInvalidArguments("Expected object", .{}, globalObject).asObjectRef();
+ return .zero;
+ }
+
+ const socket_config = SocketConfig.fromJS(opts, globalObject, exception) orelse {
+ return .zero;
+ };
+ var hostname_or_unix = socket_config.hostname_or_unix;
+ var port = socket_config.port;
+ var ssl = socket_config.ssl;
+ var handlers = socket_config.handlers;
+ handlers.is_server = true;
+
+ const ssl_enabled = ssl != null;
+
+ var socket = Listener{
+ .handlers = handlers,
+ .connection = if (port) |port_| .{
+ .host = .{ .host = (hostname_or_unix.cloneIfNeeded() catch unreachable).slice(), .port = port_ },
+ } else .{
+ .unix = (hostname_or_unix.cloneIfNeeded() catch unreachable).slice(),
+ },
+ .ssl = ssl_enabled,
+ };
+
+ socket.handlers.protect();
+
+ if (socket_config.default_data != .zero) {
+ socket.strong_data = JSC.Strong.create(socket_config.default_data, globalObject);
+ }
+
+ const socket_flags: i32 = 0;
+
+ var ctx_opts: uws.us_socket_context_options_t = undefined;
+ @memset(@ptrCast([*]u8, &ctx_opts), 0, @sizeOf(uws.us_socket_context_options_t));
+
+ if (ssl) |ssl_config| {
+ ctx_opts.key_file_name = ssl_config.key_file_name;
+ ctx_opts.cert_file_name = ssl_config.cert_file_name;
+ ctx_opts.ca_file_name = ssl_config.ca_file_name;
+ ctx_opts.dh_params_file_name = ssl_config.dh_params_file_name;
+ ctx_opts.passphrase = ssl_config.passphrase;
+ ctx_opts.ssl_prefer_low_memory_usage = @boolToInt(ssl_config.low_memory_mode);
+ }
+
+ socket.socket_context = uws.us_create_socket_context(@boolToInt(ssl_enabled), uws.Loop.get().?, @sizeOf(usize), ctx_opts);
+
+ if (ssl) |ssl_config| {
+ uws.us_socket_context_add_server_name(1, socket.socket_context, ssl_config.server_name, ctx_opts, null);
+ }
+
+ var this: *Listener = handlers.vm.allocator.create(Listener) catch @panic("OOM");
+ this.* = socket;
+ this.socket_context.?.ext(ssl_enabled, *Listener).?.* = this;
+
+ var this_value = this.toJS(globalObject);
+ this.strong_self.set(globalObject, this_value);
+ this.poll_ref.ref(handlers.vm);
+
+ if (ssl_enabled) {
+ uws.NewSocketHandler(true).configure(
+ this.socket_context.?,
+ true,
+ *TLSSocket,
+ struct {
+ pub const onOpen = NewSocket(true).onOpen;
+ pub const onCreate = onCreateTLS;
+ pub const onClose = NewSocket(true).onClose;
+ pub const onData = NewSocket(true).onData;
+ pub const onWritable = NewSocket(true).onWritable;
+ pub const onTimeout = NewSocket(true).onTimeout;
+ pub const onConnectError = NewSocket(true).onConnectError;
+ pub const onEnd = NewSocket(true).onEnd;
+ },
+ );
+ } else {
+ uws.NewSocketHandler(false).configure(
+ this.socket_context.?,
+ true,
+ *TCPSocket,
+ struct {
+ pub const onOpen = NewSocket(false).onOpen;
+ pub const onCreate = onCreateTCP;
+ pub const onClose = NewSocket(false).onClose;
+ pub const onData = NewSocket(false).onData;
+ pub const onWritable = NewSocket(false).onWritable;
+ pub const onTimeout = NewSocket(false).onTimeout;
+ pub const onConnectError = NewSocket(false).onConnectError;
+ pub const onEnd = NewSocket(false).onEnd;
+ },
+ );
+ }
+
+ switch (this.connection) {
+ .host => |c| {
+ var host = bun.default_allocator.dupeZ(u8, c.host) catch unreachable;
+ defer bun.default_allocator.destroy(host.ptr);
+ this.listener = uws.us_socket_context_listen(@boolToInt(ssl_enabled), this.socket_context, host, c.port, socket_flags, 8) orelse {
+ exception.* = JSC.toInvalidArguments(
+ "Failed to listen at {s}:{d}",
+ .{
+ bun.span(host),
+ c.port,
+ },
+ globalObject,
+ ).asObjectRef();
+ this.poll_ref.unref(handlers.vm);
+
+ this.strong_self.clear();
+ this.strong_data.clear();
+
+ return .zero;
+ };
+ },
+ .unix => |u| {
+ var host = bun.default_allocator.dupeZ(u8, u) catch unreachable;
+ defer bun.default_allocator.destroy(host.ptr);
+ this.listener = uws.us_socket_context_listen_unix(@boolToInt(ssl_enabled), this.socket_context, host, socket_flags, 8) orelse {
+ exception.* = JSC.toInvalidArguments(
+ "Failed to listen on socket {s}",
+ .{
+ bun.span(host),
+ },
+ globalObject,
+ ).asObjectRef();
+ this.poll_ref.unref(handlers.vm);
+
+ this.strong_self.clear();
+ this.strong_data.clear();
+
+ return .zero;
+ };
+ },
+ }
+
+ return this_value;
+ }
+
+ pub fn onCreateTLS(
+ socket: uws.NewSocketHandler(true),
+ ) void {
+ onCreate(true, socket);
+ }
+
+ pub fn onCreateTCP(
+ socket: uws.NewSocketHandler(false),
+ ) void {
+ onCreate(false, socket);
+ }
+
+ pub fn constructor(globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) ?*Listener {
+ globalObject.throw("Cannot construct Listener", .{});
+ return null;
+ }
+
+ pub fn onCreate(comptime ssl: bool, socket: uws.NewSocketHandler(ssl)) void {
+ JSC.markBinding(@src());
+ log("onCreate", .{});
+ var listener: *Listener = socket.context().ext(ssl, *Listener).?.*;
+ const Socket = NewSocket(ssl);
+ std.debug.assert(ssl == listener.ssl);
+
+ var this_socket = listener.handlers.vm.allocator.create(Socket) catch @panic("Out of memory");
+ this_socket.* = Socket{
+ .handlers = &listener.handlers,
+ .this_value = listener.strong_data.get() orelse JSValue.zero,
+ .socket = socket,
+ };
+ socket.ext(**anyopaque).?.* = bun.cast(**anyopaque, this_socket);
+ socket.timeout(120000);
+ }
+
+ pub fn stop(this: *Listener, _: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
+ log("close", .{});
+
+ var listener = this.listener orelse return JSValue.jsUndefined();
+ this.listener = null;
+ listener.close(this.ssl);
+ if (this.handlers.active_connections == 0) {
+ this.poll_ref.unref(this.handlers.vm);
+ this.handlers.unprotect();
+ this.socket_context.?.deinit(this.ssl);
+ this.socket_context = null;
+ this.strong_self.clear();
+ this.strong_data.clear();
+ }
+
+ return JSValue.jsUndefined();
+ }
+
+ pub fn finalize(this: *Listener) callconv(.C) void {
+ log("Finalize", .{});
+ this.deinit();
+ }
+
+ pub fn deinit(this: *Listener) void {
+ this.strong_self.deinit();
+ this.strong_data.deinit();
+ this.poll_ref.unref(this.handlers.vm);
+ std.debug.assert(this.listener == null);
+ std.debug.assert(this.handlers.active_connections == 0);
+
+ if (this.socket_context) |ctx| {
+ ctx.deinit(this.ssl);
+ }
+
+ this.handlers.unprotect();
+ this.connection.deinit();
+ bun.default_allocator.destroy(this);
+ }
+
+ pub fn getConnectionsCount(this: *Listener, _: *JSC.JSGlobalObject) callconv(.C) JSValue {
+ return JSValue.jsNumber(this.handlers.active_connections);
+ }
+
+ pub fn getUnix(this: *Listener, globalObject: *JSC.JSGlobalObject) callconv(.C) JSValue {
+ if (this.connection != .unix) {
+ return JSValue.jsUndefined();
+ }
+
+ return ZigString.init(this.connection.unix).withEncoding().toValueGC(globalObject);
+ }
+
+ pub fn getHostname(this: *Listener, globalObject: *JSC.JSGlobalObject) callconv(.C) JSValue {
+ if (this.connection != .host) {
+ return JSValue.jsUndefined();
+ }
+
+ return ZigString.init(this.connection.host.host).withEncoding().toValueGC(globalObject);
+ }
+
+ pub fn getPort(this: *Listener, _: *JSC.JSGlobalObject) callconv(.C) JSValue {
+ if (this.connection != .host) {
+ return JSValue.jsUndefined();
+ }
+
+ return JSValue.jsNumber(this.connection.host.port);
+ }
+
+ pub fn ref(this: *Listener, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ var this_value = callframe.this();
+ if (this.listener == null) return JSValue.jsUndefined();
+ this.poll_ref.ref(globalObject.bunVM());
+ this.strong_self.set(globalObject, this_value);
+ return JSValue.jsUndefined();
+ }
+
+ pub fn unref(this: *Listener, globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
+ if (!this.poll_ref.isActive()) return JSValue.jsUndefined();
+
+ this.poll_ref.unref(globalObject.bunVM());
+ if (this.handlers.active_connections == 0) {
+ this.strong_self.clear();
+ }
+ return JSValue.jsUndefined();
+ }
+
+ pub fn connect(
+ globalObject: *JSC.JSGlobalObject,
+ opts: JSValue,
+ exception: JSC.C.ExceptionRef,
+ ) JSValue {
+ if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) {
+ exception.* = JSC.toInvalidArguments("Expected options object", .{}, globalObject).asObjectRef();
+ return .zero;
+ }
+
+ const socket_config = SocketConfig.fromJS(opts, globalObject, exception) orelse {
+ return .zero;
+ };
+ var hostname_or_unix = socket_config.hostname_or_unix;
+ var port = socket_config.port;
+ var ssl = socket_config.ssl;
+ var handlers = socket_config.handlers;
+ var default_data = socket_config.default_data;
+
+ const ssl_enabled = ssl != null;
+
+ handlers.protect();
+
+ var ctx_opts: uws.us_socket_context_options_t = undefined;
+ @memset(@ptrCast([*]u8, &ctx_opts), 0, @sizeOf(uws.us_socket_context_options_t));
+
+ if (ssl) |ssl_config| {
+ if (ssl_config.key_file_name != null)
+ ctx_opts.key_file_name = ssl_config.key_file_name;
+ if (ssl_config.cert_file_name != null)
+ ctx_opts.cert_file_name = ssl_config.cert_file_name;
+ if (ssl_config.ca_file_name != null)
+ ctx_opts.ca_file_name = ssl_config.ca_file_name;
+ if (ssl_config.dh_params_file_name != null)
+ ctx_opts.dh_params_file_name = ssl_config.dh_params_file_name;
+ if (ssl_config.passphrase != null)
+ ctx_opts.passphrase = ssl_config.passphrase;
+ ctx_opts.ssl_prefer_low_memory_usage = @boolToInt(ssl_config.low_memory_mode);
+ }
+
+ var socket_context = uws.us_create_socket_context(@boolToInt(ssl_enabled), uws.Loop.get().?, @sizeOf(usize), ctx_opts).?;
+ var connection: Listener.UnixOrHost = if (port) |port_| .{
+ .host = .{ .host = (hostname_or_unix.cloneIfNeeded() catch unreachable).slice(), .port = port_ },
+ } else .{
+ .unix = (hostname_or_unix.cloneIfNeeded() catch unreachable).slice(),
+ };
+
+ if (ssl_enabled) {
+ uws.NewSocketHandler(true).configure(
+ socket_context,
+ true,
+ *TLSSocket,
+ struct {
+ pub const onOpen = NewSocket(true).onOpen;
+ pub const onClose = NewSocket(true).onClose;
+ pub const onData = NewSocket(true).onData;
+ pub const onWritable = NewSocket(true).onWritable;
+ pub const onTimeout = NewSocket(true).onTimeout;
+ pub const onConnectError = NewSocket(true).onConnectError;
+ pub const onEnd = NewSocket(true).onEnd;
+ },
+ );
+ } else {
+ uws.NewSocketHandler(false).configure(
+ socket_context,
+ true,
+ *TCPSocket,
+ struct {
+ pub const onOpen = NewSocket(false).onOpen;
+ pub const onClose = NewSocket(false).onClose;
+ pub const onData = NewSocket(false).onData;
+ pub const onWritable = NewSocket(false).onWritable;
+ pub const onTimeout = NewSocket(false).onTimeout;
+ pub const onConnectError = NewSocket(false).onConnectError;
+ pub const onEnd = NewSocket(false).onEnd;
+ },
+ );
+ }
+
+ default_data.ensureStillAlive();
+
+ // const socket_flags: i32 = 0;
+
+ var handlers_ptr = handlers.vm.allocator.create(Handlers) catch @panic("OOM");
+ handlers_ptr.* = handlers;
+ handlers_ptr.is_server = false;
+
+ if (ssl_enabled) {
+ var tls = handlers.vm.allocator.create(TLSSocket) catch @panic("OOM");
+
+ tls.* = .{
+ .handlers = handlers_ptr,
+ .this_value = default_data,
+ .socket = undefined,
+ };
+
+ var promise = JSC.JSPromise.create(globalObject);
+ var promise_value = promise.asValue(globalObject);
+ handlers.promise.set(globalObject, promise_value);
+
+ tls.doConnect(connection, socket_context) catch {
+ handlers_ptr.unprotect();
+ socket_context.deinit(true);
+ handlers.vm.allocator.destroy(handlers_ptr);
+ handlers.promise.deinit();
+ bun.default_allocator.destroy(tls);
+ exception.* = ZigString.static("Failed to connect").toErrorInstance(globalObject).asObjectRef();
+ return .zero;
+ };
+
+ return promise_value;
+ } else {
+ var tcp = handlers.vm.allocator.create(TCPSocket) catch @panic("OOM");
+
+ tcp.* = .{
+ .handlers = handlers_ptr,
+ .this_value = default_data,
+ .socket = undefined,
+ };
+ var promise = JSC.JSPromise.create(globalObject);
+ var promise_value = promise.asValue(globalObject);
+ handlers.promise.set(globalObject, promise_value);
+
+ tcp.doConnect(connection, socket_context) catch {
+ handlers_ptr.unprotect();
+ socket_context.deinit(false);
+ handlers.vm.allocator.destroy(handlers_ptr);
+ handlers.promise.deinit();
+ bun.default_allocator.destroy(tcp);
+ exception.* = ZigString.static("Failed to connect").toErrorInstance(globalObject).asObjectRef();
+ return .zero;
+ };
+
+ return promise_value;
+ }
+ }
+};
+
+fn JSSocketType(comptime ssl: bool) type {
+ if (!ssl) {
+ return JSC.Codegen.JSTCPSocket;
+ } else {
+ return JSC.Codegen.JSTLSSocket;
+ }
+}
+
+fn NewSocket(comptime ssl: bool) type {
+ return struct {
+ pub const Socket = uws.NewSocketHandler(ssl);
+ socket: Socket,
+ detached: bool = false,
+ handlers: *Handlers,
+ this_value: JSC.JSValue = .zero,
+ poll_ref: JSC.PollRef = JSC.PollRef.init(),
+ reffer: JSC.Ref = JSC.Ref.init(),
+ last_4: [4]u8 = .{ 0, 0, 0, 0 },
+
+ const This = @This();
+ const log = Output.scoped(.Socket, false);
+
+ pub usingnamespace JSSocketType(ssl);
+
+ pub fn doConnect(this: *This, connection: Listener.UnixOrHost, socket_ctx: *uws.SocketContext) !void {
+ switch (connection) {
+ .host => |c| {
+ _ = @This().Socket.connectPtr(
+ c.host,
+ c.port,
+ socket_ctx,
+ @This(),
+ this,
+ "socket",
+ ) orelse return error.ConnectionFailed;
+ },
+ .unix => |u| {
+ _ = @This().Socket.connectUnixPtr(
+ u,
+ socket_ctx,
+ @This(),
+ this,
+ "socket",
+ ) orelse return error.ConnectionFailed;
+ },
+ }
+ }
+
+ pub fn constructor(globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) ?*This {
+ globalObject.throw("Cannot construct Socket", .{});
+ return null;
+ }
+
+ pub fn onWritable(
+ this: *This,
+ _: Socket,
+ ) void {
+ JSC.markBinding(@src());
+ if (this.detached) return;
+ var handlers = this.handlers;
+ const callback = handlers.onWritable;
+ if (callback == .zero) {
+ return;
+ }
+
+ const this_value = this.getThisValue(handlers.globalObject);
+ const result = callback.callWithThis(handlers.globalObject, this_value, &[_]JSValue{
+ this_value,
+ });
+
+ if (!result.isEmptyOrUndefinedOrNull() and result.isAnyError(handlers.globalObject)) {
+ if (handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result })) {
+ return;
+ }
+
+ handlers.vm.runErrorHandler(result, null);
+ }
+ }
+ pub fn onTimeout(
+ this: *This,
+ _: Socket,
+ ) void {
+ JSC.markBinding(@src());
+ if (this.detached) return;
+ this.detached = true;
+ var handlers = this.handlers;
+ this.poll_ref.unref(handlers.vm);
+ var globalObject = handlers.globalObject;
+ const callback = handlers.onTimeout;
+
+ this.markInactive();
+ if (callback == .zero) {
+ return;
+ }
+
+ const this_value = this.getThisValue(globalObject);
+ const result = callback.callWithThis(globalObject, this_value, &[_]JSValue{
+ this_value,
+ });
+
+ if (!result.isEmptyOrUndefinedOrNull() and result.isAnyError(globalObject)) {
+ if (handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result })) {
+ return;
+ }
+
+ handlers.vm.runErrorHandler(result, null);
+ }
+ }
+ pub fn onConnectError(this: *This, socket: Socket, errno: c_int) void {
+ JSC.markBinding(@src());
+ log("onConnectError({d}", .{errno});
+ this.detached = true;
+ var handlers = this.handlers;
+ this.poll_ref.unref(handlers.vm);
+ var err = JSC.SystemError{
+ .errno = errno,
+ .message = ZigString.init("Failed to connect"),
+ .syscall = ZigString.init("connect"),
+ };
+ _ = handlers.rejectPromise(err.toErrorInstance(handlers.globalObject));
+ this.reffer.unref(handlers.vm);
+ handlers.markInactive(ssl, socket.context());
+ this.finalize();
+ }
+
+ pub fn markActive(this: *This) void {
+ if (!this.reffer.has) {
+ this.handlers.active_connections += 1;
+ this.reffer.ref(this.handlers.vm);
+ }
+ }
+
+ pub fn markInactive(this: *This) void {
+ if (this.reffer.has) {
+ var vm = this.handlers.vm;
+ this.handlers.markInactive(ssl, this.socket.context());
+ this.reffer.unref(vm);
+ this.poll_ref.unref(vm);
+ }
+
+ if (this.this_value != .zero) {
+ this.this_value.unprotect();
+ }
+ }
+
+ pub fn onOpen(this: *This, socket: Socket) void {
+ JSC.markBinding(@src());
+ log("onOpen", .{});
+ this.poll_ref.ref(this.handlers.vm);
+ this.detached = false;
+ this.socket = socket;
+ socket.ext(**anyopaque).?.* = bun.cast(**anyopaque, this);
+ var handlers = this.handlers;
+ const old_this_value = this.this_value;
+ this.this_value = .zero;
+ const this_value = this.getThisValue(handlers.globalObject);
+
+ if (old_this_value != .zero) {
+ This.dataSetCached(this_value, handlers.globalObject, old_this_value);
+ }
+
+ if (handlers.onOpen == .zero and old_this_value == .zero) {
+ this.markActive();
+ this.handlers.resolvePromise(this_value);
+ return;
+ }
+
+ handlers.resolvePromise(this_value);
+
+ const result = handlers.onOpen.callWithThis(handlers.globalObject, this_value, &[_]JSValue{
+ this_value,
+ });
+
+ if (!result.isEmptyOrUndefinedOrNull() and result.isAnyError(handlers.globalObject)) {
+ if (!this.socket.isClosed()) {
+ log("Closing due to error", .{});
+ this.detached = true;
+ this.socket.close(0, null);
+ } else {
+ log("Already closed", .{});
+ }
+
+ if (handlers.rejectPromise(this_value)) {
+ return;
+ }
+
+ if (handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result })) {
+ return;
+ }
+
+ handlers.vm.runErrorHandler(result, null);
+ return;
+ }
+
+ this.markActive();
+ }
+
+ pub fn getThisValue(this: *This, globalObject: *JSC.JSGlobalObject) JSValue {
+ if (this.this_value == .zero) {
+ const value = this.toJS(globalObject);
+ this.this_value = value;
+ value.protect();
+ return value;
+ }
+
+ return this.this_value;
+ }
+
+ pub fn onEnd(this: *This, _: Socket) void {
+ JSC.markBinding(@src());
+ log("onEnd", .{});
+ this.detached = true;
+ var handlers = this.handlers;
+ const callback = handlers.onEnd;
+
+ if (callback == .zero) {
+ return;
+ }
+
+ const this_value = this.getThisValue(handlers.globalObject);
+ const result = callback.callWithThis(handlers.globalObject, this_value, &[_]JSValue{
+ this_value,
+ });
+
+ if (!result.isEmptyOrUndefinedOrNull() and result.isAnyError(handlers.globalObject)) {
+ if (handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result })) {
+ return;
+ }
+
+ handlers.vm.runErrorHandler(result, null);
+ }
+ }
+
+ pub fn onClose(this: *This, _: Socket, err: c_int, _: ?*anyopaque) void {
+ JSC.markBinding(@src());
+ log("onClose", .{});
+ this.detached = true;
+ var handlers = this.handlers;
+ this.poll_ref.unref(handlers.vm);
+
+ const callback = handlers.onClose;
+ var globalObject = handlers.globalObject;
+
+ if (callback == .zero) {
+ this.markInactive();
+ return;
+ }
+
+ const this_value = this.getThisValue(globalObject);
+
+ const result = callback.callWithThis(globalObject, this_value, &[_]JSValue{
+ this_value,
+ JSValue.jsNumber(@as(i32, err)),
+ });
+
+ if (!result.isEmptyOrUndefinedOrNull() and result.isAnyError(globalObject)) {
+ if (handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result })) {
+ return;
+ }
+
+ handlers.vm.runErrorHandler(result, null);
+ }
+ }
+
+ pub fn onData(this: *This, _: Socket, data: []const u8) void {
+ JSC.markBinding(@src());
+ if (comptime Environment.allow_assert) {
+ log("onData({d})", .{data.len});
+ }
+
+ if (this.detached) return;
+ var handlers = this.handlers;
+ // const encoding = handlers.encoding;
+ const callback = handlers.onData;
+ if (callback == .zero) {
+ return;
+ }
+
+ const output_value = JSC.ArrayBuffer.create(handlers.globalObject, data, .Uint8Array);
+
+ const this_value = this.getThisValue(handlers.globalObject);
+ const result = callback.callWithThis(handlers.globalObject, this_value, &[_]JSValue{
+ this_value,
+ output_value,
+ });
+
+ if (!result.isEmptyOrUndefinedOrNull() and result.isAnyError(handlers.globalObject)) {
+ if (handlers.callErrorHandler(this_value, &[_]JSC.JSValue{ this_value, result })) {
+ return;
+ }
+
+ handlers.vm.runErrorHandler(result, null);
+ }
+ }
+
+ pub fn getData(
+ _: *This,
+ _: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ log("getData()", .{});
+ return JSValue.jsUndefined();
+ }
+
+ pub fn setData(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ value: JSC.JSValue,
+ ) callconv(.C) bool {
+ log("setData()", .{});
+ This.dataSetCached(this.this_value, globalObject, value);
+ return true;
+ }
+
+ pub fn getListener(
+ this: *This,
+ _: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ if (!this.handlers.is_server or this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ return @fieldParentPtr(Listener, "handlers", this.handlers).strong_self.get() orelse JSValue.jsUndefined();
+ }
+
+ pub fn getReadyState(
+ this: *This,
+ _: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ log("getReadyState()", .{});
+
+ if (this.detached) {
+ return JSValue.jsNumber(@as(i32, -1));
+ } else if (this.socket.isClosed()) {
+ return JSValue.jsNumber(@as(i32, 0));
+ } else if (this.socket.isEstablished()) {
+ return JSValue.jsNumber(@as(i32, 1));
+ } else if (this.socket.isShutdown()) {
+ return JSValue.jsNumber(@as(i32, -2));
+ } else {
+ return JSValue.jsNumber(@as(i32, 2));
+ }
+ }
+
+ pub fn timeout(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ const args = callframe.arguments(1);
+ if (this.detached) return JSValue.jsUndefined();
+ if (args.len == 0) {
+ globalObject.throw("Expected 1 argument, got 0", .{});
+ return .zero;
+ }
+ const t = args.ptr[0].toInt32();
+ if (t < 0) {
+ globalObject.throw("Timeout must be a positive integer", .{});
+ return .zero;
+ }
+
+ this.socket.timeout(@intCast(c_uint, t));
+
+ return JSValue.jsUndefined();
+ }
+
+ pub fn write(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+
+ if (this.detached) {
+ return JSValue.jsNumber(@as(i32, -1));
+ }
+
+ const args = callframe.arguments(4);
+
+ if (args.len == 0) {
+ globalObject.throw("Expected 1 - 4 arguments, got 0", .{});
+ return .zero;
+ }
+
+ return this.writeOrEnd(globalObject, args.ptr[0..args.len], false);
+ }
+
+ pub fn getLocalPort(
+ this: *This,
+ _: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ return JSValue.jsNumber(this.socket.localPort());
+ }
+
+ pub fn getRemoteAddress(
+ this: *This,
+ globalThis: *JSC.JSGlobalObject,
+ ) callconv(.C) JSValue {
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ var buf: [512]u8 = undefined;
+ var length: i32 = 512;
+ this.socket.remoteAddress(&buf, &length);
+ const address = buf[0..@intCast(usize, @minimum(length, 0))];
+
+ if (address.len == 0) {
+ return JSValue.jsUndefined();
+ }
+
+ return ZigString.init(address).toValueGC(globalThis);
+ }
+
+ fn writeMaybeCorked(this: *This, buffer: []const u8, is_end: bool) i32 {
+ // we don't cork yet but we might later
+ return this.socket.write(buffer, is_end);
+ }
+
+ fn writeOrEnd(this: *This, globalObject: *JSC.JSGlobalObject, args: []const JSC.JSValue, is_end: bool) JSValue {
+ if (args.ptr[0].isEmptyOrUndefinedOrNull()) {
+ globalObject.throw("Expected an ArrayBufferView, a string, or a Blob", .{});
+ return .zero;
+ }
+
+ if (this.socket.isShutdown() or this.socket.isClosed()) {
+ return JSValue.jsNumber(@as(i32, -1));
+ }
+
+ if (args.ptr[0].asArrayBuffer(globalObject)) |array_buffer| {
+ var slice = array_buffer.slice();
+
+ if (args.len > 1) {
+ if (!args.ptr[1].isAnyInt()) {
+ globalObject.throw("Expected offset integer, got {any}", .{args.ptr[1].getZigString(globalObject)});
+ return .zero;
+ }
+
+ const offset = @minimum(args.ptr[1].toUInt64NoTruncate(), slice.len);
+ slice = slice[offset..];
+
+ if (args.len > 2) {
+ if (!args.ptr[2].isAnyInt()) {
+ globalObject.throw("Expected length integer, got {any}", .{args.ptr[2].getZigString(globalObject)});
+ return .zero;
+ }
+
+ const length = @minimum(args.ptr[2].toUInt64NoTruncate(), slice.len);
+ slice = slice[0..length];
+ }
+ }
+
+ if (slice.len == 0) {
+ return JSValue.jsNumber(@as(i32, 0));
+ }
+
+ return JSValue.jsNumber(this.writeMaybeCorked(slice, is_end));
+ } else if (args.ptr[0].jsType() == .DOMWrapper) {
+ const blob: JSC.WebCore.AnyBlob = getter: {
+ if (args.ptr[0].as(JSC.WebCore.Blob)) |blob| {
+ break :getter JSC.WebCore.AnyBlob{ .Blob = blob.* };
+ } else if (args.ptr[0].as(JSC.WebCore.Response)) |response| {
+ response.body.value.toBlobIfPossible();
+
+ if (response.body.value.tryUseAsAnyBlob()) |blob| {
+ break :getter blob;
+ }
+
+ globalObject.throw("Only Blob/buffered bodies are supported for now", .{});
+ return .zero;
+ } else if (args.ptr[0].as(JSC.WebCore.Request)) |request| {
+ request.body.toBlobIfPossible();
+ if (request.body.tryUseAsAnyBlob()) |blob| {
+ break :getter blob;
+ }
+
+ globalObject.throw("Only Blob/buffered bodies are supported for now", .{});
+ return .zero;
+ }
+
+ globalObject.throw("Expected Blob, Request or Response", .{});
+ return .zero;
+ };
+
+ if (!blob.needsToReadFile()) {
+ var slice = blob.slice();
+
+ if (args.len > 1) {
+ if (!args.ptr[1].isAnyInt()) {
+ globalObject.throw("Expected offset integer, got {any}", .{args.ptr[1].getZigString(globalObject)});
+ return .zero;
+ }
+
+ const offset = @minimum(args.ptr[1].toUInt64NoTruncate(), slice.len);
+ slice = slice[offset..];
+
+ if (args.len > 2) {
+ if (!args.ptr[2].isAnyInt()) {
+ globalObject.throw("Expected length integer, got {any}", .{args.ptr[2].getZigString(globalObject)});
+ return .zero;
+ }
+
+ const length = @minimum(args.ptr[2].toUInt64NoTruncate(), slice.len);
+ slice = slice[0..length];
+ }
+ }
+
+ if (slice.len == 0) {
+ return JSValue.jsNumber(@as(i32, 0));
+ }
+
+ return JSValue.jsNumber(this.writeMaybeCorked(slice, is_end));
+ }
+
+ globalObject.throw("sendfile() not implemented yet", .{});
+ return .zero;
+ } else if (args.ptr[0].toStringOrNull(globalObject)) |jsstring| {
+ var zig_str = jsstring.toSlice(globalObject, globalObject.bunVM().allocator);
+ defer zig_str.deinit();
+
+ var slice = zig_str.slice();
+
+ if (args.len > 1) {
+ if (!args.ptr[1].isAnyInt()) {
+ globalObject.throw("Expected offset integer, got {any}", .{args.ptr[1].getZigString(globalObject)});
+ return .zero;
+ }
+
+ const offset = @minimum(args.ptr[1].toUInt64NoTruncate(), slice.len);
+ slice = slice[offset..];
+
+ if (args.len > 2) {
+ if (!args.ptr[2].isAnyInt()) {
+ globalObject.throw("Expected length integer, got {any}", .{args.ptr[2].getZigString(globalObject)});
+ return .zero;
+ }
+
+ const length = @minimum(args.ptr[2].toUInt64NoTruncate(), slice.len);
+ slice = slice[0..length];
+ }
+ }
+
+ return JSValue.jsNumber(this.writeMaybeCorked(slice, is_end));
+ } else {
+ globalObject.throw("Expected ArrayBufferView, a string, or a Blob", .{});
+ return .zero;
+ }
+ }
+
+ pub fn flush(
+ this: *This,
+ _: *JSC.JSGlobalObject,
+ _: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ if (!this.detached)
+ this.socket.flush();
+
+ return JSValue.jsUndefined();
+ }
+
+ pub fn shutdown(
+ this: *This,
+ _: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ const args = callframe.arguments(1);
+ if (!this.detached) {
+ if (args.len > 0 and args.ptr[0].toBoolean()) {
+ this.socket.shutdownRead();
+ } else {
+ this.socket.shutdown();
+ }
+ }
+
+ return JSValue.jsUndefined();
+ }
+
+ pub fn end(
+ this: *This,
+ globalObject: *JSC.JSGlobalObject,
+ callframe: *JSC.CallFrame,
+ ) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+
+ const args = callframe.arguments(4);
+
+ if (args.len == 0) {
+ log("end()", .{});
+ if (!this.detached) {
+ if (!this.socket.isClosed()) this.socket.flush();
+ this.detached = true;
+ this.markInactive();
+ if (!this.socket.isClosed())
+ this.socket.close(0, null);
+ }
+
+ return JSValue.jsUndefined();
+ }
+
+ log("end({d} args)", .{args.len});
+
+ if (this.detached) {
+ return JSValue.jsNumber(@as(i32, -1));
+ }
+
+ const result = this.writeOrEnd(globalObject, args.ptr[0..args.len], true);
+ if (result != .zero and result.toInt32() > 0) {
+ this.socket.flush();
+ this.detached = true;
+ this.markInactive();
+ if (!this.socket.isClosed())
+ this.socket.close(0, null);
+ }
+
+ return result;
+ }
+
+ pub fn ref(this: *This, globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ if (this.detached) return JSValue.jsUndefined();
+ this.poll_ref.ref(globalObject.bunVM());
+ return JSValue.jsUndefined();
+ }
+
+ pub fn unref(this: *This, globalObject: *JSC.JSGlobalObject, _: *JSC.CallFrame) callconv(.C) JSValue {
+ JSC.markBinding(@src());
+ this.poll_ref.unref(globalObject.bunVM());
+ return JSValue.jsUndefined();
+ }
+
+ pub fn finalize(this: *This) callconv(.C) void {
+ log("finalize()", .{});
+ if (!this.detached and !this.socket.isClosed()) {
+ this.detached = true;
+ this.socket.close(0, null);
+ }
+ this.markInactive();
+ if (this.poll_ref.isActive()) this.poll_ref.unref(JSC.VirtualMachine.vm);
+ }
+
+ pub fn reload(this: *This, globalObject: *JSC.JSGlobalObject, callframe: *JSC.CallFrame) callconv(.C) JSValue {
+ const args = callframe.arguments(1);
+
+ if (args.len < 1) {
+ globalObject.throw("Expected 1 argument", .{});
+ return .zero;
+ }
+
+ if (this.detached) {
+ return JSValue.jsUndefined();
+ }
+
+ const opts = args.ptr[0];
+ if (opts.isEmptyOrUndefinedOrNull() or opts.isBoolean() or !opts.isObject()) {
+ globalObject.throw("Expected options object", .{});
+ return .zero;
+ }
+
+ var exception: JSC.C.JSValueRef = null;
+
+ var socket_obj = opts.get(globalObject, "socket") orelse {
+ globalObject.throw("Expected \"socket\" option", .{});
+ return .zero;
+ };
+
+ const handlers = Handlers.fromJS(globalObject, socket_obj, &exception) orelse {
+ globalObject.throwValue(exception.?.value());
+ return .zero;
+ };
+
+ var prev_handlers = this.handlers;
+ prev_handlers.unprotect();
+ this.handlers.* = handlers; // TODO: this is a memory leak
+ this.handlers.protect();
+
+ return JSValue.jsUndefined();
+ }
+ };
+}
+
+pub const TCPSocket = NewSocket(false);
+pub const TLSSocket = NewSocket(true);
diff --git a/src/bun.js/api/sockets.classes.ts b/src/bun.js/api/sockets.classes.ts
new file mode 100644
index 000000000..0c72d1d8d
--- /dev/null
+++ b/src/bun.js/api/sockets.classes.ts
@@ -0,0 +1,130 @@
+import { define } from "../scripts/class-definitions";
+
+function generate(ssl) {
+ return define({
+ name: ssl ? "TCPSocket" : "TLSSocket",
+ JSType: "0b11101110",
+ proto: {
+ write: {
+ fn: "write",
+ length: 3,
+ },
+ end: {
+ fn: "end",
+ length: 3,
+ },
+
+ // },
+ listener: {
+ getter: "getListener",
+ },
+
+ timeout: {
+ fn: "timeout",
+ length: 1,
+ },
+
+ flush: {
+ fn: "flush",
+ length: 0,
+ },
+
+ shutdown: {
+ fn: "shutdown",
+ length: 1,
+ },
+
+ ref: {
+ fn: "ref",
+ length: 0,
+ },
+ unref: {
+ fn: "unref",
+ length: 0,
+ },
+
+ localPort: {
+ getter: "getLocalPort",
+ },
+ // cork: {
+ // fn: "cork",
+ // length: 1,
+ // },
+ data: {
+ getter: "getData",
+ cache: true,
+ setter: "setData",
+ },
+ readyState: {
+ getter: "getReadyState",
+ },
+
+ // topics: {
+ // getter: "getTopics",
+ // },
+
+ remoteAddress: {
+ getter: "getRemoteAddress",
+ cache: true,
+ },
+
+ reload: {
+ fn: "reload",
+ length: 1,
+ },
+ },
+ finalize: true,
+ construct: true,
+ klass: {},
+ });
+}
+export default [
+ generate(true),
+ generate(false),
+ define({
+ name: "Listener",
+ JSType: "0b11101110",
+ proto: {
+ stop: {
+ fn: "stop",
+ length: 1,
+ },
+
+ ref: {
+ fn: "ref",
+ length: 0,
+ },
+ unref: {
+ fn: "unref",
+ length: 0,
+ },
+
+ port: {
+ getter: "getPort",
+ },
+
+ unix: {
+ getter: "getUnix",
+ cache: true,
+ },
+
+ reload: {
+ fn: "reload",
+ length: 1,
+ },
+
+ hostname: {
+ getter: "getHostname",
+ cache: true,
+ },
+
+ data: {
+ getter: "getData",
+ setter: "setData",
+ },
+ },
+ finalize: true,
+ construct: true,
+ klass: {},
+ }),
+];
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
index 5014f0d4e..3ec74c09c 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMClientIsoSubspaces.h
@@ -1,4 +1,7 @@
-std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSubprocess;
+std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTCPSocket;
+std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTCPSocketConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTLSSocket;
+std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForTLSSocketConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForListener;
+std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForListenerConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSubprocess;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSubprocessConstructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA1;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForSHA1Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMD5;
std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMD5Constructor;std::unique_ptr<GCClient::IsoSubspace> m_clientSubspaceForMD4;
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
index 149dfe8b8..11c6780ac 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+DOMIsoSubspaces.h
@@ -1,4 +1,7 @@
-std::unique_ptr<IsoSubspace> m_subspaceForSubprocess;
+std::unique_ptr<IsoSubspace> m_subspaceForTCPSocket;
+std::unique_ptr<IsoSubspace> m_subspaceForTCPSocketConstructor;std::unique_ptr<IsoSubspace> m_subspaceForTLSSocket;
+std::unique_ptr<IsoSubspace> m_subspaceForTLSSocketConstructor;std::unique_ptr<IsoSubspace> m_subspaceForListener;
+std::unique_ptr<IsoSubspace> m_subspaceForListenerConstructor;std::unique_ptr<IsoSubspace> m_subspaceForSubprocess;
std::unique_ptr<IsoSubspace> m_subspaceForSubprocessConstructor;std::unique_ptr<IsoSubspace> m_subspaceForSHA1;
std::unique_ptr<IsoSubspace> m_subspaceForSHA1Constructor;std::unique_ptr<IsoSubspace> m_subspaceForMD5;
std::unique_ptr<IsoSubspace> m_subspaceForMD5Constructor;std::unique_ptr<IsoSubspace> m_subspaceForMD4;
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
index 3de6262da..0ca7db3db 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureHeader.h
@@ -1,3 +1,21 @@
+JSC::Structure* JSTCPSocketStructure() { return m_JSTCPSocket.getInitializedOnMainThread(this); }
+ JSC::JSObject* JSTCPSocketConstructor() { return m_JSTCPSocket.constructorInitializedOnMainThread(this); }
+ JSC::JSValue JSTCPSocketPrototype() { return m_JSTCPSocket.prototypeInitializedOnMainThread(this); }
+ JSC::LazyClassStructure m_JSTCPSocket;
+ bool hasJSTCPSocketSetterValue { false };
+ mutable JSC::WriteBarrier<JSC::Unknown> m_JSTCPSocketSetterValue;
+JSC::Structure* JSTLSSocketStructure() { return m_JSTLSSocket.getInitializedOnMainThread(this); }
+ JSC::JSObject* JSTLSSocketConstructor() { return m_JSTLSSocket.constructorInitializedOnMainThread(this); }
+ JSC::JSValue JSTLSSocketPrototype() { return m_JSTLSSocket.prototypeInitializedOnMainThread(this); }
+ JSC::LazyClassStructure m_JSTLSSocket;
+ bool hasJSTLSSocketSetterValue { false };
+ mutable JSC::WriteBarrier<JSC::Unknown> m_JSTLSSocketSetterValue;
+JSC::Structure* JSListenerStructure() { return m_JSListener.getInitializedOnMainThread(this); }
+ JSC::JSObject* JSListenerConstructor() { return m_JSListener.constructorInitializedOnMainThread(this); }
+ JSC::JSValue JSListenerPrototype() { return m_JSListener.prototypeInitializedOnMainThread(this); }
+ JSC::LazyClassStructure m_JSListener;
+ bool hasJSListenerSetterValue { false };
+ mutable JSC::WriteBarrier<JSC::Unknown> m_JSListenerSetterValue;
JSC::Structure* JSSubprocessStructure() { return m_JSSubprocess.getInitializedOnMainThread(this); }
JSC::JSObject* JSSubprocessConstructor() { return m_JSSubprocess.constructorInitializedOnMainThread(this); }
JSC::JSValue JSSubprocessPrototype() { return m_JSSubprocess.prototypeInitializedOnMainThread(this); }
diff --git a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
index e449c2904..b1144a1e8 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses+lazyStructureImpl.h
@@ -1,4 +1,22 @@
void GlobalObject::initGeneratedLazyClasses() {
+ m_JSTCPSocket.initLater(
+ [](LazyClassStructure::Initializer& init) {
+ init.setPrototype(WebCore::JSTCPSocket::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
+ init.setStructure(WebCore::JSTCPSocket::createStructure(init.vm, init.global, init.prototype));
+ init.setConstructor(WebCore::JSTCPSocketConstructor::create(init.vm, init.global, WebCore::JSTCPSocketConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<WebCore::JSTCPSocketPrototype*>(init.prototype)));
+ });
+ m_JSTLSSocket.initLater(
+ [](LazyClassStructure::Initializer& init) {
+ init.setPrototype(WebCore::JSTLSSocket::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
+ init.setStructure(WebCore::JSTLSSocket::createStructure(init.vm, init.global, init.prototype));
+ init.setConstructor(WebCore::JSTLSSocketConstructor::create(init.vm, init.global, WebCore::JSTLSSocketConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<WebCore::JSTLSSocketPrototype*>(init.prototype)));
+ });
+ m_JSListener.initLater(
+ [](LazyClassStructure::Initializer& init) {
+ init.setPrototype(WebCore::JSListener::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
+ init.setStructure(WebCore::JSListener::createStructure(init.vm, init.global, init.prototype));
+ init.setConstructor(WebCore::JSListenerConstructor::create(init.vm, init.global, WebCore::JSListenerConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), jsCast<WebCore::JSListenerPrototype*>(init.prototype)));
+ });
m_JSSubprocess.initLater(
[](LazyClassStructure::Initializer& init) {
init.setPrototype(WebCore::JSSubprocess::createPrototype(init.vm, reinterpret_cast<Zig::GlobalObject*>(init.global)));
@@ -87,6 +105,9 @@ void GlobalObject::initGeneratedLazyClasses() {
template<typename Visitor>
void GlobalObject::visitGeneratedLazyClasses(GlobalObject *thisObject, Visitor& visitor)
{
+ thisObject->m_JSTCPSocket.visit(visitor); visitor.append(thisObject->m_JSTCPSocketSetterValue);
+ thisObject->m_JSTLSSocket.visit(visitor); visitor.append(thisObject->m_JSTLSSocketSetterValue);
+ thisObject->m_JSListener.visit(visitor); visitor.append(thisObject->m_JSListenerSetterValue);
thisObject->m_JSSubprocess.visit(visitor); visitor.append(thisObject->m_JSSubprocessSetterValue);
thisObject->m_JSSHA1.visit(visitor); visitor.append(thisObject->m_JSSHA1SetterValue);
thisObject->m_JSMD5.visit(visitor); visitor.append(thisObject->m_JSMD5SetterValue);
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp
index 26fcec7b6..fad332acc 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.cpp
+++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp
@@ -23,7 +23,1371 @@ namespace WebCore {
using namespace JSC;
using namespace Zig;
-extern "C" void* SubprocessClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+extern "C" void* TCPSocketClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+JSC_DECLARE_CUSTOM_GETTER(jsTCPSocketConstructor);
+extern "C" void TCPSocketClass__finalize(void*);
+
+extern "C" JSC::EncodedJSValue TCPSocketPrototype__getData(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TCPSocketPrototype__dataGetterWrap);
+
+
+extern "C" bool TCPSocketPrototype__setData(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::EncodedJSValue value);
+JSC_DECLARE_CUSTOM_SETTER(TCPSocketPrototype__dataSetterWrap);
+
+
+extern "C" EncodedJSValue TCPSocketPrototype__end(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TCPSocketPrototype__endCallback);
+
+
+extern "C" EncodedJSValue TCPSocketPrototype__flush(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TCPSocketPrototype__flushCallback);
+
+
+extern "C" JSC::EncodedJSValue TCPSocketPrototype__getListener(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TCPSocketPrototype__listenerGetterWrap);
+
+
+extern "C" JSC::EncodedJSValue TCPSocketPrototype__getLocalPort(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TCPSocketPrototype__localPortGetterWrap);
+
+
+extern "C" JSC::EncodedJSValue TCPSocketPrototype__getReadyState(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TCPSocketPrototype__readyStateGetterWrap);
+
+
+extern "C" EncodedJSValue TCPSocketPrototype__ref(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TCPSocketPrototype__refCallback);
+
+
+extern "C" EncodedJSValue TCPSocketPrototype__reload(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TCPSocketPrototype__reloadCallback);
+
+
+extern "C" JSC::EncodedJSValue TCPSocketPrototype__getRemoteAddress(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TCPSocketPrototype__remoteAddressGetterWrap);
+
+
+extern "C" EncodedJSValue TCPSocketPrototype__shutdown(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TCPSocketPrototype__shutdownCallback);
+
+
+extern "C" EncodedJSValue TCPSocketPrototype__timeout(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TCPSocketPrototype__timeoutCallback);
+
+
+extern "C" EncodedJSValue TCPSocketPrototype__unref(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TCPSocketPrototype__unrefCallback);
+
+
+extern "C" EncodedJSValue TCPSocketPrototype__write(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TCPSocketPrototype__writeCallback);
+
+
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTCPSocketPrototype, JSTCPSocketPrototype::Base);
+
+
+ static const HashTableValue JSTCPSocketPrototypeTableValues[] = {
+{ "data"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TCPSocketPrototype__dataGetterWrap, TCPSocketPrototype__dataSetterWrap } } ,
+{ "end"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TCPSocketPrototype__endCallback, 3 } } ,
+{ "flush"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TCPSocketPrototype__flushCallback, 0 } } ,
+{ "listener"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TCPSocketPrototype__listenerGetterWrap, 0 } } ,
+{ "localPort"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TCPSocketPrototype__localPortGetterWrap, 0 } } ,
+{ "readyState"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TCPSocketPrototype__readyStateGetterWrap, 0 } } ,
+{ "ref"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TCPSocketPrototype__refCallback, 0 } } ,
+{ "reload"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TCPSocketPrototype__reloadCallback, 1 } } ,
+{ "remoteAddress"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TCPSocketPrototype__remoteAddressGetterWrap, 0 } } ,
+{ "shutdown"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TCPSocketPrototype__shutdownCallback, 1 } } ,
+{ "timeout"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TCPSocketPrototype__timeoutCallback, 1 } } ,
+{ "unref"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TCPSocketPrototype__unrefCallback, 0 } } ,
+{ "write"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TCPSocketPrototype__writeCallback, 3 } }
+ };
+
+
+
+const ClassInfo JSTCPSocketPrototype::s_info = { "TCPSocket"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTCPSocketPrototype) };
+
+
+
+JSC_DEFINE_CUSTOM_GETTER(jsTCPSocketConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto* prototype = jsDynamicCast<JSTCPSocketPrototype*>(JSValue::decode(thisValue));
+
+ if (UNLIKELY(!prototype))
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ return JSValue::encode(globalObject->JSTCPSocketConstructor());
+}
+
+
+
+JSC_DEFINE_CUSTOM_GETTER(TCPSocketPrototype__dataGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTCPSocket* thisObject = jsCast<JSTCPSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_data.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ TCPSocketPrototype__getData(thisObject->wrapped(), globalObject)
+ );
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_data.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+extern "C" void TCPSocketPrototype__dataSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSTCPSocket*>(JSValue::decode(thisValue));
+ thisObject->m_data.set(vm, thisObject, JSValue::decode(value));
+}
+
+
+JSC_DEFINE_CUSTOM_SETTER(TCPSocketPrototype__dataSetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTCPSocket* thisObject = jsCast<JSTCPSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ auto result = TCPSocketPrototype__setData(thisObject->wrapped(), lexicalGlobalObject, encodedValue);
+
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TCPSocketPrototype__endCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTCPSocket* thisObject = jsDynamicCast<JSTCPSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TCPSocketPrototype__end(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TCPSocketPrototype__flushCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTCPSocket* thisObject = jsDynamicCast<JSTCPSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TCPSocketPrototype__flush(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(TCPSocketPrototype__listenerGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTCPSocket* thisObject = jsCast<JSTCPSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = TCPSocketPrototype__getListener(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(TCPSocketPrototype__localPortGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTCPSocket* thisObject = jsCast<JSTCPSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = TCPSocketPrototype__getLocalPort(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(TCPSocketPrototype__readyStateGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTCPSocket* thisObject = jsCast<JSTCPSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = TCPSocketPrototype__getReadyState(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TCPSocketPrototype__refCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTCPSocket* thisObject = jsDynamicCast<JSTCPSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TCPSocketPrototype__ref(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TCPSocketPrototype__reloadCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTCPSocket* thisObject = jsDynamicCast<JSTCPSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TCPSocketPrototype__reload(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(TCPSocketPrototype__remoteAddressGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTCPSocket* thisObject = jsCast<JSTCPSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_remoteAddress.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ TCPSocketPrototype__getRemoteAddress(thisObject->wrapped(), globalObject)
+ );
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_remoteAddress.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+extern "C" void TCPSocketPrototype__remoteAddressSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSTCPSocket*>(JSValue::decode(thisValue));
+ thisObject->m_remoteAddress.set(vm, thisObject, JSValue::decode(value));
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TCPSocketPrototype__shutdownCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTCPSocket* thisObject = jsDynamicCast<JSTCPSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TCPSocketPrototype__shutdown(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TCPSocketPrototype__timeoutCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTCPSocket* thisObject = jsDynamicCast<JSTCPSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TCPSocketPrototype__timeout(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TCPSocketPrototype__unrefCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTCPSocket* thisObject = jsDynamicCast<JSTCPSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TCPSocketPrototype__unref(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TCPSocketPrototype__writeCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTCPSocket* thisObject = jsDynamicCast<JSTCPSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TCPSocketPrototype__write(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+void JSTCPSocketPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSTCPSocket::info(), JSTCPSocketPrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+void JSTCPSocketConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSTCPSocketPrototype* prototype)
+{
+ Base::finishCreation(vm, 0, "TCPSocket"_s, PropertyAdditionMode::WithoutStructureTransition);
+
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+ ASSERT(inherits(info()));
+}
+
+JSTCPSocketConstructor* JSTCPSocketConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSTCPSocketPrototype* prototype) {
+ JSTCPSocketConstructor* ptr = new (NotNull, JSC::allocateCell<JSTCPSocketConstructor>(vm)) JSTCPSocketConstructor(vm, structure, construct);
+ ptr->finishCreation(vm, globalObject, prototype);
+ return ptr;
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSTCPSocketConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
+{
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ JSC::VM &vm = globalObject->vm();
+ JSObject* newTarget = asObject(callFrame->newTarget());
+ auto* constructor = globalObject->JSTCPSocketConstructor();
+ Structure* structure = globalObject->JSTCPSocketStructure();
+ if (constructor != newTarget) {
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* functionGlobalObject = reinterpret_cast<Zig::GlobalObject*>(
+ // ShadowRealm functions belong to a different global object.
+ getFunctionRealm(globalObject, newTarget)
+ );
+ RETURN_IF_EXCEPTION(scope, {});
+ structure = InternalFunction::createSubclassStructure(
+ globalObject,
+ newTarget,
+ functionGlobalObject->JSTCPSocketStructure()
+ );
+ }
+
+ void* ptr = TCPSocketClass__construct(globalObject, callFrame);
+
+ if (UNLIKELY(!ptr)) {
+ return JSValue::encode(JSC::jsUndefined());
+ }
+
+ JSTCPSocket* instance = JSTCPSocket::create(vm, globalObject, structure, ptr);
+
+
+ return JSValue::encode(instance);
+}
+
+extern "C" EncodedJSValue TCPSocket__create(Zig::GlobalObject* globalObject, void* ptr) {
+ auto &vm = globalObject->vm();
+ JSC::Structure* structure = globalObject->JSTCPSocketStructure();
+ JSTCPSocket* instance = JSTCPSocket::create(vm, globalObject, structure, ptr);
+
+ return JSValue::encode(instance);
+}
+
+void JSTCPSocketConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSTCPSocketPrototype* prototype)
+{
+
+}
+
+const ClassInfo JSTCPSocketConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTCPSocketConstructor) };
+
+
+ extern "C" EncodedJSValue TCPSocket__getConstructor(Zig::GlobalObject* globalObject) {
+ return JSValue::encode(globalObject->JSTCPSocketConstructor());
+ }
+
+JSTCPSocket::~JSTCPSocket()
+{
+ if (m_ctx) {
+ TCPSocketClass__finalize(m_ctx);
+ }
+}
+void JSTCPSocket::destroy(JSCell* cell)
+{
+ static_cast<JSTCPSocket*>(cell)->JSTCPSocket::~JSTCPSocket();
+}
+
+const ClassInfo JSTCPSocket::s_info = { "TCPSocket"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTCPSocket) };
+
+void JSTCPSocket::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+JSTCPSocket* JSTCPSocket::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx) {
+ JSTCPSocket* ptr = new (NotNull, JSC::allocateCell<JSTCPSocket>(vm)) JSTCPSocket(vm, structure, ctx);
+ ptr->finishCreation(vm);
+ return ptr;
+}
+
+extern "C" void* TCPSocket__fromJS(JSC::EncodedJSValue value) {
+ JSC::JSValue decodedValue = JSC::JSValue::decode(value);
+ if (!decodedValue || decodedValue.isUndefinedOrNull())
+ return nullptr;
+
+ JSTCPSocket* object = JSC::jsDynamicCast<JSTCPSocket*>(decodedValue);
+
+ if (!object)
+ return nullptr;
+
+ return object->wrapped();
+}
+
+extern "C" bool TCPSocket__dangerouslySetPtr(JSC::EncodedJSValue value, void* ptr) {
+ JSTCPSocket* object = JSC::jsDynamicCast<JSTCPSocket*>(JSValue::decode(value));
+ if (!object)
+ return false;
+
+ object->m_ctx = ptr;
+ return true;
+}
+
+
+extern "C" const size_t TCPSocket__ptrOffset = JSTCPSocket::offsetOfWrapped();
+
+void JSTCPSocket::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<JSTCPSocket*>(cell);
+ if (void* wrapped = thisObject->wrapped()) {
+ // if (thisObject->scriptExecutionContext())
+ // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
+ }
+ Base::analyzeHeap(cell, analyzer);
+}
+
+JSObject* JSTCPSocket::createPrototype(VM& vm, JSDOMGlobalObject* globalObject)
+{
+ return JSTCPSocketPrototype::create(vm, globalObject, JSTCPSocketPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+}
+
+template<typename Visitor>
+void JSTCPSocket::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ JSTCPSocket* thisObject = jsCast<JSTCPSocket*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+
+ visitor.append(thisObject->m_data);
+ visitor.append(thisObject->m_remoteAddress);
+}
+
+DEFINE_VISIT_CHILDREN(JSTCPSocket);extern "C" void* TLSSocketClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+JSC_DECLARE_CUSTOM_GETTER(jsTLSSocketConstructor);
+extern "C" void TLSSocketClass__finalize(void*);
+
+extern "C" JSC::EncodedJSValue TLSSocketPrototype__getData(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TLSSocketPrototype__dataGetterWrap);
+
+
+extern "C" bool TLSSocketPrototype__setData(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::EncodedJSValue value);
+JSC_DECLARE_CUSTOM_SETTER(TLSSocketPrototype__dataSetterWrap);
+
+
+extern "C" EncodedJSValue TLSSocketPrototype__end(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TLSSocketPrototype__endCallback);
+
+
+extern "C" EncodedJSValue TLSSocketPrototype__flush(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TLSSocketPrototype__flushCallback);
+
+
+extern "C" JSC::EncodedJSValue TLSSocketPrototype__getListener(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TLSSocketPrototype__listenerGetterWrap);
+
+
+extern "C" JSC::EncodedJSValue TLSSocketPrototype__getLocalPort(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TLSSocketPrototype__localPortGetterWrap);
+
+
+extern "C" JSC::EncodedJSValue TLSSocketPrototype__getReadyState(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TLSSocketPrototype__readyStateGetterWrap);
+
+
+extern "C" EncodedJSValue TLSSocketPrototype__ref(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TLSSocketPrototype__refCallback);
+
+
+extern "C" EncodedJSValue TLSSocketPrototype__reload(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TLSSocketPrototype__reloadCallback);
+
+
+extern "C" JSC::EncodedJSValue TLSSocketPrototype__getRemoteAddress(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(TLSSocketPrototype__remoteAddressGetterWrap);
+
+
+extern "C" EncodedJSValue TLSSocketPrototype__shutdown(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TLSSocketPrototype__shutdownCallback);
+
+
+extern "C" EncodedJSValue TLSSocketPrototype__timeout(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TLSSocketPrototype__timeoutCallback);
+
+
+extern "C" EncodedJSValue TLSSocketPrototype__unref(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TLSSocketPrototype__unrefCallback);
+
+
+extern "C" EncodedJSValue TLSSocketPrototype__write(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(TLSSocketPrototype__writeCallback);
+
+
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSTLSSocketPrototype, JSTLSSocketPrototype::Base);
+
+
+ static const HashTableValue JSTLSSocketPrototypeTableValues[] = {
+{ "data"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TLSSocketPrototype__dataGetterWrap, TLSSocketPrototype__dataSetterWrap } } ,
+{ "end"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TLSSocketPrototype__endCallback, 3 } } ,
+{ "flush"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TLSSocketPrototype__flushCallback, 0 } } ,
+{ "listener"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TLSSocketPrototype__listenerGetterWrap, 0 } } ,
+{ "localPort"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TLSSocketPrototype__localPortGetterWrap, 0 } } ,
+{ "readyState"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TLSSocketPrototype__readyStateGetterWrap, 0 } } ,
+{ "ref"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TLSSocketPrototype__refCallback, 0 } } ,
+{ "reload"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TLSSocketPrototype__reloadCallback, 1 } } ,
+{ "remoteAddress"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, TLSSocketPrototype__remoteAddressGetterWrap, 0 } } ,
+{ "shutdown"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TLSSocketPrototype__shutdownCallback, 1 } } ,
+{ "timeout"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TLSSocketPrototype__timeoutCallback, 1 } } ,
+{ "unref"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TLSSocketPrototype__unrefCallback, 0 } } ,
+{ "write"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, TLSSocketPrototype__writeCallback, 3 } }
+ };
+
+
+
+const ClassInfo JSTLSSocketPrototype::s_info = { "TLSSocket"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTLSSocketPrototype) };
+
+
+
+JSC_DEFINE_CUSTOM_GETTER(jsTLSSocketConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto* prototype = jsDynamicCast<JSTLSSocketPrototype*>(JSValue::decode(thisValue));
+
+ if (UNLIKELY(!prototype))
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ return JSValue::encode(globalObject->JSTLSSocketConstructor());
+}
+
+
+
+JSC_DEFINE_CUSTOM_GETTER(TLSSocketPrototype__dataGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTLSSocket* thisObject = jsCast<JSTLSSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_data.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ TLSSocketPrototype__getData(thisObject->wrapped(), globalObject)
+ );
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_data.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+extern "C" void TLSSocketPrototype__dataSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSTLSSocket*>(JSValue::decode(thisValue));
+ thisObject->m_data.set(vm, thisObject, JSValue::decode(value));
+}
+
+
+JSC_DEFINE_CUSTOM_SETTER(TLSSocketPrototype__dataSetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTLSSocket* thisObject = jsCast<JSTLSSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ auto result = TLSSocketPrototype__setData(thisObject->wrapped(), lexicalGlobalObject, encodedValue);
+
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TLSSocketPrototype__endCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTLSSocket* thisObject = jsDynamicCast<JSTLSSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TLSSocketPrototype__end(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TLSSocketPrototype__flushCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTLSSocket* thisObject = jsDynamicCast<JSTLSSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TLSSocketPrototype__flush(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(TLSSocketPrototype__listenerGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTLSSocket* thisObject = jsCast<JSTLSSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = TLSSocketPrototype__getListener(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(TLSSocketPrototype__localPortGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTLSSocket* thisObject = jsCast<JSTLSSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = TLSSocketPrototype__getLocalPort(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(TLSSocketPrototype__readyStateGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTLSSocket* thisObject = jsCast<JSTLSSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = TLSSocketPrototype__getReadyState(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TLSSocketPrototype__refCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTLSSocket* thisObject = jsDynamicCast<JSTLSSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TLSSocketPrototype__ref(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TLSSocketPrototype__reloadCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTLSSocket* thisObject = jsDynamicCast<JSTLSSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TLSSocketPrototype__reload(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(TLSSocketPrototype__remoteAddressGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSTLSSocket* thisObject = jsCast<JSTLSSocket*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_remoteAddress.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ TLSSocketPrototype__getRemoteAddress(thisObject->wrapped(), globalObject)
+ );
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_remoteAddress.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+extern "C" void TLSSocketPrototype__remoteAddressSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSTLSSocket*>(JSValue::decode(thisValue));
+ thisObject->m_remoteAddress.set(vm, thisObject, JSValue::decode(value));
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TLSSocketPrototype__shutdownCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTLSSocket* thisObject = jsDynamicCast<JSTLSSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TLSSocketPrototype__shutdown(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TLSSocketPrototype__timeoutCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTLSSocket* thisObject = jsDynamicCast<JSTLSSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TLSSocketPrototype__timeout(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TLSSocketPrototype__unrefCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTLSSocket* thisObject = jsDynamicCast<JSTLSSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TLSSocketPrototype__unref(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(TLSSocketPrototype__writeCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSTLSSocket* thisObject = jsDynamicCast<JSTLSSocket*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return TLSSocketPrototype__write(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+void JSTLSSocketPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSTLSSocket::info(), JSTLSSocketPrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+void JSTLSSocketConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSTLSSocketPrototype* prototype)
+{
+ Base::finishCreation(vm, 0, "TLSSocket"_s, PropertyAdditionMode::WithoutStructureTransition);
+
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+ ASSERT(inherits(info()));
+}
+
+JSTLSSocketConstructor* JSTLSSocketConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSTLSSocketPrototype* prototype) {
+ JSTLSSocketConstructor* ptr = new (NotNull, JSC::allocateCell<JSTLSSocketConstructor>(vm)) JSTLSSocketConstructor(vm, structure, construct);
+ ptr->finishCreation(vm, globalObject, prototype);
+ return ptr;
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSTLSSocketConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
+{
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ JSC::VM &vm = globalObject->vm();
+ JSObject* newTarget = asObject(callFrame->newTarget());
+ auto* constructor = globalObject->JSTLSSocketConstructor();
+ Structure* structure = globalObject->JSTLSSocketStructure();
+ if (constructor != newTarget) {
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* functionGlobalObject = reinterpret_cast<Zig::GlobalObject*>(
+ // ShadowRealm functions belong to a different global object.
+ getFunctionRealm(globalObject, newTarget)
+ );
+ RETURN_IF_EXCEPTION(scope, {});
+ structure = InternalFunction::createSubclassStructure(
+ globalObject,
+ newTarget,
+ functionGlobalObject->JSTLSSocketStructure()
+ );
+ }
+
+ void* ptr = TLSSocketClass__construct(globalObject, callFrame);
+
+ if (UNLIKELY(!ptr)) {
+ return JSValue::encode(JSC::jsUndefined());
+ }
+
+ JSTLSSocket* instance = JSTLSSocket::create(vm, globalObject, structure, ptr);
+
+
+ return JSValue::encode(instance);
+}
+
+extern "C" EncodedJSValue TLSSocket__create(Zig::GlobalObject* globalObject, void* ptr) {
+ auto &vm = globalObject->vm();
+ JSC::Structure* structure = globalObject->JSTLSSocketStructure();
+ JSTLSSocket* instance = JSTLSSocket::create(vm, globalObject, structure, ptr);
+
+ return JSValue::encode(instance);
+}
+
+void JSTLSSocketConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSTLSSocketPrototype* prototype)
+{
+
+}
+
+const ClassInfo JSTLSSocketConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTLSSocketConstructor) };
+
+
+ extern "C" EncodedJSValue TLSSocket__getConstructor(Zig::GlobalObject* globalObject) {
+ return JSValue::encode(globalObject->JSTLSSocketConstructor());
+ }
+
+JSTLSSocket::~JSTLSSocket()
+{
+ if (m_ctx) {
+ TLSSocketClass__finalize(m_ctx);
+ }
+}
+void JSTLSSocket::destroy(JSCell* cell)
+{
+ static_cast<JSTLSSocket*>(cell)->JSTLSSocket::~JSTLSSocket();
+}
+
+const ClassInfo JSTLSSocket::s_info = { "TLSSocket"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSTLSSocket) };
+
+void JSTLSSocket::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+JSTLSSocket* JSTLSSocket::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx) {
+ JSTLSSocket* ptr = new (NotNull, JSC::allocateCell<JSTLSSocket>(vm)) JSTLSSocket(vm, structure, ctx);
+ ptr->finishCreation(vm);
+ return ptr;
+}
+
+extern "C" void* TLSSocket__fromJS(JSC::EncodedJSValue value) {
+ JSC::JSValue decodedValue = JSC::JSValue::decode(value);
+ if (!decodedValue || decodedValue.isUndefinedOrNull())
+ return nullptr;
+
+ JSTLSSocket* object = JSC::jsDynamicCast<JSTLSSocket*>(decodedValue);
+
+ if (!object)
+ return nullptr;
+
+ return object->wrapped();
+}
+
+extern "C" bool TLSSocket__dangerouslySetPtr(JSC::EncodedJSValue value, void* ptr) {
+ JSTLSSocket* object = JSC::jsDynamicCast<JSTLSSocket*>(JSValue::decode(value));
+ if (!object)
+ return false;
+
+ object->m_ctx = ptr;
+ return true;
+}
+
+
+extern "C" const size_t TLSSocket__ptrOffset = JSTLSSocket::offsetOfWrapped();
+
+void JSTLSSocket::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<JSTLSSocket*>(cell);
+ if (void* wrapped = thisObject->wrapped()) {
+ // if (thisObject->scriptExecutionContext())
+ // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
+ }
+ Base::analyzeHeap(cell, analyzer);
+}
+
+JSObject* JSTLSSocket::createPrototype(VM& vm, JSDOMGlobalObject* globalObject)
+{
+ return JSTLSSocketPrototype::create(vm, globalObject, JSTLSSocketPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+}
+
+template<typename Visitor>
+void JSTLSSocket::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ JSTLSSocket* thisObject = jsCast<JSTLSSocket*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+
+ visitor.append(thisObject->m_data);
+ visitor.append(thisObject->m_remoteAddress);
+}
+
+DEFINE_VISIT_CHILDREN(JSTLSSocket);extern "C" void* ListenerClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+JSC_DECLARE_CUSTOM_GETTER(jsListenerConstructor);
+extern "C" void ListenerClass__finalize(void*);
+
+extern "C" JSC::EncodedJSValue ListenerPrototype__getData(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(ListenerPrototype__dataGetterWrap);
+
+
+extern "C" bool ListenerPrototype__setData(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::EncodedJSValue value);
+JSC_DECLARE_CUSTOM_SETTER(ListenerPrototype__dataSetterWrap);
+
+
+extern "C" JSC::EncodedJSValue ListenerPrototype__getHostname(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(ListenerPrototype__hostnameGetterWrap);
+
+
+extern "C" JSC::EncodedJSValue ListenerPrototype__getPort(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(ListenerPrototype__portGetterWrap);
+
+
+extern "C" EncodedJSValue ListenerPrototype__ref(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ListenerPrototype__refCallback);
+
+
+extern "C" EncodedJSValue ListenerPrototype__reload(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ListenerPrototype__reloadCallback);
+
+
+extern "C" EncodedJSValue ListenerPrototype__stop(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ListenerPrototype__stopCallback);
+
+
+extern "C" JSC::EncodedJSValue ListenerPrototype__getUnix(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
+JSC_DECLARE_CUSTOM_GETTER(ListenerPrototype__unixGetterWrap);
+
+
+extern "C" EncodedJSValue ListenerPrototype__unref(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(ListenerPrototype__unrefCallback);
+
+
+STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSListenerPrototype, JSListenerPrototype::Base);
+
+
+ static const HashTableValue JSListenerPrototypeTableValues[] = {
+{ "data"_s, static_cast<unsigned>(JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ListenerPrototype__dataGetterWrap, ListenerPrototype__dataSetterWrap } } ,
+{ "hostname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ListenerPrototype__hostnameGetterWrap, 0 } } ,
+{ "port"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ListenerPrototype__portGetterWrap, 0 } } ,
+{ "ref"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ListenerPrototype__refCallback, 0 } } ,
+{ "reload"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ListenerPrototype__reloadCallback, 1 } } ,
+{ "stop"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ListenerPrototype__stopCallback, 1 } } ,
+{ "unix"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, ListenerPrototype__unixGetterWrap, 0 } } ,
+{ "unref"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, ListenerPrototype__unrefCallback, 0 } }
+ };
+
+
+
+const ClassInfo JSListenerPrototype::s_info = { "Listener"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSListenerPrototype) };
+
+
+
+JSC_DEFINE_CUSTOM_GETTER(jsListenerConstructor, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName))
+{
+ VM& vm = JSC::getVM(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ auto* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto* prototype = jsDynamicCast<JSListenerPrototype*>(JSValue::decode(thisValue));
+
+ if (UNLIKELY(!prototype))
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ return JSValue::encode(globalObject->JSListenerConstructor());
+}
+
+
+
+JSC_DEFINE_CUSTOM_GETTER(ListenerPrototype__dataGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSListener* thisObject = jsCast<JSListener*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = ListenerPrototype__getData(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_CUSTOM_SETTER(ListenerPrototype__dataSetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSListener* thisObject = jsCast<JSListener*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ auto result = ListenerPrototype__setData(thisObject->wrapped(), lexicalGlobalObject, encodedValue);
+
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(ListenerPrototype__hostnameGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSListener* thisObject = jsCast<JSListener*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_hostname.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ ListenerPrototype__getHostname(thisObject->wrapped(), globalObject)
+ );
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_hostname.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+extern "C" void ListenerPrototype__hostnameSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSListener*>(JSValue::decode(thisValue));
+ thisObject->m_hostname.set(vm, thisObject, JSValue::decode(value));
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(ListenerPrototype__portGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSListener* thisObject = jsCast<JSListener*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+ JSC::EncodedJSValue result = ListenerPrototype__getPort(thisObject->wrapped(), globalObject);
+ RETURN_IF_EXCEPTION(throwScope, {});
+ RELEASE_AND_RETURN(throwScope, result);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ListenerPrototype__refCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSListener* thisObject = jsDynamicCast<JSListener*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ListenerPrototype__ref(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ListenerPrototype__reloadCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSListener* thisObject = jsDynamicCast<JSListener*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ListenerPrototype__reload(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ListenerPrototype__stopCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSListener* thisObject = jsDynamicCast<JSListener*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ListenerPrototype__stop(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+JSC_DEFINE_CUSTOM_GETTER(ListenerPrototype__unixGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
+{
+ auto& vm = lexicalGlobalObject->vm();
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSListener* thisObject = jsCast<JSListener*>(JSValue::decode(thisValue));
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ if (JSValue cachedValue = thisObject->m_unix.get())
+ return JSValue::encode(cachedValue);
+
+ JSC::JSValue result = JSC::JSValue::decode(
+ ListenerPrototype__getUnix(thisObject->wrapped(), globalObject)
+ );
+ RETURN_IF_EXCEPTION(throwScope, {});
+ thisObject->m_unix.set(vm, thisObject, result);
+ RELEASE_AND_RETURN(throwScope, JSValue::encode(result));
+}
+extern "C" void ListenerPrototype__unixSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject *globalObject, JSC::EncodedJSValue value)
+{
+ auto& vm = globalObject->vm();
+ auto* thisObject = jsCast<JSListener*>(JSValue::decode(thisValue));
+ thisObject->m_unix.set(vm, thisObject, JSValue::decode(value));
+}
+
+
+JSC_DEFINE_HOST_FUNCTION(ListenerPrototype__unrefCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSListener* thisObject = jsDynamicCast<JSListener*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ return throwVMTypeError(lexicalGlobalObject, throwScope);
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+ return ListenerPrototype__unref(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
+
+void JSListenerPrototype::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
+{
+ Base::finishCreation(vm);
+ reifyStaticProperties(vm, JSListener::info(), JSListenerPrototypeTableValues, *this);
+ JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
+}
+
+void JSListenerConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSListenerPrototype* prototype)
+{
+ Base::finishCreation(vm, 0, "Listener"_s, PropertyAdditionMode::WithoutStructureTransition);
+
+ putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
+ ASSERT(inherits(info()));
+}
+
+JSListenerConstructor* JSListenerConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSListenerPrototype* prototype) {
+ JSListenerConstructor* ptr = new (NotNull, JSC::allocateCell<JSListenerConstructor>(vm)) JSListenerConstructor(vm, structure, construct);
+ ptr->finishCreation(vm, globalObject, prototype);
+ return ptr;
+}
+
+JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES JSListenerConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
+{
+ Zig::GlobalObject *globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
+ JSC::VM &vm = globalObject->vm();
+ JSObject* newTarget = asObject(callFrame->newTarget());
+ auto* constructor = globalObject->JSListenerConstructor();
+ Structure* structure = globalObject->JSListenerStructure();
+ if (constructor != newTarget) {
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ auto* functionGlobalObject = reinterpret_cast<Zig::GlobalObject*>(
+ // ShadowRealm functions belong to a different global object.
+ getFunctionRealm(globalObject, newTarget)
+ );
+ RETURN_IF_EXCEPTION(scope, {});
+ structure = InternalFunction::createSubclassStructure(
+ globalObject,
+ newTarget,
+ functionGlobalObject->JSListenerStructure()
+ );
+ }
+
+ void* ptr = ListenerClass__construct(globalObject, callFrame);
+
+ if (UNLIKELY(!ptr)) {
+ return JSValue::encode(JSC::jsUndefined());
+ }
+
+ JSListener* instance = JSListener::create(vm, globalObject, structure, ptr);
+
+
+ return JSValue::encode(instance);
+}
+
+extern "C" EncodedJSValue Listener__create(Zig::GlobalObject* globalObject, void* ptr) {
+ auto &vm = globalObject->vm();
+ JSC::Structure* structure = globalObject->JSListenerStructure();
+ JSListener* instance = JSListener::create(vm, globalObject, structure, ptr);
+
+ return JSValue::encode(instance);
+}
+
+void JSListenerConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSListenerPrototype* prototype)
+{
+
+}
+
+const ClassInfo JSListenerConstructor::s_info = { "Function"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSListenerConstructor) };
+
+
+ extern "C" EncodedJSValue Listener__getConstructor(Zig::GlobalObject* globalObject) {
+ return JSValue::encode(globalObject->JSListenerConstructor());
+ }
+
+JSListener::~JSListener()
+{
+ if (m_ctx) {
+ ListenerClass__finalize(m_ctx);
+ }
+}
+void JSListener::destroy(JSCell* cell)
+{
+ static_cast<JSListener*>(cell)->JSListener::~JSListener();
+}
+
+const ClassInfo JSListener::s_info = { "Listener"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSListener) };
+
+void JSListener::finishCreation(VM& vm)
+{
+ Base::finishCreation(vm);
+ ASSERT(inherits(info()));
+}
+
+JSListener* JSListener::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx) {
+ JSListener* ptr = new (NotNull, JSC::allocateCell<JSListener>(vm)) JSListener(vm, structure, ctx);
+ ptr->finishCreation(vm);
+ return ptr;
+}
+
+extern "C" void* Listener__fromJS(JSC::EncodedJSValue value) {
+ JSC::JSValue decodedValue = JSC::JSValue::decode(value);
+ if (!decodedValue || decodedValue.isUndefinedOrNull())
+ return nullptr;
+
+ JSListener* object = JSC::jsDynamicCast<JSListener*>(decodedValue);
+
+ if (!object)
+ return nullptr;
+
+ return object->wrapped();
+}
+
+extern "C" bool Listener__dangerouslySetPtr(JSC::EncodedJSValue value, void* ptr) {
+ JSListener* object = JSC::jsDynamicCast<JSListener*>(JSValue::decode(value));
+ if (!object)
+ return false;
+
+ object->m_ctx = ptr;
+ return true;
+}
+
+
+extern "C" const size_t Listener__ptrOffset = JSListener::offsetOfWrapped();
+
+void JSListener::analyzeHeap(JSCell* cell, HeapAnalyzer& analyzer)
+{
+ auto* thisObject = jsCast<JSListener*>(cell);
+ if (void* wrapped = thisObject->wrapped()) {
+ // if (thisObject->scriptExecutionContext())
+ // analyzer.setLabelForCell(cell, "url " + thisObject->scriptExecutionContext()->url().string());
+ }
+ Base::analyzeHeap(cell, analyzer);
+}
+
+JSObject* JSListener::createPrototype(VM& vm, JSDOMGlobalObject* globalObject)
+{
+ return JSListenerPrototype::create(vm, globalObject, JSListenerPrototype::createStructure(vm, globalObject, globalObject->objectPrototype()));
+}
+
+template<typename Visitor>
+void JSListener::visitChildrenImpl(JSCell* cell, Visitor& visitor)
+{
+ JSListener* thisObject = jsCast<JSListener*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, info());
+ Base::visitChildren(thisObject, visitor);
+
+
+ visitor.append(thisObject->m_hostname);
+ visitor.append(thisObject->m_unix);
+}
+
+DEFINE_VISIT_CHILDREN(JSListener);extern "C" void* SubprocessClass__construct(JSC::JSGlobalObject*, JSC::CallFrame*);
JSC_DECLARE_CUSTOM_GETTER(jsSubprocessConstructor);
extern "C" void SubprocessClass__finalize(void*);
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h
index 45e47f81a..c344437cc 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.h
+++ b/src/bun.js/bindings/ZigGeneratedClasses.h
@@ -15,6 +15,381 @@ namespace WebCore {
using namespace Zig;
using namespace JSC;
+class JSTCPSocket final : public JSC::JSDestructibleObject {
+ public:
+ using Base = JSC::JSDestructibleObject;
+ static JSTCPSocket* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx);
+
+ DECLARE_EXPORT_INFO;
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<JSTCPSocket, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForTCPSocket.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForTCPSocket = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForTCPSocket.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForTCPSocket = WTFMove(space); });
+ }
+
+ static void destroy(JSC::JSCell*);
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(static_cast<JSC::JSType>(0b11101110), StructureFlags), info());
+ }
+
+ static JSObject* createPrototype(VM& vm, JSDOMGlobalObject* globalObject);
+
+ ~JSTCPSocket();
+
+ void* wrapped() const { return m_ctx; }
+
+ void detach()
+ {
+ m_ctx = nullptr;
+ }
+
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+ static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSTCPSocket, m_ctx); }
+
+ void* m_ctx { nullptr };
+
+
+ JSTCPSocket(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
+ : Base(vm, structure)
+ {
+ m_ctx = sinkPtr;
+ }
+
+ void finishCreation(JSC::VM&);
+
+ DECLARE_VISIT_CHILDREN;
+
+ mutable JSC::WriteBarrier<JSC::Unknown> m_data;
+mutable JSC::WriteBarrier<JSC::Unknown> m_remoteAddress;
+ };
+class JSTCPSocketPrototype final : public JSC::JSNonFinalObject {
+ public:
+ using Base = JSC::JSNonFinalObject;
+
+ static JSTCPSocketPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSTCPSocketPrototype* ptr = new (NotNull, JSC::allocateCell<JSTCPSocketPrototype>(vm)) JSTCPSocketPrototype(vm, globalObject, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ private:
+ JSTCPSocketPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+ };
+
+ class JSTCPSocketConstructor final : public JSC::InternalFunction {
+ public:
+ using Base = JSC::InternalFunction;
+ static JSTCPSocketConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSTCPSocketPrototype* prototype);
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+ static constexpr bool needsDestruction = false;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
+ }
+
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<JSTCPSocketConstructor, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForTCPSocketConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForTCPSocketConstructor = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForTCPSocketConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForTCPSocketConstructor = WTFMove(space); });
+ }
+
+
+ void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSTCPSocketPrototype* prototype);
+
+ // Must be defined for each specialization class.
+ static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+ DECLARE_EXPORT_INFO;
+ private:
+ JSTCPSocketConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
+ : Base(vm, structure, nativeFunction, nativeFunction)
+
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSTCPSocketPrototype* prototype);
+ };
+class JSTLSSocket final : public JSC::JSDestructibleObject {
+ public:
+ using Base = JSC::JSDestructibleObject;
+ static JSTLSSocket* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx);
+
+ DECLARE_EXPORT_INFO;
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<JSTLSSocket, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForTLSSocket.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForTLSSocket = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForTLSSocket.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForTLSSocket = WTFMove(space); });
+ }
+
+ static void destroy(JSC::JSCell*);
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(static_cast<JSC::JSType>(0b11101110), StructureFlags), info());
+ }
+
+ static JSObject* createPrototype(VM& vm, JSDOMGlobalObject* globalObject);
+
+ ~JSTLSSocket();
+
+ void* wrapped() const { return m_ctx; }
+
+ void detach()
+ {
+ m_ctx = nullptr;
+ }
+
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+ static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSTLSSocket, m_ctx); }
+
+ void* m_ctx { nullptr };
+
+
+ JSTLSSocket(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
+ : Base(vm, structure)
+ {
+ m_ctx = sinkPtr;
+ }
+
+ void finishCreation(JSC::VM&);
+
+ DECLARE_VISIT_CHILDREN;
+
+ mutable JSC::WriteBarrier<JSC::Unknown> m_data;
+mutable JSC::WriteBarrier<JSC::Unknown> m_remoteAddress;
+ };
+class JSTLSSocketPrototype final : public JSC::JSNonFinalObject {
+ public:
+ using Base = JSC::JSNonFinalObject;
+
+ static JSTLSSocketPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSTLSSocketPrototype* ptr = new (NotNull, JSC::allocateCell<JSTLSSocketPrototype>(vm)) JSTLSSocketPrototype(vm, globalObject, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ private:
+ JSTLSSocketPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+ };
+
+ class JSTLSSocketConstructor final : public JSC::InternalFunction {
+ public:
+ using Base = JSC::InternalFunction;
+ static JSTLSSocketConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSTLSSocketPrototype* prototype);
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+ static constexpr bool needsDestruction = false;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
+ }
+
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<JSTLSSocketConstructor, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForTLSSocketConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForTLSSocketConstructor = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForTLSSocketConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForTLSSocketConstructor = WTFMove(space); });
+ }
+
+
+ void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSTLSSocketPrototype* prototype);
+
+ // Must be defined for each specialization class.
+ static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+ DECLARE_EXPORT_INFO;
+ private:
+ JSTLSSocketConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
+ : Base(vm, structure, nativeFunction, nativeFunction)
+
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSTLSSocketPrototype* prototype);
+ };
+class JSListener final : public JSC::JSDestructibleObject {
+ public:
+ using Base = JSC::JSDestructibleObject;
+ static JSListener* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, void* ctx);
+
+ DECLARE_EXPORT_INFO;
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<JSListener, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForListener.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForListener = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForListener.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForListener = WTFMove(space); });
+ }
+
+ static void destroy(JSC::JSCell*);
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(static_cast<JSC::JSType>(0b11101110), StructureFlags), info());
+ }
+
+ static JSObject* createPrototype(VM& vm, JSDOMGlobalObject* globalObject);
+
+ ~JSListener();
+
+ void* wrapped() const { return m_ctx; }
+
+ void detach()
+ {
+ m_ctx = nullptr;
+ }
+
+ static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&);
+ static ptrdiff_t offsetOfWrapped() { return OBJECT_OFFSETOF(JSListener, m_ctx); }
+
+ void* m_ctx { nullptr };
+
+
+ JSListener(JSC::VM& vm, JSC::Structure* structure, void* sinkPtr)
+ : Base(vm, structure)
+ {
+ m_ctx = sinkPtr;
+ }
+
+ void finishCreation(JSC::VM&);
+
+ DECLARE_VISIT_CHILDREN;
+
+ mutable JSC::WriteBarrier<JSC::Unknown> m_hostname;
+mutable JSC::WriteBarrier<JSC::Unknown> m_unix;
+ };
+class JSListenerPrototype final : public JSC::JSNonFinalObject {
+ public:
+ using Base = JSC::JSNonFinalObject;
+
+ static JSListenerPrototype* create(JSC::VM& vm, JSGlobalObject* globalObject, JSC::Structure* structure)
+ {
+ JSListenerPrototype* ptr = new (NotNull, JSC::allocateCell<JSListenerPrototype>(vm)) JSListenerPrototype(vm, globalObject, structure);
+ ptr->finishCreation(vm, globalObject);
+ return ptr;
+ }
+
+ DECLARE_INFO;
+ template<typename CellType, JSC::SubspaceAccess>
+ static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return &vm.plainObjectSpace();
+ }
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
+ }
+
+ private:
+ JSListenerPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
+ : Base(vm, structure)
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
+ };
+
+ class JSListenerConstructor final : public JSC::InternalFunction {
+ public:
+ using Base = JSC::InternalFunction;
+ static JSListenerConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSListenerPrototype* prototype);
+
+ static constexpr unsigned StructureFlags = Base::StructureFlags;
+ static constexpr bool needsDestruction = false;
+
+ static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
+ {
+ return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::InternalFunctionType, StructureFlags), info());
+ }
+
+ template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ if constexpr (mode == JSC::SubspaceAccess::Concurrently)
+ return nullptr;
+ return WebCore::subspaceForImpl<JSListenerConstructor, WebCore::UseCustomHeapCellType::No>(
+ vm,
+ [](auto& spaces) { return spaces.m_clientSubspaceForListenerConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForListenerConstructor = WTFMove(space); },
+ [](auto& spaces) { return spaces.m_subspaceForListenerConstructor.get(); },
+ [](auto& spaces, auto&& space) { spaces.m_subspaceForListenerConstructor = WTFMove(space); });
+ }
+
+
+ void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSListenerPrototype* prototype);
+
+ // Must be defined for each specialization class.
+ static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
+ DECLARE_EXPORT_INFO;
+ private:
+ JSListenerConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
+ : Base(vm, structure, nativeFunction, nativeFunction)
+
+ {
+ }
+
+ void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSListenerPrototype* prototype);
+ };
class JSSubprocess final : public JSC::JSDestructibleObject {
public:
using Base = JSC::JSDestructibleObject;
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index c19d3888b..7918e9197 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -163,8 +163,8 @@ using JSBuffer = WebCore::JSBuffer;
#include "DOMJITHelpers.h"
#include <JavaScriptCore/DFGAbstractHeap.h>
-#include "JSCryptoKey.h"
-#include "JSSubtleCrypto.h"
+#include "webcrypto/JSCryptoKey.h"
+#include "webcrypto/JSSubtleCrypto.h"
#include "OnigurumaRegExp.h"
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 6a89db7b9..6d5f87662 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -1486,7 +1486,7 @@ pub const JSPromise = extern struct {
) JSValue {
if (value.isEmpty()) {
return resolvedPromiseValue(globalObject, JSValue.jsUndefined());
- } else if (value.isEmptyOrUndefinedOrNull()) {
+ } else if (value.isEmptyOrUndefinedOrNull() or !value.isCell()) {
return resolvedPromiseValue(globalObject, value);
}
diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig
index 5cb04779a..062372efe 100644
--- a/src/bun.js/bindings/generated_classes.zig
+++ b/src/bun.js/bindings/generated_classes.zig
@@ -7,6 +7,365 @@ pub const StaticGetterType = fn (*JSC.JSGlobalObject, JSC.JSValue, JSC.JSValue)
pub const StaticSetterType = fn (*JSC.JSGlobalObject, JSC.JSValue, JSC.JSValue, JSC.JSValue) callconv(.C) bool;
pub const StaticCallbackType = fn (*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue;
+pub const JSTCPSocket = struct {
+ const TCPSocket = Classes.TCPSocket;
+ const GetterType = fn (*TCPSocket, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
+ const SetterType = fn (*TCPSocket, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool;
+ const CallbackType = fn (*TCPSocket, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue;
+
+ /// Return the pointer to the wrapped object.
+ /// If the object does not match the type, return null.
+ pub fn fromJS(value: JSC.JSValue) ?*TCPSocket {
+ JSC.markBinding(@src());
+ return TCPSocket__fromJS(value);
+ }
+
+ extern fn TCPSocketPrototype__dataSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for data on TCPSocket
+ /// This value will be visited by the garbage collector.
+ pub fn dataSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ TCPSocketPrototype__dataSetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn TCPSocketPrototype__remoteAddressSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for remoteAddress on TCPSocket
+ /// This value will be visited by the garbage collector.
+ pub fn remoteAddressSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ TCPSocketPrototype__remoteAddressSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// Get the TCPSocket constructor value.
+ /// This loads lazily from the global object.
+ pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding(@src());
+ return TCPSocket__getConstructor(globalObject);
+ }
+
+ /// Create a new instance of TCPSocket
+ pub fn toJS(this: *TCPSocket, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding(@src());
+ if (comptime Environment.allow_assert) {
+ const value__ = TCPSocket__create(globalObject, this);
+ std.debug.assert(value__.as(TCPSocket).? == this); // If this fails, likely a C ABI issue.
+ return value__;
+ } else {
+ return TCPSocket__create(globalObject, this);
+ }
+ }
+
+ /// Modify the internal ptr to point to a new instance of TCPSocket.
+ pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*TCPSocket) bool {
+ JSC.markBinding(@src());
+ return TCPSocket__dangerouslySetPtr(value, ptr);
+ }
+
+ extern fn TCPSocket__fromJS(JSC.JSValue) ?*TCPSocket;
+ extern fn TCPSocket__getConstructor(*JSC.JSGlobalObject) JSC.JSValue;
+
+ extern fn TCPSocket__create(globalObject: *JSC.JSGlobalObject, ptr: ?*TCPSocket) JSC.JSValue;
+
+ extern fn TCPSocket__dangerouslySetPtr(JSC.JSValue, ?*TCPSocket) bool;
+
+ comptime {
+ if (@TypeOf(TCPSocket.constructor) != (fn (*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*TCPSocket)) {
+ @compileLog("TCPSocket.constructor is not a constructor");
+ }
+
+ if (@TypeOf(TCPSocket.finalize) != (fn (*TCPSocket) callconv(.C) void)) {
+ @compileLog("TCPSocket.finalize is not a finalizer");
+ }
+
+ if (@TypeOf(TCPSocket.getData) != GetterType)
+ @compileLog("Expected TCPSocket.getData to be a getter");
+
+ if (@TypeOf(TCPSocket.setData) != SetterType)
+ @compileLog("Expected TCPSocket.setData to be a setter");
+ if (@TypeOf(TCPSocket.end) != CallbackType)
+ @compileLog("Expected TCPSocket.end to be a callback");
+ if (@TypeOf(TCPSocket.flush) != CallbackType)
+ @compileLog("Expected TCPSocket.flush to be a callback");
+ if (@TypeOf(TCPSocket.getListener) != GetterType)
+ @compileLog("Expected TCPSocket.getListener to be a getter");
+
+ if (@TypeOf(TCPSocket.getLocalPort) != GetterType)
+ @compileLog("Expected TCPSocket.getLocalPort to be a getter");
+
+ if (@TypeOf(TCPSocket.getReadyState) != GetterType)
+ @compileLog("Expected TCPSocket.getReadyState to be a getter");
+
+ if (@TypeOf(TCPSocket.ref) != CallbackType)
+ @compileLog("Expected TCPSocket.ref to be a callback");
+ if (@TypeOf(TCPSocket.reload) != CallbackType)
+ @compileLog("Expected TCPSocket.reload to be a callback");
+ if (@TypeOf(TCPSocket.getRemoteAddress) != GetterType)
+ @compileLog("Expected TCPSocket.getRemoteAddress to be a getter");
+
+ if (@TypeOf(TCPSocket.shutdown) != CallbackType)
+ @compileLog("Expected TCPSocket.shutdown to be a callback");
+ if (@TypeOf(TCPSocket.timeout) != CallbackType)
+ @compileLog("Expected TCPSocket.timeout to be a callback");
+ if (@TypeOf(TCPSocket.unref) != CallbackType)
+ @compileLog("Expected TCPSocket.unref to be a callback");
+ if (@TypeOf(TCPSocket.write) != CallbackType)
+ @compileLog("Expected TCPSocket.write to be a callback");
+ if (!JSC.is_bindgen) {
+ @export(TCPSocket.constructor, .{ .name = "TCPSocketClass__construct" });
+ @export(TCPSocket.end, .{ .name = "TCPSocketPrototype__end" });
+ @export(TCPSocket.finalize, .{ .name = "TCPSocketClass__finalize" });
+ @export(TCPSocket.flush, .{ .name = "TCPSocketPrototype__flush" });
+ @export(TCPSocket.getData, .{ .name = "TCPSocketPrototype__getData" });
+ @export(TCPSocket.getListener, .{ .name = "TCPSocketPrototype__getListener" });
+ @export(TCPSocket.getLocalPort, .{ .name = "TCPSocketPrototype__getLocalPort" });
+ @export(TCPSocket.getReadyState, .{ .name = "TCPSocketPrototype__getReadyState" });
+ @export(TCPSocket.getRemoteAddress, .{ .name = "TCPSocketPrototype__getRemoteAddress" });
+ @export(TCPSocket.ref, .{ .name = "TCPSocketPrototype__ref" });
+ @export(TCPSocket.reload, .{ .name = "TCPSocketPrototype__reload" });
+ @export(TCPSocket.setData, .{ .name = "TCPSocketPrototype__setData" });
+ @export(TCPSocket.shutdown, .{ .name = "TCPSocketPrototype__shutdown" });
+ @export(TCPSocket.timeout, .{ .name = "TCPSocketPrototype__timeout" });
+ @export(TCPSocket.unref, .{ .name = "TCPSocketPrototype__unref" });
+ @export(TCPSocket.write, .{ .name = "TCPSocketPrototype__write" });
+ }
+ }
+};
+pub const JSTLSSocket = struct {
+ const TLSSocket = Classes.TLSSocket;
+ const GetterType = fn (*TLSSocket, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
+ const SetterType = fn (*TLSSocket, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool;
+ const CallbackType = fn (*TLSSocket, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue;
+
+ /// Return the pointer to the wrapped object.
+ /// If the object does not match the type, return null.
+ pub fn fromJS(value: JSC.JSValue) ?*TLSSocket {
+ JSC.markBinding(@src());
+ return TLSSocket__fromJS(value);
+ }
+
+ extern fn TLSSocketPrototype__dataSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for data on TLSSocket
+ /// This value will be visited by the garbage collector.
+ pub fn dataSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ TLSSocketPrototype__dataSetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn TLSSocketPrototype__remoteAddressSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for remoteAddress on TLSSocket
+ /// This value will be visited by the garbage collector.
+ pub fn remoteAddressSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ TLSSocketPrototype__remoteAddressSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// Get the TLSSocket constructor value.
+ /// This loads lazily from the global object.
+ pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding(@src());
+ return TLSSocket__getConstructor(globalObject);
+ }
+
+ /// Create a new instance of TLSSocket
+ pub fn toJS(this: *TLSSocket, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding(@src());
+ if (comptime Environment.allow_assert) {
+ const value__ = TLSSocket__create(globalObject, this);
+ std.debug.assert(value__.as(TLSSocket).? == this); // If this fails, likely a C ABI issue.
+ return value__;
+ } else {
+ return TLSSocket__create(globalObject, this);
+ }
+ }
+
+ /// Modify the internal ptr to point to a new instance of TLSSocket.
+ pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*TLSSocket) bool {
+ JSC.markBinding(@src());
+ return TLSSocket__dangerouslySetPtr(value, ptr);
+ }
+
+ extern fn TLSSocket__fromJS(JSC.JSValue) ?*TLSSocket;
+ extern fn TLSSocket__getConstructor(*JSC.JSGlobalObject) JSC.JSValue;
+
+ extern fn TLSSocket__create(globalObject: *JSC.JSGlobalObject, ptr: ?*TLSSocket) JSC.JSValue;
+
+ extern fn TLSSocket__dangerouslySetPtr(JSC.JSValue, ?*TLSSocket) bool;
+
+ comptime {
+ if (@TypeOf(TLSSocket.constructor) != (fn (*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*TLSSocket)) {
+ @compileLog("TLSSocket.constructor is not a constructor");
+ }
+
+ if (@TypeOf(TLSSocket.finalize) != (fn (*TLSSocket) callconv(.C) void)) {
+ @compileLog("TLSSocket.finalize is not a finalizer");
+ }
+
+ if (@TypeOf(TLSSocket.getData) != GetterType)
+ @compileLog("Expected TLSSocket.getData to be a getter");
+
+ if (@TypeOf(TLSSocket.setData) != SetterType)
+ @compileLog("Expected TLSSocket.setData to be a setter");
+ if (@TypeOf(TLSSocket.end) != CallbackType)
+ @compileLog("Expected TLSSocket.end to be a callback");
+ if (@TypeOf(TLSSocket.flush) != CallbackType)
+ @compileLog("Expected TLSSocket.flush to be a callback");
+ if (@TypeOf(TLSSocket.getListener) != GetterType)
+ @compileLog("Expected TLSSocket.getListener to be a getter");
+
+ if (@TypeOf(TLSSocket.getLocalPort) != GetterType)
+ @compileLog("Expected TLSSocket.getLocalPort to be a getter");
+
+ if (@TypeOf(TLSSocket.getReadyState) != GetterType)
+ @compileLog("Expected TLSSocket.getReadyState to be a getter");
+
+ if (@TypeOf(TLSSocket.ref) != CallbackType)
+ @compileLog("Expected TLSSocket.ref to be a callback");
+ if (@TypeOf(TLSSocket.reload) != CallbackType)
+ @compileLog("Expected TLSSocket.reload to be a callback");
+ if (@TypeOf(TLSSocket.getRemoteAddress) != GetterType)
+ @compileLog("Expected TLSSocket.getRemoteAddress to be a getter");
+
+ if (@TypeOf(TLSSocket.shutdown) != CallbackType)
+ @compileLog("Expected TLSSocket.shutdown to be a callback");
+ if (@TypeOf(TLSSocket.timeout) != CallbackType)
+ @compileLog("Expected TLSSocket.timeout to be a callback");
+ if (@TypeOf(TLSSocket.unref) != CallbackType)
+ @compileLog("Expected TLSSocket.unref to be a callback");
+ if (@TypeOf(TLSSocket.write) != CallbackType)
+ @compileLog("Expected TLSSocket.write to be a callback");
+ if (!JSC.is_bindgen) {
+ @export(TLSSocket.constructor, .{ .name = "TLSSocketClass__construct" });
+ @export(TLSSocket.end, .{ .name = "TLSSocketPrototype__end" });
+ @export(TLSSocket.finalize, .{ .name = "TLSSocketClass__finalize" });
+ @export(TLSSocket.flush, .{ .name = "TLSSocketPrototype__flush" });
+ @export(TLSSocket.getData, .{ .name = "TLSSocketPrototype__getData" });
+ @export(TLSSocket.getListener, .{ .name = "TLSSocketPrototype__getListener" });
+ @export(TLSSocket.getLocalPort, .{ .name = "TLSSocketPrototype__getLocalPort" });
+ @export(TLSSocket.getReadyState, .{ .name = "TLSSocketPrototype__getReadyState" });
+ @export(TLSSocket.getRemoteAddress, .{ .name = "TLSSocketPrototype__getRemoteAddress" });
+ @export(TLSSocket.ref, .{ .name = "TLSSocketPrototype__ref" });
+ @export(TLSSocket.reload, .{ .name = "TLSSocketPrototype__reload" });
+ @export(TLSSocket.setData, .{ .name = "TLSSocketPrototype__setData" });
+ @export(TLSSocket.shutdown, .{ .name = "TLSSocketPrototype__shutdown" });
+ @export(TLSSocket.timeout, .{ .name = "TLSSocketPrototype__timeout" });
+ @export(TLSSocket.unref, .{ .name = "TLSSocketPrototype__unref" });
+ @export(TLSSocket.write, .{ .name = "TLSSocketPrototype__write" });
+ }
+ }
+};
+pub const JSListener = struct {
+ const Listener = Classes.Listener;
+ const GetterType = fn (*Listener, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
+ const SetterType = fn (*Listener, *JSC.JSGlobalObject, JSC.JSValue) callconv(.C) bool;
+ const CallbackType = fn (*Listener, *JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) JSC.JSValue;
+
+ /// Return the pointer to the wrapped object.
+ /// If the object does not match the type, return null.
+ pub fn fromJS(value: JSC.JSValue) ?*Listener {
+ JSC.markBinding(@src());
+ return Listener__fromJS(value);
+ }
+
+ extern fn ListenerPrototype__hostnameSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for hostname on Listener
+ /// This value will be visited by the garbage collector.
+ pub fn hostnameSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ ListenerPrototype__hostnameSetCachedValue(thisValue, globalObject, value);
+ }
+
+ extern fn ListenerPrototype__unixSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void;
+
+ /// Set the cached value for unix on Listener
+ /// This value will be visited by the garbage collector.
+ pub fn unixSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void {
+ JSC.markBinding(@src());
+ ListenerPrototype__unixSetCachedValue(thisValue, globalObject, value);
+ }
+
+ /// Get the Listener constructor value.
+ /// This loads lazily from the global object.
+ pub fn getConstructor(globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding(@src());
+ return Listener__getConstructor(globalObject);
+ }
+
+ /// Create a new instance of Listener
+ pub fn toJS(this: *Listener, globalObject: *JSC.JSGlobalObject) JSC.JSValue {
+ JSC.markBinding(@src());
+ if (comptime Environment.allow_assert) {
+ const value__ = Listener__create(globalObject, this);
+ std.debug.assert(value__.as(Listener).? == this); // If this fails, likely a C ABI issue.
+ return value__;
+ } else {
+ return Listener__create(globalObject, this);
+ }
+ }
+
+ /// Modify the internal ptr to point to a new instance of Listener.
+ pub fn dangerouslySetPtr(value: JSC.JSValue, ptr: ?*Listener) bool {
+ JSC.markBinding(@src());
+ return Listener__dangerouslySetPtr(value, ptr);
+ }
+
+ extern fn Listener__fromJS(JSC.JSValue) ?*Listener;
+ extern fn Listener__getConstructor(*JSC.JSGlobalObject) JSC.JSValue;
+
+ extern fn Listener__create(globalObject: *JSC.JSGlobalObject, ptr: ?*Listener) JSC.JSValue;
+
+ extern fn Listener__dangerouslySetPtr(JSC.JSValue, ?*Listener) bool;
+
+ comptime {
+ if (@TypeOf(Listener.constructor) != (fn (*JSC.JSGlobalObject, *JSC.CallFrame) callconv(.C) ?*Listener)) {
+ @compileLog("Listener.constructor is not a constructor");
+ }
+
+ if (@TypeOf(Listener.finalize) != (fn (*Listener) callconv(.C) void)) {
+ @compileLog("Listener.finalize is not a finalizer");
+ }
+
+ if (@TypeOf(Listener.getData) != GetterType)
+ @compileLog("Expected Listener.getData to be a getter");
+
+ if (@TypeOf(Listener.setData) != SetterType)
+ @compileLog("Expected Listener.setData to be a setter");
+ if (@TypeOf(Listener.getHostname) != GetterType)
+ @compileLog("Expected Listener.getHostname to be a getter");
+
+ if (@TypeOf(Listener.getPort) != GetterType)
+ @compileLog("Expected Listener.getPort to be a getter");
+
+ if (@TypeOf(Listener.ref) != CallbackType)
+ @compileLog("Expected Listener.ref to be a callback");
+ if (@TypeOf(Listener.reload) != CallbackType)
+ @compileLog("Expected Listener.reload to be a callback");
+ if (@TypeOf(Listener.stop) != CallbackType)
+ @compileLog("Expected Listener.stop to be a callback");
+ if (@TypeOf(Listener.getUnix) != GetterType)
+ @compileLog("Expected Listener.getUnix to be a getter");
+
+ if (@TypeOf(Listener.unref) != CallbackType)
+ @compileLog("Expected Listener.unref to be a callback");
+ if (!JSC.is_bindgen) {
+ @export(Listener.constructor, .{ .name = "ListenerClass__construct" });
+ @export(Listener.finalize, .{ .name = "ListenerClass__finalize" });
+ @export(Listener.getData, .{ .name = "ListenerPrototype__getData" });
+ @export(Listener.getHostname, .{ .name = "ListenerPrototype__getHostname" });
+ @export(Listener.getPort, .{ .name = "ListenerPrototype__getPort" });
+ @export(Listener.getUnix, .{ .name = "ListenerPrototype__getUnix" });
+ @export(Listener.ref, .{ .name = "ListenerPrototype__ref" });
+ @export(Listener.reload, .{ .name = "ListenerPrototype__reload" });
+ @export(Listener.setData, .{ .name = "ListenerPrototype__setData" });
+ @export(Listener.stop, .{ .name = "ListenerPrototype__stop" });
+ @export(Listener.unref, .{ .name = "ListenerPrototype__unref" });
+ }
+ }
+};
pub const JSSubprocess = struct {
const Subprocess = Classes.Subprocess;
const GetterType = fn (*Subprocess, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue;
@@ -1392,6 +1751,9 @@ pub const JSBlob = struct {
};
comptime {
+ _ = JSTCPSocket;
+ _ = JSTLSSocket;
+ _ = JSListener;
_ = JSSubprocess;
_ = JSSHA1;
_ = JSMD5;
diff --git a/src/bun.js/bindings/generated_classes_list.zig b/src/bun.js/bindings/generated_classes_list.zig
index 0f74343f6..acae606e3 100644
--- a/src/bun.js/bindings/generated_classes_list.zig
+++ b/src/bun.js/bindings/generated_classes_list.zig
@@ -15,4 +15,7 @@ pub const Classes = struct {
pub const Blob = JSC.WebCore.Blob;
pub const Subprocess = JSC.Subprocess;
pub const ServerWebSocket = JSC.API.ServerWebSocket;
+ pub const TCPSocket = JSC.API.TCPSocket;
+ pub const TLSSocket = JSC.API.TLSSocket;
+ pub const Listener = JSC.API.Listener;
};
diff --git a/src/bun.js/bindings/headers-cpp.h b/src/bun.js/bindings/headers-cpp.h
index 539e71afc..47ca7ef31 100644
--- a/src/bun.js/bindings/headers-cpp.h
+++ b/src/bun.js/bindings/headers-cpp.h
@@ -1,4 +1,4 @@
-//-- AUTOGENERATED FILE -- 1666254195
+//-- AUTOGENERATED FILE -- 1666335003
// clang-format off
#pragma once
diff --git a/src/bun.js/bindings/headers.h b/src/bun.js/bindings/headers.h
index de4eb42d4..d0b3cc938 100644
--- a/src/bun.js/bindings/headers.h
+++ b/src/bun.js/bindings/headers.h
@@ -1,5 +1,5 @@
// clang-format off
-//-- AUTOGENERATED FILE -- 1666254195
+//-- AUTOGENERATED FILE -- 1666335003
#pragma once
#include <stddef.h>
diff --git a/src/deps/uws.zig b/src/deps/uws.zig
index 9b4903657..06d46fd3d 100644
--- a/src/deps/uws.zig
+++ b/src/deps/uws.zig
@@ -10,6 +10,7 @@ pub const LIBUS_LISTEN_DEFAULT: i32 = 0;
pub const LIBUS_LISTEN_EXCLUSIVE_PORT: i32 = 1;
pub const Socket = opaque {};
const bun = @import("../global.zig");
+const uws = @This();
const BoringSSL = @import("boringssl");
fn NativeSocketHandleType(comptime ssl: bool) type {
@@ -53,7 +54,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type {
return us_socket_context(
comptime ssl_int,
this.socket,
- );
+ ).?;
}
pub fn flush(this: ThisSocket) void {
return us_socket_flush(
@@ -143,6 +144,52 @@ pub fn NewSocketHandler(comptime ssl: bool) type {
return holder;
}
+ pub fn connectPtr(
+ host: []const u8,
+ port: i32,
+ socket_ctx: *SocketContext,
+ comptime Context: type,
+ ctx: *Context,
+ comptime socket_field_name: []const u8,
+ ) ?*Context {
+ const this_socket = connectAnon(host, port, socket_ctx, ctx) orelse return null;
+ @field(ctx, socket_field_name) = this_socket;
+ return ctx;
+ }
+
+ pub fn connectUnixPtr(
+ path: []const u8,
+ socket_ctx: *SocketContext,
+ comptime Context: type,
+ ctx: *Context,
+ comptime socket_field_name: []const u8,
+ ) ?*Context {
+ const this_socket = connectUnixAnon(path, socket_ctx, ctx) orelse return null;
+ @field(ctx, socket_field_name) = this_socket;
+ return ctx;
+ }
+
+ pub fn connectUnixAnon(
+ path: []const u8,
+ socket_ctx: *SocketContext,
+ ctx: *anyopaque,
+ ) ?ThisSocket {
+ var stack_fallback = std.heap.stackFallback(1024, bun.default_allocator);
+ var allocator = stack_fallback.get();
+ var path_ = allocator.dupeZ(u8, path) catch return null;
+ defer allocator.free(path_);
+
+ var socket = us_socket_context_connect_unix(comptime ssl_int, socket_ctx, path_, 0, 8) orelse return null;
+ const socket_ = ThisSocket{ .socket = socket };
+ var holder = socket_.ext(*anyopaque) orelse {
+ if (comptime bun.Environment.allow_assert) unreachable;
+ _ = us_socket_close_connecting(comptime ssl_int, socket);
+ return null;
+ };
+ holder.* = ctx;
+ return socket_;
+ }
+
pub fn connectAnon(
host: []const u8,
port: i32,
@@ -167,6 +214,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type {
pub fn configure(
ctx: *SocketContext,
+ comptime deref: bool,
comptime ContextType: type,
comptime Fields: anytype,
) void {
@@ -177,17 +225,37 @@ pub fn NewSocketHandler(comptime ssl: bool) type {
@sizeOf(usize)
else
std.meta.alignment(ContextType);
+ const deref_ = deref;
+ const ValueType = if (deref) ContextType else *ContextType;
+ fn getValue(socket: *Socket) ValueType {
+ if (comptime ContextType == anyopaque) {
+ return us_socket_ext(comptime ssl_int, socket).?;
+ }
+
+ if (comptime deref_) {
+ return (ThisSocket{ .socket = socket }).ext(ContextType).?.*;
+ }
- pub fn on_open(socket: *Socket, _: i32, _: [*c]u8, _: i32) callconv(.C) ?*Socket {
+ return (ThisSocket{ .socket = socket }).ext(ContextType).?;
+ }
+
+ pub fn on_open(socket: *Socket, is_client: i32, _: [*c]u8, _: i32) callconv(.C) ?*Socket {
+ if (comptime @hasDecl(Fields, "onCreate")) {
+ if (is_client == 0) {
+ Fields.onCreate(
+ ThisSocket{ .socket = socket },
+ );
+ }
+ }
Fields.onOpen(
- @ptrCast(*ContextType, @alignCast(alignment, us_socket_ext(comptime ssl_int, socket).?)),
+ getValue(socket),
ThisSocket{ .socket = socket },
);
return socket;
}
pub fn on_close(socket: *Socket, code: i32, reason: ?*anyopaque) callconv(.C) ?*Socket {
Fields.onClose(
- @ptrCast(*ContextType, @alignCast(alignment, us_socket_ext(comptime ssl_int, socket).?)),
+ getValue(socket),
ThisSocket{ .socket = socket },
code,
reason,
@@ -196,7 +264,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type {
}
pub fn on_data(socket: *Socket, buf: ?[*]u8, len: i32) callconv(.C) ?*Socket {
Fields.onData(
- @ptrCast(*ContextType, @alignCast(alignment, us_socket_ext(comptime ssl_int, socket).?)),
+ getValue(socket),
ThisSocket{ .socket = socket },
buf.?[0..@intCast(usize, len)],
);
@@ -204,21 +272,21 @@ pub fn NewSocketHandler(comptime ssl: bool) type {
}
pub fn on_writable(socket: *Socket) callconv(.C) ?*Socket {
Fields.onWritable(
- @ptrCast(*ContextType, @alignCast(alignment, us_socket_ext(comptime ssl_int, socket).?)),
+ getValue(socket),
ThisSocket{ .socket = socket },
);
return socket;
}
pub fn on_timeout(socket: *Socket) callconv(.C) ?*Socket {
Fields.onTimeout(
- @ptrCast(*ContextType, @alignCast(alignment, us_socket_ext(comptime ssl_int, socket).?)),
+ getValue(socket),
ThisSocket{ .socket = socket },
);
return socket;
}
pub fn on_connect_error(socket: *Socket, code: i32) callconv(.C) ?*Socket {
Fields.onConnectError(
- @ptrCast(*ContextType, @alignCast(alignment, us_socket_ext(comptime ssl_int, socket).?)),
+ getValue(socket),
ThisSocket{ .socket = socket },
code,
);
@@ -226,7 +294,7 @@ pub fn NewSocketHandler(comptime ssl: bool) type {
}
pub fn on_end(socket: *Socket) callconv(.C) ?*Socket {
Fields.onEnd(
- @ptrCast(*ContextType, @alignCast(alignment, us_socket_ext(comptime ssl_int, socket).?)),
+ getValue(socket),
ThisSocket{ .socket = socket },
);
return socket;
@@ -306,6 +374,24 @@ pub const SocketContext = opaque {
pub fn getNativeHandle(this: *SocketContext, comptime ssl: bool) *anyopaque {
return us_socket_context_get_native_handle(comptime @as(i32, @boolToInt(ssl)), this).?;
}
+
+ pub fn deinit(this: *SocketContext, ssl: bool) void {
+ us_socket_context_free(@as(i32, @boolToInt(ssl)), this);
+ }
+
+ pub fn ext(this: *SocketContext, ssl: bool, comptime ContextType: type) ?*ContextType {
+ const alignment = if (ContextType == *anyopaque)
+ @sizeOf(usize)
+ else
+ std.meta.alignment(ContextType);
+
+ var ptr = us_socket_context_ext(
+ @boolToInt(ssl),
+ this,
+ ) orelse return null;
+
+ return @ptrCast(*ContextType, @alignCast(alignment, ptr));
+ }
};
pub const Loop = extern struct {
internal_loop_data: InternalLoopData align(16),
@@ -450,12 +536,12 @@ pub const us_socket_context_options_t = extern struct {
};
extern fn SocketContextimestamp(ssl: i32, context: ?*SocketContext) c_ushort;
-extern fn us_socket_context_add_server_name(ssl: i32, context: ?*SocketContext, hostname_pattern: [*c]const u8, options: us_socket_context_options_t, ?*anyopaque) void;
+pub extern fn us_socket_context_add_server_name(ssl: i32, context: ?*SocketContext, hostname_pattern: [*c]const u8, options: us_socket_context_options_t, ?*anyopaque) void;
extern fn us_socket_context_remove_server_name(ssl: i32, context: ?*SocketContext, hostname_pattern: [*c]const u8) void;
extern fn us_socket_context_on_server_name(ssl: i32, context: ?*SocketContext, cb: ?fn (?*SocketContext, [*c]const u8) callconv(.C) void) void;
extern fn us_socket_context_get_native_handle(ssl: i32, context: ?*SocketContext) ?*anyopaque;
pub extern fn us_create_socket_context(ssl: i32, loop: ?*Loop, ext_size: i32, options: us_socket_context_options_t) ?*SocketContext;
-extern fn us_socket_context_free(ssl: i32, context: ?*SocketContext) void;
+pub extern fn us_socket_context_free(ssl: i32, context: ?*SocketContext) void;
extern fn us_socket_context_on_open(ssl: i32, context: ?*SocketContext, on_open: fn (*Socket, i32, [*c]u8, i32) callconv(.C) ?*Socket) void;
extern fn us_socket_context_on_close(ssl: i32, context: ?*SocketContext, on_close: fn (*Socket, i32, ?*anyopaque) callconv(.C) ?*Socket) void;
extern fn us_socket_context_on_data(ssl: i32, context: ?*SocketContext, on_data: fn (*Socket, [*c]u8, i32) callconv(.C) ?*Socket) void;
@@ -465,9 +551,10 @@ extern fn us_socket_context_on_connect_error(ssl: i32, context: ?*SocketContext,
extern fn us_socket_context_on_end(ssl: i32, context: ?*SocketContext, on_end: fn (*Socket) callconv(.C) ?*Socket) void;
extern fn us_socket_context_ext(ssl: i32, context: ?*SocketContext) ?*anyopaque;
-extern fn us_socket_context_listen(ssl: i32, context: ?*SocketContext, host: [*c]const u8, port: i32, options: i32, socket_ext_size: i32) ?*listen_socket_t;
-
+pub extern fn us_socket_context_listen(ssl: i32, context: ?*SocketContext, host: [*c]const u8, port: i32, options: i32, socket_ext_size: i32) ?*ListenSocket;
+pub extern fn us_socket_context_listen_unix(ssl: i32, context: ?*SocketContext, path: [*c]const u8, options: i32, socket_ext_size: i32) ?*ListenSocket;
pub extern fn us_socket_context_connect(ssl: i32, context: ?*SocketContext, host: [*c]const u8, port: i32, source_host: [*c]const u8, options: i32, socket_ext_size: i32) ?*Socket;
+pub extern fn us_socket_context_connect_unix(ssl: i32, context: ?*SocketContext, path: [*c]const u8, options: i32, socket_ext_size: i32) ?*Socket;
pub extern fn us_socket_is_established(ssl: i32, s: ?*Socket) i32;
pub extern fn us_socket_close_connecting(ssl: i32, s: ?*Socket) ?*Socket;
pub extern fn us_socket_context_loop(ssl: i32, context: ?*SocketContext) ?*Loop;
@@ -804,7 +891,7 @@ pub const WebSocketBehavior = extern struct {
};
}
};
-pub const uws_listen_handler = ?fn (?*listen_socket_t, ?*anyopaque) callconv(.C) void;
+pub const uws_listen_handler = ?fn (?*ListenSocket, ?*anyopaque) callconv(.C) void;
pub const uws_method_handler = ?fn (*uws_res, *Request, ?*anyopaque) callconv(.C) void;
pub const uws_filter_handler = ?fn (*uws_res, i32, ?*anyopaque) callconv(.C) void;
pub const uws_missing_server_handler = ?fn ([*c]const u8, ?*anyopaque) callconv(.C) void;
@@ -852,8 +939,12 @@ pub const Request = opaque {
extern fn uws_req_get_parameter(res: *Request, index: c_ushort, dest: *[*]const u8) usize;
};
-const listen_socket_t = opaque {};
-extern fn us_listen_socket_close(ssl: i32, ls: *listen_socket_t) void;
+pub const ListenSocket = opaque {
+ pub fn close(this: *ListenSocket, ssl: bool) void {
+ us_listen_socket_close(@boolToInt(ssl), this);
+ }
+};
+extern fn us_listen_socket_close(ssl: i32, ls: *ListenSocket) void;
pub fn NewApp(comptime ssl: bool) type {
return opaque {
@@ -907,11 +998,11 @@ pub fn NewApp(comptime ssl: bool) type {
}
pub const ListenSocket = opaque {
- pub inline fn close(this: *ListenSocket) void {
+ pub inline fn close(this: *ThisApp.ListenSocket) void {
if (comptime is_bindgen) {
unreachable;
}
- return us_listen_socket_close(ssl_flag, @ptrCast(*listen_socket_t, this));
+ return us_listen_socket_close(ssl_flag, @ptrCast(*uws.ListenSocket, this));
}
};
@@ -1046,19 +1137,20 @@ pub fn NewApp(comptime ssl: bool) type {
port: i32,
comptime UserData: type,
user_data: UserData,
- comptime handler: fn (UserData, ?*ListenSocket, uws_app_listen_config_t) void,
+ comptime handler: fn (UserData, ?*ThisApp.ListenSocket, uws_app_listen_config_t) void,
) void {
if (comptime is_bindgen) {
unreachable;
}
const Wrapper = struct {
- pub fn handle(socket: ?*listen_socket_t, conf: uws_app_listen_config_t, data: ?*anyopaque) callconv(.C) void {
+ const handler = handler;
+ pub fn handle(socket: ?*uws.ListenSocket, conf: uws_app_listen_config_t, data: ?*anyopaque) callconv(.C) void {
if (comptime UserData == void) {
- @call(.{ .modifier = .always_inline }, handler, .{ void{}, @ptrCast(?*ListenSocket, socket), conf });
+ @call(.{ .modifier = .always_inline }, handler, .{ void{}, @ptrCast(?*ThisApp.ListenSocket, socket), conf });
} else {
@call(.{ .modifier = .always_inline }, handler, .{
@ptrCast(UserData, @alignCast(@alignOf(UserData), data.?)),
- @ptrCast(?*ListenSocket, socket),
+ @ptrCast(?*ThisApp.ListenSocket, socket),
conf,
});
}
@@ -1071,17 +1163,19 @@ pub fn NewApp(comptime ssl: bool) type {
app: *ThisApp,
comptime UserData: type,
user_data: UserData,
- comptime handler: fn (UserData, ?*ListenSocket) void,
+ comptime handler: fn (UserData, ?*ThisApp.ListenSocket) void,
config: uws_app_listen_config_t,
) void {
const Wrapper = struct {
- pub fn handle(socket: ?*listen_socket_t, data: ?*anyopaque) callconv(.C) void {
+ const handler = handler;
+
+ pub fn handle(socket: ?*uws.ListenSocket, data: ?*anyopaque) callconv(.C) void {
if (comptime UserData == void) {
- @call(.{ .modifier = .always_inline }, handler, .{ void{}, @ptrCast(?*ListenSocket, socket) });
+ @call(.{ .modifier = .always_inline }, handler, .{ void{}, @ptrCast(?*ThisApp.ListenSocket, socket) });
} else {
@call(.{ .modifier = .always_inline }, handler, .{
@ptrCast(UserData, @alignCast(@alignOf(UserData), data.?)),
- @ptrCast(?*ListenSocket, socket),
+ @ptrCast(?*ThisApp.ListenSocket, socket),
});
}
}
diff --git a/src/http/websocket_http_client.zig b/src/http/websocket_http_client.zig
index ac6d605bd..f0cdc2e54 100644
--- a/src/http/websocket_http_client.zig
+++ b/src/http/websocket_http_client.zig
@@ -149,6 +149,7 @@ pub fn NewHTTPUpgradeClient(comptime ssl: bool) type {
Socket.configure(
ctx,
+ false,
HTTPClient,
struct {
pub const onOpen = handleOpen;
@@ -793,6 +794,7 @@ pub fn NewWebSocketClient(comptime ssl: bool) type {
Socket.configure(
ctx,
+ false,
WebSocket,
struct {
pub const onClose = handleClose;
diff --git a/src/http_client_async.zig b/src/http_client_async.zig
index c566f29bf..c49979e7f 100644
--- a/src/http_client_async.zig
+++ b/src/http_client_async.zig
@@ -100,6 +100,7 @@ fn NewHTTPContext(comptime ssl: bool) type {
HTTPSocket.configure(
this.us_socket_context,
+ false,
anyopaque,
Handler,
);
diff --git a/src/jsc.zig b/src/jsc.zig
index b9e7b8db5..4d98536d9 100644
--- a/src/jsc.zig
+++ b/src/jsc.zig
@@ -26,13 +26,16 @@ pub const Jest = @import("./bun.js/test/jest.zig");
pub const API = struct {
pub const Transpiler = @import("./bun.js/api/transpiler.zig");
pub const Server = @import("./bun.js/api/server.zig").Server;
+ pub const ServerConfig = @import("./bun.js/api/server.zig").ServerConfig;
pub const ServerWebSocket = @import("./bun.js/api/server.zig").ServerWebSocket;
pub const SSLServer = @import("./bun.js/api/server.zig").SSLServer;
pub const DebugServer = @import("./bun.js/api/server.zig").DebugServer;
pub const DebugSSLServer = @import("./bun.js/api/server.zig").DebugSSLServer;
pub const Bun = @import("./bun.js/api/bun.zig");
pub const Router = @import("./bun.js/api/router.zig");
- pub const ServerConfig = @import("./bun.js/api/server.zig").ServerConfig;
+ pub const TCPSocket = @import("./bun.js/api/bun/socket.zig").TCPSocket;
+ pub const TLSSocket = @import("./bun.js/api/bun/socket.zig").TLSSocket;
+ pub const Listener = @import("./bun.js/api/bun/socket.zig").Listener;
};
pub const FFI = @import("./bun.js/api/ffi.zig").FFI;
pub const Node = struct {
diff --git a/test/bun.js/tcp-server.test.ts b/test/bun.js/tcp-server.test.ts
new file mode 100644
index 000000000..f0dfc8ce5
--- /dev/null
+++ b/test/bun.js/tcp-server.test.ts
@@ -0,0 +1,114 @@
+import { listen, connect, finalizationCounter } from "bun";
+import { expect, describe, it } from "bun:test";
+import * as JSC from "bun:jsc";
+
+var decoder = new TextDecoder();
+
+it("echo server 1 on 1", async () => {
+ // wrap it in a separate closure so the GC knows to clean it up
+ // the sockets & listener don't escape the closure
+ await (async function () {
+ var resolve, reject, serverResolve, serverReject;
+ var prom = new Promise((resolve1, reject1) => {
+ resolve = resolve1;
+ reject = reject1;
+ });
+ var serverProm = new Promise((resolve1, reject1) => {
+ serverResolve = resolve1;
+ serverReject = reject1;
+ });
+
+ var serverData, clientData;
+ const handlers = {
+ open(socket) {
+ socket.data.counter = 1;
+ if (!socket.data?.isServer) {
+ clientData = socket.data;
+ clientData.sendQueue = ["client: Hello World! " + 0];
+ if (!socket.write("client: Hello World! " + 0)) {
+ socket.data = { pending: "server: Hello World! " + 0 };
+ }
+ } else {
+ serverData = socket.data;
+ serverData.sendQueue = ["server: Hello World! " + 0];
+ }
+
+ if (clientData) clientData.other = serverData;
+ if (serverData) serverData.other = clientData;
+ if (clientData) clientData.other = serverData;
+ if (serverData) serverData.other = clientData;
+ },
+ data(socket, buffer) {
+ const msg = `${
+ socket.data.isServer ? "server:" : "client:"
+ } Hello World! ${socket.data.counter++}`;
+ socket.data.sendQueue.push(msg);
+
+ expect(decoder.decode(buffer)).toBe(socket.data.other.sendQueue.pop());
+
+ if (socket.data.counter > 10) {
+ if (!socket.data.finished) {
+ socket.data.finished = true;
+ if (socket.data.isServer) {
+ setTimeout(() => {
+ serverResolve();
+ socket.end();
+ }, 1);
+ } else {
+ setTimeout(() => {
+ resolve();
+ socket.end();
+ }, 1);
+ }
+ }
+ }
+
+ if (!socket.write(msg)) {
+ socket.data.pending = msg;
+ return;
+ }
+ },
+ error(socket, error) {
+ reject(error);
+ },
+ drain(socket) {
+ reject(new Error("Unexpected backpressure"));
+ },
+ };
+
+ var server = listen({
+ socket: handlers,
+ hostname: "localhost",
+ port: 8084,
+ data: {
+ isServer: true,
+ counter: 0,
+ },
+ });
+ connect({
+ socket: handlers,
+ hostname: "localhost",
+ port: 8084,
+ data: {
+ counter: 0,
+ },
+ });
+ await Promise.all([prom, serverProm]);
+ server.stop();
+ server = serverData = clientData = undefined;
+ Bun.gc(true);
+ })();
+
+ // Tell the garbage collector for sure that we're done with the sockets
+ await new Promise((resolve, reject) => {
+ setTimeout(() => {
+ Bun.gc(true);
+ resolve();
+ }, 1);
+ });
+
+ // assert we don't leak the sockets
+ // we expect 1 because that's the prototype / structure
+ expect(JSC.heapStats().objectTypeCounts.TCPSocket).toBe(1);
+ expect(JSC.heapStats().objectTypeCounts.Listener).toBe(1);
+});