diff options
author | 2023-08-25 21:08:41 -0700 | |
---|---|---|
committer | 2023-08-25 21:08:41 -0700 | |
commit | d98a93c3181426ea0565193303d3e63d3796231c (patch) | |
tree | 71a8d96bc4b75d902643ec877c03070cca8fcf45 | |
parent | f70bb2497b2406e89afec3ee8a36a3b10ef66334 (diff) | |
download | bun-d98a93c3181426ea0565193303d3e63d3796231c.tar.gz bun-d98a93c3181426ea0565193303d3e63d3796231c.tar.zst bun-d98a93c3181426ea0565193303d3e63d3796231c.zip |
Automatically hot reload Bun.serve() (#4344)
* Automatically hot reload Bun.serve()
* Update doc
* Update example
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
-rw-r--r-- | docs/runtime/hot.md | 38 | ||||
-rw-r--r-- | examples/bun-hot-websockets.js | 4 | ||||
-rw-r--r-- | packages/bun-types/bun.d.ts | 24 | ||||
-rw-r--r-- | src/bun.js/api/bun.zig | 60 | ||||
-rw-r--r-- | src/bun.js/api/server.classes.ts | 4 | ||||
-rw-r--r-- | src/bun.js/api/server.zig | 108 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.cpp | 144 | ||||
-rw-r--r-- | src/bun.js/bindings/ZigGeneratedClasses.h | 4 | ||||
-rw-r--r-- | src/bun.js/bindings/generated_classes.zig | 104 | ||||
-rw-r--r-- | src/bun.js/javascript.zig | 8 | ||||
-rw-r--r-- | src/bun.js/rare_data.zig | 62 |
11 files changed, 503 insertions, 57 deletions
diff --git a/docs/runtime/hot.md b/docs/runtime/hot.md index 0797187de..7f0b04c28 100644 --- a/docs/runtime/hot.md +++ b/docs/runtime/hot.md @@ -102,55 +102,25 @@ Traditional file watchers like `nodemon` restart the entire process, so HTTP ser Bun provides the following simplified API for implementing HTTP servers. Refer to [API > HTTP](/docs/api/http) for full details. ```ts#server.ts -import {type Serve} from "bun"; +import {serve} from "bun"; globalThis.count ??= 0; globalThis.count++; -export default { +serve({ fetch(req: Request) { return new Response(`Reloaded ${globalThis.count} times`); }, port: 3000, -} satisfies Serve; +}); ``` The file above is simply exporting an object with a `fetch` handler defined. When this file is executed, Bun interprets this as an HTTP server and passes the exported object into `Bun.serve`. -Unlike an explicit call to `Bun.serve`, the object-based syntax works out of the box with `bun --hot`. When you save the file, your HTTP server be reloaded with the updated code without the process being restarted. This results in seriously fast refresh speeds. +When you save the file, your HTTP server be reloaded with the updated code without the process being restarted. This results in seriously fast refresh speeds. {% image src="https://user-images.githubusercontent.com/709451/195477632-5fd8a73e-014d-4589-9ba2-e075ad9eb040.gif" alt="Bun vs Nodemon refresh speeds" caption="Bun on the left, Nodemon on the right." /%} -For more fine-grained control, you can use the `Bun.serve` API directly and handle the server reloading manually. - -```ts#server.ts -import type {Serve, Server} from "bun"; - -// make TypeScript happy -declare global { - var count: number; - var server: Server; -} - -globalThis.count ??= 0; -globalThis.count++; - -// define server parameters -const serverOptions: Serve = { - port: 3000, - fetch(req) { - return new Response(`Reloaded ${globalThis.count} times`); - } -}; - -if (!globalThis.server) { - globalThis.server = Bun.serve(serverOptions); -} else { - // reload server - globalThis.server.reload(serverOptions); -} -``` - {% callout %} **Note** — In a future version of Bun, support for Vite's `import.meta.hot` is planned to enable better lifecycle management for hot reloading and to align with the ecosystem. diff --git a/examples/bun-hot-websockets.js b/examples/bun-hot-websockets.js index 7cdaf0f02..37d823a22 100644 --- a/examples/bun-hot-websockets.js +++ b/examples/bun-hot-websockets.js @@ -38,7 +38,7 @@ const styles = css` } `; -export default { +Bun.serve({ websocket: { message(ws, msg) { ws.send(styles); @@ -86,4 +86,4 @@ export default { }, ); }, -}; +}); diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index 76db42715..2df53a301 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -1820,6 +1820,21 @@ declare module "bun" { this: Server, request: Errorlike, ) => Response | Promise<Response> | undefined | void | Promise<undefined>; + + /** + * Uniquely identify a server instance with an ID + * + * ### When bun is started with the `--hot` flag + * + * This string will be used to hot reload the server without interrupting + * pending requests or websockets. If not provided, a value will be + * generated. To disable hot reloading, set this value to `null`. + * + * ### When bun is not started with the `--hot` flag + * + * This string will currently do nothing. But in the future it could be useful for logs or metrics. + */ + id?: string | null; } export type AnyFunction = (..._: any[]) => any; @@ -2345,6 +2360,15 @@ declare module "bun" { * */ readonly development: boolean; + + /** + * An identifier of the server instance + * + * When bun is started with the `--hot` flag, this ID is used to hot reload the server without interrupting pending requests or websockets. + * + * When bun is not started with the `--hot` flag, this ID is currently unused. + */ + readonly id: string; } /** diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index a9d7ed970..71b065993 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -2481,7 +2481,7 @@ pub fn serve( callframe: *JSC.CallFrame, ) callconv(.C) JSC.JSValue { const arguments = callframe.arguments(2).slice(); - const config: JSC.API.ServerConfig = brk: { + var config: JSC.API.ServerConfig = brk: { var exception_ = [1]JSC.JSValueRef{null}; var exception = &exception_; @@ -2497,6 +2497,40 @@ pub fn serve( var exception_value: *JSC.JSValue = undefined; + if (config.allow_hot) { + if (globalObject.bunVM().hotMap()) |hot| { + if (config.id.len == 0) { + config.id = config.computeID(globalObject.allocator()); + } + + if (hot.getEntry(config.id)) |entry| { + switch (entry.tag()) { + @field(@TypeOf(entry.tag()), @typeName(JSC.API.HTTPServer)) => { + var server: *JSC.API.HTTPServer = entry.as(JSC.API.HTTPServer); + server.onReloadFromZig(&config, globalObject); + return server.thisObject; + }, + @field(@TypeOf(entry.tag()), @typeName(JSC.API.DebugHTTPServer)) => { + var server: *JSC.API.DebugHTTPServer = entry.as(JSC.API.DebugHTTPServer); + server.onReloadFromZig(&config, globalObject); + return server.thisObject; + }, + @field(@TypeOf(entry.tag()), @typeName(JSC.API.DebugHTTPSServer)) => { + var server: *JSC.API.DebugHTTPSServer = entry.as(JSC.API.DebugHTTPSServer); + server.onReloadFromZig(&config, globalObject); + return server.thisObject; + }, + @field(@TypeOf(entry.tag()), @typeName(JSC.API.HTTPSServer)) => { + var server: *JSC.API.HTTPSServer = entry.as(JSC.API.HTTPSServer); + server.onReloadFromZig(&config, globalObject); + return server.thisObject; + }, + else => {}, + } + } + } + } + // Listen happens on the next tick! // This is so we can return a Server object if (config.ssl_config != null) { @@ -2515,6 +2549,12 @@ pub fn serve( obj.protect(); server.thisObject = obj; + + if (config.allow_hot) { + if (globalObject.bunVM().hotMap()) |hot| { + hot.insert(config.id, server); + } + } return obj; } else { var server = JSC.API.HTTPSServer.init(config, globalObject.ptr()); @@ -2530,6 +2570,12 @@ pub fn serve( const obj = server.toJS(globalObject); obj.protect(); server.thisObject = obj; + + if (config.allow_hot) { + if (globalObject.bunVM().hotMap()) |hot| { + hot.insert(config.id, server); + } + } return obj; } } else { @@ -2547,6 +2593,12 @@ pub fn serve( const obj = server.toJS(globalObject); obj.protect(); server.thisObject = obj; + + if (config.allow_hot) { + if (globalObject.bunVM().hotMap()) |hot| { + hot.insert(config.id, server); + } + } return obj; } else { var server = JSC.API.HTTPServer.init(config, globalObject.ptr()); @@ -2563,6 +2615,12 @@ pub fn serve( obj.protect(); server.thisObject = obj; + + if (config.allow_hot) { + if (globalObject.bunVM().hotMap()) |hot| { + hot.insert(config.id, server); + } + } return obj; } } diff --git a/src/bun.js/api/server.classes.ts b/src/bun.js/api/server.classes.ts index 7db8a3444..544f37ce6 100644 --- a/src/bun.js/api/server.classes.ts +++ b/src/bun.js/api/server.classes.ts @@ -27,6 +27,10 @@ function generate(name) { port: { getter: "getPort", }, + id: { + getter: "getId", + cache: true, + }, pendingRequests: { getter: "getPendingRequests", }, diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 81a50a5a7..01f06ebf2 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -158,6 +158,36 @@ pub const ServerConfig = struct { inspector: bool = false, reuse_port: bool = false, + id: []const u8 = "", + allow_hot: bool = true, + + pub fn computeID(this: *const ServerConfig, allocator: std.mem.Allocator) []const u8 { + var arraylist = std.ArrayList(u8).init(allocator); + var writer = arraylist.writer(); + + writer.writeAll("[http]-") catch {}; + switch (this.address) { + .tcp => { + if (this.address.tcp.hostname) |host| { + writer.print("tcp:{s}:{d}", .{ + bun.sliceTo(host, 0), + this.address.tcp.port, + }) catch {}; + } else { + writer.print("tcp:localhost:{d}", .{ + this.address.tcp.port, + }) catch {}; + } + }, + .unix => { + writer.print("unix:{s}", .{ + bun.sliceTo(this.address.unix, 0), + }) catch {}; + }, + } + + return arraylist.items; + } pub const SSLConfig = struct { server_name: [*c]const u8 = null, @@ -794,6 +824,23 @@ pub const ServerConfig = struct { } } + if (arg.get(global, "id")) |id| { + if (id.isUndefinedOrNull()) { + args.allow_hot = false; + } else { + const id_str = id.toSlice( + global, + bun.default_allocator, + ); + + if (id_str.len > 0) { + args.id = (id_str.cloneIfNeeded(bun.default_allocator) catch unreachable).slice(); + } else { + args.allow_hot = false; + } + } + } + if (arg.get(global, "development")) |dev| { args.development = dev.coerce(bool, global); args.reuse_port = !args.development; @@ -4867,26 +4914,8 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp return JSC.jsBoolean(true); } - pub fn onReload( - this: *ThisServer, - globalThis: *JSC.JSGlobalObject, - callframe: *JSC.CallFrame, - ) callconv(.C) JSC.JSValue { - const arguments = callframe.arguments(1).slice(); - if (arguments.len < 1) { - globalThis.throwNotEnoughArguments("reload", 1, 0); - return .zero; - } - - var args_slice = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); - defer args_slice.deinit(); - var exception_ref = [_]JSC.C.JSValueRef{null}; - var exception: JSC.C.ExceptionRef = &exception_ref; - var new_config = ServerConfig.fromJS(globalThis, &args_slice, exception); - if (exception.* != null) { - globalThis.throwValue(exception_ref[0].?.value()); - return .zero; - } + pub fn onReloadFromZig(this: *ThisServer, new_config: *ServerConfig, globalThis: *JSC.JSGlobalObject) void { + httplog("onReload", .{}); // only reload those two if (this.config.onRequest != new_config.onRequest) { @@ -4915,6 +4944,30 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp this.config.websocket = ws.*; } // we don't remove it } + } + + pub fn onReload( + this: *ThisServer, + globalThis: *JSC.JSGlobalObject, + callframe: *JSC.CallFrame, + ) callconv(.C) JSC.JSValue { + const arguments = callframe.arguments(1).slice(); + if (arguments.len < 1) { + globalThis.throwNotEnoughArguments("reload", 1, 0); + return .zero; + } + + var args_slice = JSC.Node.ArgumentsSlice.init(globalThis.bunVM(), arguments); + defer args_slice.deinit(); + var exception_ref = [_]JSC.C.JSValueRef{null}; + var exception: JSC.C.ExceptionRef = &exception_ref; + var new_config = ServerConfig.fromJS(globalThis, &args_slice, exception); + if (exception.* != null) { + globalThis.throwValue(exception_ref[0].?.value()); + return .zero; + } + + this.onReloadFromZig(&new_config, globalThis); return this.thisObject; } @@ -5066,6 +5119,15 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp return JSC.JSValue.jsNumber(listener.getLocalPort()); } + pub fn getId( + this: *ThisServer, + globalThis: *JSC.JSGlobalObject, + ) callconv(.C) JSC.JSValue { + var str = bun.String.create(this.config.id); + defer str.deref(); + return str.toJS(globalThis); + } + pub fn getPendingRequests( this: *ThisServer, _: *JSC.JSGlobalObject, @@ -5170,6 +5232,12 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp } pub fn stop(this: *ThisServer, abrupt: bool) void { + if (this.config.allow_hot and this.config.id.len > 0) { + if (this.globalThis.bunVM().hotMap()) |hot| { + hot.remove(this.config.id); + } + } + this.stopListening(abrupt); this.deinitIfWeCan(); } diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp index 0ab7a1b5d..497408632 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.cpp +++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp @@ -4176,6 +4176,9 @@ JSC_DECLARE_HOST_FUNCTION(DebugHTTPSServerPrototype__fetchCallback); extern "C" JSC::EncodedJSValue DebugHTTPSServerPrototype__getHostname(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(DebugHTTPSServerPrototype__hostnameGetterWrap); +extern "C" JSC::EncodedJSValue DebugHTTPSServerPrototype__getId(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(DebugHTTPSServerPrototype__idGetterWrap); + extern "C" JSC::EncodedJSValue DebugHTTPSServerPrototype__getPendingRequests(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(DebugHTTPSServerPrototype__pendingRequestsGetterWrap); @@ -4206,6 +4209,7 @@ static const HashTableValue JSDebugHTTPSServerPrototypeTableValues[] = { { "development"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__developmentGetterWrap, 0 } }, { "fetch"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPSServerPrototype__fetchCallback, 1 } }, { "hostname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__hostnameGetterWrap, 0 } }, + { "id"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__idGetterWrap, 0 } }, { "pendingRequests"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__pendingRequestsGetterWrap, 0 } }, { "pendingWebSockets"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__pendingWebSocketsGetterWrap, 0 } }, { "port"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPSServerPrototype__portGetterWrap, 0 } }, @@ -4301,6 +4305,37 @@ extern "C" EncodedJSValue DebugHTTPSServerPrototype__hostnameGetCachedValue(JSC: return JSValue::encode(thisObject->m_hostname.get()); } +JSC_DEFINE_CUSTOM_GETTER(DebugHTTPSServerPrototype__idGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSDebugHTTPSServer* thisObject = jsCast<JSDebugHTTPSServer*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_id.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + DebugHTTPSServerPrototype__getId(thisObject->wrapped(), globalObject)); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_id.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); +} + +extern "C" void DebugHTTPSServerPrototype__idSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSDebugHTTPSServer*>(JSValue::decode(thisValue)); + thisObject->m_id.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue DebugHTTPSServerPrototype__idGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSDebugHTTPSServer*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_id.get()); +} + JSC_DEFINE_CUSTOM_GETTER(DebugHTTPSServerPrototype__pendingRequestsGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -4564,6 +4599,7 @@ void JSDebugHTTPSServer::visitAdditionalChildren(Visitor& visitor) ASSERT_GC_OBJECT_INHERITS(thisObject, info()); visitor.append(thisObject->m_hostname); + visitor.append(thisObject->m_id); } DEFINE_VISIT_ADDITIONAL_CHILDREN(JSDebugHTTPSServer); @@ -4622,6 +4658,9 @@ JSC_DECLARE_HOST_FUNCTION(DebugHTTPServerPrototype__fetchCallback); extern "C" JSC::EncodedJSValue DebugHTTPServerPrototype__getHostname(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(DebugHTTPServerPrototype__hostnameGetterWrap); +extern "C" JSC::EncodedJSValue DebugHTTPServerPrototype__getId(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(DebugHTTPServerPrototype__idGetterWrap); + extern "C" JSC::EncodedJSValue DebugHTTPServerPrototype__getPendingRequests(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(DebugHTTPServerPrototype__pendingRequestsGetterWrap); @@ -4652,6 +4691,7 @@ static const HashTableValue JSDebugHTTPServerPrototypeTableValues[] = { { "development"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__developmentGetterWrap, 0 } }, { "fetch"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, DebugHTTPServerPrototype__fetchCallback, 1 } }, { "hostname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__hostnameGetterWrap, 0 } }, + { "id"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__idGetterWrap, 0 } }, { "pendingRequests"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__pendingRequestsGetterWrap, 0 } }, { "pendingWebSockets"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__pendingWebSocketsGetterWrap, 0 } }, { "port"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, DebugHTTPServerPrototype__portGetterWrap, 0 } }, @@ -4747,6 +4787,37 @@ extern "C" EncodedJSValue DebugHTTPServerPrototype__hostnameGetCachedValue(JSC:: return JSValue::encode(thisObject->m_hostname.get()); } +JSC_DEFINE_CUSTOM_GETTER(DebugHTTPServerPrototype__idGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSDebugHTTPServer* thisObject = jsCast<JSDebugHTTPServer*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_id.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + DebugHTTPServerPrototype__getId(thisObject->wrapped(), globalObject)); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_id.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); +} + +extern "C" void DebugHTTPServerPrototype__idSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSDebugHTTPServer*>(JSValue::decode(thisValue)); + thisObject->m_id.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue DebugHTTPServerPrototype__idGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSDebugHTTPServer*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_id.get()); +} + JSC_DEFINE_CUSTOM_GETTER(DebugHTTPServerPrototype__pendingRequestsGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -5010,6 +5081,7 @@ void JSDebugHTTPServer::visitAdditionalChildren(Visitor& visitor) ASSERT_GC_OBJECT_INHERITS(thisObject, info()); visitor.append(thisObject->m_hostname); + visitor.append(thisObject->m_id); } DEFINE_VISIT_ADDITIONAL_CHILDREN(JSDebugHTTPServer); @@ -11359,6 +11431,9 @@ JSC_DECLARE_HOST_FUNCTION(HTTPSServerPrototype__fetchCallback); extern "C" JSC::EncodedJSValue HTTPSServerPrototype__getHostname(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(HTTPSServerPrototype__hostnameGetterWrap); +extern "C" JSC::EncodedJSValue HTTPSServerPrototype__getId(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(HTTPSServerPrototype__idGetterWrap); + extern "C" JSC::EncodedJSValue HTTPSServerPrototype__getPendingRequests(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(HTTPSServerPrototype__pendingRequestsGetterWrap); @@ -11389,6 +11464,7 @@ static const HashTableValue JSHTTPSServerPrototypeTableValues[] = { { "development"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__developmentGetterWrap, 0 } }, { "fetch"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPSServerPrototype__fetchCallback, 1 } }, { "hostname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__hostnameGetterWrap, 0 } }, + { "id"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__idGetterWrap, 0 } }, { "pendingRequests"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__pendingRequestsGetterWrap, 0 } }, { "pendingWebSockets"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__pendingWebSocketsGetterWrap, 0 } }, { "port"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPSServerPrototype__portGetterWrap, 0 } }, @@ -11484,6 +11560,37 @@ extern "C" EncodedJSValue HTTPSServerPrototype__hostnameGetCachedValue(JSC::Enco return JSValue::encode(thisObject->m_hostname.get()); } +JSC_DEFINE_CUSTOM_GETTER(HTTPSServerPrototype__idGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSHTTPSServer* thisObject = jsCast<JSHTTPSServer*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_id.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + HTTPSServerPrototype__getId(thisObject->wrapped(), globalObject)); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_id.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); +} + +extern "C" void HTTPSServerPrototype__idSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSHTTPSServer*>(JSValue::decode(thisValue)); + thisObject->m_id.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue HTTPSServerPrototype__idGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSHTTPSServer*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_id.get()); +} + JSC_DEFINE_CUSTOM_GETTER(HTTPSServerPrototype__pendingRequestsGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -11747,6 +11854,7 @@ void JSHTTPSServer::visitAdditionalChildren(Visitor& visitor) ASSERT_GC_OBJECT_INHERITS(thisObject, info()); visitor.append(thisObject->m_hostname); + visitor.append(thisObject->m_id); } DEFINE_VISIT_ADDITIONAL_CHILDREN(JSHTTPSServer); @@ -11805,6 +11913,9 @@ JSC_DECLARE_HOST_FUNCTION(HTTPServerPrototype__fetchCallback); extern "C" JSC::EncodedJSValue HTTPServerPrototype__getHostname(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(HTTPServerPrototype__hostnameGetterWrap); +extern "C" JSC::EncodedJSValue HTTPServerPrototype__getId(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); +JSC_DECLARE_CUSTOM_GETTER(HTTPServerPrototype__idGetterWrap); + extern "C" JSC::EncodedJSValue HTTPServerPrototype__getPendingRequests(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject); JSC_DECLARE_CUSTOM_GETTER(HTTPServerPrototype__pendingRequestsGetterWrap); @@ -11835,6 +11946,7 @@ static const HashTableValue JSHTTPServerPrototypeTableValues[] = { { "development"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__developmentGetterWrap, 0 } }, { "fetch"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, HTTPServerPrototype__fetchCallback, 1 } }, { "hostname"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__hostnameGetterWrap, 0 } }, + { "id"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__idGetterWrap, 0 } }, { "pendingRequests"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__pendingRequestsGetterWrap, 0 } }, { "pendingWebSockets"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__pendingWebSocketsGetterWrap, 0 } }, { "port"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, HTTPServerPrototype__portGetterWrap, 0 } }, @@ -11930,6 +12042,37 @@ extern "C" EncodedJSValue HTTPServerPrototype__hostnameGetCachedValue(JSC::Encod return JSValue::encode(thisObject->m_hostname.get()); } +JSC_DEFINE_CUSTOM_GETTER(HTTPServerPrototype__idGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) +{ + auto& vm = lexicalGlobalObject->vm(); + Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject); + auto throwScope = DECLARE_THROW_SCOPE(vm); + JSHTTPServer* thisObject = jsCast<JSHTTPServer*>(JSValue::decode(thisValue)); + JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject); + + if (JSValue cachedValue = thisObject->m_id.get()) + return JSValue::encode(cachedValue); + + JSC::JSValue result = JSC::JSValue::decode( + HTTPServerPrototype__getId(thisObject->wrapped(), globalObject)); + RETURN_IF_EXCEPTION(throwScope, {}); + thisObject->m_id.set(vm, thisObject, result); + RELEASE_AND_RETURN(throwScope, JSValue::encode(result)); +} + +extern "C" void HTTPServerPrototype__idSetCachedValue(JSC::EncodedJSValue thisValue, JSC::JSGlobalObject* globalObject, JSC::EncodedJSValue value) +{ + auto& vm = globalObject->vm(); + auto* thisObject = jsCast<JSHTTPServer*>(JSValue::decode(thisValue)); + thisObject->m_id.set(vm, thisObject, JSValue::decode(value)); +} + +extern "C" EncodedJSValue HTTPServerPrototype__idGetCachedValue(JSC::EncodedJSValue thisValue) +{ + auto* thisObject = jsCast<JSHTTPServer*>(JSValue::decode(thisValue)); + return JSValue::encode(thisObject->m_id.get()); +} + JSC_DEFINE_CUSTOM_GETTER(HTTPServerPrototype__pendingRequestsGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) { auto& vm = lexicalGlobalObject->vm(); @@ -12193,6 +12336,7 @@ void JSHTTPServer::visitAdditionalChildren(Visitor& visitor) ASSERT_GC_OBJECT_INHERITS(thisObject, info()); visitor.append(thisObject->m_hostname); + visitor.append(thisObject->m_id); } DEFINE_VISIT_ADDITIONAL_CHILDREN(JSHTTPServer); diff --git a/src/bun.js/bindings/ZigGeneratedClasses.h b/src/bun.js/bindings/ZigGeneratedClasses.h index b8b694068..e0b10ff55 100644 --- a/src/bun.js/bindings/ZigGeneratedClasses.h +++ b/src/bun.js/bindings/ZigGeneratedClasses.h @@ -511,6 +511,7 @@ public: DECLARE_VISIT_OUTPUT_CONSTRAINTS; mutable JSC::WriteBarrier<JSC::Unknown> m_hostname; + mutable JSC::WriteBarrier<JSC::Unknown> m_id; }; class JSDebugHTTPServer final : public JSC::JSDestructibleObject { @@ -567,6 +568,7 @@ public: DECLARE_VISIT_OUTPUT_CONSTRAINTS; mutable JSC::WriteBarrier<JSC::Unknown> m_hostname; + mutable JSC::WriteBarrier<JSC::Unknown> m_id; }; class JSDirent final : public JSC::JSDestructibleObject { @@ -1415,6 +1417,7 @@ public: DECLARE_VISIT_OUTPUT_CONSTRAINTS; mutable JSC::WriteBarrier<JSC::Unknown> m_hostname; + mutable JSC::WriteBarrier<JSC::Unknown> m_id; }; class JSHTTPServer final : public JSC::JSDestructibleObject { @@ -1471,6 +1474,7 @@ public: DECLARE_VISIT_OUTPUT_CONSTRAINTS; mutable JSC::WriteBarrier<JSC::Unknown> m_hostname; + mutable JSC::WriteBarrier<JSC::Unknown> m_id; }; class JSListener final : public JSC::JSDestructibleObject { diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig index e98b8f973..116947c24 100644 --- a/src/bun.js/bindings/generated_classes.zig +++ b/src/bun.js/bindings/generated_classes.zig @@ -1242,6 +1242,28 @@ pub const JSDebugHTTPSServer = struct { return result; } + extern fn DebugHTTPSServerPrototype__idSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn DebugHTTPSServerPrototype__idGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `DebugHTTPSServer.id` setter + /// This value will be visited by the garbage collector. + pub fn idSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + DebugHTTPSServerPrototype__idSetCachedValue(thisValue, globalObject, value); + } + + /// `DebugHTTPSServer.id` getter + /// This value will be visited by the garbage collector. + pub fn idGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = DebugHTTPSServerPrototype__idGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + /// Create a new instance of DebugHTTPSServer pub fn toJS(this: *DebugHTTPSServer, globalObject: *JSC.JSGlobalObject) JSC.JSValue { JSC.markBinding(@src()); @@ -1286,6 +1308,9 @@ pub const JSDebugHTTPSServer = struct { if (@TypeOf(DebugHTTPSServer.getHostname) != GetterType) @compileLog("Expected DebugHTTPSServer.getHostname to be a getter"); + if (@TypeOf(DebugHTTPSServer.getId) != GetterType) + @compileLog("Expected DebugHTTPSServer.getId to be a getter"); + if (@TypeOf(DebugHTTPSServer.getPendingRequests) != GetterType) @compileLog("Expected DebugHTTPSServer.getPendingRequests to be a getter"); @@ -1315,6 +1340,7 @@ pub const JSDebugHTTPSServer = struct { @export(DebugHTTPSServer.finalize, .{ .name = "DebugHTTPSServerClass__finalize" }); @export(DebugHTTPSServer.getDevelopment, .{ .name = "DebugHTTPSServerPrototype__getDevelopment" }); @export(DebugHTTPSServer.getHostname, .{ .name = "DebugHTTPSServerPrototype__getHostname" }); + @export(DebugHTTPSServer.getId, .{ .name = "DebugHTTPSServerPrototype__getId" }); @export(DebugHTTPSServer.getPendingRequests, .{ .name = "DebugHTTPSServerPrototype__getPendingRequests" }); @export(DebugHTTPSServer.getPendingWebSockets, .{ .name = "DebugHTTPSServerPrototype__getPendingWebSockets" }); @export(DebugHTTPSServer.getPort, .{ .name = "DebugHTTPSServerPrototype__getPort" }); @@ -1359,6 +1385,28 @@ pub const JSDebugHTTPServer = struct { return result; } + extern fn DebugHTTPServerPrototype__idSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn DebugHTTPServerPrototype__idGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `DebugHTTPServer.id` setter + /// This value will be visited by the garbage collector. + pub fn idSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + DebugHTTPServerPrototype__idSetCachedValue(thisValue, globalObject, value); + } + + /// `DebugHTTPServer.id` getter + /// This value will be visited by the garbage collector. + pub fn idGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = DebugHTTPServerPrototype__idGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + /// Create a new instance of DebugHTTPServer pub fn toJS(this: *DebugHTTPServer, globalObject: *JSC.JSGlobalObject) JSC.JSValue { JSC.markBinding(@src()); @@ -1403,6 +1451,9 @@ pub const JSDebugHTTPServer = struct { if (@TypeOf(DebugHTTPServer.getHostname) != GetterType) @compileLog("Expected DebugHTTPServer.getHostname to be a getter"); + if (@TypeOf(DebugHTTPServer.getId) != GetterType) + @compileLog("Expected DebugHTTPServer.getId to be a getter"); + if (@TypeOf(DebugHTTPServer.getPendingRequests) != GetterType) @compileLog("Expected DebugHTTPServer.getPendingRequests to be a getter"); @@ -1432,6 +1483,7 @@ pub const JSDebugHTTPServer = struct { @export(DebugHTTPServer.finalize, .{ .name = "DebugHTTPServerClass__finalize" }); @export(DebugHTTPServer.getDevelopment, .{ .name = "DebugHTTPServerPrototype__getDevelopment" }); @export(DebugHTTPServer.getHostname, .{ .name = "DebugHTTPServerPrototype__getHostname" }); + @export(DebugHTTPServer.getId, .{ .name = "DebugHTTPServerPrototype__getId" }); @export(DebugHTTPServer.getPendingRequests, .{ .name = "DebugHTTPServerPrototype__getPendingRequests" }); @export(DebugHTTPServer.getPendingWebSockets, .{ .name = "DebugHTTPServerPrototype__getPendingWebSockets" }); @export(DebugHTTPServer.getPort, .{ .name = "DebugHTTPServerPrototype__getPort" }); @@ -3059,6 +3111,28 @@ pub const JSHTTPSServer = struct { return result; } + extern fn HTTPSServerPrototype__idSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn HTTPSServerPrototype__idGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `HTTPSServer.id` setter + /// This value will be visited by the garbage collector. + pub fn idSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + HTTPSServerPrototype__idSetCachedValue(thisValue, globalObject, value); + } + + /// `HTTPSServer.id` getter + /// This value will be visited by the garbage collector. + pub fn idGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = HTTPSServerPrototype__idGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + /// Create a new instance of HTTPSServer pub fn toJS(this: *HTTPSServer, globalObject: *JSC.JSGlobalObject) JSC.JSValue { JSC.markBinding(@src()); @@ -3103,6 +3177,9 @@ pub const JSHTTPSServer = struct { if (@TypeOf(HTTPSServer.getHostname) != GetterType) @compileLog("Expected HTTPSServer.getHostname to be a getter"); + if (@TypeOf(HTTPSServer.getId) != GetterType) + @compileLog("Expected HTTPSServer.getId to be a getter"); + if (@TypeOf(HTTPSServer.getPendingRequests) != GetterType) @compileLog("Expected HTTPSServer.getPendingRequests to be a getter"); @@ -3132,6 +3209,7 @@ pub const JSHTTPSServer = struct { @export(HTTPSServer.finalize, .{ .name = "HTTPSServerClass__finalize" }); @export(HTTPSServer.getDevelopment, .{ .name = "HTTPSServerPrototype__getDevelopment" }); @export(HTTPSServer.getHostname, .{ .name = "HTTPSServerPrototype__getHostname" }); + @export(HTTPSServer.getId, .{ .name = "HTTPSServerPrototype__getId" }); @export(HTTPSServer.getPendingRequests, .{ .name = "HTTPSServerPrototype__getPendingRequests" }); @export(HTTPSServer.getPendingWebSockets, .{ .name = "HTTPSServerPrototype__getPendingWebSockets" }); @export(HTTPSServer.getPort, .{ .name = "HTTPSServerPrototype__getPort" }); @@ -3176,6 +3254,28 @@ pub const JSHTTPServer = struct { return result; } + extern fn HTTPServerPrototype__idSetCachedValue(JSC.JSValue, *JSC.JSGlobalObject, JSC.JSValue) void; + + extern fn HTTPServerPrototype__idGetCachedValue(JSC.JSValue) JSC.JSValue; + + /// `HTTPServer.id` setter + /// This value will be visited by the garbage collector. + pub fn idSetCached(thisValue: JSC.JSValue, globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) void { + JSC.markBinding(@src()); + HTTPServerPrototype__idSetCachedValue(thisValue, globalObject, value); + } + + /// `HTTPServer.id` getter + /// This value will be visited by the garbage collector. + pub fn idGetCached(thisValue: JSC.JSValue) ?JSC.JSValue { + JSC.markBinding(@src()); + const result = HTTPServerPrototype__idGetCachedValue(thisValue); + if (result == .zero) + return null; + + return result; + } + /// Create a new instance of HTTPServer pub fn toJS(this: *HTTPServer, globalObject: *JSC.JSGlobalObject) JSC.JSValue { JSC.markBinding(@src()); @@ -3220,6 +3320,9 @@ pub const JSHTTPServer = struct { if (@TypeOf(HTTPServer.getHostname) != GetterType) @compileLog("Expected HTTPServer.getHostname to be a getter"); + if (@TypeOf(HTTPServer.getId) != GetterType) + @compileLog("Expected HTTPServer.getId to be a getter"); + if (@TypeOf(HTTPServer.getPendingRequests) != GetterType) @compileLog("Expected HTTPServer.getPendingRequests to be a getter"); @@ -3249,6 +3352,7 @@ pub const JSHTTPServer = struct { @export(HTTPServer.finalize, .{ .name = "HTTPServerClass__finalize" }); @export(HTTPServer.getDevelopment, .{ .name = "HTTPServerPrototype__getDevelopment" }); @export(HTTPServer.getHostname, .{ .name = "HTTPServerPrototype__getHostname" }); + @export(HTTPServer.getId, .{ .name = "HTTPServerPrototype__getId" }); @export(HTTPServer.getPendingRequests, .{ .name = "HTTPServerPrototype__getPendingRequests" }); @export(HTTPServer.getPendingWebSockets, .{ .name = "HTTPServerPrototype__getPendingWebSockets" }); @export(HTTPServer.getPort, .{ .name = "HTTPServerPrototype__getPort" }); diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 01f6383af..fc2bd7a05 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -766,6 +766,14 @@ pub const VirtualMachine = struct { return debugger.next_debugger_id; } + pub fn hotMap(this: *VirtualMachine) ?*JSC.RareData.HotMap { + if (this.hot_reload != .hot) { + return null; + } + + return this.rareData().hotMap(this.allocator); + } + pub var has_created_debugger: bool = false; pub const Debugger = struct { diff --git a/src/bun.js/rare_data.zig b/src/bun.js/rare_data.zig index 216b56eda..ab9cc9ea4 100644 --- a/src/bun.js/rare_data.zig +++ b/src/bun.js/rare_data.zig @@ -19,6 +19,8 @@ stdout_store: ?*Blob.Store = null, entropy_cache: ?*EntropyCache = null, +hot_map: ?HotMap = null, + // TODO: make this per JSGlobalObject instead of global // This does not handle ShadowRealm correctly! tail_cleanup_hook: ?*CleanupHook = null, @@ -30,6 +32,14 @@ global_dns_data: ?*JSC.DNS.GlobalData = null, mime_types: ?bun.HTTP.MimeType.Map = null, +pub fn hotMap(this: *RareData, allocator: std.mem.Allocator) *HotMap { + if (this.hot_map == null) { + this.hot_map = HotMap.init(allocator); + } + + return &this.hot_map.?; +} + pub fn mimeTypeFromString(this: *RareData, allocator: std.mem.Allocator, str: []const u8) ?bun.HTTP.MimeType { if (this.mime_types == null) { this.mime_types = bun.HTTP.MimeType.createHashTable( @@ -40,6 +50,58 @@ pub fn mimeTypeFromString(this: *RareData, allocator: std.mem.Allocator, str: [] return this.mime_types.?.get(str); } +pub const HotMap = struct { + _map: bun.StringArrayHashMap(Entry), + + const HTTPServer = JSC.API.HTTPServer; + const HTTPSServer = JSC.API.HTTPSServer; + const DebugHTTPServer = JSC.API.DebugHTTPServer; + const DebugHTTPSServer = JSC.API.DebugHTTPSServer; + const TCPSocket = JSC.API.TCPSocket; + const TLSSocket = JSC.API.TLSSocket; + const Listener = JSC.API.Listener; + const Entry = bun.TaggedPointerUnion(.{ + HTTPServer, + HTTPSServer, + DebugHTTPServer, + DebugHTTPSServer, + TCPSocket, + TLSSocket, + Listener, + }); + + pub fn init(allocator: std.mem.Allocator) HotMap { + return .{ + ._map = bun.StringArrayHashMap(Entry).init(allocator), + }; + } + + pub fn get(this: *HotMap, key: []const u8, comptime Type: type) ?*Type { + var entry = this._map.get(key) orelse return null; + return entry.get(Type); + } + + pub fn getEntry(this: *HotMap, key: []const u8) ?Entry { + return this._map.get(key) orelse return null; + } + + pub fn insert(this: *HotMap, key: []const u8, ptr: anytype) void { + var entry = this._map.getOrPut(key) catch @panic("Out of memory"); + if (entry.found_existing) { + @panic("HotMap already contains key"); + } + + entry.key_ptr.* = this._map.allocator.dupe(u8, key) catch @panic("Out of memory"); + entry.value_ptr.* = Entry.init(ptr); + } + + pub fn remove(this: *HotMap, key: []const u8) void { + var entry = this._map.getEntry(key) orelse return; + bun.default_allocator.free(entry.key_ptr.*); + _ = this._map.orderedRemove(key); + } +}; + pub fn filePolls(this: *RareData, vm: *JSC.VirtualMachine) *JSC.FilePoll.HiveArray { return this.file_polls_ orelse { this.file_polls_ = vm.allocator.create(JSC.FilePoll.HiveArray) catch unreachable; |