/** SHEIN 批量公共库:按 target 直连页面,避免多处 attach(URL) 抢到同一个标签 */ import { CDP } from '/tmp/cdp3.mjs'; export const wait = ms => new Promise(z => setTimeout(z, ms)); export const BASE = process.env.CDP_BASE || 'http://127.0.0.1:9223'; /** 新开一个页面并返回它自己的 CDP 连接(不会被别的同 URL 标签抢走) */ export async function newPage(url = 'about:blank') { const r = await fetch(`${BASE}/json/new?${encodeURIComponent(url)}`, { method: 'PUT' }); const t = await r.json(); const c = await CDP.connect(t.webSocketDebuggerUrl); await c.send('Page.enable'); await c.send('Runtime.enable'); c.targetId = t.id; c.pageUrl = url; return c; } export async function closePage(c) { try { await fetch(`${BASE}/json/close/${c.targetId}`); } catch {} try { c.close(); } catch {} } export async function listPages() { return (await (await fetch(`${BASE}/json/list`)).json()).filter(t => t.type === 'page'); } /** 关掉所有匹配 url 的旧标签(清理重复 tab,attach(URL) 才不会抢错) */ export async function closePagesByUrl(part) { const ps = (await listPages()).filter(t => t.url.includes(part)); for (const t of ps) await fetch(`${BASE}/json/close/${t.id}`).catch(() => {}); return ps.length; } export const P = `document.querySelector('#app').__vue_app__.config.globalProperties.$pinia`; export const stub = store => `(()=>{const p=${P};return p._s.get('${store}').$state;})()`; export async function state(c, store) { return c.evalJS(`(()=>{const p=${P};const s=p._s.get('${store}').$state;return JSON.stringify(s.formState||s);})()`); } /** 在指定页面上点「保存」并抓 12 秒内的被吞消息 */ export async function installHook(c) { await c.evalJS(`(()=>{ window.__cap=[]; function wrap(o,n,l){ try{const f=o[n]; o[n]=function(){ try{window.__cap.push(l+': '+[...arguments].map(a=>typeof a==='string'?a:JSON.stringify(a)).join(' ').slice(0,170));}catch(e){} return f.apply(o,arguments);}; }catch(e){} } try{['error','warning','info','success'].forEach(k=>wrap(MYJ.message,k,'MYJ.'+k));}catch(e){} try{['error','warning','info','success'].forEach(k=>wrap(antd.message,k,'antd.'+k));}catch(e){} return 1;})()`); } export async function readHook(c) { return String(await c.evalJS(`JSON.stringify(window.__cap||[])`)); } export async function clickByText(c, re, tag = 'button') { return c.evalJS(`(()=>{const x=[...document.querySelectorAll('${tag}')].filter(e=>e.offsetParent!==null).find(e=>new RegExp(${JSON.stringify(re)}).test((e.innerText||'').trim())); if(!x) return 'nf'; x.scrollIntoView({block:'center'}); for(const ev of ['mousedown','mouseup','click']) x.dispatchEvent(new MouseEvent(ev,{bubbles:true,cancelable:true,view:window})); return (x.innerText||'').trim().slice(0,20);})()`); }