aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js')
-rw-r--r--src/bun.js/api/bun.classes.ts5
-rw-r--r--src/bun.js/api/bun.zig1
-rw-r--r--src/bun.js/api/bun/subprocess.zig159
-rw-r--r--src/bun.js/bindings/CommonJSModuleRecord.cpp8
-rw-r--r--src/bun.js/bindings/ImportMetaObject.cpp14
-rw-r--r--src/bun.js/bindings/JSBuffer.cpp67
-rw-r--r--src/bun.js/bindings/JSReadableHelper.cpp263
-rw-r--r--src/bun.js/bindings/JSReadableHelper.h13
-rw-r--r--src/bun.js/bindings/JSReadableState.cpp426
-rw-r--r--src/bun.js/bindings/JSReadableState.h154
-rw-r--r--src/bun.js/bindings/Process.cpp78
-rw-r--r--src/bun.js/bindings/Process.lut.h233
-rw-r--r--src/bun.js/bindings/Serialization.cpp49
-rw-r--r--src/bun.js/bindings/ZigGeneratedClasses.cpp32
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.cpp64
-rw-r--r--src/bun.js/bindings/ZigGlobalObject.h13
-rw-r--r--src/bun.js/bindings/bindings.zig7
-rw-r--r--src/bun.js/bindings/generated_classes.zig3
-rw-r--r--src/bun.js/bindings/webcore/EventEmitter.h2
-rw-r--r--src/bun.js/ipc.zig238
-rw-r--r--src/bun.js/javascript.zig127
-rw-r--r--src/bun.js/module_loader.zig366
-rw-r--r--src/bun.js/modules/NodeModuleModule.h44
-rw-r--r--src/bun.js/node/node_fs_watcher.zig11
-rw-r--r--src/bun.js/node/types.zig2
-rw-r--r--src/bun.js/rare_data.zig18
26 files changed, 1159 insertions, 1238 deletions
diff --git a/src/bun.js/api/bun.classes.ts b/src/bun.js/api/bun.classes.ts
index 6d8e80b6d..36f48f790 100644
--- a/src/bun.js/api/bun.classes.ts
+++ b/src/bun.js/api/bun.classes.ts
@@ -44,6 +44,11 @@ export default [
length: 0,
},
+ send: {
+ fn: "doSend",
+ length: 1,
+ },
+
kill: {
fn: "kill",
length: 1,
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig
index f86031caf..36e52821f 100644
--- a/src/bun.js/api/bun.zig
+++ b/src/bun.js/api/bun.zig
@@ -4426,6 +4426,7 @@ pub const EnvironmentVariables = struct {
}
return len;
}
+
pub fn getEnvValue(globalObject: *JSC.JSGlobalObject, name: ZigString) ?ZigString {
var vm = globalObject.bunVM();
var sliced = name.toSlice(vm.allocator);
diff --git a/src/bun.js/api/bun/subprocess.zig b/src/bun.js/api/bun/subprocess.zig
index c3244131d..50bd846ac 100644
--- a/src/bun.js/api/bun/subprocess.zig
+++ b/src/bun.js/api/bun/subprocess.zig
@@ -1,4 +1,3 @@
-const Bun = @This();
const default_allocator = @import("root").bun.default_allocator;
const bun = @import("root").bun;
const Environment = bun.Environment;
@@ -14,6 +13,8 @@ const JSC = @import("root").bun.JSC;
const JSValue = JSC.JSValue;
const JSGlobalObject = JSC.JSGlobalObject;
const Which = @import("../../../which.zig");
+const uws = @import("../../../deps/uws.zig");
+const IPC = @import("../../ipc.zig");
pub const Subprocess = struct {
const log = Output.scoped(.Subprocess, false);
@@ -61,15 +62,27 @@ pub const Subprocess = struct {
is_sync: bool = false,
this_jsvalue: JSC.JSValue = .zero,
+ ipc: IPCMode,
+ // this is only ever accessed when `ipc` is not `none`
+ ipc_socket: IPC.Socket = undefined,
+ ipc_callback: JSC.Strong = .{},
+ ipc_buffer: bun.ByteList,
+
pub const SignalCode = bun.SignalCode;
+ pub const IPCMode = enum {
+ none,
+ bun,
+ // json,
+ };
+
pub fn hasExited(this: *const Subprocess) bool {
return this.exit_code != null or this.waitpid_err != null or this.signal_code != null;
}
pub fn updateHasPendingActivityFlag(this: *Subprocess) void {
@fence(.SeqCst);
- this.has_pending_activity.store(this.waitpid_err == null and this.exit_code == null, .SeqCst);
+ this.has_pending_activity.store(this.waitpid_err == null and this.exit_code == null and this.ipc == .none, .SeqCst);
}
pub fn hasPendingActivity(this: *Subprocess) callconv(.C) bool {
@@ -79,7 +92,7 @@ pub const Subprocess = struct {
pub fn updateHasPendingActivity(this: *Subprocess) void {
@fence(.Release);
- this.has_pending_activity.store(this.waitpid_err == null and this.exit_code == null, .Release);
+ this.has_pending_activity.store(this.waitpid_err == null and this.exit_code == null and this.ipc == .none, .Release);
}
pub fn ref(this: *Subprocess) void {
@@ -411,6 +424,35 @@ pub const Subprocess = struct {
return JSC.JSValue.jsUndefined();
}
+ pub fn doSend(this: *Subprocess, global: *JSC.JSGlobalObject, callFrame: *JSC.CallFrame) callconv(.C) JSValue {
+ if (this.ipc == .none) {
+ global.throw("Subprocess.send() can only be used if an IPC channel is open.", .{});
+ return .zero;
+ }
+
+ if (callFrame.argumentsCount() == 0) {
+ global.throwInvalidArguments("Subprocess.send() requires one argument", .{});
+ return .zero;
+ }
+
+ const value = callFrame.argument(0);
+
+ const success = IPC.serializeJSValueForSubprocess(
+ global,
+ value,
+ this.ipc_socket.fd(),
+ );
+ if (!success) return .zero;
+
+ return JSC.JSValue.jsUndefined();
+ }
+
+ pub fn disconnect(this: *Subprocess) void {
+ if (this.ipc == .none) return;
+ this.ipc_socket.close(0, null);
+ this.ipc = .none;
+ }
+
pub fn getPid(
this: *Subprocess,
_: *JSGlobalObject,
@@ -1070,8 +1112,11 @@ pub const Subprocess = struct {
var PATH = jsc_vm.bundler.env.get("PATH") orelse "";
var argv: std.ArrayListUnmanaged(?[*:0]const u8) = undefined;
var cmd_value = JSValue.zero;
- var detached: bool = false;
+ var detached = false;
var args = args_;
+ var ipc_mode = IPCMode.none;
+ var ipc_callback: JSValue = .zero;
+
{
if (args.isEmptyOrUndefinedOrNull()) {
globalThis.throwInvalidArguments("cmd must be an array", .{});
@@ -1164,7 +1209,11 @@ pub const Subprocess = struct {
globalThis.throwInvalidArguments("onExit must be a function or undefined", .{});
return .zero;
}
- on_exit_callback = onExit_.withAsyncContextIfNeeded(globalThis);
+
+ on_exit_callback = if (comptime is_sync)
+ onExit_
+ else
+ onExit_.withAsyncContextIfNeeded(globalThis);
}
}
@@ -1186,8 +1235,13 @@ pub const Subprocess = struct {
return .zero;
};
+ // If the env object does not include a $PATH, it must disable path lookup for argv[0]
+ PATH = "";
+
while (object_iter.next()) |key| {
var value = object_iter.value;
+ if (value == .undefined) continue;
+
var line = std.fmt.allocPrintZ(allocator, "{}={}", .{ key, value.getZigString(globalThis) }) catch {
globalThis.throw("out of memory", .{});
return .zero;
@@ -1209,7 +1263,7 @@ pub const Subprocess = struct {
if (!stdio_val.isEmptyOrUndefinedOrNull()) {
if (stdio_val.jsType().isArray()) {
var stdio_iter = stdio_val.arrayIterator(globalThis);
- stdio_iter.len = @min(stdio_iter.len, 3);
+ stdio_iter.len = @min(stdio_iter.len, 4);
var i: u32 = 0;
while (stdio_iter.next()) |value| : (i += 1) {
if (!extractStdio(globalThis, i, value, &stdio))
@@ -1250,6 +1304,15 @@ pub const Subprocess = struct {
detached = detached_val.toBoolean();
}
}
+
+ if (args.get(globalThis, "ipc")) |val| {
+ if (val.isCell() and val.isCallable(globalThis.vm())) {
+ // In the future, we should add a way to use a different IPC serialization format, specifically `json`.
+ // but the only use case this has is doing interop with node.js IPC and other programs.
+ ipc_mode = .bun;
+ ipc_callback = val.withAsyncContextIfNeeded(globalThis);
+ }
+ }
}
}
@@ -1328,6 +1391,42 @@ pub const Subprocess = struct {
return .zero;
};
+ // IPC is currently implemented in a very limited way.
+ //
+ // Node lets you pass as many fds as you want, they all become be sockets; then, IPC is just a special
+ // runtime-owned version of "pipe" (in which pipe is a misleading name since they're bidirectional sockets).
+ //
+ // Bun currently only supports three fds: stdin, stdout, and stderr, which are all unidirectional
+ //
+ // And then fd 3 is assigned specifically and only for IPC. This is quite lame, because Node.js allows
+ // the ipc fd to be any number and it just works. But most people only care about the default `.fork()`
+ // behavior, where this workaround suffices.
+ //
+ // When Bun.spawn() is given a `.onMessage` callback, it enables IPC as follows:
+ var socket: IPC.Socket = undefined;
+ if (ipc_mode != .none) {
+ if (comptime is_sync) {
+ globalThis.throwInvalidArguments("IPC is not supported in Bun.spawnSync", .{});
+ return .zero;
+ }
+
+ env_array.ensureUnusedCapacity(allocator, 2) catch |err| return globalThis.handleError(err, "in posix_spawn");
+ env_array.appendAssumeCapacity("BUN_INTERNAL_IPC_FD=3");
+
+ var fds: [2]uws.LIBUS_SOCKET_DESCRIPTOR = undefined;
+ socket = uws.newSocketFromPair(
+ jsc_vm.rareData().spawnIPCContext(jsc_vm),
+ @sizeOf(*Subprocess),
+ &fds,
+ ) orelse {
+ globalThis.throw("failed to create socket pair: E{s}", .{
+ @tagName(bun.sys.getErrno(-1)),
+ });
+ return .zero;
+ };
+ actions.dup2(fds[1], 3) catch |err| return globalThis.handleError(err, "in posix_spawn");
+ }
+
env_array.append(allocator, null) catch {
globalThis.throw("out of memory", .{});
return .zero;
@@ -1389,7 +1488,6 @@ pub const Subprocess = struct {
globalThis.throw("out of memory", .{});
return .zero;
};
-
// When run synchronously, subprocess isn't garbage collected
subprocess.* = Subprocess{
.globalThis = globalThis,
@@ -1404,7 +1502,16 @@ pub const Subprocess = struct {
.stderr = Readable.init(stdio[bun.STDERR_FD], stderr_pipe[0], jsc_vm.allocator, default_max_buffer_size),
.on_exit_callback = if (on_exit_callback != .zero) JSC.Strong.create(on_exit_callback, globalThis) else .{},
.is_sync = is_sync,
+ .ipc = ipc_mode,
+ // will be assigned in the block below
+ .ipc_socket = socket,
+ .ipc_buffer = bun.ByteList{},
+ .ipc_callback = if (ipc_callback != .zero) JSC.Strong.create(ipc_callback, globalThis) else undefined,
};
+ if (ipc_mode != .none) {
+ var ptr = socket.ext(*Subprocess);
+ ptr.?.* = subprocess;
+ }
if (subprocess.stdin == .pipe) {
subprocess.stdin.pipe.signal = JSC.WebCore.Signal.init(&subprocess.stdin);
@@ -1610,6 +1717,7 @@ pub const Subprocess = struct {
globalThis: *JSC.JSGlobalObject,
this_jsvalue: JSC.JSValue,
) void {
+ log("onExit {d}, code={d}", .{ this.pid, if (this.exit_code) |e| @as(i32, @intCast(e)) else -1 });
defer this.updateHasPendingActivity();
this_jsvalue.ensureStillAlive();
this.has_waitpid_task = false;
@@ -1715,7 +1823,6 @@ pub const Subprocess = struct {
try actions.dup2(std_fileno, std_fileno);
}
},
-
.ignore => {
const flag = if (std_fileno == bun.STDIN_FD) @as(u32, os.O.RDONLY) else @as(u32, std.os.O.WRONLY);
try actions.openZ(std_fileno, "/dev/null", flag, 0o664);
@@ -1867,10 +1974,46 @@ pub const Subprocess = struct {
.held = JSC.Strong.create(array_buffer.value, globalThis),
},
};
+
return true;
}
globalThis.throwInvalidArguments("stdio must be an array of 'inherit', 'ignore', or null", .{});
return false;
}
+
+ pub fn handleIPCMessage(
+ this: *Subprocess,
+ message: IPC.DecodedIPCMessage,
+ ) void {
+ switch (message) {
+ // In future versions we can read this in order to detect version mismatches,
+ // or disable future optimizations if the subprocess is old.
+ .version => |v| {
+ IPC.log("Child IPC version is {d}", .{v});
+ },
+ .data => |data| {
+ IPC.log("Received IPC message from child", .{});
+ if (this.ipc_callback.get()) |cb| {
+ const result = cb.callWithThis(
+ this.globalThis,
+ this.this_jsvalue,
+ &[_]JSValue{data},
+ );
+ data.ensureStillAlive();
+ if (result.isAnyError()) {
+ this.globalThis.bunVM().onUnhandledError(this.globalThis, result);
+ }
+ }
+ },
+ }
+ }
+
+ pub fn handleIPCClose(this: *Subprocess, _: IPC.Socket) void {
+ // uSocket is already freed so calling .close() on the socket can segfault
+ this.ipc = .none;
+ this.updateHasPendingActivity();
+ }
+
+ pub const IPCHandler = IPC.NewIPCHandler(Subprocess);
};
diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp
index a1f5781d7..b94386ab3 100644
--- a/src/bun.js/bindings/CommonJSModuleRecord.cpp
+++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp
@@ -230,7 +230,13 @@ void RequireFunctionPrototype::finishCreation(JSC::VM& vm)
JSC::Identifier::fromString(vm, "main"_s),
JSC::GetterSetter::create(vm, globalObject(), requireDotMainFunction, JSValue()),
PropertyAttribute::Builtin | PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | 0);
- this->putDirect(vm, JSC::Identifier::fromString(vm, "extensions"_s), constructEmptyObject(globalObject()), 0);
+
+ auto extensions = constructEmptyObject(globalObject());
+ extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".js"_s), jsBoolean(true), 0);
+ extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".json"_s), jsBoolean(true), 0);
+ extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".node"_s), jsBoolean(true), 0);
+
+ this->putDirect(vm, JSC::Identifier::fromString(vm, "extensions"_s), extensions, 0);
}
JSC_DEFINE_CUSTOM_GETTER(getterFilename, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName))
diff --git a/src/bun.js/bindings/ImportMetaObject.cpp b/src/bun.js/bindings/ImportMetaObject.cpp
index 328b9f940..c53235824 100644
--- a/src/bun.js/bindings/ImportMetaObject.cpp
+++ b/src/bun.js/bindings/ImportMetaObject.cpp
@@ -239,6 +239,20 @@ extern "C" EncodedJSValue functionImportMeta__resolveSyncPrivate(JSC::JSGlobalOb
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::JSValue {}));
+ if (!isESM) {
+ auto* global = jsDynamicCast<Zig::GlobalObject*>(globalObject);
+ if (LIKELY(global)) {
+ auto overrideHandler = global->m_nodeModuleOverriddenResolveFilename.get();
+ if (UNLIKELY(overrideHandler)) {
+ ASSERT(overrideHandler.isCallable(globalObject));
+ MarkedArgumentBuffer args;
+ args.append(moduleName);
+ args.append(from);
+ return JSValue::encode(JSC::call(globalObject, overrideHandler, JSC::getCallData(overrideHandler), JSC::jsUndefined(), args));
+ }
+ }
+ }
+
auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), JSValue::encode(from), isESM);
if (!JSC::JSValue::decode(result).isString()) {
diff --git a/src/bun.js/bindings/JSBuffer.cpp b/src/bun.js/bindings/JSBuffer.cpp
index 934fc9b6c..ad901b0e4 100644
--- a/src/bun.js/bindings/JSBuffer.cpp
+++ b/src/bun.js/bindings/JSBuffer.cpp
@@ -1429,12 +1429,12 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JS
{
auto& vm = JSC::getVM(lexicalGlobalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
- uint32_t offset = 0;
- uint32_t length = castedThis->length();
- uint32_t byteLength = length;
+ uint32_t start = 0;
+ uint32_t end = castedThis->length();
+ uint32_t byteLength = end;
WebCore::BufferEncodingType encoding = WebCore::BufferEncodingType::utf8;
- if (length == 0)
+ if (end == 0)
return JSC::JSValue::encode(JSC::jsEmptyString(vm));
size_t argsCount = callFrame->argumentCount();
@@ -1443,66 +1443,33 @@ static inline JSC::EncodedJSValue jsBufferPrototypeFunction_toStringBody(JSC::JS
JSC::JSValue arg2 = callFrame->argument(1);
JSC::JSValue arg3 = callFrame->argument(2);
- // This method could be called in following forms:
- // - toString()
- // - toString(encoding)
- // - toString(encoding, start)
- // - toString(encoding, start, end)
- // - toString(offset, length)
- // - toString(offset, length, encoding)
if (argsCount == 0)
- return jsBufferToString(vm, lexicalGlobalObject, castedThis, offset, length, encoding);
+ return jsBufferToString(vm, lexicalGlobalObject, castedThis, start, end, encoding);
- if (arg1.isString()) {
+ if (!arg1.isUndefined()) {
encoding = parseEncoding(lexicalGlobalObject, scope, arg1);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined()));
+ }
- if (!arg3.isUndefined()) {
- // length is end
- length = std::min(byteLength, static_cast<uint32_t>(arg3.toInt32(lexicalGlobalObject)));
- RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined()));
- }
-
- int32_t istart = 0;
-
- if (!arg2.isUndefined()) {
- istart = arg2.toInt32(lexicalGlobalObject);
- RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined()));
- }
+ if (!arg2.isUndefined()) {
+ int32_t istart = arg2.toInt32(lexicalGlobalObject);
+ RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined()));
if (istart < 0) {
throwTypeError(lexicalGlobalObject, scope, "Start must be a positive integer"_s);
return JSC::JSValue::encode(jsUndefined());
}
- offset = static_cast<uint32_t>(istart);
- length = (length > offset) ? (length - offset) : 0;
- } else {
-
- int32_t ioffset = 0;
-
- if (!arg1.isUndefined()) {
- ioffset = arg1.toInt32(lexicalGlobalObject);
- RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined()));
- }
-
- if (ioffset < 0) {
- throwTypeError(lexicalGlobalObject, scope, "Offset must be a positive integer"_s);
- return JSC::JSValue::encode(jsUndefined());
- }
- offset = static_cast<uint32_t>(ioffset);
- length = (length > offset) ? (length - offset) : 0;
-
- if (!arg3.isUndefined()) {
- encoding = parseEncoding(lexicalGlobalObject, scope, arg3);
- RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined()));
- }
+ start = static_cast<uint32_t>(istart);
+ }
- if (!arg2.isUndefined())
- length = std::min(length, static_cast<uint32_t>(arg2.toInt32(lexicalGlobalObject)));
+ if (!arg3.isUndefined()) {
+ // length is end
+ end = std::min(byteLength, static_cast<uint32_t>(arg3.toInt32(lexicalGlobalObject)));
+ RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(jsUndefined()));
}
- return jsBufferToString(vm, lexicalGlobalObject, castedThis, offset, length, encoding);
+ return jsBufferToString(vm, lexicalGlobalObject, castedThis, start, end > start ? end - start : 0, encoding);
}
// DOMJIT makes it slower! TODO: investigate why
diff --git a/src/bun.js/bindings/JSReadableHelper.cpp b/src/bun.js/bindings/JSReadableHelper.cpp
deleted file mode 100644
index 0c459f329..000000000
--- a/src/bun.js/bindings/JSReadableHelper.cpp
+++ /dev/null
@@ -1,263 +0,0 @@
-#include "JSReadableHelper.h"
-#include "JSReadableState.h"
-#include "JSBufferList.h"
-#include "JSBuffer.h"
-#include "JSEventEmitter.h"
-#include "JSStringDecoder.h"
-#include "JavaScriptCore/Lookup.h"
-#include "JavaScriptCore/ObjectConstructor.h"
-#include "ZigGlobalObject.h"
-#include "JSDOMOperation.h"
-#include "JSDOMAttribute.h"
-#include "headers.h"
-#include "JSDOMConvertEnumeration.h"
-#include "JavaScriptCore/StrongInlines.h"
-#include "BunClientData.h"
-
-namespace WebCore {
-using namespace JSC;
-
-#define JSReadableHelper_EXTRACT_STREAM_STATE \
- VM& vm = lexicalGlobalObject->vm(); \
- auto throwScope = DECLARE_THROW_SCOPE(vm); \
- \
- if (callFrame->argumentCount() < 2) { \
- throwTypeError(lexicalGlobalObject, throwScope, "Not enough arguments"_s); \
- return JSValue::encode(jsUndefined()); \
- } \
- \
- JSObject* stream = callFrame->uncheckedArgument(0).toObject(lexicalGlobalObject); \
- RETURN_IF_EXCEPTION(throwScope, JSValue::encode(jsUndefined())); \
- JSReadableState* state = jsCast<JSReadableState*>(callFrame->uncheckedArgument(1)); \
- if (!state) { \
- throwTypeError(lexicalGlobalObject, throwScope, "Second argument not ReadableState"_s); \
- return JSValue::encode(jsUndefined()); \
- }
-
-static bool callRead(JSValue stream, JSFunction* read, JSC::MarkedArgumentBuffer&& args, JSC::VM& vm, JSC::JSGlobalObject* lexicalGlobalObject, EventEmitter& emitter)
-{
- WTF::NakedPtr<JSC::Exception> exceptionPtr;
- JSC::CallData callData = JSC::getCallData(read);
- JSValue ret = call(lexicalGlobalObject, read, callData, JSValue(stream), WTFMove(args), exceptionPtr);
- if (auto* exception = exceptionPtr.get()) {
- JSC::Identifier errorEventName = JSC::Identifier::fromString(vm, "error"_s);
- if (emitter.hasEventListeners(errorEventName)) {
- args.clear();
- JSValue val = exception->value();
- if (!val) {
- val = jsUndefined();
- }
- args.append(val);
- emitter.emitForBindings(errorEventName, args);
- } else {
- reportException(lexicalGlobalObject, exception);
- }
- return true;
- }
-
- return !ret.isUndefinedOrNull();
-}
-
-JSC_DEFINE_HOST_FUNCTION(jsReadable_maybeReadMore, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
-{
- JSReadableHelper_EXTRACT_STREAM_STATE
-
- auto clientData
- = WebCore::clientData(vm);
- auto readIdentifier = clientData->builtinNames().readPublicName();
- auto read = stream->get(lexicalGlobalObject, readIdentifier);
-
- auto callData = JSC::getCallData(read);
- if (callData.type == CallData::Type::None) {
- throwException(lexicalGlobalObject, throwScope, createNotAFunctionError(lexicalGlobalObject, read));
- return JSValue::encode({});
- }
-
- auto* jsEmitter = jsEventEmitterCastFast(vm, lexicalGlobalObject, stream);
- RETURN_IF_EXCEPTION(throwScope, {});
- if (UNLIKELY(!jsEmitter)) {
- throwTypeError(lexicalGlobalObject, throwScope, "Stream must be an EventEmitter"_s);
- return JSValue::encode(JSValue {});
- }
- auto& emitter = jsEmitter->wrapped();
-
- while (
- !state->getBool(JSReadableState::reading) && !state->getBool(JSReadableState::ended) && (state->m_length < state->m_highWaterMark || (state->m_flowing > 0 && state->m_length == 0))) {
- int64_t len = state->m_length;
- MarkedArgumentBuffer args;
- args.append(jsNumber(0));
-
- callRead(stream, jsCast<JSFunction*>(read), WTFMove(args), vm, lexicalGlobalObject, emitter);
-
- if (len == state->m_length)
- break;
- }
- RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined()));
-}
-
-void flow(JSGlobalObject* lexicalGlobalObject, JSObject* streamObj, JSReadableState* state)
-{
- VM& vm = lexicalGlobalObject->vm();
- auto throwScope = DECLARE_THROW_SCOPE(vm);
-
- auto clientData = WebCore::clientData(vm);
- auto readIdentifier = clientData->builtinNames().readPublicName();
- auto read = streamObj->get(lexicalGlobalObject, readIdentifier);
-
- auto callData = JSC::getCallData(read);
- if (callData.type == CallData::Type::None) {
- throwException(lexicalGlobalObject, throwScope, createNotAFunctionError(lexicalGlobalObject, read));
- return;
- }
-
- if (state->m_flowing > 0) {
- WebCore::EventEmitter& emitter = jsEventEmitterCastFast(vm, lexicalGlobalObject, streamObj)->wrapped();
-
- while (state->m_flowing > 0) {
-
- if (!callRead(streamObj, jsCast<JSFunction*>(read), MarkedArgumentBuffer(), vm, lexicalGlobalObject, emitter)) {
- break;
- }
- }
- }
-}
-
-JSC_DEFINE_HOST_FUNCTION(jsReadable_resume, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
-{
- JSReadableHelper_EXTRACT_STREAM_STATE
-
- auto* jsEmitterWrap
- = jsEventEmitterCastFast(vm, lexicalGlobalObject, stream);
-
- if (UNLIKELY(!jsEmitterWrap)) {
- throwTypeError(lexicalGlobalObject, throwScope, "Stream must be an EventEmitter"_s);
- return JSValue::encode(JSValue {});
- }
-
- auto& emitter = jsEmitterWrap->wrapped();
- auto clientData = WebCore::clientData(vm);
- auto readIdentifier = clientData->builtinNames().readPublicName();
-
- if (!state->getBool(JSReadableState::reading)) {
- // stream.read(0)
- MarkedArgumentBuffer args;
- args.append(jsNumber(0));
-
- callRead(stream, jsCast<JSFunction*>(stream->get(lexicalGlobalObject, readIdentifier)), WTFMove(args), vm, lexicalGlobalObject, emitter);
- }
-
- state->setBool(JSReadableState::resumeScheduled, true);
- // stream.emit('resume')
- auto eventType = clientData->builtinNames().resumePublicName();
- MarkedArgumentBuffer args;
-
- emitter.emitForBindings(eventType, args);
-
- flow(lexicalGlobalObject, stream, state);
-
- if (state->m_flowing > 0 && !state->getBool(JSReadableState::reading)) {
- // stream.read(0)
- auto read = stream->get(lexicalGlobalObject, readIdentifier);
- auto callData = JSC::getCallData(read);
- if (callData.type == CallData::Type::None) {
- throwException(lexicalGlobalObject, throwScope, createNotAFunctionError(lexicalGlobalObject, read));
- return JSValue::encode(jsUndefined());
- }
- MarkedArgumentBuffer args;
- args.append(jsNumber(0));
- callRead(stream, jsCast<JSFunction*>(read), WTFMove(args), vm, lexicalGlobalObject, emitter);
- }
- RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined()));
-}
-
-EncodedJSValue emitReadable_(JSGlobalObject* lexicalGlobalObject, JSObject* stream, JSReadableState* state)
-{
- VM& vm = lexicalGlobalObject->vm();
- auto throwScope = DECLARE_THROW_SCOPE(vm);
- JSValue errored = state->m_errored.get();
- if (!state->getBool(JSReadableState::destroyed) && !errored.toBoolean(lexicalGlobalObject) && (state->m_length || state->getBool(JSReadableState::ended))) {
- // stream.emit('readable')
- auto clientData = WebCore::clientData(vm);
-
- auto eventType = clientData->builtinNames().readablePublicName();
- MarkedArgumentBuffer args;
- auto* emitter
- = jsEventEmitterCastFast(vm, lexicalGlobalObject, stream);
- if (UNLIKELY(!emitter)) {
- throwTypeError(lexicalGlobalObject, throwScope, "Stream must be an EventEmitter"_s);
- return JSValue::encode(JSValue {});
- }
- emitter->wrapped().emitForBindings(eventType, args);
-
- state->setBool(JSReadableState::emittedReadable, false);
- }
-
- state->setBool(JSReadableState::needReadable, state->m_flowing <= 0 && !state->getBool(JSReadableState::ended) && state->m_length <= state->m_highWaterMark);
- flow(lexicalGlobalObject, stream, state);
- return JSValue::encode(jsUndefined());
-}
-
-JSC_DEFINE_HOST_FUNCTION(jsReadable_emitReadable_, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
-{
- JSReadableHelper_EXTRACT_STREAM_STATE
-
- emitReadable_(lexicalGlobalObject, stream, state);
-
- RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined()));
-}
-
-EncodedJSValue emitReadable(JSGlobalObject* lexicalGlobalObject, JSObject* stream, JSReadableState* state)
-{
- VM& vm = lexicalGlobalObject->vm();
-
- state->setBool(JSReadableState::needReadable, false);
- if (!state->getBool(JSReadableState::emittedReadable)) {
- state->setBool(JSReadableState::emittedReadable, true);
- Zig::GlobalObject* globalObject = reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject);
- globalObject->queueMicrotask(JSValue(globalObject->emitReadableNextTickFunction()), JSValue(stream), JSValue(state), JSValue {}, JSValue {});
- }
- return JSValue::encode(jsUndefined());
-}
-
-JSC_DEFINE_HOST_FUNCTION(jsReadable_emitReadable, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
-{
- JSReadableHelper_EXTRACT_STREAM_STATE
-
- RELEASE_AND_RETURN(throwScope, emitReadable(lexicalGlobalObject, stream, state));
-}
-
-JSC_DEFINE_HOST_FUNCTION(jsReadable_onEofChunk, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
-{
- JSReadableHelper_EXTRACT_STREAM_STATE
-
- if (state->getBool(JSReadableState::ended))
- RELEASE_AND_RETURN(throwScope, JSValue::encode(jsUndefined()));
-
- auto decoder = jsDynamicCast<JSStringDecoder*>(state->m_decoder.get());
- if (decoder) {
- JSString* chunk = jsDynamicCast<JSString*>(decoder->end(vm, lexicalGlobalObject, nullptr, 0));
- if (chunk && chunk->length()) {
- auto buffer = jsDynamicCast<JSBufferList*>(state->m_buffer.get());
- if (!buffer) {
- throwTypeError(lexicalGlobalObject, throwScope, "Not buffer on stream"_s);
- return JSValue::encode(jsUndefined());
- }
- buffer->push(vm, JSValue(chunk));
- state->m_length += state->getBool(JSReadableState::objectMode) ? 1 : chunk->length();
- }
- }
-
- state->setBool(JSReadableState::ended, true);
-
- if (state->getBool(JSReadableState::sync)) {
- RELEASE_AND_RETURN(throwScope, emitReadable(lexicalGlobalObject, stream, state));
- } else {
- state->setBool(JSReadableState::needReadable, false);
- state->setBool(JSReadableState::emittedReadable, true);
- RELEASE_AND_RETURN(throwScope, emitReadable_(lexicalGlobalObject, stream, state));
- }
-}
-
-#undef JSReadableHelper_EXTRACT_STREAM_STATE
-
-} // namespace WebCore
diff --git a/src/bun.js/bindings/JSReadableHelper.h b/src/bun.js/bindings/JSReadableHelper.h
deleted file mode 100644
index 3e2554c2b..000000000
--- a/src/bun.js/bindings/JSReadableHelper.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-#include "root.h"
-
-namespace WebCore {
-
-JSC_DECLARE_HOST_FUNCTION(jsReadable_maybeReadMore);
-JSC_DECLARE_HOST_FUNCTION(jsReadable_resume);
-JSC_DECLARE_HOST_FUNCTION(jsReadable_emitReadable);
-JSC_DECLARE_HOST_FUNCTION(jsReadable_onEofChunk);
-JSC_DECLARE_HOST_FUNCTION(jsReadable_emitReadable_);
-
-} // namespace WebCore
diff --git a/src/bun.js/bindings/JSReadableState.cpp b/src/bun.js/bindings/JSReadableState.cpp
deleted file mode 100644
index 1f3a36def..000000000
--- a/src/bun.js/bindings/JSReadableState.cpp
+++ /dev/null
@@ -1,426 +0,0 @@
-#include "JSReadableState.h"
-#include "JSBufferList.h"
-#include "JSBuffer.h"
-#include "JavaScriptCore/Lookup.h"
-#include "JavaScriptCore/ObjectConstructor.h"
-#include "ZigGlobalObject.h"
-#include "JSDOMOperation.h"
-#include "JSDOMAttribute.h"
-#include "headers.h"
-#include "JSDOMConvertEnumeration.h"
-#include "BunClientData.h"
-
-namespace WebCore {
-
-using namespace JSC;
-
-static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_pipesCount);
-
-int64_t getHighWaterMark(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options)
-{
- auto throwScope = DECLARE_THROW_SCOPE(vm);
-
- // We must use getIfPropertyExists because:
- // - it might be a getter
- // - it might be from a super class
- auto* clientData = WebCore::clientData(vm);
- if (JSValue highWaterMarkVal = options->getIfPropertyExists(globalObject, clientData->builtinNames().highWaterMarkPublicName())) {
- if (isDuplex && (highWaterMarkVal.isUndefined() || highWaterMarkVal.isNull())) {
- highWaterMarkVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "readableObjectMode"_s));
- }
-
- if (highWaterMarkVal && highWaterMarkVal.isNumber()) {
- return highWaterMarkVal.toInt32(globalObject);
- }
- }
-
- return -1;
-}
-
-void JSReadableState::finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options)
-{
- Base::finishCreation(vm);
-
- if (options != nullptr) {
- JSC::JSValue objectModeVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "objectMode"_s));
- if (isDuplex && !objectModeVal) {
- objectModeVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "readableObjectMode"_s));
- }
- if (objectModeVal && objectModeVal.toBoolean(globalObject))
- setBool(JSReadableState::Mask::objectMode, true);
- }
-
- m_highWaterMark = getBool(
- JSReadableState::Mask::objectMode)
- ? 16
- : 16 * 1024; // default value
-
- if (options != nullptr) {
- int64_t customHightWaterMark = getHighWaterMark(vm, globalObject, isDuplex, options);
- if (customHightWaterMark >= 0)
- m_highWaterMark = customHightWaterMark;
- }
-
- m_buffer.set(vm, this, JSBufferList::create(vm, globalObject, reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBufferListStructure()));
- m_pipes.set(vm, this, JSC::constructEmptyArray(globalObject, nullptr, 0));
-
- if (options != nullptr) {
- JSC::JSValue emitCloseVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "emitClose"_s));
- if (!emitCloseVal || emitCloseVal.toBoolean(globalObject))
- setBool(JSReadableState::Mask::emitClose, true);
- // Has it been destroyed.
- JSC::JSValue autoDestroyVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "autoDestroy"_s));
- if (!autoDestroyVal || autoDestroyVal.toBoolean(globalObject))
- setBool(JSReadableState::Mask::autoDestroy, true);
- } else {
- setBool(JSReadableState::Mask::emitClose, true);
- setBool(JSReadableState::Mask::autoDestroy, true);
- }
-
- // Indicates whether the stream has finished destroying.
- m_errored.set(vm, this, JSC::jsNull());
-
- // Ref the piped dest which we need a drain event on it
- // type: null | Writable | Set<Writable>.
- if (options == nullptr) {
- m_defaultEncoding.set(vm, this, JSC::jsString(vm, WTF::String("utf8"_s)));
- } else {
- if (JSC::JSValue defaultEncodingVal = getIfPropertyExists(globalObject, PropertyName(JSC::Identifier::fromString(vm, "defaultEncoding"_s)))) {
- m_defaultEncoding.set(vm, this, defaultEncodingVal);
- } else {
- m_defaultEncoding.set(vm, this, JSC::jsString(vm, WTF::String("utf8"_s)));
- }
- }
-
- m_awaitDrainWriters.set(vm, this, JSC::jsNull());
- JSValue decodeValue = JSC::jsNull();
- JSValue encodingValue = JSC::jsNull();
-
- if (options != nullptr) {
- JSC::JSValue encodingVal = options->getIfPropertyExists(globalObject, JSC::Identifier::fromString(vm, "encoding"_s));
- if (encodingVal && encodingVal.isString()) {
- auto constructor = reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSStringDecoder();
- auto constructData = JSC::getConstructData(constructor);
- MarkedArgumentBuffer args;
- args.append(encodingVal);
- JSObject* decoder = JSC::construct(globalObject, constructor, constructData, args);
- decodeValue = decoder;
- encodingValue = encodingVal;
- }
- }
-
- m_decoder.set(vm, this, decodeValue);
- m_encoding.set(vm, this, encodingValue);
-
- // ReadableState.constructed is set to false during construction when a _construct method is implemented
- // this is here so that the ReadableState behavior tracks the behavior in node, and that calling Readable.read
- // will work when we return early from construct because there is no Readable._construct implemented
- // See: https://github.com/nodejs/node/blob/main/lib/internal/streams/readable.js
- setBool(JSReadableState::Mask::constructed, true);
-}
-
-const JSC::ClassInfo JSReadableState::s_info = { "ReadableState"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableState) };
-
-JSC::GCClient::IsoSubspace* JSReadableState::subspaceForImpl(JSC::VM& vm)
-{
- return WebCore::subspaceForImpl<JSReadableState, UseCustomHeapCellType::No>(
- vm,
- [](auto& spaces) { return spaces.m_clientSubspaceForReadableState.get(); },
- [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForReadableState = std::forward<decltype(space)>(space); },
- [](auto& spaces) { return spaces.m_subspaceForReadableState.get(); },
- [](auto& spaces, auto&& space) { spaces.m_subspaceForReadableState = std::forward<decltype(space)>(space); });
-}
-
-template<typename Visitor>
-void JSReadableState::visitChildrenImpl(JSCell* cell, Visitor& visitor)
-{
- JSReadableState* state = jsCast<JSReadableState*>(cell);
- ASSERT_GC_OBJECT_INHERITS(state, info());
- Base::visitChildren(state, visitor);
- visitor.append(state->m_buffer);
- visitor.append(state->m_pipes);
- visitor.append(state->m_errored);
- visitor.append(state->m_defaultEncoding);
- visitor.append(state->m_awaitDrainWriters);
- visitor.append(state->m_decoder);
- visitor.append(state->m_encoding);
-}
-DEFINE_VISIT_CHILDREN(JSReadableState);
-
-STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(JSReadableStatePrototype, JSReadableStatePrototype::Base);
-
-JSC_DEFINE_CUSTOM_GETTER(jsReadableState_pipesCount, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
-{
- auto& vm = JSC::getVM(lexicalGlobalObject);
- auto throwScope = DECLARE_THROW_SCOPE(vm);
- JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue));
- if (!state) {
- RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
- }
- JSArray* pipes = JSC::jsDynamicCast<JSArray*>(state->m_pipes.get());
- if (!pipes) {
- RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined()));
- }
- RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(pipes->length())));
-}
-
-#define JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(NAME) \
- static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \
- JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \
- { \
- auto& vm = JSC::getVM(lexicalGlobalObject); \
- auto throwScope = DECLARE_THROW_SCOPE(vm); \
- JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
- if (!state) { \
- RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \
- } \
- if (state->m_##NAME == 0) \
- RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNull())); \
- RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsBoolean(state->m_##NAME > 0))); \
- } \
- static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \
- JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \
- { \
- auto& vm = JSC::getVM(lexicalGlobalObject); \
- auto throwScope = DECLARE_THROW_SCOPE(vm); \
- JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
- if (!state) { \
- RETURN_IF_EXCEPTION(throwScope, false); \
- } \
- auto value = JSC::JSValue::decode(encodedValue); \
- state->m_##NAME = value.isNull() ? 0 : value.toBoolean(lexicalGlobalObject) ? 1 \
- : -1; \
- RELEASE_AND_RETURN(throwScope, true); \
- }
-
-JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(paused)
- JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER(flowing)
-
-#undef JSReadableState_NULLABLE_BOOLEAN_GETTER_SETTER
-
-#define JSReadableState_NUMBER_GETTER_SETTER(NAME) \
- static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \
- JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \
- { \
- auto& vm = JSC::getVM(lexicalGlobalObject); \
- auto throwScope = DECLARE_THROW_SCOPE(vm); \
- JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
- if (!state) { \
- RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \
- } \
- RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsNumber(state->m_##NAME))); \
- } \
- \
- static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \
- JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \
- { \
- auto& vm = JSC::getVM(lexicalGlobalObject); \
- auto throwScope = DECLARE_THROW_SCOPE(vm); \
- JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
- if (!state) { \
- RETURN_IF_EXCEPTION(throwScope, false); \
- } \
- state->m_##NAME = JSC::JSValue::decode(encodedValue).toNumber(lexicalGlobalObject); \
- RETURN_IF_EXCEPTION(throwScope, false); \
- RELEASE_AND_RETURN(throwScope, true); \
- }
-
- JSReadableState_NUMBER_GETTER_SETTER(length)
- JSReadableState_NUMBER_GETTER_SETTER(highWaterMark)
-
-#undef JSReadableState_NUMBER_GETTER_SETTER
-
-#define JSReadableState_BOOLEAN_GETTER_SETTER(NAME) \
- static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \
- JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \
- { \
- auto& vm = JSC::getVM(lexicalGlobalObject); \
- auto throwScope = DECLARE_THROW_SCOPE(vm); \
- JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
- if (!state) { \
- RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \
- } \
- RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(JSC::jsBoolean(state->getBool(JSReadableState::Mask::NAME)))); \
- } \
- \
- static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \
- JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \
- { \
- auto& vm = JSC::getVM(lexicalGlobalObject); \
- auto throwScope = DECLARE_THROW_SCOPE(vm); \
- JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
- if (!state) { \
- RETURN_IF_EXCEPTION(throwScope, false); \
- } \
- state->setBool(JSReadableState::Mask::NAME, JSC::JSValue::decode(encodedValue).toBoolean(lexicalGlobalObject)); \
- RELEASE_AND_RETURN(throwScope, true); \
- }
-
- JSReadableState_BOOLEAN_GETTER_SETTER(objectMode)
- JSReadableState_BOOLEAN_GETTER_SETTER(ended)
- JSReadableState_BOOLEAN_GETTER_SETTER(endEmitted)
- JSReadableState_BOOLEAN_GETTER_SETTER(reading)
- JSReadableState_BOOLEAN_GETTER_SETTER(constructed)
- JSReadableState_BOOLEAN_GETTER_SETTER(sync)
- JSReadableState_BOOLEAN_GETTER_SETTER(needReadable)
- JSReadableState_BOOLEAN_GETTER_SETTER(emittedReadable)
- JSReadableState_BOOLEAN_GETTER_SETTER(readableListening)
- JSReadableState_BOOLEAN_GETTER_SETTER(resumeScheduled)
- JSReadableState_BOOLEAN_GETTER_SETTER(errorEmitted)
- JSReadableState_BOOLEAN_GETTER_SETTER(emitClose)
- JSReadableState_BOOLEAN_GETTER_SETTER(autoDestroy)
- JSReadableState_BOOLEAN_GETTER_SETTER(destroyed)
- JSReadableState_BOOLEAN_GETTER_SETTER(closed)
- JSReadableState_BOOLEAN_GETTER_SETTER(closeEmitted)
- JSReadableState_BOOLEAN_GETTER_SETTER(multiAwaitDrain)
- JSReadableState_BOOLEAN_GETTER_SETTER(readingMore)
- JSReadableState_BOOLEAN_GETTER_SETTER(dataEmitted)
-
-#undef JSReadableState_BOOLEAN_GETTER_SETTER
-
-#define JSReadableState_JSVALUE_GETTER_SETTER(NAME) \
- static JSC_DECLARE_CUSTOM_GETTER(jsReadableState_##NAME); \
- JSC_DEFINE_CUSTOM_GETTER(jsReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName)) \
- { \
- auto& vm = JSC::getVM(lexicalGlobalObject); \
- auto throwScope = DECLARE_THROW_SCOPE(vm); \
- JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
- if (!state) { \
- RETURN_IF_EXCEPTION(throwScope, JSC::JSValue::encode(JSC::jsUndefined())); \
- } \
- RELEASE_AND_RETURN(throwScope, JSC::JSValue::encode(state->m_##NAME.get())); \
- } \
- static JSC_DECLARE_CUSTOM_SETTER(setJSReadableState_##NAME); \
- JSC_DEFINE_CUSTOM_SETTER(setJSReadableState_##NAME, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, EncodedJSValue encodedValue, PropertyName attributeName)) \
- { \
- auto& vm = JSC::getVM(lexicalGlobalObject); \
- auto throwScope = DECLARE_THROW_SCOPE(vm); \
- JSReadableState* state = JSC::jsDynamicCast<JSReadableState*>(JSValue::decode(thisValue)); \
- if (!state) { \
- RETURN_IF_EXCEPTION(throwScope, false); \
- } \
- auto value = JSC::JSValue::decode(encodedValue); \
- state->m_##NAME.set(vm, state, value); \
- RELEASE_AND_RETURN(throwScope, true); \
- }
-
- JSReadableState_JSVALUE_GETTER_SETTER(buffer)
- JSReadableState_JSVALUE_GETTER_SETTER(pipes)
- JSReadableState_JSVALUE_GETTER_SETTER(errored)
- JSReadableState_JSVALUE_GETTER_SETTER(defaultEncoding)
- JSReadableState_JSVALUE_GETTER_SETTER(awaitDrainWriters)
- JSReadableState_JSVALUE_GETTER_SETTER(decoder)
- JSReadableState_JSVALUE_GETTER_SETTER(encoding)
-
-#undef JSReadableState_JSVALUE_GETTER_SETTER
-
-#define JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(NAME) \
- { \
-#NAME ""_s, static_cast < unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, \
- { \
- HashTableValue::GetterSetterType, jsReadableState_##NAME, setJSReadableState_##NAME \
- } \
- }
-
- /* Hash table for prototype */
- static const HashTableValue JSReadableStatePrototypeTableValues[]
- = {
- { "pipesCount"_s, static_cast<unsigned>(JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute), NoIntrinsic, { HashTableValue::GetterSetterType, jsReadableState_pipesCount, 0 } },
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(paused),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(flowing),
-
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(objectMode),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(ended),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(endEmitted),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(reading),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(constructed),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(sync),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(needReadable),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(emittedReadable),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(readableListening),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(resumeScheduled),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(errorEmitted),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(emitClose),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(autoDestroy),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(destroyed),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(closed),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(closeEmitted),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(multiAwaitDrain),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(readingMore),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(dataEmitted),
-
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(length),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(highWaterMark),
-
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(buffer),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(pipes),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(errored),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(defaultEncoding),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(awaitDrainWriters),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(decoder),
- JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE(encoding),
- };
-
-#undef JSReadableState_GETTER_SETTER_HASH_TABLE_VALUE
-
-void JSReadableStatePrototype::finishCreation(VM& vm, JSC::JSGlobalObject* globalThis)
-{
- Base::finishCreation(vm);
- reifyStaticProperties(vm, JSReadableState::info(), JSReadableStatePrototypeTableValues, *this);
- JSC_TO_STRING_TAG_WITHOUT_TRANSITION();
-}
-
-const ClassInfo JSReadableStatePrototype::s_info = { "ReadableState"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStatePrototype) };
-
-void JSReadableStateConstructor::finishCreation(VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype)
-{
- Base::finishCreation(vm, 0, "ReadableState"_s, PropertyAdditionMode::WithoutStructureTransition);
- putDirectWithoutTransition(vm, vm.propertyNames->prototype, prototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly);
- ASSERT(inherits(info()));
-}
-
-JSReadableStateConstructor* JSReadableStateConstructor::create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSReadableStatePrototype* prototype)
-{
- JSReadableStateConstructor* ptr = new (NotNull, JSC::allocateCell<JSReadableStateConstructor>(vm)) JSReadableStateConstructor(vm, structure, construct);
- ptr->finishCreation(vm, globalObject, prototype);
- return ptr;
-}
-
-JSC::EncodedJSValue JSReadableStateConstructor::construct(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame)
-{
- JSC::VM& vm = lexicalGlobalObject->vm();
- auto throwScope = DECLARE_THROW_SCOPE(vm);
- if (callFrame->argumentCount() < 3) {
- throwVMError(lexicalGlobalObject, throwScope, createNotEnoughArgumentsError(lexicalGlobalObject));
- return JSValue::encode(jsUndefined());
- }
- JSValue optionsVal = callFrame->uncheckedArgument(0);
- JSValue streamVal = callFrame->uncheckedArgument(1);
- JSValue isDuplexVal = callFrame->uncheckedArgument(2);
-
- bool isDuplex;
- if (!isDuplexVal.isBoolean()) {
- // change this to `stream instanceof Duplex` after native Duplex is implemented.
- JSC::throwTypeError(lexicalGlobalObject, throwScope, "isDuplex should be boolean"_s);
- return JSValue::encode(jsUndefined());
- }
- isDuplex = isDuplexVal.toBoolean(lexicalGlobalObject);
- RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
- JSObject* options = nullptr;
- if (optionsVal && optionsVal.isObject()) {
- options = optionsVal.toObject(lexicalGlobalObject);
- }
- RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-
- JSReadableState* stringDecoder = JSReadableState::create(
- vm, lexicalGlobalObject, reinterpret_cast<Zig::GlobalObject*>(lexicalGlobalObject)->JSReadableStateStructure(), isDuplex, options);
- return JSC::JSValue::encode(stringDecoder);
-}
-
-void JSReadableStateConstructor::initializeProperties(VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype)
-{
-}
-
-const ClassInfo JSReadableStateConstructor::s_info = { "ReadableState"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSReadableStateConstructor) };
-
-} // namespace Zig
diff --git a/src/bun.js/bindings/JSReadableState.h b/src/bun.js/bindings/JSReadableState.h
deleted file mode 100644
index c67baebad..000000000
--- a/src/bun.js/bindings/JSReadableState.h
+++ /dev/null
@@ -1,154 +0,0 @@
-#pragma once
-
-#include "root.h"
-#include "BufferEncodingType.h"
-
-namespace WebCore {
-using namespace JSC;
-
-class JSReadableState : public JSC::JSDestructibleObject {
- using Base = JSC::JSDestructibleObject;
-
-public:
- JSReadableState(JSC::VM& vm, JSC::Structure* structure)
- : Base(vm, structure)
- , m_paused(0)
- {
- }
-
- DECLARE_VISIT_CHILDREN;
- DECLARE_INFO;
-
- static constexpr unsigned StructureFlags = Base::StructureFlags;
-
- template<typename, JSC::SubspaceAccess mode> static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm)
- {
- if constexpr (mode == JSC::SubspaceAccess::Concurrently)
- return nullptr;
- return subspaceForImpl(vm);
- }
-
- static JSC::GCClient::IsoSubspace* subspaceForImpl(JSC::VM& vm);
-
- 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());
- }
-
- static JSReadableState* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, bool isDuplex, JSObject* options)
- {
- JSReadableState* accessor = new (NotNull, JSC::allocateCell<JSReadableState>(vm)) JSReadableState(vm, structure);
- accessor->finishCreation(vm, globalObject, isDuplex, options);
- return accessor;
- }
-
- void finishCreation(JSC::VM& vm, JSC::JSGlobalObject* globalObject, bool isDuplex, JSObject* options);
- static void destroy(JSCell*) {}
-
- enum Mask : uint32_t {
- objectMode = 1 << 0,
- emitClose = 1 << 1,
- autoDestroy = 1 << 2,
- ended = 1 << 3,
- endEmitted = 1 << 4,
- reading = 1 << 5,
- constructed = 1 << 6,
- sync = 1 << 7,
- needReadable = 1 << 8,
- emittedReadable = 1 << 9,
- readableListening = 1 << 10,
- resumeScheduled = 1 << 11,
- errorEmitted = 1 << 12,
- destroyed = 1 << 13,
- closed = 1 << 14,
- closeEmitted = 1 << 15,
- multiAwaitDrain = 1 << 16,
- readingMore = 1 << 17,
- dataEmitted = 1 << 18,
- };
-
- constexpr bool getBool(Mask mask) { return m_bools.contains(mask); }
- constexpr void setBool(Mask mask, bool val)
- {
- m_bools.set(mask, val);
- }
-
- // 0 for null, 1 for true, -1 for false
- int8_t m_paused = 0;
- int8_t m_flowing = 0;
-
- WTF::OptionSet<Mask> m_bools;
-
- int64_t m_length = 0;
- int64_t m_highWaterMark;
-
- mutable WriteBarrier<Unknown> m_buffer;
- mutable WriteBarrier<Unknown> m_pipes;
- mutable WriteBarrier<Unknown> m_errored;
- mutable WriteBarrier<Unknown> m_defaultEncoding;
- mutable WriteBarrier<Unknown> m_awaitDrainWriters;
- mutable WriteBarrier<Unknown> m_decoder;
- mutable WriteBarrier<Unknown> m_encoding;
-};
-
-class JSReadableStatePrototype : public JSC::JSNonFinalObject {
-public:
- using Base = JSC::JSNonFinalObject;
- static JSReadableStatePrototype* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure)
- {
- JSReadableStatePrototype* ptr = new (NotNull, JSC::allocateCell<JSReadableStatePrototype>(vm)) JSReadableStatePrototype(vm, 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:
- JSReadableStatePrototype(JSC::VM& vm, JSC::Structure* structure)
- : Base(vm, structure)
- {
- }
-
- void finishCreation(JSC::VM&, JSC::JSGlobalObject*);
-};
-
-class JSReadableStateConstructor final : public JSC::InternalFunction {
-public:
- using Base = JSC::InternalFunction;
- static JSReadableStateConstructor* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure, JSReadableStatePrototype* 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());
- }
-
- void initializeProperties(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype);
-
- // Must be defined for each specialization class.
- static JSC::EncodedJSValue JSC_HOST_CALL_ATTRIBUTES construct(JSC::JSGlobalObject*, JSC::CallFrame*);
- DECLARE_EXPORT_INFO;
-
-private:
- JSReadableStateConstructor(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction nativeFunction)
- : Base(vm, structure, nativeFunction, nativeFunction)
- {
- }
-
- void finishCreation(JSC::VM&, JSC::JSGlobalObject* globalObject, JSReadableStatePrototype* prototype);
-};
-
-}
diff --git a/src/bun.js/bindings/Process.cpp b/src/bun.js/bindings/Process.cpp
index 252d00075..282cf6460 100644
--- a/src/bun.js/bindings/Process.cpp
+++ b/src/bun.js/bindings/Process.cpp
@@ -76,7 +76,10 @@ extern "C" uint8_t Bun__getExitCode(void*);
extern "C" uint8_t Bun__setExitCode(void*, uint8_t);
extern "C" void* Bun__getVM();
extern "C" Zig::GlobalObject* Bun__getDefaultGlobal();
+extern "C" bool Bun__GlobalObject__hasIPC(JSGlobalObject*);
extern "C" const char* Bun__githubURL;
+extern "C" JSC_DECLARE_HOST_FUNCTION(Bun__Process__send);
+extern "C" JSC_DECLARE_HOST_FUNCTION(Bun__Process__disconnect);
static void dispatchExitInternal(JSC::JSGlobalObject* globalObject, Process* process, int exitCode)
{
@@ -525,6 +528,21 @@ static void loadSignalNumberMap()
static void onDidChangeListeners(EventEmitter& eventEmitter, const Identifier& eventName, bool isAdded)
{
+ if (eventName.string() == "message"_s) {
+ if (isAdded) {
+ if (Bun__GlobalObject__hasIPC(eventEmitter.scriptExecutionContext()->jsGlobalObject())
+ && eventEmitter.listenerCount(eventName) == 1) {
+ eventEmitter.scriptExecutionContext()->refEventLoop();
+ eventEmitter.m_hasIPCRef = true;
+ }
+ } else {
+ if (eventEmitter.listenerCount(eventName) == 0 && eventEmitter.m_hasIPCRef) {
+ eventEmitter.scriptExecutionContext()->unrefEventLoop();
+ }
+ }
+ return;
+ }
+
loadSignalNumberMap();
static std::once_flag signalNumberToNameMapOnceFlag;
@@ -739,6 +757,20 @@ JSC_DEFINE_CUSTOM_SETTER(setProcessExitCode, (JSC::JSGlobalObject * lexicalGloba
return true;
}
+JSC_DEFINE_CUSTOM_GETTER(processConnected, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName name))
+{
+ Process* process = jsDynamicCast<Process*>(JSValue::decode(thisValue));
+ if (!process) {
+ return JSValue::encode(jsUndefined());
+ }
+
+ return JSValue::encode(jsBoolean(Bun__GlobalObject__hasIPC(process->globalObject())));
+}
+JSC_DEFINE_CUSTOM_SETTER(setProcessConnected, (JSC::JSGlobalObject * lexicalGlobalObject, JSC::EncodedJSValue thisValue, JSC::EncodedJSValue value, JSC::PropertyName))
+{
+ return false;
+}
+
static JSValue constructVersions(VM& vm, JSObject* processObject)
{
auto* globalObject = processObject->globalObject();
@@ -912,6 +944,26 @@ static JSValue constructStdin(VM& vm, JSObject* processObject)
RELEASE_AND_RETURN(scope, result);
}
+static JSValue constructProcessSend(VM& vm, JSObject* processObject)
+{
+ auto* globalObject = processObject->globalObject();
+ if (Bun__GlobalObject__hasIPC(globalObject)) {
+ return JSC::JSFunction::create(vm, globalObject, 1, String("send"_s), Bun__Process__send, ImplementationVisibility::Public);
+ } else {
+ return jsNumber(4);
+ }
+}
+
+static JSValue constructProcessDisconnect(VM& vm, JSObject* processObject)
+{
+ auto* globalObject = processObject->globalObject();
+ if (Bun__GlobalObject__hasIPC(globalObject)) {
+ return JSC::JSFunction::create(vm, globalObject, 1, String("disconnect"_s), Bun__Process__disconnect, ImplementationVisibility::Public);
+ } else {
+ return jsUndefined();
+ }
+}
+
static JSValue constructPid(VM& vm, JSObject* processObject)
{
return jsNumber(getpid());
@@ -1687,6 +1739,29 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionKill,
return JSValue::encode(jsUndefined());
}
+extern "C" void Process__emitMessageEvent(Zig::GlobalObject* global, EncodedJSValue value)
+{
+ auto* process = static_cast<Process*>(global->processObject());
+ auto& vm = global->vm();
+ auto ident = Identifier::fromString(vm, "message"_s);
+ if (process->wrapped().hasEventListeners(ident)) {
+ JSC::MarkedArgumentBuffer args;
+ args.append(JSValue::decode(value));
+ process->wrapped().emit(ident, args);
+ }
+}
+
+extern "C" void Process__emitDisconnectEvent(Zig::GlobalObject* global)
+{
+ auto* process = static_cast<Process*>(global->processObject());
+ auto& vm = global->vm();
+ auto ident = Identifier::fromString(vm, "disconnect"_s);
+ if (process->wrapped().hasEventListeners(ident)) {
+ JSC::MarkedArgumentBuffer args;
+ process->wrapped().emit(ident, args);
+ }
+}
+
/* Source for Process.lut.h
@begin processObjectTable
abort Process_functionAbort Function 1
@@ -1699,9 +1774,11 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionKill,
browser constructBrowser PropertyCallback
chdir Process_functionChdir Function 1
config constructProcessConfigObject PropertyCallback
+ connected processConnected CustomAccessor
cpuUsage Process_functionCpuUsage Function 1
cwd Process_functionCwd Function 1
debugPort processDebugPort CustomAccessor
+ disconnect constructProcessDisconnect PropertyCallback
dlopen Process_functionDlopen Function 1
emitWarning Process_emitWarning Function 1
env constructEnv PropertyCallback
@@ -1731,6 +1808,7 @@ JSC_DEFINE_HOST_FUNCTION(Process_functionKill,
release constructProcessReleaseObject PropertyCallback
revision constructRevision PropertyCallback
setSourceMapsEnabled Process_stubEmptyFunction Function 1
+ send constructProcessSend PropertyCallback
stderr constructStderr PropertyCallback
stdin constructStdin PropertyCallback
stdout constructStdout PropertyCallback
diff --git a/src/bun.js/bindings/Process.lut.h b/src/bun.js/bindings/Process.lut.h
index 4086fb19e..dda54ff01 100644
--- a/src/bun.js/bindings/Process.lut.h
+++ b/src/bun.js/bindings/Process.lut.h
@@ -1,6 +1,6 @@
// File generated via `make generate-builtins`
-static const struct CompactHashIndex processObjectTableIndex[143] = {
- { 44, -1 },
+static const struct CompactHashIndex processObjectTableIndex[267] = {
+ { 47, -1 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
@@ -11,13 +11,12 @@ static const struct CompactHashIndex processObjectTableIndex[143] = {
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
- { 15, 129 },
{ -1, -1 },
{ -1, -1 },
- { 18, 139 },
{ -1, -1 },
- { 46, -1 },
+ { 20, -1 },
{ -1, -1 },
+ { 49, -1 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
@@ -33,37 +32,166 @@ static const struct CompactHashIndex processObjectTableIndex[143] = {
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
- { 3, 142 },
- { 1, 128 },
{ -1, -1 },
- { 60, -1 },
{ -1, -1 },
- { 10, -1 },
+ { 8, -1 },
+ { -1, -1 },
+ { -1, -1 },
{ -1, -1 },
{ -1, -1 },
- { 32, -1 },
{ -1, -1 },
{ -1, -1 },
+ { 34, -1 },
{ -1, -1 },
{ -1, -1 },
- { 53, -1 },
- { 27, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 29, -1 },
+ { 13, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 59, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 55, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 43, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 0, -1 },
+ { 28, -1 },
+ { 37, -1 },
+ { 42, -1 },
+ { -1, -1 },
+ { 25, -1 },
{ 12, -1 },
{ -1, -1 },
+ { -1, -1 },
+ { 62, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 33, -1 },
+ { 44, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 26, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 22, -1 },
+ { -1, -1 },
+ { 5, -1 },
+ { -1, -1 },
+ { 64, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 27, 261 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 23, 262 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 50, 265 },
+ { -1, -1 },
{ 19, -1 },
{ -1, -1 },
- { 14, 138 },
{ -1, -1 },
- { 37, -1 },
{ -1, -1 },
- { 39, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 17, 257 },
+ { -1, -1 },
+ { 14, -1 },
+ { 57, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 3, 266 },
+ { 1, -1 },
+ { -1, -1 },
+ { 63, -1 },
+ { -1, -1 },
+ { 11, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
{ 56, -1 },
- { 36, -1 },
- { 6, 140 },
{ -1, -1 },
- { 52, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 10, 256 },
+ { -1, -1 },
+ { 16, 263 },
+ { -1, -1 },
+ { 39, -1 },
+ { -1, -1 },
+ { 41, -1 },
+ { -1, -1 },
+ { 38, -1 },
+ { 6, 264 },
+ { -1, -1 },
+ { -1, -1 },
{ 4, -1 },
- { 48, -1 },
+ { 51, -1 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
@@ -75,77 +203,73 @@ static const struct CompactHashIndex processObjectTableIndex[143] = {
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
- { 41, -1 },
{ -1, -1 },
- { 29, 133 },
{ -1, -1 },
- { 0, -1 },
- { 26, 136 },
- { 16, 130 },
- { 40, -1 },
+ { 31, 260 },
+ { -1, -1 },
+ { -1, -1 },
+ { 48, -1 },
+ { 18, 258 },
+ { -1, -1 },
{ -1, -1 },
- { 23, -1 },
- { 11, -1 },
{ -1, -1 },
{ -1, -1 },
- { 59, -1 },
{ -1, -1 },
{ -1, -1 },
- { 31, 137 },
{ -1, -1 },
- { 30, -1 },
- { 22, -1 },
{ -1, -1 },
{ -1, -1 },
+ { 53, -1 },
+ { -1, -1 },
+ { 32, -1 },
{ 24, -1 },
{ -1, -1 },
{ -1, -1 },
- { 20, -1 },
{ -1, -1 },
- { 5, -1 },
{ -1, -1 },
- { 61, -1 },
- { 49, -1 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
- { 13, 131 },
+ { -1, -1 },
+ { -1, -1 },
+ { 52, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 15, 259 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
{ 9, -1 },
- { 25, 134 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
- { 21, 135 },
{ -1, -1 },
{ -1, -1 },
{ -1, -1 },
- { 47, 141 },
{ -1, -1 },
- { 17, -1 },
- { 8, -1 },
- { 28, -1 },
- { 33, 132 },
- { 34, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { -1, -1 },
+ { 21, -1 },
+ { 30, -1 },
{ 35, -1 },
- { 38, -1 },
- { 42, -1 },
- { 43, -1 },
+ { 36, -1 },
+ { 40, -1 },
{ 45, -1 },
- { 50, -1 },
- { 51, -1 },
+ { 46, -1 },
{ 54, -1 },
- { 55, -1 },
- { 57, -1 },
{ 58, -1 },
+ { 60, -1 },
+ { 61, -1 },
};
-static const struct HashTableValue processObjectTableValues[62] = {
+static const struct HashTableValue processObjectTableValues[65] = {
{ "abort"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionAbort, 1 } },
{ "allowedNodeEnvironmentFlags"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, Process_stubEmptySet } },
{ "arch"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructArch } },
@@ -156,9 +280,11 @@ static const struct HashTableValue processObjectTableValues[62] = {
{ "browser"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructBrowser } },
{ "chdir"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionChdir, 1 } },
{ "config"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructProcessConfigObject } },
+ { "connected"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processConnected, setProcessConnected } },
{ "cpuUsage"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionCpuUsage, 1 } },
{ "cwd"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionCwd, 1 } },
{ "debugPort"_s, static_cast<unsigned>(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, processDebugPort, setProcessDebugPort } },
+ { "disconnect"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructProcessDisconnect } },
{ "dlopen"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_functionDlopen, 1 } },
{ "emitWarning"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_emitWarning, 1 } },
{ "env"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructEnv } },
@@ -188,6 +314,7 @@ static const struct HashTableValue processObjectTableValues[62] = {
{ "release"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructProcessReleaseObject } },
{ "revision"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructRevision } },
{ "setSourceMapsEnabled"_s, static_cast<unsigned>(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, Process_stubEmptyFunction, 1 } },
+ { "send"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructProcessSend } },
{ "stderr"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructStderr } },
{ "stdin"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructStdin } },
{ "stdout"_s, static_cast<unsigned>(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, constructStdout } },
@@ -211,4 +338,4 @@ static const struct HashTableValue processObjectTableValues[62] = {
};
static const struct HashTable processObjectTable =
- { 62, 127, true, nullptr, processObjectTableValues, processObjectTableIndex };
+ { 65, 255, true, nullptr, processObjectTableValues, processObjectTableIndex };
diff --git a/src/bun.js/bindings/Serialization.cpp b/src/bun.js/bindings/Serialization.cpp
new file mode 100644
index 000000000..89937ebbb
--- /dev/null
+++ b/src/bun.js/bindings/Serialization.cpp
@@ -0,0 +1,49 @@
+#include "root.h"
+#include "headers-handwritten.h"
+#include "ExceptionOr.h"
+#include "MessagePort.h"
+#include "SerializedScriptValue.h"
+#include "JSDOMExceptionHandling.h"
+
+using namespace JSC;
+using namespace WebCore;
+
+/// This is used for Bun.spawn() IPC because otherwise we would have to copy the data once to get it to zig, then write it.
+/// Returns `true` on success, `false` on failure + throws a JS error.
+extern "C" bool Bun__serializeJSValueForSubprocess(JSGlobalObject* globalObject, EncodedJSValue encodedValue, int fd)
+{
+ JSValue value = JSValue::decode(encodedValue);
+
+ Vector<JSC::Strong<JSC::JSObject>> transferList;
+ Vector<RefPtr<MessagePort>> dummyPorts;
+ ExceptionOr<Ref<SerializedScriptValue>> serialized = SerializedScriptValue::create(*globalObject, value, WTFMove(transferList),
+ dummyPorts);
+
+ auto& vm = globalObject->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
+
+ if (serialized.hasException()) {
+ WebCore::propagateException(*globalObject, scope,
+ serialized.releaseException());
+ RELEASE_AND_RETURN(scope, false);
+ }
+
+ auto serializedValue = serialized.releaseReturnValue();
+ auto bytes = serializedValue.ptr()->wireBytes();
+
+ uint8_t id = 2; // IPCMessageType.SerializedMessage
+ write(fd, &id, sizeof(uint8_t));
+ uint32_t size = bytes.size();
+ write(fd, &size, sizeof(uint32_t));
+ write(fd, bytes.data(), size);
+
+ RELEASE_AND_RETURN(scope, true);
+}
+
+extern "C" EncodedJSValue Bun__JSValue__deserialize(JSGlobalObject* globalObject, const uint8_t* bytes, size_t size)
+{
+ Vector<uint8_t> vector(bytes, size);
+ /// ?! did i just give ownership of these bytes to JSC?
+ auto scriptValue = SerializedScriptValue::createFromWireBytes(WTFMove(vector));
+ return JSValue::encode(scriptValue->deserialize(*globalObject, globalObject));
+} \ No newline at end of file
diff --git a/src/bun.js/bindings/ZigGeneratedClasses.cpp b/src/bun.js/bindings/ZigGeneratedClasses.cpp
index 5a10a05d3..ec2add296 100644
--- a/src/bun.js/bindings/ZigGeneratedClasses.cpp
+++ b/src/bun.js/bindings/ZigGeneratedClasses.cpp
@@ -23215,6 +23215,9 @@ JSC_DECLARE_CUSTOM_GETTER(SubprocessPrototype__readableGetterWrap);
extern "C" EncodedJSValue SubprocessPrototype__doRef(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
JSC_DECLARE_HOST_FUNCTION(SubprocessPrototype__refCallback);
+extern "C" EncodedJSValue SubprocessPrototype__doSend(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame);
+JSC_DECLARE_HOST_FUNCTION(SubprocessPrototype__sendCallback);
+
extern "C" JSC::EncodedJSValue SubprocessPrototype__getSignalCode(void* ptr, JSC::JSGlobalObject* lexicalGlobalObject);
JSC_DECLARE_CUSTOM_GETTER(SubprocessPrototype__signalCodeGetterWrap);
@@ -23243,6 +23246,7 @@ static const HashTableValue JSSubprocessPrototypeTableValues[] = {
{ "pid"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, SubprocessPrototype__pidGetterWrap, 0 } },
{ "readable"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, SubprocessPrototype__readableGetterWrap, 0 } },
{ "ref"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, SubprocessPrototype__refCallback, 0 } },
+ { "send"_s, static_cast<unsigned>(JSC::PropertyAttribute::Function | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::NativeFunctionType, SubprocessPrototype__sendCallback, 1 } },
{ "signalCode"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, SubprocessPrototype__signalCodeGetterWrap, 0 } },
{ "stderr"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, SubprocessPrototype__stderrGetterWrap, 0 } },
{ "stdin"_s, static_cast<unsigned>(JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::CustomAccessor | JSC::PropertyAttribute::DOMAttribute | PropertyAttribute::DontDelete), NoIntrinsic, { HashTableValue::GetterSetterType, SubprocessPrototype__stdinGetterWrap, 0 } },
@@ -23400,6 +23404,34 @@ JSC_DEFINE_HOST_FUNCTION(SubprocessPrototype__refCallback, (JSGlobalObject * lex
return SubprocessPrototype__doRef(thisObject->wrapped(), lexicalGlobalObject, callFrame);
}
+JSC_DEFINE_HOST_FUNCTION(SubprocessPrototype__sendCallback, (JSGlobalObject * lexicalGlobalObject, CallFrame* callFrame))
+{
+ auto& vm = lexicalGlobalObject->vm();
+
+ JSSubprocess* thisObject = jsDynamicCast<JSSubprocess*>(callFrame->thisValue());
+
+ if (UNLIKELY(!thisObject)) {
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ throwVMTypeError(lexicalGlobalObject, throwScope, "Expected 'this' to be instanceof Subprocess"_s);
+ return JSValue::encode({});
+ }
+
+ JSC::EnsureStillAliveScope thisArg = JSC::EnsureStillAliveScope(thisObject);
+
+#ifdef BUN_DEBUG
+ /** View the file name of the JS file that called this function
+ * from a debugger */
+ SourceOrigin sourceOrigin = callFrame->callerSourceOrigin(vm);
+ const char* fileName = sourceOrigin.string().utf8().data();
+ static const char* lastFileName = nullptr;
+ if (lastFileName != fileName) {
+ lastFileName = fileName;
+ }
+#endif
+
+ return SubprocessPrototype__doSend(thisObject->wrapped(), lexicalGlobalObject, callFrame);
+}
+
JSC_DEFINE_CUSTOM_GETTER(SubprocessPrototype__signalCodeGetterWrap, (JSGlobalObject * lexicalGlobalObject, EncodedJSValue thisValue, PropertyName attributeName))
{
auto& vm = lexicalGlobalObject->vm();
diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp
index 286084b4d..091cc0b29 100644
--- a/src/bun.js/bindings/ZigGlobalObject.cpp
+++ b/src/bun.js/bindings/ZigGlobalObject.cpp
@@ -90,8 +90,6 @@
#include "JSCloseEvent.h"
#include "JSFetchHeaders.h"
#include "JSStringDecoder.h"
-#include "JSReadableState.h"
-#include "JSReadableHelper.h"
#include "Process.h"
#include "AsyncContextFrame.h"
@@ -1628,7 +1626,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
switch (callFrame->argumentCount()) {
case 0: {
- JSC::throwTypeError(globalObject, scope, "lazyLoad needs 1 argument (a string)"_s);
+ JSC::throwTypeError(globalObject, scope, "$lazy needs 1 argument (a string)"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
@@ -1637,7 +1635,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
if (moduleName.isNumber()) {
switch (moduleName.toInt32(globalObject)) {
case 0: {
- JSC::throwTypeError(globalObject, scope, "lazyLoad expects a string"_s);
+ JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
@@ -1654,7 +1652,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
default: {
auto scope = DECLARE_THROW_SCOPE(globalObject->vm());
- JSC::throwTypeError(globalObject, scope, "lazyLoad expects a string"_s);
+ JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
@@ -1663,7 +1661,7 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
auto string = moduleName.toWTFString(globalObject);
if (string.isNull()) {
- JSC::throwTypeError(globalObject, scope, "lazyLoad expects a string"_s);
+ JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s);
scope.release();
return JSC::JSValue::encode(JSC::JSValue {});
}
@@ -1673,7 +1671,6 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
}
if (string == "worker_threads"_s) {
-
JSValue workerData = jsUndefined();
JSValue threadId = jsNumber(0);
@@ -1708,27 +1705,6 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
JSFunction::create(vm, globalObject, 1, fileURLToPathString, functionFileURLToPath, ImplementationVisibility::Public, NoIntrinsic));
}
- if (string == "bun:stream"_s) {
- auto* obj = constructEmptyObject(globalObject);
- obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "BufferList"_s)), reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSBufferList(), 0);
- obj->putDirect(vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "ReadableState"_s)), reinterpret_cast<Zig::GlobalObject*>(globalObject)->JSReadableState(), 0);
- obj->putDirect(
- vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "maybeReadMore"_s)),
- JSC::JSFunction::create(vm, globalObject, 0, "maybeReadMore"_s, jsReadable_maybeReadMore, ImplementationVisibility::Public), 0);
- obj->putDirect(
- vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "resume"_s)),
- JSC::JSFunction::create(vm, globalObject, 0, "resume"_s, jsReadable_resume, ImplementationVisibility::Public), 0);
- obj->putDirect(
- vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "emitReadable"_s)),
- JSC::JSFunction::create(vm, globalObject, 0, "emitReadable"_s, jsReadable_emitReadable, ImplementationVisibility::Public), 0);
- obj->putDirect(
- vm, JSC::PropertyName(JSC::Identifier::fromString(vm, "onEofChunk"_s)),
- JSC::JSFunction::create(vm, globalObject, 0, "onEofChunk"_s, jsReadable_onEofChunk, ImplementationVisibility::Public), 0);
- return JSValue::encode(obj);
- }
- if (string == "events"_s) {
- return JSValue::encode(WebCore::JSEventEmitter::getConstructor(vm, globalObject));
- }
if (string == "internal/tls"_s) {
auto* obj = constructEmptyObject(globalObject);
@@ -1759,9 +1735,9 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
return JSValue::encode(obj);
}
- if (string == "masqueradesAsUndefined"_s) {
- return JSValue::encode(InternalFunction::createFunctionThatMasqueradesAsUndefined(vm, globalObject, 0, String(), functionCallNotImplemented));
- }
+ // if (string == "masqueradesAsUndefined"_s) {
+ // return JSValue::encode(InternalFunction::createFunctionThatMasqueradesAsUndefined(vm, globalObject, 0, String(), functionCallNotImplemented));
+ // }
if (string == "vm"_s) {
auto* obj = constructEmptyObject(globalObject);
@@ -1818,9 +1794,9 @@ static JSC_DEFINE_HOST_FUNCTION(functionLazyLoad,
return JSC::JSValue::encode(obj);
}
- return JSC::JSValue::encode(JSC::jsUndefined());
-
- break;
+ JSC::throwTypeError(globalObject, scope, "$lazy expects a string"_s);
+ scope.release();
+ return JSC::JSValue::encode(JSC::JSValue {});
}
}
}
@@ -2360,6 +2336,7 @@ private:
functionNoop, ImplementationVisibility::Public, NoIntrinsic, functionNoop,
&DOMJITSignatureForPerformanceNow);
this->putDirect(vm, JSC::Identifier::fromString(vm, "mark"_s), noopNotImplemented, JSC::PropertyAttribute::DOMJITFunction | JSC::PropertyAttribute::Function);
+ this->putDirect(vm, JSC::Identifier::fromString(vm, "markResourceTiming"_s), noopNotImplemented, JSC::PropertyAttribute::DOMJITFunction | JSC::PropertyAttribute::Function);
this->putDirect(vm, JSC::Identifier::fromString(vm, "measure"_s), noopNotImplemented, JSC::PropertyAttribute::DOMJITFunction | JSC::PropertyAttribute::Function);
this->putDirect(
@@ -3004,10 +2981,6 @@ void GlobalObject::finishCreation(VM& vm)
[](const Initializer<JSFunction>& init) {
init.set(JSFunction::create(init.vm, init.owner, 4, "performMicrotask"_s, jsFunctionPerformMicrotask, ImplementationVisibility::Public));
});
- m_emitReadableNextTickFunction.initLater(
- [](const Initializer<JSFunction>& init) {
- init.set(JSFunction::create(init.vm, init.owner, 4, "emitReadable"_s, WebCore::jsReadable_emitReadable_, ImplementationVisibility::Public));
- });
m_bunSleepThenCallback.initLater(
[](const Initializer<JSFunction>& init) {
@@ -3322,18 +3295,6 @@ void GlobalObject::finishCreation(VM& vm)
init.setConstructor(constructor);
});
- m_JSReadableStateClassStructure.initLater(
- [](LazyClassStructure::Initializer& init) {
- auto* prototype = JSReadableStatePrototype::create(
- init.vm, init.global, JSReadableStatePrototype::createStructure(init.vm, init.global, init.global->objectPrototype()));
- auto* structure = JSReadableState::createStructure(init.vm, init.global, prototype);
- auto* constructor = JSReadableStateConstructor::create(
- init.vm, init.global, JSReadableStateConstructor::createStructure(init.vm, init.global, init.global->functionPrototype()), prototype);
- init.setPrototype(prototype);
- init.setStructure(structure);
- init.setConstructor(constructor);
- });
-
m_JSFFIFunctionStructure.initLater(
[](LazyClassStructure::Initializer& init) {
init.setStructure(Zig::JSFFIFunction::createStructure(init.vm, init.global, init.global->functionPrototype()));
@@ -4091,6 +4052,7 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
visitor.append(thisObject->m_readableStreamToJSON);
visitor.append(thisObject->m_readableStreamToText);
visitor.append(thisObject->m_readableStreamToFormData);
+ visitor.append(thisObject->m_nodeModuleOverriddenResolveFilename);
visitor.append(thisObject->m_JSBlobSetterValue);
visitor.append(thisObject->m_JSBroadcastChannelSetterValue);
@@ -4122,7 +4084,6 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_JSFileSinkClassStructure.visit(visitor);
thisObject->m_JSHTTPResponseSinkClassStructure.visit(visitor);
thisObject->m_JSHTTPSResponseSinkClassStructure.visit(visitor);
- thisObject->m_JSReadableStateClassStructure.visit(visitor);
thisObject->m_JSStringDecoderClassStructure.visit(visitor);
thisObject->m_NapiClassStructure.visit(visitor);
thisObject->m_JSBufferClassStructure.visit(visitor);
@@ -4148,7 +4109,6 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor)
thisObject->m_subtleCryptoObject.visit(visitor);
thisObject->m_JSHTTPResponseController.visit(visitor);
thisObject->m_callSiteStructure.visit(visitor);
- thisObject->m_emitReadableNextTickFunction.visit(visitor);
thisObject->m_JSBufferSubclassStructure.visit(visitor);
thisObject->m_cryptoObject.visit(visitor);
thisObject->m_JSDOMFileConstructor.visit(visitor);
diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h
index e622016de..7377e6693 100644
--- a/src/bun.js/bindings/ZigGlobalObject.h
+++ b/src/bun.js/bindings/ZigGlobalObject.h
@@ -238,10 +238,6 @@ public:
JSC::JSObject* JSStringDecoder() { return m_JSStringDecoderClassStructure.constructorInitializedOnMainThread(this); }
JSC::JSValue JSStringDecoderPrototype() { return m_JSStringDecoderClassStructure.prototypeInitializedOnMainThread(this); }
- JSC::Structure* JSReadableStateStructure() { return m_JSReadableStateClassStructure.getInitializedOnMainThread(this); }
- JSC::JSObject* JSReadableState() { return m_JSReadableStateClassStructure.constructorInitializedOnMainThread(this); }
- JSC::JSValue JSReadableStatePrototype() { return m_JSReadableStateClassStructure.prototypeInitializedOnMainThread(this); }
-
JSC::Structure* NodeVMScriptStructure() { return m_NodeVMScriptClassStructure.getInitializedOnMainThread(this); }
JSC::JSObject* NodeVMScript() { return m_NodeVMScriptClassStructure.constructorInitializedOnMainThread(this); }
JSC::JSValue NodeVMScriptPrototype() { return m_NodeVMScriptClassStructure.prototypeInitializedOnMainThread(this); }
@@ -261,8 +257,6 @@ public:
JSC::JSFunction* utilInspectStylizeColorFunction() { return m_utilInspectStylizeColorFunction.getInitializedOnMainThread(this); }
JSC::JSFunction* utilInspectStylizeNoColorFunction() { return m_utilInspectStylizeNoColorFunction.getInitializedOnMainThread(this); }
- JSC::JSFunction* emitReadableNextTickFunction() { return m_emitReadableNextTickFunction.getInitializedOnMainThread(this); }
-
JSObject* requireFunctionUnbound() { return m_requireFunctionUnbound.getInitializedOnMainThread(this); }
JSObject* requireResolveFunctionUnbound() { return m_requireResolveFunctionUnbound.getInitializedOnMainThread(this); }
Bun::InternalModuleRegistry* internalModuleRegistry() { return m_internalModuleRegistry.getInitializedOnMainThread(this); }
@@ -385,6 +379,10 @@ public:
mutable WriteBarrier<JSFunction> m_readableStreamToText;
mutable WriteBarrier<JSFunction> m_readableStreamToFormData;
+ // This is set when doing `require('module')._resolveFilename = ...`
+ // a hack used by Next.js to inject their versions of webpack and react
+ mutable WriteBarrier<JSFunction> m_nodeModuleOverriddenResolveFilename;
+
mutable WriteBarrier<Unknown> m_nextTickQueue;
mutable WriteBarrier<Unknown> m_BunCommonJSModuleValue;
mutable WriteBarrier<Unknown> m_JSBroadcastChannelSetterValue;
@@ -502,7 +500,6 @@ private:
LazyClassStructure m_JSFileSinkClassStructure;
LazyClassStructure m_JSHTTPResponseSinkClassStructure;
LazyClassStructure m_JSHTTPSResponseSinkClassStructure;
- LazyClassStructure m_JSReadableStateClassStructure;
LazyClassStructure m_JSStringDecoderClassStructure;
LazyClassStructure m_NapiClassStructure;
LazyClassStructure m_callSiteStructure;
@@ -526,7 +523,7 @@ private:
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectFunction;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectStylizeColorFunction;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectStylizeNoColorFunction;
- LazyProperty<JSGlobalObject, JSFunction> m_emitReadableNextTickFunction;
+
LazyProperty<JSGlobalObject, JSMap> m_lazyReadableStreamPrototypeMap;
LazyProperty<JSGlobalObject, JSMap> m_requireMap;
LazyProperty<JSGlobalObject, Structure> m_encodeIntoObjectStructure;
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig
index 532d2bc68..1a82fc5e6 100644
--- a/src/bun.js/bindings/bindings.zig
+++ b/src/bun.js/bindings/bindings.zig
@@ -4917,6 +4917,13 @@ pub const JSValue = enum(JSValueReprInt) {
JSC.markBinding(@src());
return AsyncContextFrame__withAsyncContextIfNeeded(global, this);
}
+
+ extern "c" fn Bun__JSValue__deserialize(global: *JSGlobalObject, data: [*]const u8, len: isize) JSValue;
+
+ /// Deserializes a JSValue from a serialized buffer. Zig version of `import('bun:jsc').deserialize`
+ pub inline fn deserialize(bytes: []const u8, global: *JSGlobalObject) JSValue {
+ return Bun__JSValue__deserialize(global, bytes.ptr, @intCast(bytes.len));
+ }
};
extern "c" fn AsyncContextFrame__withAsyncContextIfNeeded(global: *JSGlobalObject, callback: JSValue) JSValue;
diff --git a/src/bun.js/bindings/generated_classes.zig b/src/bun.js/bindings/generated_classes.zig
index e7e16e889..329506718 100644
--- a/src/bun.js/bindings/generated_classes.zig
+++ b/src/bun.js/bindings/generated_classes.zig
@@ -6140,6 +6140,8 @@ pub const JSSubprocess = struct {
if (@TypeOf(Subprocess.doRef) != CallbackType)
@compileLog("Expected Subprocess.doRef to be a callback but received " ++ @typeName(@TypeOf(Subprocess.doRef)));
+ if (@TypeOf(Subprocess.doSend) != CallbackType)
+ @compileLog("Expected Subprocess.doSend to be a callback but received " ++ @typeName(@TypeOf(Subprocess.doSend)));
if (@TypeOf(Subprocess.getSignalCode) != GetterType)
@compileLog("Expected Subprocess.getSignalCode to be a getter");
@@ -6159,6 +6161,7 @@ pub const JSSubprocess = struct {
if (!JSC.is_bindgen) {
@export(Subprocess.doRef, .{ .name = "SubprocessPrototype__doRef" });
+ @export(Subprocess.doSend, .{ .name = "SubprocessPrototype__doSend" });
@export(Subprocess.doUnref, .{ .name = "SubprocessPrototype__doUnref" });
@export(Subprocess.finalize, .{ .name = "SubprocessClass__finalize" });
@export(Subprocess.getExitCode, .{ .name = "SubprocessPrototype__getExitCode" });
diff --git a/src/bun.js/bindings/webcore/EventEmitter.h b/src/bun.js/bindings/webcore/EventEmitter.h
index 8db59c188..23687d43a 100644
--- a/src/bun.js/bindings/webcore/EventEmitter.h
+++ b/src/bun.js/bindings/webcore/EventEmitter.h
@@ -94,6 +94,8 @@ public:
}
}
+ bool m_hasIPCRef { false };
+
private:
EventEmitter(ScriptExecutionContext& context)
: ContextDestructionObserver(&context)
diff --git a/src/bun.js/ipc.zig b/src/bun.js/ipc.zig
new file mode 100644
index 000000000..05b9d683b
--- /dev/null
+++ b/src/bun.js/ipc.zig
@@ -0,0 +1,238 @@
+const uws = @import("../deps/uws.zig");
+const bun = @import("root").bun;
+const Environment = bun.Environment;
+const Global = bun.Global;
+const strings = bun.strings;
+const string = bun.string;
+const Output = @import("root").bun.Output;
+const MutableString = @import("root").bun.MutableString;
+const std = @import("std");
+const Allocator = std.mem.Allocator;
+const JSC = @import("root").bun.JSC;
+const JSValue = JSC.JSValue;
+const JSGlobalObject = JSC.JSGlobalObject;
+
+pub const log = Output.scoped(.IPC, false);
+
+pub const ipcHeaderLength = @sizeOf(u8) + @sizeOf(u32);
+pub const ipcVersion = 1;
+
+pub const DecodedIPCMessage = union(enum) {
+ version: u32,
+ data: JSValue,
+};
+
+pub const DecodeIPCMessageResult = struct {
+ bytes_consumed: u32,
+ message: DecodedIPCMessage,
+};
+
+pub const IPCDecodeError = error{ NotEnoughBytes, InvalidFormat };
+
+pub const IPCMessageType = enum(u8) {
+ Version = 1,
+ SerializedMessage = 2,
+ _,
+};
+
+/// Given potentially unfinished buffer `data`, attempt to decode and process a message from it.
+/// Returns `NotEnoughBytes` if there werent enough bytes
+/// Returns `InvalidFormat` if the message was invalid, probably close the socket in this case
+/// otherwise returns the number of bytes consumed.
+pub fn decodeIPCMessage(
+ data: []const u8,
+ globalThis: *JSC.JSGlobalObject,
+) IPCDecodeError!DecodeIPCMessageResult {
+ if (data.len < ipcHeaderLength) {
+ return IPCDecodeError.NotEnoughBytes;
+ }
+
+ const message_type: IPCMessageType = @enumFromInt(data[0]);
+ const message_len: u32 = @as(*align(1) const u32, @ptrCast(data[1 .. @sizeOf(u32) + 1])).*;
+
+ log("Received IPC message type {d} ({s}) len {d}", .{
+ @intFromEnum(message_type),
+ std.enums.tagName(IPCMessageType, message_type) orelse "unknown",
+ message_len,
+ });
+
+ switch (message_type) {
+ .Version => {
+ return .{
+ .bytes_consumed = ipcHeaderLength,
+ .message = .{ .version = message_len },
+ };
+ },
+ .SerializedMessage => {
+ if (data.len < (ipcHeaderLength + message_len)) {
+ return IPCDecodeError.NotEnoughBytes;
+ }
+
+ const message = data[ipcHeaderLength .. ipcHeaderLength + message_len];
+ const deserialized = JSValue.deserialize(message, globalThis);
+
+ if (deserialized == .zero) {
+ return IPCDecodeError.InvalidFormat;
+ }
+
+ return .{
+ .bytes_consumed = ipcHeaderLength + message_len,
+ .message = .{ .data = deserialized },
+ };
+ },
+ else => {
+ return IPCDecodeError.InvalidFormat;
+ },
+ }
+}
+
+pub const Socket = uws.NewSocketHandler(false);
+
+/// This type is shared between VirtualMachine and Subprocess for their respective IPC handlers
+///
+/// `Context` must be a struct that implements this interface:
+/// struct {
+/// globalThis: ?*JSGlobalObject,
+/// ipc_buffer: bun.ByteList,
+///
+/// fn handleIPCMessage(*Context, DecodedIPCMessage) void
+/// fn handleIPCClose(*Context, Socket) void
+/// }
+pub fn NewIPCHandler(comptime Context: type) type {
+ return struct {
+ pub fn onOpen(
+ _: *Context,
+ socket: Socket,
+ ) void {
+ // Write the version message
+ const Data = extern struct {
+ type: IPCMessageType align(1) = .Version,
+ version: u32 align(1) = ipcVersion,
+ };
+ const data: []const u8 = comptime @as([@sizeOf(Data)]u8, @bitCast(Data{}))[0..];
+ _ = socket.write(data, false);
+ socket.flush();
+ }
+ pub fn onClose(
+ this: *Context,
+ socket: Socket,
+ _: c_int,
+ _: ?*anyopaque,
+ ) void {
+ // ?! does uSockets .close call onClose?
+ log("onClose\n", .{});
+ this.handleIPCClose(socket);
+ }
+ // extern fn getpid() i32;
+ pub fn onData(
+ this: *Context,
+ socket: Socket,
+ data_: []const u8,
+ ) void {
+ var data = data_;
+ log("onData {}", .{std.fmt.fmtSliceHexLower(data)});
+
+ // if (comptime Context == bun.JSC.VirtualMachine.IPCInstance) {
+ // logDataOnly("{d} -> '{}'", .{ getpid(), std.fmt.fmtSliceHexLower(data) });
+ // }
+
+ // In the VirtualMachine case, `globalThis` is an optional, in case
+ // the vm is freed before the socket closes.
+ var globalThis = switch (@typeInfo(@TypeOf(this.globalThis))) {
+ .Pointer => this.globalThis,
+ .Optional => brk: {
+ if (this.globalThis) |global| {
+ break :brk global;
+ }
+ this.handleIPCClose(socket);
+ socket.close(0, null);
+ return;
+ },
+ else => @panic("Unexpected globalThis type: " ++ @typeName(@TypeOf(this.globalThis))),
+ };
+
+ // Decode the message with just the temporary buffer, and if that
+ // fails (not enough bytes) then we allocate to .ipc_buffer
+ if (this.ipc_buffer.len == 0) {
+ while (true) {
+ const result = decodeIPCMessage(data, globalThis) catch |e| switch (e) {
+ error.NotEnoughBytes => {
+ _ = this.ipc_buffer.write(bun.default_allocator, data) catch @panic("OOM");
+ log("hit NotEnoughBytes", .{});
+ return;
+ },
+ error.InvalidFormat => {
+ Output.printErrorln("InvalidFormatError during IPC message handling", .{});
+ this.handleIPCClose(socket);
+ socket.close(0, null);
+ return;
+ },
+ };
+
+ this.handleIPCMessage(result.message);
+
+ if (result.bytes_consumed < data.len) {
+ data = data[result.bytes_consumed..];
+ } else {
+ return;
+ }
+ }
+ }
+
+ _ = this.ipc_buffer.write(bun.default_allocator, data) catch @panic("OOM");
+
+ var slice = this.ipc_buffer.slice();
+ while (true) {
+ const result = decodeIPCMessage(slice, globalThis) catch |e| switch (e) {
+ error.NotEnoughBytes => {
+ // copy the remaining bytes to the start of the buffer
+ std.mem.copyForwards(u8, this.ipc_buffer.ptr[0..slice.len], slice);
+ this.ipc_buffer.len = @truncate(slice.len);
+ log("hit NotEnoughBytes2", .{});
+ return;
+ },
+ error.InvalidFormat => {
+ Output.printErrorln("InvalidFormatError during IPC message handling", .{});
+ this.handleIPCClose(socket);
+ socket.close(0, null);
+ return;
+ },
+ };
+
+ this.handleIPCMessage(result.message);
+
+ if (result.bytes_consumed < slice.len) {
+ slice = slice[result.bytes_consumed..];
+ } else {
+ // clear the buffer
+ this.ipc_buffer.len = 0;
+ return;
+ }
+ }
+ }
+
+ pub fn onWritable(
+ _: *Context,
+ _: Socket,
+ ) void {}
+ pub fn onTimeout(
+ _: *Context,
+ _: Socket,
+ ) void {}
+ pub fn onConnectError(
+ _: *Context,
+ _: Socket,
+ _: c_int,
+ ) void {}
+ pub fn onEnd(
+ _: *Context,
+ _: Socket,
+ ) void {}
+ };
+}
+
+/// This is used for Bun.spawn() IPC because otherwise we would have to copy the data once to get it to zig, then write it.
+/// Returns `true` on success, `false` on failure + throws a JS error.
+extern fn Bun__serializeJSValueForSubprocess(global: *JSC.JSGlobalObject, value: JSValue, fd: bun.FileDescriptor) bool;
+
+pub const serializeJSValueForSubprocess = Bun__serializeJSValueForSubprocess;
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index 212e6be71..6fd4cf557 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -84,6 +84,7 @@ const EventLoop = JSC.EventLoop;
const PendingResolution = @import("../resolver/resolver.zig").PendingResolution;
const ThreadSafeFunction = JSC.napi.ThreadSafeFunction;
const PackageManager = @import("../install/install.zig").PackageManager;
+const IPC = @import("ipc.zig");
const ModuleLoader = JSC.ModuleLoader;
const FetchFlags = JSC.FetchFlags;
@@ -259,7 +260,6 @@ pub const SavedSourceMap = struct {
const uws = @import("root").bun.uws;
pub export fn Bun__getDefaultGlobal() *JSGlobalObject {
- _ = @sizeOf(JSC.VirtualMachine) + 1;
return JSC.VirtualMachine.get().global;
}
@@ -280,20 +280,41 @@ export fn Bun__readOriginTimerStart(vm: *JSC.VirtualMachine) f64 {
return @as(f64, @floatCast((@as(f64, @floatFromInt(vm.origin_timestamp)) + JSC.VirtualMachine.origin_relative_epoch) / 1_000_000.0));
}
-// comptime {
-// if (!JSC.is_bindgen) {
-// _ = Bun__getDefaultGlobal;
-// _ = Bun__getVM;
-// _ = Bun__drainMicrotasks;
-// _ = Bun__queueTask;
-// _ = Bun__queueTaskConcurrently;
-// _ = Bun__handleRejectedPromise;
-// _ = Bun__readOriginTimer;
-// _ = Bun__onDidAppendPlugin;
-// _ = Bun__readOriginTimerStart;
-// _ = Bun__reportUnhandledError;
-// }
-// }
+pub export fn Bun__GlobalObject__hasIPC(global: *JSC.JSGlobalObject) bool {
+ return global.bunVM().ipc != null;
+}
+
+pub export fn Bun__Process__send(
+ globalObject: *JSGlobalObject,
+ callFrame: *JSC.CallFrame,
+) JSValue {
+ if (callFrame.argumentsCount() < 1) {
+ globalObject.throwInvalidArguments("process.send requires at least one argument", .{});
+ return .zero;
+ }
+ var vm = globalObject.bunVM();
+ if (vm.ipc) |ipc| {
+ const fd = ipc.socket.fd();
+ const success = IPC.serializeJSValueForSubprocess(
+ globalObject,
+ callFrame.argument(0),
+ fd,
+ );
+ return if (success) .undefined else .zero;
+ } else {
+ globalObject.throw("IPC Socket is no longer open.", .{});
+ return .zero;
+ }
+}
+
+pub export fn Bun__Process__disconnect(
+ globalObject: *JSGlobalObject,
+ callFrame: *JSC.CallFrame,
+) JSValue {
+ _ = callFrame;
+ _ = globalObject;
+ return .undefined;
+}
/// This function is called on the main thread
/// The bunVM() call will assert this
@@ -485,7 +506,6 @@ pub const VirtualMachine = struct {
is_us_loop_entered: bool = false,
pending_internal_promise: *JSC.JSInternalPromise = undefined,
auto_install_dependencies: bool = false,
- load_builtins_from_path: []const u8 = "",
onUnhandledRejection: *const OnUnhandledRejection = defaultOnUnhandledRejection,
onUnhandledRejectionCtx: ?*anyopaque = null,
@@ -500,6 +520,7 @@ pub const VirtualMachine = struct {
gc_controller: JSC.GarbageCollectionController = .{},
worker: ?*JSC.WebWorker = null,
+ ipc: ?*IPCInstance = null,
debugger: ?Debugger = null,
has_started_debugger: bool = false,
@@ -643,12 +664,15 @@ pub const VirtualMachine = struct {
pub fn loadExtraEnv(this: *VirtualMachine) void {
var map = this.bundler.env.map;
- if (map.get("BUN_SHOW_BUN_STACKFRAMES") != null)
+ if (map.get("BUN_SHOW_BUN_STACKFRAMES") != null) {
this.hide_bun_stackframes = false;
+ }
- if (map.get("BUN_OVERRIDE_MODULE_PATH")) |override_path| {
- if (override_path.len > 0) {
- this.load_builtins_from_path = override_path;
+ if (map.map.fetchSwapRemove("BUN_INTERNAL_IPC_FD")) |kv| {
+ if (std.fmt.parseInt(i32, kv.value, 10) catch null) |fd| {
+ this.initIPCInstance(fd);
+ } else {
+ Output.printErrorln("Failed to parse BUN_INTERNAL_IPC_FD", .{});
}
}
@@ -2712,6 +2736,69 @@ pub const VirtualMachine = struct {
}
}
+ extern fn Process__emitMessageEvent(global: *JSGlobalObject, value: JSValue) void;
+ extern fn Process__emitDisconnectEvent(global: *JSGlobalObject) void;
+
+ pub const IPCInstance = struct {
+ globalThis: ?*JSGlobalObject,
+ socket: IPC.Socket,
+ uws_context: *uws.SocketContext,
+ ipc_buffer: bun.ByteList,
+
+ pub fn handleIPCMessage(
+ this: *IPCInstance,
+ message: IPC.DecodedIPCMessage,
+ ) void {
+ switch (message) {
+ // In future versions we can read this in order to detect version mismatches,
+ // or disable future optimizations if the subprocess is old.
+ .version => |v| {
+ IPC.log("Parent IPC version is {d}", .{v});
+ },
+ .data => |data| {
+ IPC.log("Received IPC message from parent", .{});
+ if (this.globalThis) |global| {
+ Process__emitMessageEvent(global, data);
+ }
+ },
+ }
+ }
+
+ pub fn handleIPCClose(this: *IPCInstance, _: IPC.Socket) void {
+ if (this.globalThis) |global| {
+ var vm = global.bunVM();
+ vm.ipc = null;
+ Process__emitDisconnectEvent(global);
+ }
+ uws.us_socket_context_free(0, this.uws_context);
+ bun.default_allocator.destroy(this);
+ }
+
+ pub const Handlers = IPC.NewIPCHandler(IPCInstance);
+ };
+
+ pub fn initIPCInstance(this: *VirtualMachine, fd: i32) void {
+ this.event_loop.ensureWaker();
+ const context = uws.us_create_socket_context(0, this.event_loop_handle.?, @sizeOf(usize), .{}).?;
+ IPC.Socket.configure(context, true, *IPCInstance, IPCInstance.Handlers);
+
+ const socket = uws.newSocketFromFd(context, @sizeOf(*IPCInstance), fd) orelse {
+ uws.us_socket_context_free(0, context);
+ Output.prettyWarnln("Failed to initialize IPC connection to parent", .{});
+ return;
+ };
+
+ var instance = bun.default_allocator.create(IPCInstance) catch @panic("OOM");
+ instance.* = .{
+ .globalThis = this.global,
+ .socket = socket,
+ .uws_context = context,
+ .ipc_buffer = bun.ByteList{},
+ };
+ var ptr = socket.ext(*IPCInstance);
+ ptr.?.* = instance;
+ this.ipc = instance;
+ }
comptime {
if (!JSC.is_bindgen)
_ = Bun__remapStackFramePositions;
diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig
index 0c3313a46..f5e5cde72 100644
--- a/src/bun.js/module_loader.zig
+++ b/src/bun.js/module_loader.zig
@@ -2282,67 +2282,69 @@ pub const HardcodedModule = enum {
pub const Map = bun.ComptimeStringMap(
HardcodedModule,
.{
- .{ "buffer", HardcodedModule.@"node:buffer" },
.{ "bun", HardcodedModule.bun },
.{ "bun:ffi", HardcodedModule.@"bun:ffi" },
.{ "bun:jsc", HardcodedModule.@"bun:jsc" },
.{ "bun:main", HardcodedModule.@"bun:main" },
.{ "bun:sqlite", HardcodedModule.@"bun:sqlite" },
.{ "detect-libc", HardcodedModule.@"detect-libc" },
- .{ "node:assert", HardcodedModule.@"node:assert" },
- .{ "node:assert/strict", HardcodedModule.@"node:assert/strict" },
- .{ "node:async_hooks", HardcodedModule.@"node:async_hooks" },
- .{ "node:buffer", HardcodedModule.@"node:buffer" },
- .{ "node:child_process", HardcodedModule.@"node:child_process" },
- .{ "node:cluster", HardcodedModule.@"node:cluster" },
- .{ "node:console", HardcodedModule.@"node:console" },
- .{ "node:constants", HardcodedModule.@"node:constants" },
- .{ "node:crypto", HardcodedModule.@"node:crypto" },
- .{ "node:dgram", HardcodedModule.@"node:dgram" },
- .{ "node:diagnostics_channel", HardcodedModule.@"node:diagnostics_channel" },
- .{ "node:dns", HardcodedModule.@"node:dns" },
- .{ "node:dns/promises", HardcodedModule.@"node:dns/promises" },
- .{ "node:domain", HardcodedModule.@"node:domain" },
- .{ "node:events", HardcodedModule.@"node:events" },
- .{ "node:fs", HardcodedModule.@"node:fs" },
- .{ "node:fs/promises", HardcodedModule.@"node:fs/promises" },
- .{ "node:http", HardcodedModule.@"node:http" },
- .{ "node:http2", HardcodedModule.@"node:http2" },
- .{ "node:https", HardcodedModule.@"node:https" },
- .{ "node:inspector", HardcodedModule.@"node:inspector" },
- .{ "node:module", HardcodedModule.@"node:module" },
- .{ "node:net", HardcodedModule.@"node:net" },
- .{ "node:os", HardcodedModule.@"node:os" },
- .{ "node:path", HardcodedModule.@"node:path" },
- .{ "node:path/posix", HardcodedModule.@"node:path/posix" },
- .{ "node:path/win32", HardcodedModule.@"node:path/win32" },
- .{ "node:punycode", HardcodedModule.@"node:punycode" },
- .{ "node:perf_hooks", HardcodedModule.@"node:perf_hooks" },
- .{ "node:process", HardcodedModule.@"node:process" },
- .{ "node:querystring", HardcodedModule.@"node:querystring" },
.{ "node-fetch", HardcodedModule.@"node-fetch" },
.{ "isomorphic-fetch", HardcodedModule.@"isomorphic-fetch" },
+
+ .{ "assert", HardcodedModule.@"node:assert" },
+ .{ "assert/strict", HardcodedModule.@"node:assert/strict" },
+ .{ "async_hooks", HardcodedModule.@"node:async_hooks" },
+ .{ "buffer", HardcodedModule.@"node:buffer" },
+ .{ "child_process", HardcodedModule.@"node:child_process" },
+ .{ "cluster", HardcodedModule.@"node:cluster" },
+ .{ "console", HardcodedModule.@"node:console" },
+ .{ "constants", HardcodedModule.@"node:constants" },
+ .{ "crypto", HardcodedModule.@"node:crypto" },
+ .{ "dgram", HardcodedModule.@"node:dgram" },
+ .{ "diagnostics_channel", HardcodedModule.@"node:diagnostics_channel" },
+ .{ "dns", HardcodedModule.@"node:dns" },
+ .{ "dns/promises", HardcodedModule.@"node:dns/promises" },
+ .{ "domain", HardcodedModule.@"node:domain" },
+ .{ "events", HardcodedModule.@"node:events" },
+ .{ "fs", HardcodedModule.@"node:fs" },
+ .{ "fs/promises", HardcodedModule.@"node:fs/promises" },
+ .{ "http", HardcodedModule.@"node:http" },
+ .{ "http2", HardcodedModule.@"node:http2" },
+ .{ "https", HardcodedModule.@"node:https" },
+ .{ "inspector", HardcodedModule.@"node:inspector" },
+ .{ "module", HardcodedModule.@"node:module" },
+ .{ "net", HardcodedModule.@"node:net" },
+ .{ "os", HardcodedModule.@"node:os" },
+ .{ "path", HardcodedModule.@"node:path" },
+ .{ "path/posix", HardcodedModule.@"node:path/posix" },
+ .{ "path/win32", HardcodedModule.@"node:path/win32" },
+ .{ "punycode", HardcodedModule.@"node:punycode" },
+ .{ "perf_hooks", HardcodedModule.@"node:perf_hooks" },
+ .{ "process", HardcodedModule.@"node:process" },
+ .{ "querystring", HardcodedModule.@"node:querystring" },
.{ "node:readline", HardcodedModule.@"node:readline" },
- .{ "node:readline/promises", HardcodedModule.@"node:readline/promises" },
- .{ "node:repl", HardcodedModule.@"node:repl" },
- .{ "node:stream", HardcodedModule.@"node:stream" },
- .{ "node:stream/consumers", HardcodedModule.@"node:stream/consumers" },
- .{ "node:stream/promises", HardcodedModule.@"node:stream/promises" },
- .{ "node:stream/web", HardcodedModule.@"node:stream/web" },
- .{ "node:string_decoder", HardcodedModule.@"node:string_decoder" },
- .{ "node:timers", HardcodedModule.@"node:timers" },
- .{ "node:timers/promises", HardcodedModule.@"node:timers/promises" },
- .{ "node:tls", HardcodedModule.@"node:tls" },
- .{ "node:trace_events", HardcodedModule.@"node:trace_events" },
- .{ "node:tty", HardcodedModule.@"node:tty" },
- .{ "node:url", HardcodedModule.@"node:url" },
- .{ "node:util", HardcodedModule.@"node:util" },
- .{ "node:util/types", HardcodedModule.@"node:util/types" },
- .{ "node:v8", HardcodedModule.@"node:v8" },
- .{ "node:vm", HardcodedModule.@"node:vm" },
- .{ "node:wasi", HardcodedModule.@"node:wasi" },
- .{ "node:worker_threads", HardcodedModule.@"node:worker_threads" },
- .{ "node:zlib", HardcodedModule.@"node:zlib" },
+ .{ "readline", HardcodedModule.@"node:readline" },
+ .{ "readline/promises", HardcodedModule.@"node:readline/promises" },
+ .{ "repl", HardcodedModule.@"node:repl" },
+ .{ "stream", HardcodedModule.@"node:stream" },
+ .{ "stream/consumers", HardcodedModule.@"node:stream/consumers" },
+ .{ "stream/promises", HardcodedModule.@"node:stream/promises" },
+ .{ "stream/web", HardcodedModule.@"node:stream/web" },
+ .{ "string_decoder", HardcodedModule.@"node:string_decoder" },
+ .{ "timers", HardcodedModule.@"node:timers" },
+ .{ "timers/promises", HardcodedModule.@"node:timers/promises" },
+ .{ "tls", HardcodedModule.@"node:tls" },
+ .{ "trace_events", HardcodedModule.@"node:trace_events" },
+ .{ "tty", HardcodedModule.@"node:tty" },
+ .{ "url", HardcodedModule.@"node:url" },
+ .{ "util", HardcodedModule.@"node:util" },
+ .{ "util/types", HardcodedModule.@"node:util/types" },
+ .{ "v8", HardcodedModule.@"node:v8" },
+ .{ "vm", HardcodedModule.@"node:vm" },
+ .{ "wasi", HardcodedModule.@"node:wasi" },
+ .{ "worker_threads", HardcodedModule.@"node:worker_threads" },
+ .{ "zlib", HardcodedModule.@"node:zlib" },
+
.{ "undici", HardcodedModule.undici },
.{ "ws", HardcodedModule.ws },
.{ "@vercel/fetch", HardcodedModule.@"@vercel/fetch" },
@@ -2358,138 +2360,136 @@ pub const HardcodedModule = enum {
pub const Aliases = struct {
// Used by both Bun and Node.
const common_alias_kvs = .{
- .{ "node:assert", .{ .path = "node:assert" } },
- .{ "node:assert/strict", .{ .path = "node:assert/strict" } },
- .{ "node:async_hooks", .{ .path = "node:async_hooks" } },
- .{ "node:buffer", .{ .path = "node:buffer" } },
- .{ "node:child_process", .{ .path = "node:child_process" } },
- .{ "node:cluster", .{ .path = "node:cluster" } },
- .{ "node:console", .{ .path = "node:console" } },
- .{ "node:constants", .{ .path = "node:constants" } },
- .{ "node:crypto", .{ .path = "node:crypto" } },
- .{ "node:dgram", .{ .path = "node:dgram" } },
- .{ "node:diagnostics_channel", .{ .path = "node:diagnostics_channel" } },
- .{ "node:dns", .{ .path = "node:dns" } },
- .{ "node:dns/promises", .{ .path = "node:dns/promises" } },
- .{ "node:domain", .{ .path = "node:domain" } },
- .{ "node:events", .{ .path = "node:events" } },
- .{ "node:fs", .{ .path = "node:fs" } },
- .{ "node:fs/promises", .{ .path = "node:fs/promises" } },
- .{ "node:http", .{ .path = "node:http" } },
- .{ "node:http2", .{ .path = "node:http2" } },
- .{ "node:https", .{ .path = "node:https" } },
- .{ "node:inspector", .{ .path = "node:inspector" } },
- .{ "node:module", .{ .path = "node:module" } },
- .{ "node:net", .{ .path = "node:net" } },
- .{ "node:os", .{ .path = "node:os" } },
- .{ "node:path", .{ .path = "node:path" } },
- .{ "node:path/posix", .{ .path = "node:path/posix" } },
- .{ "node:path/win32", .{ .path = "node:path/win32" } },
- .{ "node:perf_hooks", .{ .path = "node:perf_hooks" } },
- .{ "node:process", .{ .path = "node:process" } },
- .{ "node:punycode", .{ .path = "node:punycode" } },
- .{ "node:querystring", .{ .path = "node:querystring" } },
- .{ "node:readline", .{ .path = "node:readline" } },
- .{ "node:readline/promises", .{ .path = "node:readline/promises" } },
- .{ "node:repl", .{ .path = "node:repl" } },
- .{ "node:stream", .{ .path = "node:stream" } },
- .{ "node:stream/consumers", .{ .path = "node:stream/consumers" } },
- .{ "node:stream/promises", .{ .path = "node:stream/promises" } },
- .{ "node:stream/web", .{ .path = "node:stream/web" } },
- .{ "node:string_decoder", .{ .path = "node:string_decoder" } },
- .{ "node:timers", .{ .path = "node:timers" } },
- .{ "node:timers/promises", .{ .path = "node:timers/promises" } },
- .{ "node:tls", .{ .path = "node:tls" } },
- .{ "node:trace_events", .{ .path = "node:trace_events" } },
- .{ "node:tty", .{ .path = "node:tty" } },
- .{ "node:url", .{ .path = "node:url" } },
- .{ "node:util", .{ .path = "node:util" } },
- .{ "node:util/types", .{ .path = "node:util/types" } },
- .{ "node:v8", .{ .path = "node:v8" } },
- .{ "node:vm", .{ .path = "node:vm" } },
- .{ "node:wasi", .{ .path = "node:wasi" } },
- .{ "node:worker_threads", .{ .path = "node:worker_threads" } },
- .{ "node:zlib", .{ .path = "node:zlib" } },
-
- .{ "assert", .{ .path = "node:assert" } },
- .{ "assert/strict", .{ .path = "node:assert/strict" } },
- .{ "async_hooks", .{ .path = "node:async_hooks" } },
- .{ "buffer", .{ .path = "node:buffer" } },
- .{ "child_process", .{ .path = "node:child_process" } },
- .{ "cluster", .{ .path = "node:cluster" } },
- .{ "console", .{ .path = "node:console" } },
- .{ "constants", .{ .path = "node:constants" } },
- .{ "crypto", .{ .path = "node:crypto" } },
- .{ "dgram", .{ .path = "node:dgram" } },
- .{ "diagnostics_channel", .{ .path = "node:diagnostics_channel" } },
- .{ "dns", .{ .path = "node:dns" } },
- .{ "dns/promises", .{ .path = "node:dns/promises" } },
- .{ "domain", .{ .path = "node:domain" } },
- .{ "events", .{ .path = "node:events" } },
- .{ "fs", .{ .path = "node:fs" } },
- .{ "fs/promises", .{ .path = "node:fs/promises" } },
- .{ "http", .{ .path = "node:http" } },
- .{ "http2", .{ .path = "node:http2" } },
- .{ "https", .{ .path = "node:https" } },
- .{ "inspector", .{ .path = "node:inspector" } },
- .{ "module", .{ .path = "node:module" } },
- .{ "net", .{ .path = "node:net" } },
- .{ "os", .{ .path = "node:os" } },
- .{ "path", .{ .path = "node:path" } },
- .{ "path/posix", .{ .path = "node:path/posix" } },
- .{ "path/win32", .{ .path = "node:path/win32" } },
- .{ "perf_hooks", .{ .path = "node:perf_hooks" } },
- .{ "process", .{ .path = "node:process" } },
- .{ "punycode", .{ .path = "node:punycode" } },
- .{ "querystring", .{ .path = "node:querystring" } },
- .{ "readline", .{ .path = "node:readline" } },
- .{ "readline/promises", .{ .path = "node:readline/promises" } },
- .{ "repl", .{ .path = "node:repl" } },
- .{ "stream", .{ .path = "node:stream" } },
- .{ "stream/consumers", .{ .path = "node:stream/consumers" } },
- .{ "stream/promises", .{ .path = "node:stream/promises" } },
- .{ "stream/web", .{ .path = "node:stream/web" } },
- .{ "string_decoder", .{ .path = "node:string_decoder" } },
- .{ "timers", .{ .path = "node:timers" } },
- .{ "timers/promises", .{ .path = "node:timers/promises" } },
- .{ "tls", .{ .path = "node:tls" } },
- .{ "trace_events", .{ .path = "node:trace_events" } },
- .{ "tty", .{ .path = "node:tty" } },
- .{ "url", .{ .path = "node:url" } },
- .{ "util", .{ .path = "node:util" } },
- .{ "util/types", .{ .path = "node:util/types" } },
- .{ "v8", .{ .path = "node:v8" } },
- .{ "vm", .{ .path = "node:vm" } },
- .{ "wasi", .{ .path = "node:wasi" } },
- .{ "worker_threads", .{ .path = "node:worker_threads" } },
- .{ "zlib", .{ .path = "node:zlib" } },
+ .{ "node:assert", .{ .path = "assert" } },
+ .{ "node:assert/strict", .{ .path = "assert/strict" } },
+ .{ "node:async_hooks", .{ .path = "async_hooks" } },
+ .{ "node:buffer", .{ .path = "buffer" } },
+ .{ "node:child_process", .{ .path = "child_process" } },
+ .{ "node:cluster", .{ .path = "cluster" } },
+ .{ "node:console", .{ .path = "console" } },
+ .{ "node:constants", .{ .path = "constants" } },
+ .{ "node:crypto", .{ .path = "crypto" } },
+ .{ "node:dgram", .{ .path = "dgram" } },
+ .{ "node:diagnostics_channel", .{ .path = "diagnostics_channel" } },
+ .{ "node:dns", .{ .path = "dns" } },
+ .{ "node:dns/promises", .{ .path = "dns/promises" } },
+ .{ "node:domain", .{ .path = "domain" } },
+ .{ "node:events", .{ .path = "events" } },
+ .{ "node:fs", .{ .path = "fs" } },
+ .{ "node:fs/promises", .{ .path = "fs/promises" } },
+ .{ "node:http", .{ .path = "http" } },
+ .{ "node:http2", .{ .path = "http2" } },
+ .{ "node:https", .{ .path = "https" } },
+ .{ "node:inspector", .{ .path = "inspector" } },
+ .{ "node:module", .{ .path = "module" } },
+ .{ "node:net", .{ .path = "net" } },
+ .{ "node:os", .{ .path = "os" } },
+ .{ "node:path", .{ .path = "path" } },
+ .{ "node:path/posix", .{ .path = "path/posix" } },
+ .{ "node:path/win32", .{ .path = "path/win32" } },
+ .{ "node:perf_hooks", .{ .path = "perf_hooks" } },
+ .{ "node:process", .{ .path = "process" } },
+ .{ "node:punycode", .{ .path = "punycode" } },
+ .{ "node:querystring", .{ .path = "querystring" } },
+ .{ "node:readline", .{ .path = "readline" } },
+ .{ "node:readline/promises", .{ .path = "readline/promises" } },
+ .{ "node:repl", .{ .path = "repl" } },
+ .{ "node:stream", .{ .path = "stream" } },
+ .{ "node:stream/consumers", .{ .path = "stream/consumers" } },
+ .{ "node:stream/promises", .{ .path = "stream/promises" } },
+ .{ "node:stream/web", .{ .path = "stream/web" } },
+ .{ "node:string_decoder", .{ .path = "string_decoder" } },
+ .{ "node:timers", .{ .path = "timers" } },
+ .{ "node:timers/promises", .{ .path = "timers/promises" } },
+ .{ "node:tls", .{ .path = "tls" } },
+ .{ "node:trace_events", .{ .path = "trace_events" } },
+ .{ "node:tty", .{ .path = "tty" } },
+ .{ "node:url", .{ .path = "url" } },
+ .{ "node:util", .{ .path = "util" } },
+ .{ "node:util/types", .{ .path = "util/types" } },
+ .{ "node:v8", .{ .path = "v8" } },
+ .{ "node:vm", .{ .path = "vm" } },
+ .{ "node:wasi", .{ .path = "wasi" } },
+ .{ "node:worker_threads", .{ .path = "worker_threads" } },
+ .{ "node:zlib", .{ .path = "zlib" } },
+
+ .{ "assert", .{ .path = "assert" } },
+ .{ "assert/strict", .{ .path = "assert/strict" } },
+ .{ "async_hooks", .{ .path = "async_hooks" } },
+ .{ "buffer", .{ .path = "buffer" } },
+ .{ "child_process", .{ .path = "child_process" } },
+ .{ "cluster", .{ .path = "cluster" } },
+ .{ "console", .{ .path = "console" } },
+ .{ "constants", .{ .path = "constants" } },
+ .{ "crypto", .{ .path = "crypto" } },
+ .{ "dgram", .{ .path = "dgram" } },
+ .{ "diagnostics_channel", .{ .path = "diagnostics_channel" } },
+ .{ "dns", .{ .path = "dns" } },
+ .{ "dns/promises", .{ .path = "dns/promises" } },
+ .{ "domain", .{ .path = "domain" } },
+ .{ "events", .{ .path = "events" } },
+ .{ "fs", .{ .path = "fs" } },
+ .{ "fs/promises", .{ .path = "fs/promises" } },
+ .{ "http", .{ .path = "http" } },
+ .{ "http2", .{ .path = "http2" } },
+ .{ "https", .{ .path = "https" } },
+ .{ "inspector", .{ .path = "inspector" } },
+ .{ "module", .{ .path = "module" } },
+ .{ "net", .{ .path = "net" } },
+ .{ "os", .{ .path = "os" } },
+ .{ "path", .{ .path = "path" } },
+ .{ "path/posix", .{ .path = "path/posix" } },
+ .{ "path/win32", .{ .path = "path/win32" } },
+ .{ "perf_hooks", .{ .path = "perf_hooks" } },
+ .{ "process", .{ .path = "process" } },
+ .{ "punycode", .{ .path = "punycode" } },
+ .{ "querystring", .{ .path = "querystring" } },
+ .{ "readline", .{ .path = "readline" } },
+ .{ "readline/promises", .{ .path = "readline/promises" } },
+ .{ "repl", .{ .path = "repl" } },
+ .{ "stream", .{ .path = "stream" } },
+ .{ "stream/consumers", .{ .path = "stream/consumers" } },
+ .{ "stream/promises", .{ .path = "stream/promises" } },
+ .{ "stream/web", .{ .path = "stream/web" } },
+ .{ "string_decoder", .{ .path = "string_decoder" } },
+ .{ "timers", .{ .path = "timers" } },
+ .{ "timers/promises", .{ .path = "timers/promises" } },
+ .{ "tls", .{ .path = "tls" } },
+ .{ "trace_events", .{ .path = "trace_events" } },
+ .{ "tty", .{ .path = "tty" } },
+ .{ "url", .{ .path = "url" } },
+ .{ "util", .{ .path = "util" } },
+ .{ "util/types", .{ .path = "util/types" } },
+ .{ "v8", .{ .path = "v8" } },
+ .{ "vm", .{ .path = "vm" } },
+ .{ "wasi", .{ .path = "wasi" } },
+ .{ "worker_threads", .{ .path = "worker_threads" } },
+ .{ "zlib", .{ .path = "zlib" } },
// It implements the same interface
- .{ "sys", .{ .path = "node:util" } },
- .{ "node:sys", .{ .path = "node:util" } },
+ .{ "sys", .{ .path = "util" } },
+ .{ "node:sys", .{ .path = "util" } },
// These are returned in builtinModules, but probably not many packages use them
// so we will just alias them.
- .{ "_http_agent", .{ .path = "node:http" } },
- .{ "_http_client", .{ .path = "node:http" } },
- .{ "_http_common", .{ .path = "node:http" } },
- .{ "_http_incoming", .{ .path = "node:http" } },
- .{ "_http_outgoing", .{ .path = "node:http" } },
- .{ "_http_server", .{ .path = "node:http" } },
- .{ "_stream_duplex", .{ .path = "node:stream" } },
- .{ "_stream_passthrough", .{ .path = "node:stream" } },
- .{ "_stream_readable", .{ .path = "node:stream" } },
- .{ "_stream_transform", .{ .path = "node:stream" } },
- .{ "_stream_writable", .{ .path = "node:stream" } },
- .{ "_stream_wrap", .{ .path = "node:stream" } },
- .{ "_tls_wrap", .{ .path = "node:tls" } },
- .{ "_tls_common", .{ .path = "node:tls" } },
-
- // Older versions of `readable-stream` is incompatible with latest
- // version of Node.js Stream API, which `bun` implements
- // .{ "readable-stream", .{ .path = "node:stream" } },
- // .{ "readable-stream/consumer", .{ .path = "node:stream/consumers" } },
- // .{ "readable-stream/web", .{ .path = "node:stream/web" } },
+ .{ "_http_agent", .{ .path = "http" } },
+ .{ "_http_client", .{ .path = "http" } },
+ .{ "_http_common", .{ .path = "http" } },
+ .{ "_http_incoming", .{ .path = "http" } },
+ .{ "_http_outgoing", .{ .path = "http" } },
+ .{ "_http_server", .{ .path = "http" } },
+ .{ "_stream_duplex", .{ .path = "stream" } },
+ .{ "_stream_passthrough", .{ .path = "stream" } },
+ .{ "_stream_readable", .{ .path = "stream" } },
+ .{ "_stream_transform", .{ .path = "stream" } },
+ .{ "_stream_writable", .{ .path = "stream" } },
+ .{ "_stream_wrap", .{ .path = "stream" } },
+ .{ "_tls_wrap", .{ .path = "tls" } },
+ .{ "_tls_common", .{ .path = "tls" } },
+
+ .{ "next/dist/compiled/ws", .{ .path = "ws" } },
+ .{ "next/dist/compiled/node-fetch", .{ .path = "node-fetch" } },
+ .{ "next/dist/compiled/undici", .{ .path = "undici" } },
};
const bun_extra_alias_kvs = .{
@@ -2511,13 +2511,13 @@ pub const HardcodedModule = enum {
.{ "ws", .{ .path = "ws" } },
.{ "ws/lib/websocket", .{ .path = "ws" } },
- .{ "inspector/promises", .{ .path = "node:inspector" } },
- .{ "node:inspector/promises", .{ .path = "node:inspector" } },
+ .{ "inspector/promises", .{ .path = "inspector" } },
+ .{ "node:inspector/promises", .{ .path = "inspector" } },
};
const node_alias_kvs = .{
- .{ "inspector/promises", .{ .path = "node:inspector/promises" } },
- .{ "node:inspector/promises", .{ .path = "node:inspector/promises" } },
+ .{ "inspector/promises", .{ .path = "inspector/promises" } },
+ .{ "node:inspector/promises", .{ .path = "inspector/promises" } },
.{ "node:test", .{ .path = "node:test" } },
};
diff --git a/src/bun.js/modules/NodeModuleModule.h b/src/bun.js/modules/NodeModuleModule.h
index 7c8f6ee14..b3c34eb5e 100644
--- a/src/bun.js/modules/NodeModuleModule.h
+++ b/src/bun.js/modules/NodeModuleModule.h
@@ -270,6 +270,40 @@ template <std::size_t N, class T> consteval std::size_t countof(T (&)[N]) {
return N;
}
+JSC_DEFINE_CUSTOM_GETTER(get_resolveFilename, (JSGlobalObject * globalObject,
+ EncodedJSValue thisValue,
+ PropertyName propertyName)) {
+ auto override = static_cast<Zig::GlobalObject *>(globalObject)
+ ->m_nodeModuleOverriddenResolveFilename.get();
+ if (override) {
+ return JSValue::encode(override);
+ }
+ // Instead of storing the original function on the global object and have
+ // those extra bytes, just have it be a property alias.
+ JSObject *thisObject = JSValue::decode(thisValue).getObject();
+ if (!thisObject)
+ return JSValue::encode(jsUndefined());
+ auto &vm = globalObject->vm();
+ return JSValue::encode(thisObject->getDirect(
+ vm, Identifier::fromString(vm, "__resolveFilename"_s)));
+}
+
+JSC_DEFINE_CUSTOM_SETTER(set_resolveFilename,
+ (JSGlobalObject * globalObject,
+ EncodedJSValue thisValue, EncodedJSValue value,
+ PropertyName propertyName)) {
+ auto valueJS = JSValue::decode(value);
+ if (valueJS.isCell()) {
+ if (auto fn = jsDynamicCast<JSFunction *>(valueJS.asCell())) {
+ static_cast<Zig::GlobalObject *>(globalObject)
+ ->m_nodeModuleOverriddenResolveFilename.set(globalObject->vm(),
+ globalObject, fn);
+ return true;
+ }
+ }
+ return false;
+}
+
namespace Zig {
DEFINE_NATIVE_MODULE(NodeModule) {
@@ -303,6 +337,14 @@ DEFINE_NATIVE_MODULE(NodeModule) {
put(Identifier::fromString(vm, "Module"_s), defaultObject);
+ defaultObject->putDirectCustomAccessor(
+ vm, JSC::Identifier::fromString(vm, "_resolveFilename"_s),
+ JSC::CustomGetterSetter::create(vm, get_resolveFilename,
+ set_resolveFilename),
+ JSC::PropertyAttribute::CustomAccessor | 0);
+ putNativeFn(Identifier::fromString(vm, "__resolveFilename"_s),
+ jsFunctionResolveFileName);
+
putNativeFn(Identifier::fromString(vm, "createRequire"_s),
jsFunctionNodeModuleCreateRequire);
putNativeFn(Identifier::fromString(vm, "paths"_s),
@@ -314,8 +356,6 @@ DEFINE_NATIVE_MODULE(NodeModule) {
putNativeFn(Identifier::fromString(vm, "SourceMap"_s), jsFunctionSourceMap);
putNativeFn(Identifier::fromString(vm, "isBuiltin"_s),
jsFunctionIsBuiltinModule);
- putNativeFn(Identifier::fromString(vm, "_resolveFilename"_s),
- jsFunctionResolveFileName);
putNativeFn(Identifier::fromString(vm, "_nodeModulePaths"_s),
Resolver__nodeModulePathsForJS);
putNativeFn(Identifier::fromString(vm, "wrap"_s), jsFunctionWrap);
diff --git a/src/bun.js/node/node_fs_watcher.zig b/src/bun.js/node/node_fs_watcher.zig
index d6d2f8a2f..ccb1a987f 100644
--- a/src/bun.js/node/node_fs_watcher.zig
+++ b/src/bun.js/node/node_fs_watcher.zig
@@ -351,11 +351,11 @@ pub const FSWatcher = struct {
// already aborted?
if (s.aborted()) {
// safely abort next tick
- var current_task: FSWatchTask = .{
+ this.current_task = .{
.ctx = this,
};
- current_task.append("", .abort, false);
- current_task.enqueue();
+ this.current_task.append("", .abort, false);
+ this.current_task.enqueue();
} else {
// watch for abortion
this.signal = s.listen(FSWatcher, this, FSWatcher.emitAbort);
@@ -587,7 +587,10 @@ pub const FSWatcher = struct {
errdefer ctx.deinit();
- ctx.path_watcher = try PathWatcher.watch(vm, file_path_z, args.recursive, onPathUpdate, onUpdateEnd, bun.cast(*anyopaque, ctx));
+ ctx.path_watcher = if (args.signal == null or !args.signal.?.aborted())
+ try PathWatcher.watch(vm, file_path_z, args.recursive, onPathUpdate, onUpdateEnd, bun.cast(*anyopaque, ctx))
+ else
+ null;
ctx.initJS(args.listener);
return ctx;
}
diff --git a/src/bun.js/node/types.zig b/src/bun.js/node/types.zig
index 328b71b60..51af22052 100644
--- a/src/bun.js/node/types.zig
+++ b/src/bun.js/node/types.zig
@@ -2480,7 +2480,7 @@ pub const Process = struct {
}
vm.onExit();
- std.os.exit(code);
+ bun.Global.exit(code);
}
pub export const Bun__version: [*:0]const u8 = "v" ++ bun.Global.package_json_version;
diff --git a/src/bun.js/rare_data.zig b/src/bun.js/rare_data.zig
index 706826033..44e482049 100644
--- a/src/bun.js/rare_data.zig
+++ b/src/bun.js/rare_data.zig
@@ -11,6 +11,8 @@ const bun = @import("root").bun;
const WebSocketClientMask = @import("../http/websocket_http_client.zig").Mask;
const UUID = @import("./uuid.zig");
const StatWatcherScheduler = @import("./node/node_fs_stat_watcher.zig").StatWatcherScheduler;
+const IPC = @import("./ipc.zig");
+const uws = @import("root").bun.uws;
boring_ssl_engine: ?*BoringSSL.ENGINE = null,
editor_context: EditorContext = EditorContext{},
@@ -31,6 +33,8 @@ file_polls_: ?*JSC.FilePoll.Store = null,
global_dns_data: ?*JSC.DNS.GlobalData = null,
+spawn_ipc_usockets_context: ?*uws.SocketContext = null,
+
mime_types: ?bun.HTTP.MimeType.Map = null,
node_fs_stat_watcher_scheduler: ?*StatWatcherScheduler = null,
@@ -310,6 +314,20 @@ pub fn stdin(rare: *RareData) *Blob.Store {
};
}
+const Subprocess = @import("./api/bun/subprocess.zig").Subprocess;
+
+pub fn spawnIPCContext(rare: *RareData, vm: *JSC.VirtualMachine) *uws.SocketContext {
+ if (rare.spawn_ipc_usockets_context) |ctx| {
+ return ctx;
+ }
+
+ var opts: uws.us_socket_context_options_t = .{};
+ const ctx = uws.us_create_socket_context(0, vm.event_loop_handle.?, @sizeOf(usize), opts).?;
+ IPC.Socket.configure(ctx, true, *Subprocess, Subprocess.IPCHandler);
+ rare.spawn_ipc_usockets_context = ctx;
+ return ctx;
+}
+
pub fn globalDNSResolver(rare: *RareData, vm: *JSC.VirtualMachine) *JSC.DNS.DNSResolver {
if (rare.global_dns_data == null) {
rare.global_dns_data = JSC.DNS.GlobalData.init(vm.allocator, vm);