// Dev: evaluate one expression in a page (brave CDP on :9333) and print // the full result. Usage: node dev/cdp-probe.mjs [timeoutMs] const [url, expr, timeoutMs = '20000'] = process.argv.slice(2); if (!url || !expr) { console.error('usage: node dev/cdp-probe.mjs [timeoutMs]'); process.exit(2); } const CDP = '127.0.0.1:9333'; const deadline = Date.now() + Number(timeoutMs); const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); let target = await (await fetch(`http://${CDP}/json/list`)).json() .then((ts) => ts.find((t) => t.type === 'page')); if (!target) { target = await (await fetch(`http://${CDP}/json/new?${encodeURIComponent(url)}`, { method: 'PUT' })).json(); } const ws = new WebSocket(target.webSocketDebuggerUrl); let id = 0; const pending = new Map(); const send = (method, params = {}) => new Promise((res, rej) => { const mid = ++id; pending.set(mid, { res, rej }); ws.send(JSON.stringify({ id: mid, method, params })); }); await new Promise((res, rej) => { ws.onopen = res; ws.onerror = (e) => rej(new Error('ws error: ' + (e?.message ?? '?'))); }); ws.onmessage = (m) => { const msg = JSON.parse(m.data); if (msg.id && pending.has(msg.id)) { const { res, rej } = pending.get(msg.id); pending.delete(msg.id); msg.error ? rej(new Error(msg.error.message)) : res(msg.result); } }; await send('Page.enable'); await send('Runtime.enable'); await send('Page.navigate', { url }); const loaded = new Promise((res) => setTimeout(res, 3000)); // let it settle await loaded; const evaluate = async (e) => { const r = await send('Runtime.evaluate', { expression: e, returnByValue: true, awaitPromise: true }); if (r.exceptionDetails) throw new Error('page: ' + (r.exceptionDetails.exception?.description ?? r.exceptionDetails.text)); return r.result?.value; }; let out = null; while (Date.now() < deadline) { out = await evaluate(expr).catch(() => null); if (out !== null && out !== undefined) break; await sleep(300); } console.log(JSON.stringify(out, null, 2)); ws.close(); process.exit(0);