bun_runtime 0.5.4

Bao runtime integration — JS engine + Bun API + event loop
// @trace REQ-ENG-006 [api:node:domain]
// Deprecated Node.js module — minimal compatibility implementation.
// Domain is essentially an EventEmitter with .run() and error interception.
use ::std::ptr::NonNull;
use bun_core::ZBox;

use mozjs::jsapi::*;
use mozjs::jsval::{BooleanValue, JSVal, ObjectValue, StringValue, UndefinedValue};
use mozjs::rooted;
use mozjs::rust::wrappers2 as w2;

use crate::require::cache_builtin;

/// Point the Domain prototype at the events module's EventEmitter
/// prototype (Domain inherits from EventEmitter when the events builtin is
/// already installed; a missing events/EventEmitter face leaves the plain
/// object prototype — every guard is a no-op fallthrough).
fn inherit_domain_proto_from_events(cx: &mut mozjs::context::JSContext, proto_obj: *mut JSObject) {
    unsafe {
        let events_obj = crate::gc_store::gc_store_get(cx.raw_cx(), "builtin:events");
        let Some(events) = events_obj else { return };
        if events.is_null() {
            return;
        }
        rooted!(&in(cx) let events_root = events);
        let mut ee_proto = UndefinedValue();
        JS_GetProperty(
            cx.raw_cx(),
            events_root.handle().into(),
            c"EventEmitter".as_ptr(),
            MutableHandle::<Value> {
                _phantom_0: ::std::marker::PhantomData,
                ptr: &mut ee_proto,
            },
        );
        if !ee_proto.is_object() {
            return;
        }
        rooted!(&in(cx) let ee_ctor = ee_proto.to_object());
        let mut ee_proto_val = UndefinedValue();
        JS_GetProperty(
            cx.raw_cx(),
            ee_ctor.handle().into(),
            c"prototype".as_ptr(),
            MutableHandle::<Value> {
                _phantom_0: ::std::marker::PhantomData,
                ptr: &mut ee_proto_val,
            },
        );
        if !ee_proto_val.is_object() {
            return;
        }
        rooted!(&in(cx) let ee_proto_obj = ee_proto_val.to_object());
        rooted!(&in(cx) let proto_root = proto_obj);
        JS_SetPrototype(
            cx.raw_cx(),
            proto_root.handle().into(),
            ee_proto_obj.handle().into(),
        );
    }
}

/// Define the Domain-specific prototype methods (run/add/remove/bind/
/// intercept/enter/exit/dispose).
fn define_domain_proto_methods(cx: &mut mozjs::context::JSContext, proto_obj: *mut JSObject) {
    unsafe {
    rooted!(&in(cx) let proto_root = proto_obj);
    w2::JS_DefineFunction(
        cx,
        proto_root.handle(),
        c"run".as_ptr(),
        Some(domain_run),
        1,
        JSPROP_ENUMERATE as u32,
    );
    w2::JS_DefineFunction(
        cx,
        proto_root.handle(),
        c"add".as_ptr(),
        Some(domain_add),
        1,
        JSPROP_ENUMERATE as u32,
    );
    w2::JS_DefineFunction(
        cx,
        proto_root.handle(),
        c"remove".as_ptr(),
        Some(domain_remove),
        1,
        JSPROP_ENUMERATE as u32,
    );
    w2::JS_DefineFunction(
        cx,
        proto_root.handle(),
        c"bind".as_ptr(),
        Some(domain_bind),
        1,
        JSPROP_ENUMERATE as u32,
    );
    w2::JS_DefineFunction(
        cx,
        proto_root.handle(),
        c"intercept".as_ptr(),
        Some(domain_intercept),
        1,
        JSPROP_ENUMERATE as u32,
    );
    w2::JS_DefineFunction(
        cx,
        proto_root.handle(),
        c"enter".as_ptr(),
        Some(domain_enter),
        0,
        JSPROP_ENUMERATE as u32,
    );
    w2::JS_DefineFunction(
        cx,
        proto_root.handle(),
        c"exit".as_ptr(),
        Some(domain_exit),
        0,
        JSPROP_ENUMERATE as u32,
    );
    w2::JS_DefineFunction(
        cx,
        proto_root.handle(),
        c"dispose".as_ptr(),
        Some(domain_dispose),
        0,
        JSPROP_ENUMERATE as u32,
    );
    }
}

