publishport-opencli 1.0.22 → 1.0.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/clis/boss/utils.js +14 -8
- package/dist/src/browser/page.d.ts +1 -0
- package/dist/src/browser/page.js +4 -4
- package/package.json +1 -1
package/clis/boss/utils.js
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
|
-
import{ArgumentError as f,AuthRequiredError as p,CommandExecutionError as u,EmptyResultError as m}from"@jackwener/opencli/errors";const d="www.zhipin.com",w=`https://${d}/web/chat/index`,
|
|
1
|
+
import{ArgumentError as f,AuthRequiredError as p,CommandExecutionError as u,EmptyResultError as m}from"@jackwener/opencli/errors";const d="www.zhipin.com",w=`https://${d}/web/chat/index`,g=new Set([7,37]),S="Cookie 已过期!请在当前 Chrome 浏览器中重新登录 BOSS 直聘。",b="该命令仅支持招聘端(BOSS 端)账号,请使用招聘者账号登录后重试。",I=15000;export function requirePage(e){if(!e)throw new u("Browser page required")}export function readPositiveInteger(e,t,n,o){const r=e===void 0||e===null||e===""?n:Number(e);if(!Number.isInteger(r)||r<1)throw new f(`boss ${t} must be a positive integer`);if(o!==void 0&&r>o)throw new f(`boss ${t} must be <= ${o}`);return r}export function readRequiredString(e,t){const n=String(e??"").trim();if(!n)throw new f(`boss ${t} cannot be empty`);return n}export async function navigateToChat(e,t=2){await e.goto(w);await e.wait({time:t})}export async function navigateTo(e,t,n=1){await e.goto(t);await e.wait({time:n})}export function checkAuth(e){if(g.has(e.code))throw new p(d,S)}function k(e){if(e.code===IDENTITY_MISMATCH_CODE)throw new p(d,b)}export function assertOk(e,t){if(!e||typeof e!=="object")throw new u(`${t?`${t}: `:""}Boss API returned malformed response`);if(e.code===0)return;checkAuth(e);k(e);const n=t?`${t}: `:"";throw new u(`${n}${e.message||"Unknown error"} (code=${e.code})`)}const y="__ppXhrError";function _(e,t){const n=`status=${e.status??"?"} responseURL=${e.responseURL||"(空)"} page=${e.page||"(未知)"}`;if(e.kind==="timeout")return new u(`Boss API request timed out: ${t} [${n}]`);if(e.kind==="parse")return new u(`Boss API returned non-JSON: ${t} [${n}] body=${e.body||"(空)"}`);const o=e.responseURL||"",r=o&&!o.startsWith(`https://${d}/`)?`请求被重定向到 ${o},跨域后浏览器拿不到响应。`:"请求没有拿到任何响应:跨域被拦、连接被断开或网络不通,不足以断定是平台风控。";return new u(`Boss API request failed: ${t} [${n}] ${r}`)}export async function bossFetch(e,t,n={}){const o=n.method??"GET",r=n.timeout??I,s=n.body??null,i=`
|
|
2
2
|
async () => {
|
|
3
|
-
return new Promise((resolve
|
|
3
|
+
return new Promise((resolve) => {
|
|
4
4
|
const xhr = new XMLHttpRequest();
|
|
5
5
|
xhr.open(${JSON.stringify(o)}, ${JSON.stringify(t)}, true);
|
|
6
6
|
xhr.withCredentials = true;
|
|
7
7
|
xhr.timeout = ${r};
|
|
8
8
|
xhr.setRequestHeader('Accept', 'application/json');
|
|
9
9
|
${o==="POST"?"xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');":""}
|
|
10
|
+
const fail = (kind, extra) => resolve({ ${y}: Object.assign({
|
|
11
|
+
kind,
|
|
12
|
+
status: xhr.status,
|
|
13
|
+
responseURL: xhr.responseURL || '',
|
|
14
|
+
page: location.href,
|
|
15
|
+
}, extra || {}) });
|
|
10
16
|
xhr.onload = () => {
|
|
11
17
|
try { resolve(JSON.parse(xhr.responseText)); }
|
|
12
|
-
catch(e) {
|
|
18
|
+
catch(e) { fail('parse', { body: String(xhr.responseText || '').substring(0, 200) }); }
|
|
13
19
|
};
|
|
14
|
-
xhr.onerror = () =>
|
|
15
|
-
xhr.ontimeout = () =>
|
|
20
|
+
xhr.onerror = () => fail('network');
|
|
21
|
+
xhr.ontimeout = () => fail('timeout');
|
|
16
22
|
xhr.send(${s?JSON.stringify(s):"null"});
|
|
17
23
|
});
|
|
18
24
|
}
|
|
19
|
-
`;let
|
|
25
|
+
`;let a;try{a=await e.evaluate(i)}catch(c){if(c instanceof p||c instanceof u)throw c;const l=c instanceof Error?c.message:String(c);throw new u(`Boss API request failed: ${l}`)}if(a&&typeof a==="object"&&a[y])throw _(a[y],t);if(!a||typeof a!=="object")throw new u("Boss API returned malformed response");if(!n.allowNonZero&&a.code!==0)assertOk(a);return a}export async function fetchFriendList(e,t={}){const n=t.pageNum??1,o=t.jobId??"0",r=`https://${d}/wapi/zprelation/friend/getBossFriendListV2.json?page=${n}&status=0&jobId=${o}`,s=await bossFetch(e,r,{allowNonZero:t.allowNonZero});if(t.allowNonZero&&s.code!==0)return s;const i=s.zpData?.friendList;if(!Array.isArray(i))throw new u("Boss friend list response did not include zpData.friendList");return i}export async function fetchRecommendList(e){const t=`https://${d}/wapi/zprelation/friend/greetRecSortList`,o=(await bossFetch(e,t)).zpData?.friendList;if(!Array.isArray(o))throw new u("Boss recommend response did not include zpData.friendList");return o}export async function findFriendByUid(e,t,n={}){const o=n.maxPages??1,r=n.checkGreetList??!1;for(let s=1;s<=o;s++){const i=await fetchFriendList(e,{pageNum:s,allowNonZero:n.allowNonZero});if(n.allowNonZero&&!Array.isArray(i))return{friend:null,code:i.code};const a=Array.isArray(i)?i:[],c=a.find((l)=>l.encryptUid===t);if(c)return n.allowNonZero?{friend:c,code:0}:c;if(a.length===0)break}if(r){const i=(await fetchRecommendList(e)).find((a)=>a.encryptUid===t);if(i)return n.allowNonZero?{friend:i,code:0}:i}return n.allowNonZero?{friend:null,code:0}:null}export async function clickCandidateInList(e,t){const n=String(t).replace(/[^0-9]/g,"");return(await e.evaluate(`
|
|
20
26
|
async () => {
|
|
21
27
|
const uid = ${JSON.stringify(n)};
|
|
22
28
|
const item = document.querySelector('#_' + uid + '-0') || document.querySelector('[id^="_' + uid + '"]');
|
|
@@ -72,7 +78,7 @@ import{ArgumentError as f,AuthRequiredError as p,CommandExecutionError as u,Empt
|
|
|
72
78
|
}
|
|
73
79
|
return { clicked: false };
|
|
74
80
|
}
|
|
75
|
-
`)).clicked)await e.pressKey("Enter");return!0}export function verbose(e){if(process.env.OPENCLI_VERBOSE)console.error(`[ppcli:boss] ${e}`)}export const IDENTITY_MISMATCH_CODE=24;const
|
|
81
|
+
`)).clicked)await e.pressKey("Enter");return!0}export function verbose(e){if(process.env.OPENCLI_VERBOSE)console.error(`[ppcli:boss] ${e}`)}export const IDENTITY_MISMATCH_CODE=24;const h=`https://${d}/web/geek/chat`;export async function navigateToGeekChat(e,t=2){await e.goto(h);await e.wait({time:t})}export async function readEncryptSystemId(e){return await e.evaluate(`
|
|
76
82
|
(() => {
|
|
77
83
|
// 1. Vue app state / Pinia / $route.query
|
|
78
84
|
// The chat component reads encryptSystemId from the app runtime to build
|
|
@@ -158,4 +164,4 @@ import{ArgumentError as f,AuthRequiredError as p,CommandExecutionError as u,Empt
|
|
|
158
164
|
} catch (_) {}
|
|
159
165
|
return '';
|
|
160
166
|
})()
|
|
161
|
-
`)||""}export async function fetchGeekFriendLabelList(e,t={}){const n=t.labelId??0,o=t.encryptSystemId??"",r=`https://${d}/wapi/zprelation/friend/geekFilterByLabel?labelId=${n}&encryptSystemId=${encodeURIComponent(o)}`,s=await bossFetch(e,r,{allowNonZero:t.allowNonZero});if(t.allowNonZero&&s.code!==0)return s;const i=s.zpData?.friendList;if(!Array.isArray(i))throw new u("Boss geek chat list response did not include zpData.friendList");return i}export async function fetchGeekFriendInfoList(e,t=[]){if(!t.length)return[];const n=50,o=[];for(let r=0;r<t.length;r+=n){const i=`friendIds=${t.slice(r,r+n).map(String).join(",")}`,
|
|
167
|
+
`)||""}export async function fetchGeekFriendLabelList(e,t={}){const n=t.labelId??0,o=t.encryptSystemId??"",r=`https://${d}/wapi/zprelation/friend/geekFilterByLabel?labelId=${n}&encryptSystemId=${encodeURIComponent(o)}`,s=await bossFetch(e,r,{allowNonZero:t.allowNonZero});if(t.allowNonZero&&s.code!==0)return s;const i=s.zpData?.friendList;if(!Array.isArray(i))throw new u("Boss geek chat list response did not include zpData.friendList");return i}export async function fetchGeekFriendInfoList(e,t=[]){if(!t.length)return[];const n=50,o=[];for(let r=0;r<t.length;r+=n){const i=`friendIds=${t.slice(r,r+n).map(String).join(",")}`,c=(await bossFetch(e,`https://${d}/wapi/zprelation/friend/getGeekFriendList.json`,{method:"POST",body:i})).zpData?.result;if(!Array.isArray(c))throw new u("Boss geek friend enrichment response did not include zpData.result");o.push(...c)}return o}export async function findGeekFriendByUid(e,t,n={}){const r=(await fetchGeekFriendLabelList(e,{encryptSystemId:n.encryptSystemId})).find((i)=>i.encryptFriendId===t||String(i.uid)===String(t)||String(i.friendId)===String(t));if(!r)return null;const s=await fetchGeekFriendInfoList(e,[r.friendId]);return{...r,...s[0]||{}}}export async function fetchGeekHistoryMsg(e,t,n={}){const o=n.page??1,r=t.uid,s=encodeURIComponent(t.securityId||""),i=`https://${d}/wapi/zpchat/geek/historyMsg?bossId=${r}&securityId=${s}&page=${o}&c=20&src=0`,a=await bossFetch(e,i),c=a.zpData?.messages??a.zpData?.historyMsgList;if(!Array.isArray(c))throw new u("Boss geek history response did not include a message list");if(c.length===0)throw new m("boss chatmsg","Boss returned no messages for this chat.");return c}const x=`https://${d}/web/geek/job`;export async function navigateToGeekJob(e,t=2){await e.goto(x);await e.wait({time:t})}export async function geekGet(e,t,n={},o={}){const r=new URLSearchParams;for(const[c,l]of Object.entries(n)){if(l===void 0||l===null||l==="")continue;r.set(c,String(l))}const s=r.toString(),i=`https://${d}${t}${s?`?${s}`:""}`,a=await bossFetch(e,i,o);if(o.allowNonZero&&a.code!==0)return a;return a.zpData??{}}export async function geekPost(e,t,n={},o={}){const r=new URLSearchParams;for(const[i,a]of Object.entries(n)){if(a===void 0||a===null)continue;r.set(i,String(a))}const s=await bossFetch(e,`https://${d}${t}`,{...o,method:"POST",body:r.toString()});if(o.allowNonZero&&s.code!==0)return s;return s.zpData??{}}export async function fetchGeekUserInfo(e){return geekGet(e,"/wapi/zpuser/wap/getUserInfo.json")}export async function fetchGeekBossData(e,t){const n=await geekGet(e,"/wapi/zpchat/geek/getBossData",{bossId:t});return n?.data??n??{}}export async function fetchGeekLastMsgs(e,t=[]){if(!t.length)return[];const n=await geekGet(e,"/wapi/zpchat/geek/userLastMsg",{friendIds:t.map(String).join(",")});return Array.isArray(n)?n:n?.result??[]}export async function fetchGeekAttachmentResumes(e){return(await geekGet(e,"/wapi/zpgeek/resume/attachment/checkbox.json"))?.resumeList??[]}export async function resolveGeekResumeId(e,t){const n=await fetchGeekAttachmentResumes(e);if(t){if(!n.find((s)=>String(s.resumeId)===String(t))){const s=n.map((i)=>i.resumeId||"?").join(", ")||"(空)";throw new f(`指定的 --resume-id=${t} 不在账号简历列表 [${s}] 中`)}return String(t)}if(n.length===0)throw new m("boss resumelist","账号还没有绑定附件简历,请先用 boss resumeupload 上传,或在 BOSS 直聘 App 里上传。");if(n.length===1){const r=n[0].resumeId;if(!r)throw new u("唯一附件简历缺失 resumeId 字段");return String(r)}const o=n.map((r)=>`${r.resumeId}(${r.showName||"未命名"})`).join(", ");throw new f(`账号绑定了 ${n.length} 份附件简历,请用 --resume-id 指定其中一份:${o}`)}export async function resolveGeekBoss(e,t){const n=String(t??"").trim();if(!n)throw new f("boss id cannot be empty");if(/^\d+$/.test(n))return{id:n,friend:null};const o=await findGeekFriendByUid(e,n);if(!o)throw new m("boss chatlist",`未在沟通列表中找到 ${n},请先用 boss chatlist --side geek 查 uid。`);const r=o.uid??o.friendId;if(!r)throw new u("沟通列表条目缺失 uid / friendId");return{id:String(r),friend:o}}export async function resolveGeekBossId(e,t){return(await resolveGeekBoss(e,t)).id}export async function geekAddFriend(e,t,n=""){return geekGet(e,"/wapi/zpgeek/friend/add.json",{securityId:t,lid:n})}export async function geekOpenChat(e,t,n=3){await e.goto(`${h}?id=${encodeURIComponent(String(t))}`);await e.wait({time:n})}export const CITY_CODES={"全国":"100010000","北京":"101010100","上海":"101020100","广州":"101280100","深圳":"101280600","杭州":"101210100","成都":"101270100","南京":"101190100","武汉":"101200100","西安":"101110100","苏州":"101190400","长沙":"101250100","天津":"101030100","重庆":"101040100","郑州":"101180100","东莞":"101281600","青岛":"101120200","合肥":"101220100","佛山":"101280800","宁波":"101210400","厦门":"101230200","大连":"101070200","珠海":"101280700","无锡":"101190200","济南":"101120100","福州":"101230100","昆明":"101290100","哈尔滨":"101050100","沈阳":"101070100","石家庄":"101090100","贵阳":"101260100","南宁":"101300100","太原":"101100100","海口":"101310100","兰州":"101160100","乌鲁木齐":"101130100","长春":"101060100","南昌":"101240100","常州":"101191100","温州":"101210700","嘉兴":"101210300","徐州":"101190800","香港":"101320100"};export async function isRecruiterSide(e){await navigateToChat(e);const t=await bossFetch(e,`https://${d}/wapi/zprelation/friend/getBossFriendListV2.json?page=1&status=0&jobId=0`,{allowNonZero:!0});if(t.code===0)return!0;if(t.code===IDENTITY_MISMATCH_CODE)return!1;assertOk(t,"boss 身份探测");return!1}
|
|
@@ -33,6 +33,7 @@ export declare class Page extends BasePage {
|
|
|
33
33
|
waitUntil?: 'load' | 'none';
|
|
34
34
|
settleMs?: number;
|
|
35
35
|
}): Promise<void>;
|
|
36
|
+
private _navigateOnce;
|
|
36
37
|
/** Get the active page identity (targetId) */
|
|
37
38
|
getActivePage(): string | undefined;
|
|
38
39
|
/** Bind this Page instance to a specific page identity (targetId). */
|
package/dist/src/browser/page.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import{sendCommand as a,sendCommandFull as
|
|
2
|
-
${
|
|
1
|
+
import{sendCommand as a,sendCommandFull as l}from"./daemon-client.js";import{buildEvaluateExpression as p}from"./utils.js";import{saveBase64ToFile as g}from"../utils.js";import{generateStealthJs as w,generateBeforeUnloadGuardJs as _}from"./stealth.js";import{waitForDomStableJs as k,keyEventMetadata as b}from"./dom-helpers.js";import{BasePage as v}from"./base-page.js";import{classifyBrowserError as h}from"./errors.js";import{BrowserConnectError as C}from"../errors.js";import{log as f}from"../logger.js";function m(t){if(t===null||typeof t!=="object")return!1;const{href:e,origin:s}=t;if(typeof e!=="string")return!1;return e===""||e==="about:blank"||s==="null"}function O(t,e){const s=e?.href;return new C(`Navigation to ${t} reported success but the tab is still on a blank page (${typeof s==="string"&&s?s:"about:blank"}).`,"The browser never loaded the page, so any request made from it would fail as a cross-origin error. Check that the target site is reachable in this browser.","command-failed")}function y(t){const s=(t instanceof Error?t.message:String(t)).toLowerCase();return s.includes("unknown action")&&s.includes("network-capture")||s.includes("network capture")&&s.includes("not supported")}function x(t){const e=t instanceof Error?t.message:String(t);return e.includes("stale page identity")||/^Page not found:\s*\S+\s*$/.test(e)}export class Page extends v{session;contextId;windowMode;surface;siteSession;_idleTimeout;constructor(t,e,s,n,r="browser",o){super();this.session=t;this.contextId=s;this.windowMode=n;this.surface=r;this.siteSession=o;this._idleTimeout=e}_page;_networkCaptureUnsupported=!1;_networkCaptureWarned=!1;_sessionOpts(){return{session:this.session,surface:this.surface,...this.contextId&&{contextId:this.contextId},...this._idleTimeout!=null&&{idleTimeout:this._idleTimeout},...this.windowMode&&{windowMode:this.windowMode},...this.siteSession&&{siteSession:this.siteSession}}}_cmdOpts(){return{session:this.session,surface:this.surface,...this.contextId&&{contextId:this.contextId},...this._page!==void 0&&{page:this._page},...this._idleTimeout!=null&&{idleTimeout:this._idleTimeout},...this.windowMode&&{windowMode:this.windowMode},...this.siteSession&&{siteSession:this.siteSession}}}async goto(t,e){const s=await this._navigateOnce(t,e);if(!m(s))return;f.warn(`Navigation to ${t} left the tab on a blank page; retrying once.`);const n=await this._navigateOnce(t,e);if(m(n))throw O(t,n)}async _navigateOnce(t,e){try{await a("exec",{code:_(),...this._cmdOpts()})}catch{}let s;try{s=await l("navigate",{url:t,...this._cmdOpts()})}catch(n){if(!x(n)||this._page===void 0)throw n;this._page=void 0;s=await l("navigate",{url:t,...this._cmdOpts()})}if(s.page)this._page=s.page;this._lastUrl=t;if(e?.waitUntil!=="none"){const n=e?.settleMs??1000,o={code:`${w()};
|
|
2
|
+
(${k(n,Math.min(500,n))}).then(function(reason){ return { reason: reason, href: location.href, origin: location.origin }; })`,...this._cmdOpts()};let c;try{c=await a("exec",o)}catch(i){const u=h(i);if(u.kind!=="target-navigation")throw i;try{await new Promise((d)=>setTimeout(d,u.delayMs));c=await a("exec",o)}catch(d){if(h(d).kind!=="target-navigation")throw d}}return c}try{await a("exec",{code:w(),...this._cmdOpts()})}catch{}return}getActivePage(){return this._page}setActivePage(t){this._page=t;this._lastUrl=null}_markUnsupportedNetworkCapture(){this._networkCaptureUnsupported=!0;if(this._networkCaptureWarned)return;this._networkCaptureWarned=!0;f.warn("Browser Bridge extension does not support network capture; continuing without it. Explore output may miss API endpoints until you reload or reinstall the extension.")}async evaluate(t,...e){const s=p(t,e);try{return await a("exec",{code:s,...this._cmdOpts()})}catch(n){const r=h(n);if(r.kind!=="target-navigation")throw n;await new Promise((o)=>setTimeout(o,r.delayMs));return a("exec",{code:s,...this._cmdOpts()})}}async getCookies(t={}){const e=await a("cookies",{...this._sessionOpts(),...t});return Array.isArray(e)?e:[]}async closeWindow(){try{await a("close-window",{...this._sessionOpts()})}catch{}finally{this._page=void 0;this._lastUrl=null;this._networkCaptureUnsupported=!1;this._networkCaptureWarned=!1}}async tabs(){const t=await a("tabs",{op:"list",...this._sessionOpts()});return Array.isArray(t)?t:[]}async newTab(t){const e=await l("tabs",{op:"new",...t!==void 0&&{url:t},...this._sessionOpts()});this._lastUrl=null;return e.page}async closeTab(t){const e={op:"close",...this._sessionOpts()};if(typeof t==="number")e.index=t;else if(typeof t==="string")e.page=t;else if(this._page!==void 0)e.page=this._page;const s=await a("tabs",e),n=typeof s?.closed==="string"?s.closed:void 0;if(n&&n===this._page||!n&&(t===void 0||t===this._page)){this._page=void 0;this._lastUrl=null}}async selectTab(t){const e=await l("tabs",{op:"select",...typeof t==="number"?{index:t}:{page:t},...this._sessionOpts()});if(e.page)this._page=e.page;this._lastUrl=null}async screenshot(t={}){const e=await a("screenshot",{...this._cmdOpts(),format:t.format,quality:t.quality,fullPage:t.fullPage,width:t.width,height:t.height});if(t.path)await g(e,t.path);return e}async startNetworkCapture(t=""){if(this._networkCaptureUnsupported)return!1;try{await a("network-capture-start",{pattern:t,...this._cmdOpts()});return!0}catch(e){if(!y(e))throw e;this._markUnsupportedNetworkCapture();return!1}}async readNetworkCapture(){if(this._networkCaptureUnsupported)return[];try{const t=await a("network-capture-read",{...this._cmdOpts()});return Array.isArray(t)?t:[]}catch(t){if(!y(t))throw t;this._markUnsupportedNetworkCapture();return[]}}async waitForDownload(t="",e=30000){return await a("wait-download",{pattern:t,timeoutMs:e,...this._cmdOpts()})}async setFileInput(t,e){if(!(await a("set-file-input",{files:t,selector:e,...this._cmdOpts()}))?.count)throw Error("setFileInput returned no count — command may not be supported by the extension")}async insertText(t){if(!(await a("insert-text",{text:t,...this._cmdOpts()}))?.inserted)throw Error("insertText returned no inserted flag — command may not be supported by the extension")}async frames(){const t=await a("frames",{...this._cmdOpts()});return Array.isArray(t)?t:[]}async evaluateInFrame(t,e){const s=p(t);return a("exec",{code:s,frameIndex:e,...this._cmdOpts()})}async cdp(t,e={}){return a("cdp",{cdpMethod:t,cdpParams:e,...this._cmdOpts()})}async handleJavaScriptDialog(t,e){await this.cdp("Page.handleJavaScriptDialog",{accept:t,...e!==void 0&&{promptText:e}})}async tryNativeClick(t,e){try{await this.nativeClick(t,e);return!0}catch{return!1}}async clickWithQuads(t){const e=JSON.stringify(t),s=`[data-opencli-ref="${t.replace(/"/g,"\\\"")}"]`;await this.evaluate(`
|
|
3
3
|
(() => {
|
|
4
4
|
const el = document.querySelector('[data-opencli-ref="' + ${e} + '"]');
|
|
5
5
|
if (el) el.scrollIntoView({ behavior: 'instant', block: 'center' });
|
|
6
6
|
return !!el;
|
|
7
7
|
})()
|
|
8
|
-
`);try{const
|
|
8
|
+
`);try{const n=await this.cdp("DOM.getDocument",{}),r=await this.cdp("DOM.querySelectorAll",{nodeId:n.root.nodeId,selector:s});if(!r.nodeIds?.length)throw Error("DOM node not found");const o=r.nodeIds[0];try{const c=await this.cdp("DOM.getContentQuads",{nodeId:o});if(c.quads?.length){const i=c.quads[0],u=(i[0]+i[2]+i[4]+i[6])/4,d=(i[1]+i[3]+i[5]+i[7])/4;await this.nativeClick(Math.round(u),Math.round(d));return}}catch{}try{const c=await this.cdp("DOM.getBoxModel",{nodeId:o});if(c.model?.content){const i=c.model.content,u=(i[0]+i[2]+i[4]+i[6])/4,d=(i[1]+i[3]+i[5]+i[7])/4;await this.nativeClick(Math.round(u),Math.round(d));return}}catch{}}catch{}await this.evaluate(`
|
|
9
9
|
(() => {
|
|
10
10
|
const el = document.querySelector('[data-opencli-ref="' + ${e} + '"]');
|
|
11
11
|
if (!el) throw new Error('Element not found: ' + ${e});
|
|
12
12
|
el.click();
|
|
13
13
|
return 'clicked';
|
|
14
14
|
})()
|
|
15
|
-
`)}async nativeClick(t,e){await this.cdp("Input.dispatchMouseEvent",{type:"mouseMoved",x:t,y:e});await this.cdp("Input.dispatchMouseEvent",{type:"mousePressed",x:t,y:e,button:"left",clickCount:1});await this.cdp("Input.dispatchMouseEvent",{type:"mouseReleased",x:t,y:e,button:"left",clickCount:1})}async nativeType(t){await this.cdp("Input.insertText",{text:t})}async nativeKeyPress(t,e=[]){let s=0;for(const
|
|
15
|
+
`)}async nativeClick(t,e){await this.cdp("Input.dispatchMouseEvent",{type:"mouseMoved",x:t,y:e});await this.cdp("Input.dispatchMouseEvent",{type:"mousePressed",x:t,y:e,button:"left",clickCount:1});await this.cdp("Input.dispatchMouseEvent",{type:"mouseReleased",x:t,y:e,button:"left",clickCount:1})}async nativeType(t){await this.cdp("Input.insertText",{text:t})}async nativeKeyPress(t,e=[]){let s=0;for(const r of e){if(r==="Alt")s|=1;if(r==="Ctrl"||r==="Control")s|=2;if(r==="Meta")s|=4;if(r==="Shift")s|=8}const n=b(t,e);await this.cdp("Input.dispatchKeyEvent",{type:"keyDown",key:t,modifiers:s,...n});await this.cdp("Input.dispatchKeyEvent",{type:"keyUp",key:t,modifiers:s,...n.code?{code:n.code}:{},...n.windowsVirtualKeyCode?{windowsVirtualKeyCode:n.windowsVirtualKeyCode,nativeVirtualKeyCode:n.windowsVirtualKeyCode}:{}})}}
|