const BASE = process.env.CDP_BASE || 'http://127.0.0.1:9223'; export const SAN = s => (s||'').replace(/data:[a-z+/-]+;base64,[A-Za-z0-9+/=\s]{40,}/gi,'').replace(/[A-Za-z0-9+/]{100,}={0,2}/g,'').replace(/\s+/g,' ').trim(); export async function newTarget(url='about:blank'){ const r=await fetch(`${BASE}/json/new?${encodeURIComponent(url)}`,{method:'PUT'}); return r.ok? r.json() : (await fetch(`${BASE}/json/new?${encodeURIComponent(url)}`)).json(); } export async function attach(match){ const list=await (await fetch(`${BASE}/json/list`)).json(); const ps=list.filter(t=>t.type==='page'&&(!match||t.url.includes(match))); if(!ps.length) return null; const c=await CDP.connect(ps[ps.length-1].webSocketDebuggerUrl); await c.send('Page.enable'); await c.send('Runtime.enable'); return c; } export async function closeAllTabs(){ const list=await (await fetch(`${BASE}/json/list`)).json(); for(const t of list.filter(x=>x.type==='page')) await fetch(`${BASE}/json/close/${t.id}`).catch(()=>{}); } export class CDP{ constructor(ws){this.ws=ws;this.id=0;this.pending=new Map();this.handlers=[];} static async connect(u){const ws=new WebSocket(u);await new Promise((s,j)=>{ws.onopen=s;ws.onerror=j;}); const c=new CDP(ws); ws.onmessage=ev=>{const m=JSON.parse(ev.data); if(m.id&&c.pending.has(m.id)){const{res,rej}=c.pending.get(m.id);c.pending.delete(m.id); m.error?rej(new Error(JSON.stringify(m.error))):res(m.result);} else if(m.method){for(const h of c.handlers)h(m);}}; return c;} send(method,params={}){const id=++this.id; return new Promise((res,rej)=>{this.pending.set(id,{res,rej}); this.ws.send(JSON.stringify({id,method,params})); setTimeout(()=>{if(this.pending.has(id)){this.pending.delete(id);rej(new Error('timeout '+method));}},60000);});} on(f){this.handlers.push(f);} async evalJS(e,aw=true){const r=await this.send('Runtime.evaluate',{expression:e,returnByValue:true,awaitPromise:aw}); if(r.exceptionDetails)throw new Error(JSON.stringify(r.exceptionDetails).slice(0,220));return r.result?.value;} async shot(p){const r=await this.send('Page.captureScreenshot',{format:'jpeg',quality:80}); const fs=await import('fs'); fs.writeFileSync(p,Buffer.from(r.data,'base64')); return p;} close(){try{this.ws.close();}catch{}} }