pub fn install(cx: &mut mozjs::context::JSContext) {
    rooted!(&in(cx) let domain_obj = unsafe { w2::JS_NewPlainObject(cx) });
    if domain_obj.get().is_null() {
        return;
    }

    unsafe {
        // Domain class constructor
        let domain_fn = JS_NewFunction(
            cx.raw_cx(),
            Some(domain_constructor),
            0,
            0x400,
            c"Domain".as_ptr(),
        );
        if !domain_fn.is_null() {
            let fn_obj = JS_GetFunctionObject(domain_fn);
            rooted!(&in(cx) let fn_root = fn_obj);

            // Static create() method — returns a new Domain instance
            w2::JS_DefineFunction(
                cx,
                fn_root.handle(),
                c"create".as_ptr(),
                Some(domain_create),
                0,
                JSPROP_ENUMERATE as u32,
            );

            // Instance methods defined on prototype
            rooted!(&in(cx) let proto = w2::JS_NewPlainObject(cx));
            if !proto.get().is_null() {
                // Inherit from EventEmitter
                inherit_domain_proto_from_events(cx, proto.get());

                // Domain-specific methods
                define_domain_proto_methods(cx, proto.get());

                // Wire prototype
                rooted!(&in(cx) let proto_val = ObjectValue(proto.get()));
                JS_DefineProperty(
                    cx.raw_cx(),
                    fn_root.handle().into(),
                    c"prototype".as_ptr(),
                    proto_val.handle().into(),
                    0u32,
                );
            }

            rooted!(&in(cx) let fn_val = ObjectValue(fn_root.get()));
            JS_DefineProperty(
                cx.raw_cx(),
                domain_obj.handle().into(),
                c"Domain".as_ptr(),
                fn_val.handle().into(),
                JSPROP_ENUMERATE as u32,
            );
        }

        // Default active domain instance
        w2::JS_DefineFunction(
            cx,
            domain_obj.handle(),
            c"create".as_ptr(),
            Some(domain_create),
            0,
            JSPROP_ENUMERATE as u32,
        );
    }

    cache_builtin(cx, "domain", domain_obj.get());
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_constructor(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    // Create a new Domain object (plain object with EE prototype)
    let mut wrapped_cx = mozjs::context::JSContext::from_ptr(NonNull::new_unchecked(cx));
    let cx_ref = &mut wrapped_cx;
    rooted!(&in(cx_ref) let obj = w2::JS_NewPlainObject(cx_ref));
    if obj.get().is_null() {
        args.rval().set(UndefinedValue());
        return true;
    }
    // Mark as a domain
    rooted!(&in(cx_ref) let is_domain = BooleanValue(true));
    JS_DefineProperty(
        cx,
        obj.handle().into(),
        c"_domain".as_ptr(),
        is_domain.handle().into(),
        0u32,
    );
    args.rval().set(ObjectValue(obj.get()));
    true
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_create(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    // create() returns a new Domain instance (same as new Domain())
    let mut wrapped_cx = mozjs::context::JSContext::from_ptr(NonNull::new_unchecked(cx));
    let cx_ref = &mut wrapped_cx;
    rooted!(&in(cx_ref) let obj = w2::JS_NewPlainObject(cx_ref));
    if obj.get().is_null() {
        args.rval().set(UndefinedValue());
        return true;
    }
    rooted!(&in(cx_ref) let is_domain = BooleanValue(true));
    JS_DefineProperty(
        cx,
        obj.handle().into(),
        c"_domain".as_ptr(),
        is_domain.handle().into(),
        0u32,
    );
    args.rval().set(ObjectValue(obj.get()));
    true
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_run(cx: *mut JSContext, argc: u32, vp: *mut JSVal) -> bool {
    let args = CallArgs::from_vp(vp, argc);
    if argc == 0 {
        JS_ReportErrorUTF8(cx, c"domain.run() requires a function argument".as_ptr());
        return false;
    }
    let fn_val = *args.get(0).ptr;
    if !fn_val.is_object() {
        JS_ReportErrorUTF8(cx, c"domain.run() argument must be a function".as_ptr());
        return false;
    }

    // Call the function with the domain as `this`
    let this_val = args.thisv();
    let mut wrapped_cx = mozjs::context::JSContext::from_ptr(NonNull::new_unchecked(cx));
    let cx_ref = &mut wrapped_cx;
    rooted!(&in(cx_ref) let this_obj = if this_val.is_object() { this_val.to_object() } else {
        let g = CurrentGlobalOrNull(cx);
        if g.is_null() { return true; } else { g }
    });
    rooted!(&in(cx_ref) let fn_obj = fn_val.to_object());
    rooted!(&in(cx_ref) let fn_val_obj = ObjectValue(fn_obj.get()));

    // Build additional args (after the function)
    let extra_args: Vec<JSVal> = (1..argc).map(|i| *args.get(i).ptr).collect();
    let call_args = if extra_args.is_empty() {
        HandleValueArray::empty()
    } else {
        HandleValueArray {
            length_: extra_args.len(),
            elements_: extra_args.as_ptr(),
        }
    };

    let mut rval = UndefinedValue();
    JS_CallFunctionValue(
        cx,
        this_obj.handle().into(),
        fn_val_obj.handle().into(),
        &call_args,
        MutableHandle::<Value> {
            _phantom_0: ::std::marker::PhantomData,
            ptr: &mut rval,
        },
    );

    args.rval().set(rval);
    true
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_add(_cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
    // Deprecated, no-op
    let args = CallArgs::from_vp(vp, _argc);
    args.rval().set(UndefinedValue());
    true
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_remove(_cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
    // Deprecated, no-op
    let args = CallArgs::from_vp(vp, _argc);
    args.rval().set(UndefinedValue());
    true
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_bind(_cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
    // Deprecated, no-op
    let args = CallArgs::from_vp(vp, _argc);
    args.rval().set(UndefinedValue());
    true
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_intercept(_cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
    // Deprecated, no-op
    let args = CallArgs::from_vp(vp, _argc);
    args.rval().set(UndefinedValue());
    true
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_enter(_cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
    // Deprecated, no-op
    let args = CallArgs::from_vp(vp, _argc);
    args.rval().set(UndefinedValue());
    true
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_exit(_cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
    // Deprecated, no-op
    let args = CallArgs::from_vp(vp, _argc);
    args.rval().set(UndefinedValue());
    true
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe extern "C" fn domain_dispose(_cx: *mut JSContext, _argc: u32, vp: *mut JSVal) -> bool {
    // Deprecated, no-op
    let args = CallArgs::from_vp(vp, _argc);
    args.rval().set(UndefinedValue());
    true
}