Skip to content

Instantly share code, notes, and snippets.

@evanwashere
Last active December 7, 2021 00:39
Show Gist options
  • Save evanwashere/04cfa233f613343e1c9d6fb72cfd628c to your computer and use it in GitHub Desktop.
Save evanwashere/04cfa233f613343e1c9d6fb72cfd628c to your computer and use it in GitHub Desktop.
class Emitter {
#on = Object.create(null);
#once = Object.create(null);
on(n, fn) { (this.#on[n] ?? (this.#on[n] = [])).push(fn); }
once(n, fn) { (this.#once[n] ?? (this.#once[n] = [])).push(fn); }
emit(n, ...args) { this.#on[n]?.forEach(_ => _(...args)); if (this.#once[n]) this.#once[n] = (this.#once[n].forEach(_ => _(...args)), undefined); }
off(n, fn) { if (!fn) (delete this.#on[n], delete this.#once[n]); else { let o = this.#on[n]?.indexOf(fn) ?? -1; if (o !== -1) this.#on[n].splice(o, 1); o = this.#once[n]?.indexOf(fn) ?? -1; if (o !== -1) this.#once[n].splice(o, 1); } }
}
class Inspector extends Emitter {
#seq = 0;
#socket = null;
#promises = Object.create(null);
close() { this.#socket?.close(); }
async call(method, params) {
if (!this.#socket) throw new Error('not connected');
return await new Promise((ok, err) => {
this.#promises[this.#seq] = { ok, err };
this.#socket.send(JSON.stringify({ method, params, id: this.#seq++ }));
});
}
async connect(url) {
return await new Promise((ok, err) => {
this.#socket = new WebSocket(url);
this.#socket.onopen = () => ok();
this.#socket.onerror = _ => err(_.error);
this.#socket.onclose = () => {
this.#seq = 0;
this.#socket = null;
const e = new Error('connection closed');
for (const _ in this.#promises) this.#promises[_].err(e);
this.#promises = Object.create(null);
};
this.#socket.onmessage = _ => {
const { id, error, method, params, result } = JSON.parse(_.data);
if (method === 'Runtime.executionContextDestroyed') this.#socket.close();
else if (method) this.emit(method, params);
else {
if (!error) this.#promises[id].ok(result);
else {
const e = new Error(error.message);
this.#promises[id].err((e.code = error.code, e));
}
delete this.#promises[id];
}
};
});
}
}
const inspector = new Inspector;
await inspector.connect('ws://127.0.0.1:9229/ws/9a5d113d-efa3-4512-8ab9-96efbbd12846');
const context = new Promise(r => inspector.once('Runtime.executionContextCreated', _ => r(_.context)));
console.log('connected');
await inspector.call('Runtime.enable');
await inspector.call('Runtime.runIfWaitingForDebugger');
async function evl(expr) {
const { result } = await inspector.call('Runtime.evaluate', {
replMode: true,
expression: expr,
awaitPromise: true,
objectGroup: 'repl',
generatePreview: true,
contextId: (await context).id,
});
await inspector.call('Runtime.releaseObjectGroup', { objectGroup: 'repl' });
return result;
}
while (true) {
console.log(await evl(prompt()));
}
await inspector.call('Runtime.disable');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment