mirror of
https://github.com/denoland/deno.git
synced 2024-12-21 23:04:45 -05:00
fix(ext/node): better inspector support (#26471)
implement local inspector future changes: - wire up InspectorServer to enable open/close/url - wire up connectToMainThread Fixes https://github.com/denoland/deno/issues/25004
This commit is contained in:
parent
64e887083a
commit
700f54a13c
9 changed files with 438 additions and 98 deletions
|
@ -47,6 +47,11 @@ pub trait NodePermissions {
|
|||
url: &Url,
|
||||
api_name: &str,
|
||||
) -> Result<(), PermissionCheckError>;
|
||||
fn check_net(
|
||||
&mut self,
|
||||
host: (&str, Option<u16>),
|
||||
api_name: &str,
|
||||
) -> Result<(), PermissionCheckError>;
|
||||
#[must_use = "the resolved return value to mitigate time-of-check to time-of-use issues"]
|
||||
#[inline(always)]
|
||||
fn check_read(
|
||||
|
@ -90,6 +95,14 @@ impl NodePermissions for deno_permissions::PermissionsContainer {
|
|||
deno_permissions::PermissionsContainer::check_net_url(self, url, api_name)
|
||||
}
|
||||
|
||||
fn check_net(
|
||||
&mut self,
|
||||
host: (&str, Option<u16>),
|
||||
api_name: &str,
|
||||
) -> Result<(), PermissionCheckError> {
|
||||
deno_permissions::PermissionsContainer::check_net(self, &host, api_name)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn check_read_with_api_name(
|
||||
&mut self,
|
||||
|
@ -398,6 +411,15 @@ deno_core::extension!(deno_node,
|
|||
ops::process::op_node_process_kill,
|
||||
ops::process::op_process_abort,
|
||||
ops::tls::op_get_root_certificates,
|
||||
ops::inspector::op_inspector_open<P>,
|
||||
ops::inspector::op_inspector_close,
|
||||
ops::inspector::op_inspector_url,
|
||||
ops::inspector::op_inspector_wait,
|
||||
ops::inspector::op_inspector_connect<P>,
|
||||
ops::inspector::op_inspector_dispatch,
|
||||
ops::inspector::op_inspector_disconnect,
|
||||
ops::inspector::op_inspector_emit_protocol_event,
|
||||
ops::inspector::op_inspector_enabled,
|
||||
],
|
||||
esm_entry_point = "ext:deno_node/02_init.js",
|
||||
esm = [
|
||||
|
@ -606,8 +628,8 @@ deno_core::extension!(deno_node,
|
|||
"node:http" = "http.ts",
|
||||
"node:http2" = "http2.ts",
|
||||
"node:https" = "https.ts",
|
||||
"node:inspector" = "inspector.ts",
|
||||
"node:inspector/promises" = "inspector.ts",
|
||||
"node:inspector" = "inspector.js",
|
||||
"node:inspector/promises" = "inspector/promises.js",
|
||||
"node:module" = "01_require.js",
|
||||
"node:net" = "net.ts",
|
||||
"node:os" = "os.ts",
|
||||
|
|
161
ext/node/ops/inspector.rs
Normal file
161
ext/node/ops/inspector.rs
Normal file
|
@ -0,0 +1,161 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::NodePermissions;
|
||||
use deno_core::anyhow::Error;
|
||||
use deno_core::error::generic_error;
|
||||
use deno_core::futures::channel::mpsc;
|
||||
use deno_core::op2;
|
||||
use deno_core::v8;
|
||||
use deno_core::GarbageCollected;
|
||||
use deno_core::InspectorSessionKind;
|
||||
use deno_core::InspectorSessionOptions;
|
||||
use deno_core::JsRuntimeInspector;
|
||||
use deno_core::OpState;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_inspector_enabled() -> bool {
|
||||
// TODO: hook up to InspectorServer
|
||||
false
|
||||
}
|
||||
|
||||
#[op2]
|
||||
pub fn op_inspector_open<P>(
|
||||
_state: &mut OpState,
|
||||
_port: Option<u16>,
|
||||
#[string] _host: Option<String>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
// TODO: hook up to InspectorServer
|
||||
/*
|
||||
let server = state.borrow_mut::<InspectorServer>();
|
||||
if let Some(host) = host {
|
||||
server.set_host(host);
|
||||
}
|
||||
if let Some(port) = port {
|
||||
server.set_port(port);
|
||||
}
|
||||
state
|
||||
.borrow_mut::<P>()
|
||||
.check_net((server.host(), Some(server.port())), "inspector.open")?;
|
||||
*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_inspector_close() {
|
||||
// TODO: hook up to InspectorServer
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[string]
|
||||
pub fn op_inspector_url() -> Option<String> {
|
||||
// TODO: hook up to InspectorServer
|
||||
None
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_inspector_wait(state: &OpState) -> bool {
|
||||
match state.try_borrow::<Rc<RefCell<JsRuntimeInspector>>>() {
|
||||
Some(inspector) => {
|
||||
inspector
|
||||
.borrow_mut()
|
||||
.wait_for_session_and_break_on_next_statement();
|
||||
true
|
||||
}
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_inspector_emit_protocol_event(
|
||||
#[string] _event_name: String,
|
||||
#[string] _params: String,
|
||||
) {
|
||||
// TODO: inspector channel & protocol notifications
|
||||
}
|
||||
|
||||
struct JSInspectorSession {
|
||||
tx: RefCell<Option<mpsc::UnboundedSender<String>>>,
|
||||
}
|
||||
|
||||
impl GarbageCollected for JSInspectorSession {}
|
||||
|
||||
#[op2]
|
||||
#[cppgc]
|
||||
pub fn op_inspector_connect<'s, P>(
|
||||
isolate: *mut v8::Isolate,
|
||||
scope: &mut v8::HandleScope<'s>,
|
||||
state: &mut OpState,
|
||||
connect_to_main_thread: bool,
|
||||
callback: v8::Local<'s, v8::Function>,
|
||||
) -> Result<JSInspectorSession, Error>
|
||||
where
|
||||
P: NodePermissions + 'static,
|
||||
{
|
||||
state
|
||||
.borrow_mut::<P>()
|
||||
.check_sys("inspector", "inspector.Session.connect")?;
|
||||
|
||||
if connect_to_main_thread {
|
||||
return Err(generic_error("connectToMainThread not supported"));
|
||||
}
|
||||
|
||||
let context = scope.get_current_context();
|
||||
let context = v8::Global::new(scope, context);
|
||||
let callback = v8::Global::new(scope, callback);
|
||||
|
||||
let inspector = state
|
||||
.borrow::<Rc<RefCell<JsRuntimeInspector>>>()
|
||||
.borrow_mut();
|
||||
|
||||
let tx = inspector.create_raw_session(
|
||||
InspectorSessionOptions {
|
||||
kind: InspectorSessionKind::NonBlocking {
|
||||
wait_for_disconnect: false,
|
||||
},
|
||||
},
|
||||
// The inspector connection does not keep the event loop alive but
|
||||
// when the inspector sends a message to the frontend, the JS that
|
||||
// that runs may keep the event loop alive so we have to call back
|
||||
// synchronously, instead of using the usual LocalInspectorSession
|
||||
// UnboundedReceiver<InspectorMsg> API.
|
||||
Box::new(move |message| {
|
||||
// SAFETY: This function is called directly by the inspector, so
|
||||
// 1) The isolate is still valid
|
||||
// 2) We are on the same thread as the Isolate
|
||||
let scope = unsafe { &mut v8::CallbackScope::new(&mut *isolate) };
|
||||
let context = v8::Local::new(scope, context.clone());
|
||||
let scope = &mut v8::ContextScope::new(scope, context);
|
||||
let scope = &mut v8::TryCatch::new(scope);
|
||||
let recv = v8::undefined(scope);
|
||||
if let Some(message) = v8::String::new(scope, &message.content) {
|
||||
let callback = v8::Local::new(scope, callback.clone());
|
||||
callback.call(scope, recv.into(), &[message.into()]);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
Ok(JSInspectorSession {
|
||||
tx: RefCell::new(Some(tx)),
|
||||
})
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_inspector_dispatch(
|
||||
#[cppgc] session: &JSInspectorSession,
|
||||
#[string] message: String,
|
||||
) {
|
||||
if let Some(tx) = &*session.tx.borrow() {
|
||||
let _ = tx.unbounded_send(message);
|
||||
}
|
||||
}
|
||||
|
||||
#[op2(fast)]
|
||||
pub fn op_inspector_disconnect(#[cppgc] session: &JSInspectorSession) {
|
||||
drop(session.tx.borrow_mut().take());
|
||||
}
|
|
@ -7,6 +7,7 @@ pub mod fs;
|
|||
pub mod http;
|
||||
pub mod http2;
|
||||
pub mod idna;
|
||||
pub mod inspector;
|
||||
pub mod ipc;
|
||||
pub mod os;
|
||||
pub mod process;
|
||||
|
|
210
ext/node/polyfills/inspector.js
Normal file
210
ext/node/polyfills/inspector.js
Normal file
|
@ -0,0 +1,210 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||
|
||||
import process from "node:process";
|
||||
import { EventEmitter } from "node:events";
|
||||
import { primordials } from "ext:core/mod.js";
|
||||
import {
|
||||
op_get_extras_binding_object,
|
||||
op_inspector_close,
|
||||
op_inspector_connect,
|
||||
op_inspector_disconnect,
|
||||
op_inspector_dispatch,
|
||||
op_inspector_emit_protocol_event,
|
||||
op_inspector_enabled,
|
||||
op_inspector_open,
|
||||
op_inspector_url,
|
||||
op_inspector_wait,
|
||||
} from "ext:core/ops";
|
||||
import {
|
||||
isUint32,
|
||||
validateFunction,
|
||||
validateInt32,
|
||||
validateObject,
|
||||
validateString,
|
||||
} from "ext:deno_node/internal/validators.mjs";
|
||||
import {
|
||||
ERR_INSPECTOR_ALREADY_ACTIVATED,
|
||||
ERR_INSPECTOR_ALREADY_CONNECTED,
|
||||
ERR_INSPECTOR_CLOSED,
|
||||
ERR_INSPECTOR_COMMAND,
|
||||
ERR_INSPECTOR_NOT_ACTIVE,
|
||||
ERR_INSPECTOR_NOT_CONNECTED,
|
||||
ERR_INSPECTOR_NOT_WORKER,
|
||||
} from "ext:deno_node/internal/errors.ts";
|
||||
|
||||
const {
|
||||
SymbolDispose,
|
||||
JSONParse,
|
||||
JSONStringify,
|
||||
SafeMap,
|
||||
} = primordials;
|
||||
|
||||
class Session extends EventEmitter {
|
||||
#connection = null;
|
||||
#nextId = 1;
|
||||
#messageCallbacks = new SafeMap();
|
||||
|
||||
connect() {
|
||||
if (this.#connection) {
|
||||
throw new ERR_INSPECTOR_ALREADY_CONNECTED("The inspector session");
|
||||
}
|
||||
this.#connection = op_inspector_connect(false, (m) => this.#onMessage(m));
|
||||
}
|
||||
|
||||
connectToMainThread() {
|
||||
if (isMainThread) {
|
||||
throw new ERR_INSPECTOR_NOT_WORKER();
|
||||
}
|
||||
if (this.#connection) {
|
||||
throw new ERR_INSPECTOR_ALREADY_CONNECTED("The inspector session");
|
||||
}
|
||||
this.#connection = op_inspector_connect(true, (m) => this.#onMessage(m));
|
||||
}
|
||||
|
||||
#onMessage(message) {
|
||||
const parsed = JSONParse(message);
|
||||
try {
|
||||
if (parsed.id) {
|
||||
const callback = this.#messageCallbacks.get(parsed.id);
|
||||
this.#messageCallbacks.delete(parsed.id);
|
||||
if (callback) {
|
||||
if (parsed.error) {
|
||||
return callback(
|
||||
new ERR_INSPECTOR_COMMAND(
|
||||
parsed.error.code,
|
||||
parsed.error.message,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
callback(null, parsed.result);
|
||||
}
|
||||
} else {
|
||||
this.emit(parsed.method, parsed);
|
||||
this.emit("inspectorNotification", parsed);
|
||||
}
|
||||
} catch (error) {
|
||||
process.emitWarning(error);
|
||||
}
|
||||
}
|
||||
|
||||
post(method, params, callback) {
|
||||
validateString(method, "method");
|
||||
if (!callback && typeof params === "function") {
|
||||
callback = params;
|
||||
params = null;
|
||||
}
|
||||
if (params) {
|
||||
validateObject(params, "params");
|
||||
}
|
||||
if (callback) {
|
||||
validateFunction(callback, "callback");
|
||||
}
|
||||
|
||||
if (!this.#connection) {
|
||||
throw new ERR_INSPECTOR_NOT_CONNECTED();
|
||||
}
|
||||
const id = this.#nextId++;
|
||||
const message = { id, method };
|
||||
if (params) {
|
||||
message.params = params;
|
||||
}
|
||||
if (callback) {
|
||||
this.#messageCallbacks.set(id, callback);
|
||||
}
|
||||
op_inspector_dispatch(this.#connection, JSONStringify(message));
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (!this.#connection) {
|
||||
return;
|
||||
}
|
||||
op_inspector_disconnect(this.#connection);
|
||||
this.#connection = null;
|
||||
// deno-lint-ignore prefer-primordials
|
||||
for (const callback of this.#messageCallbacks.values()) {
|
||||
process.nextTick(callback, new ERR_INSPECTOR_CLOSED());
|
||||
}
|
||||
this.#messageCallbacks.clear();
|
||||
this.#nextId = 1;
|
||||
}
|
||||
}
|
||||
|
||||
function open(port, host, wait) {
|
||||
if (op_inspector_enabled()) {
|
||||
throw new ERR_INSPECTOR_ALREADY_ACTIVATED();
|
||||
}
|
||||
// inspectorOpen() currently does not typecheck its arguments and adding
|
||||
// such checks would be a potentially breaking change. However, the native
|
||||
// open() function requires the port to fit into a 16-bit unsigned integer,
|
||||
// causing an integer overflow otherwise, so we at least need to prevent that.
|
||||
if (isUint32(port)) {
|
||||
validateInt32(port, "port", 0, 65535);
|
||||
} else {
|
||||
// equiv of handling args[0]->IsUint32()
|
||||
port = undefined;
|
||||
}
|
||||
if (typeof host !== "string") {
|
||||
// equiv of handling args[1]->IsString()
|
||||
host = undefined;
|
||||
}
|
||||
op_inspector_open(port, host);
|
||||
if (wait) {
|
||||
op_inspector_wait();
|
||||
}
|
||||
|
||||
return {
|
||||
__proto__: null,
|
||||
[SymbolDispose]() {
|
||||
_debugEnd();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function close() {
|
||||
op_inspector_close();
|
||||
}
|
||||
|
||||
function url() {
|
||||
return op_inspector_url();
|
||||
}
|
||||
|
||||
function waitForDebugger() {
|
||||
if (!op_inspector_wait()) {
|
||||
throw new ERR_INSPECTOR_NOT_ACTIVE();
|
||||
}
|
||||
}
|
||||
|
||||
function broadcastToFrontend(eventName, params) {
|
||||
validateString(eventName, "eventName");
|
||||
if (params) {
|
||||
validateObject(params, "params");
|
||||
}
|
||||
op_inspector_emit_protocol_event(eventName, JSONStringify(params ?? {}));
|
||||
}
|
||||
|
||||
const Network = {
|
||||
requestWillBeSent: (params) =>
|
||||
broadcastToFrontend("Network.requestWillBeSent", params),
|
||||
responseReceived: (params) =>
|
||||
broadcastToFrontend("Network.responseReceived", params),
|
||||
loadingFinished: (params) =>
|
||||
broadcastToFrontend("Network.loadingFinished", params),
|
||||
loadingFailed: (params) =>
|
||||
broadcastToFrontend("Network.loadingFailed", params),
|
||||
};
|
||||
|
||||
const console = op_get_extras_binding_object().console;
|
||||
|
||||
export { close, console, Network, open, Session, url, waitForDebugger };
|
||||
|
||||
export default {
|
||||
open,
|
||||
close,
|
||||
url,
|
||||
waitForDebugger,
|
||||
console,
|
||||
Session,
|
||||
Network,
|
||||
};
|
|
@ -1,82 +0,0 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||
|
||||
import { EventEmitter } from "node:events";
|
||||
import { notImplemented } from "ext:deno_node/_utils.ts";
|
||||
import { primordials } from "ext:core/mod.js";
|
||||
|
||||
const {
|
||||
SafeMap,
|
||||
} = primordials;
|
||||
|
||||
class Session extends EventEmitter {
|
||||
#connection = null;
|
||||
#nextId = 1;
|
||||
#messageCallbacks = new SafeMap();
|
||||
|
||||
/** Connects the session to the inspector back-end. */
|
||||
connect() {
|
||||
notImplemented("inspector.Session.prototype.connect");
|
||||
}
|
||||
|
||||
/** Connects the session to the main thread
|
||||
* inspector back-end. */
|
||||
connectToMainThread() {
|
||||
notImplemented("inspector.Session.prototype.connectToMainThread");
|
||||
}
|
||||
|
||||
/** Posts a message to the inspector back-end. */
|
||||
post(
|
||||
_method: string,
|
||||
_params?: Record<string, unknown>,
|
||||
_callback?: (...args: unknown[]) => void,
|
||||
) {
|
||||
notImplemented("inspector.Session.prototype.post");
|
||||
}
|
||||
|
||||
/** Immediately closes the session, all pending
|
||||
* message callbacks will be called with an
|
||||
* error.
|
||||
*/
|
||||
disconnect() {
|
||||
notImplemented("inspector.Session.prototype.disconnect");
|
||||
}
|
||||
}
|
||||
|
||||
/** Activates inspector on host and port.
|
||||
* See https://nodejs.org/api/inspector.html#inspectoropenport-host-wait */
|
||||
function open(_port?: number, _host?: string, _wait?: boolean) {
|
||||
notImplemented("inspector.Session.prototype.open");
|
||||
}
|
||||
|
||||
/** Deactivate the inspector. Blocks until there are no active connections.
|
||||
* See https://nodejs.org/api/inspector.html#inspectorclose */
|
||||
function close() {
|
||||
notImplemented("inspector.Session.prototype.close");
|
||||
}
|
||||
|
||||
/** Return the URL of the active inspector, or undefined if there is none.
|
||||
* See https://nodejs.org/api/inspector.html#inspectorurl */
|
||||
function url() {
|
||||
// TODO(kt3k): returns undefined for now, which means the inspector is not activated.
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** Blocks until a client (existing or connected later) has sent Runtime.runIfWaitingForDebugger command.
|
||||
* See https://nodejs.org/api/inspector.html#inspectorwaitfordebugger */
|
||||
function waitForDebugger() {
|
||||
notImplemented("inspector.wairForDebugger");
|
||||
}
|
||||
|
||||
const console = globalThis.console;
|
||||
|
||||
export { close, console, open, Session, url, waitForDebugger };
|
||||
|
||||
export default {
|
||||
close,
|
||||
console,
|
||||
open,
|
||||
Session,
|
||||
url,
|
||||
waitForDebugger,
|
||||
};
|
20
ext/node/polyfills/inspector/promises.js
Normal file
20
ext/node/polyfills/inspector/promises.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
|
||||
// Copyright Joyent and Node contributors. All rights reserved. MIT license.
|
||||
|
||||
import inspector from "node:inspector";
|
||||
import { promisify } from "ext:deno_node/internal/util.mjs";
|
||||
|
||||
class Session extends inspector.Session {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
Session.prototype.post = promisify(inspector.Session.prototype.post);
|
||||
|
||||
export * from "node:inspector";
|
||||
export { Session };
|
||||
|
||||
export default {
|
||||
...inspector,
|
||||
Session,
|
||||
};
|
|
@ -82,6 +82,13 @@ impl deno_node::NodePermissions for Permissions {
|
|||
) -> Result<(), PermissionCheckError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
fn check_net(
|
||||
&mut self,
|
||||
_host: (&str, Option<u16>),
|
||||
_api_name: &str,
|
||||
) -> Result<(), PermissionCheckError> {
|
||||
unreachable!("snapshotting!")
|
||||
}
|
||||
fn check_read_path<'a>(
|
||||
&mut self,
|
||||
_path: &'a Path,
|
||||
|
|
|
@ -562,7 +562,7 @@ impl WebWorker {
|
|||
extension_transpiler: Some(Rc::new(|specifier, source| {
|
||||
maybe_transpile_source(specifier, source)
|
||||
})),
|
||||
inspector: services.maybe_inspector_server.is_some(),
|
||||
inspector: true,
|
||||
feature_checker: Some(services.feature_checker),
|
||||
op_metrics_factory_fn,
|
||||
import_meta_resolve_callback: Some(Box::new(
|
||||
|
@ -579,18 +579,18 @@ impl WebWorker {
|
|||
js_runtime.op_state().borrow_mut().put(op_summary_metrics);
|
||||
}
|
||||
|
||||
// Put inspector handle into the op state so we can put a breakpoint when
|
||||
// executing a CJS entrypoint.
|
||||
let op_state = js_runtime.op_state();
|
||||
let inspector = js_runtime.inspector();
|
||||
op_state.borrow_mut().put(inspector);
|
||||
|
||||
if let Some(server) = services.maybe_inspector_server {
|
||||
server.register_inspector(
|
||||
options.main_module.to_string(),
|
||||
&mut js_runtime,
|
||||
false,
|
||||
);
|
||||
|
||||
// Put inspector handle into the op state so we can put a breakpoint when
|
||||
// executing a CJS entrypoint.
|
||||
let op_state = js_runtime.op_state();
|
||||
let inspector = js_runtime.inspector();
|
||||
op_state.borrow_mut().put(inspector);
|
||||
}
|
||||
|
||||
let (internal_handle, external_handle) = {
|
||||
|
|
|
@ -488,7 +488,7 @@ impl MainWorker {
|
|||
extension_transpiler: Some(Rc::new(|specifier, source| {
|
||||
maybe_transpile_source(specifier, source)
|
||||
})),
|
||||
inspector: options.maybe_inspector_server.is_some(),
|
||||
inspector: true,
|
||||
is_main: true,
|
||||
feature_checker: Some(services.feature_checker.clone()),
|
||||
op_metrics_factory_fn,
|
||||
|
@ -546,6 +546,12 @@ impl MainWorker {
|
|||
js_runtime.op_state().borrow_mut().put(op_summary_metrics);
|
||||
}
|
||||
|
||||
// Put inspector handle into the op state so we can put a breakpoint when
|
||||
// executing a CJS entrypoint.
|
||||
let op_state = js_runtime.op_state();
|
||||
let inspector = js_runtime.inspector();
|
||||
op_state.borrow_mut().put(inspector);
|
||||
|
||||
if let Some(server) = options.maybe_inspector_server.clone() {
|
||||
server.register_inspector(
|
||||
main_module.to_string(),
|
||||
|
@ -553,13 +559,8 @@ impl MainWorker {
|
|||
options.should_break_on_first_statement
|
||||
|| options.should_wait_for_inspector_session,
|
||||
);
|
||||
|
||||
// Put inspector handle into the op state so we can put a breakpoint when
|
||||
// executing a CJS entrypoint.
|
||||
let op_state = js_runtime.op_state();
|
||||
let inspector = js_runtime.inspector();
|
||||
op_state.borrow_mut().put(inspector);
|
||||
}
|
||||
|
||||
let (
|
||||
bootstrap_fn_global,
|
||||
dispatch_load_event_fn_global,
|
||||
|
|
Loading…
Reference in a new issue