@xbrowser/cli 1.16.0 → 1.18.0
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/dist/{browser-3KTEVTMU.js → browser-SYE57VHU.js} +3 -3
- package/dist/{browser-AOVQTGJ7.js → browser-UPKOT3V6.js} +3 -3
- package/dist/{browser-KT4FOWBO.js → browser-W3Z4HPJN.js} +2 -2
- package/dist/{cdp-driver-DKNLIA6B.js → cdp-driver-4UAV56SQ.js} +2 -2
- package/dist/{cdp-driver-OC37OT4B.js → cdp-driver-KT6HL33W.js} +2 -2
- package/dist/{cdp-driver-ALDP2CZT.js → cdp-driver-NNBPNFF2.js} +74 -3
- package/dist/{chunk-TNEN6VQ2.js → chunk-3KZ34AUC.js} +13 -2
- package/dist/{chunk-LTBNQERK.js → chunk-DVKIL7H6.js} +74 -3
- package/dist/{chunk-7V3B7VPX.js → chunk-EI2XZIDF.js} +29 -5
- package/dist/{chunk-AMI64BSD.js → chunk-IWVG4XYZ.js} +13 -2
- package/dist/{chunk-A5HJ6IRE.js → chunk-LL37GYPP.js} +74 -3
- package/dist/{chunk-GWQ5NTVE.js → chunk-MMZCBUD3.js} +29 -5
- package/dist/{chunk-5EYOEB4R.js → chunk-OU335JBI.js} +102 -7
- package/dist/cli.js +10 -7
- package/dist/daemon-main.js +10 -7
- package/dist/index.d.ts +4 -0
- package/dist/index.js +11 -8
- package/dist/{launcher-L2JNDB2H.js → launcher-44STYRJC.js} +3 -1
- package/dist/{launcher-OZXJQPNG.js → launcher-EXJHHAUL.js} +3 -1
- package/dist/{session-replayer-MJH5W7BB.js → session-replayer-J4GXUULG.js} +1 -1
- package/package.json +1 -1
|
@@ -20,9 +20,9 @@ import {
|
|
|
20
20
|
saveSessionDiskMeta,
|
|
21
21
|
setActivePage,
|
|
22
22
|
touchSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
25
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-EI2XZIDF.js";
|
|
24
|
+
import "./chunk-LL37GYPP.js";
|
|
25
|
+
import "./chunk-3KZ34AUC.js";
|
|
26
26
|
import "./chunk-GDKLH7ZY.js";
|
|
27
27
|
import "./chunk-A6LPGFAL.js";
|
|
28
28
|
import "./chunk-H2A5JUK5.js";
|
|
@@ -20,10 +20,10 @@ import {
|
|
|
20
20
|
saveSessionDiskMeta,
|
|
21
21
|
setActivePage,
|
|
22
22
|
touchSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-MMZCBUD3.js";
|
|
24
|
+
import "./chunk-DVKIL7H6.js";
|
|
25
25
|
import "./chunk-3FWLW7FS.js";
|
|
26
|
-
import "./chunk-
|
|
26
|
+
import "./chunk-3KZ34AUC.js";
|
|
27
27
|
import "./chunk-GDKLH7ZY.js";
|
|
28
28
|
import "./chunk-KFQGP6VL.js";
|
|
29
29
|
export {
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
saveSessionDiskMeta,
|
|
21
21
|
setActivePage,
|
|
22
22
|
touchSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-OU335JBI.js";
|
|
24
|
+
import "./chunk-3KZ34AUC.js";
|
|
25
25
|
import "./chunk-GDKLH7ZY.js";
|
|
26
26
|
import "./chunk-KFQGP6VL.js";
|
|
27
27
|
export {
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
scrollIntoView,
|
|
15
15
|
waitForActionable,
|
|
16
16
|
waitForNetworkIdle
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-DVKIL7H6.js";
|
|
18
18
|
import "./chunk-3FWLW7FS.js";
|
|
19
19
|
import {
|
|
20
20
|
connectToCDP,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
getCDPTargets,
|
|
23
23
|
killChrome,
|
|
24
24
|
launchChrome
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-3KZ34AUC.js";
|
|
26
26
|
import "./chunk-GDKLH7ZY.js";
|
|
27
27
|
import "./chunk-KFQGP6VL.js";
|
|
28
28
|
export {
|
|
@@ -14,14 +14,14 @@ import {
|
|
|
14
14
|
scrollIntoView,
|
|
15
15
|
waitForActionable,
|
|
16
16
|
waitForNetworkIdle
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-LL37GYPP.js";
|
|
18
18
|
import {
|
|
19
19
|
connectToCDP,
|
|
20
20
|
findChrome,
|
|
21
21
|
getCDPTargets,
|
|
22
22
|
killChrome,
|
|
23
23
|
launchChrome
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-3KZ34AUC.js";
|
|
25
25
|
import "./chunk-GDKLH7ZY.js";
|
|
26
26
|
import "./chunk-H2A5JUK5.js";
|
|
27
27
|
import "./chunk-KFQGP6VL.js";
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
getCDPTargets,
|
|
6
6
|
killChrome,
|
|
7
7
|
launchChrome
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-IWVG4XYZ.js";
|
|
9
9
|
import {
|
|
10
10
|
__require
|
|
11
11
|
} from "./chunk-3RG5ZIWI.js";
|
|
@@ -370,6 +370,19 @@ function buildStealthInitScript() {
|
|
|
370
370
|
" document.fonts.add(ff);ff.load();}catch(e2){}",
|
|
371
371
|
" });",
|
|
372
372
|
" }catch(e){}",
|
|
373
|
+
// 3g. Notification.requestPermission 延迟(d62):headless 无原生横幅,
|
|
374
|
+
// request 瞬回 denied —— 真机 request 会 pending 在横幅上数秒到分钟。
|
|
375
|
+
// 延迟 2-6s 再 resolve,模拟横幅期(用户"看了下然后拒绝")。
|
|
376
|
+
" try{",
|
|
377
|
+
" if(window.Notification&&Notification.requestPermission){",
|
|
378
|
+
" var _nrp=Notification.requestPermission.bind(Notification);",
|
|
379
|
+
" Notification.requestPermission=function(cb){",
|
|
380
|
+
" return new Promise(function(res){",
|
|
381
|
+
" setTimeout(function(){_nrp().then(function(r){if(cb)try{cb(r)}catch(e){}res(r);});},2000+Math.random()*4000);",
|
|
382
|
+
" });",
|
|
383
|
+
" };",
|
|
384
|
+
" }",
|
|
385
|
+
" }catch(e){}",
|
|
373
386
|
// 3. toString disguise (name-list based)
|
|
374
387
|
" var _ts=Function.prototype.toString;",
|
|
375
388
|
" var _hf=document.hasFocus;",
|
|
@@ -515,6 +528,49 @@ var XBMouseImpl = class {
|
|
|
515
528
|
this._x = x;
|
|
516
529
|
this._y = y;
|
|
517
530
|
}
|
|
531
|
+
/**
|
|
532
|
+
* Drag from the CURRENT cursor position to (x, y): press, traverse a
|
|
533
|
+
* bezier trajectory with the button held, release. Drives the REAL
|
|
534
|
+
* HTML5 DnD pipeline — field-verified (d59): this sequence fires
|
|
535
|
+
* dragstart → dragover… → drop → dragend, all isTrusted=true. No
|
|
536
|
+
* Input.dispatchDragEvent needed.
|
|
537
|
+
*/
|
|
538
|
+
async drag(x, y, opts = {}) {
|
|
539
|
+
const stealth = process.env.XBROWSER_STEALTH !== "off";
|
|
540
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
541
|
+
type: "mousePressed",
|
|
542
|
+
x: this._x,
|
|
543
|
+
y: this._y,
|
|
544
|
+
button: "left",
|
|
545
|
+
clickCount: 1
|
|
546
|
+
});
|
|
547
|
+
this._button = "left";
|
|
548
|
+
const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
|
|
549
|
+
const fx = this._x, fy = this._y;
|
|
550
|
+
for (let i = 1; i <= steps; i++) {
|
|
551
|
+
if (stealth) await sleep(rand(16, 28));
|
|
552
|
+
const t = i / steps;
|
|
553
|
+
this._x = fx + (x - fx) * t;
|
|
554
|
+
this._y = fy + (y - fy) * t;
|
|
555
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
556
|
+
type: "mouseMoved",
|
|
557
|
+
x: this._x,
|
|
558
|
+
y: this._y,
|
|
559
|
+
button: this._button
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
this._x = x;
|
|
563
|
+
this._y = y;
|
|
564
|
+
await sleep(rand(60, 140));
|
|
565
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
566
|
+
type: "mouseReleased",
|
|
567
|
+
x,
|
|
568
|
+
y,
|
|
569
|
+
button: "left",
|
|
570
|
+
clickCount: 1
|
|
571
|
+
});
|
|
572
|
+
this._button = "none";
|
|
573
|
+
}
|
|
518
574
|
async wheel(deltaX, deltaY) {
|
|
519
575
|
await this.send("Input.dispatchMouseEvent", {
|
|
520
576
|
type: "mouseWheel",
|
|
@@ -1255,6 +1311,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1255
1311
|
`);
|
|
1256
1312
|
return selected;
|
|
1257
1313
|
}
|
|
1314
|
+
async dragAndDrop(source, target) {
|
|
1315
|
+
const boxes = await this.page.evaluate(`
|
|
1316
|
+
(function() {
|
|
1317
|
+
const s = ${this._q(source)}, t = ${this._q(target)};
|
|
1318
|
+
if (!s || !t) return null;
|
|
1319
|
+
const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
|
|
1320
|
+
return [c(s), c(t)];
|
|
1321
|
+
})()
|
|
1322
|
+
`);
|
|
1323
|
+
if (!boxes || !boxes[0] || !boxes[1]) {
|
|
1324
|
+
throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
|
|
1325
|
+
}
|
|
1326
|
+
await this.page.mouse.move(boxes[0].x, boxes[0].y);
|
|
1327
|
+
await this.page.mouse.drag(boxes[1].x, boxes[1].y);
|
|
1328
|
+
}
|
|
1258
1329
|
async screenshot(opts = {}) {
|
|
1259
1330
|
await waitForActionable(this.page, this.selector);
|
|
1260
1331
|
const box = await this.page.evaluate(`
|
|
@@ -3359,7 +3430,7 @@ var XBBrowserImpl = class {
|
|
|
3359
3430
|
this._exitHandler = null;
|
|
3360
3431
|
}
|
|
3361
3432
|
if (this.childProcess) {
|
|
3362
|
-
const { killChrome: killChrome2 } = await import("./launcher-
|
|
3433
|
+
const { killChrome: killChrome2 } = await import("./launcher-EXJHHAUL.js");
|
|
3363
3434
|
await killChrome2(this.childProcess, this.tmpDir);
|
|
3364
3435
|
}
|
|
3365
3436
|
await this.conn.close();
|
|
@@ -3494,7 +3565,7 @@ var XBBrowserImpl = class {
|
|
|
3494
3565
|
if (pageTargets.length === 0 && httpFallbackUrl) {
|
|
3495
3566
|
console.log(`[discoverContexts] Target.getTargets returned ${targetInfos.length} targets (0 page type). Falling back to HTTP /json/list at ${httpFallbackUrl}`);
|
|
3496
3567
|
try {
|
|
3497
|
-
const { getCDPTargets: getCDPTargets2 } = await import("./launcher-
|
|
3568
|
+
const { getCDPTargets: getCDPTargets2 } = await import("./launcher-EXJHHAUL.js");
|
|
3498
3569
|
const httpPages = await getCDPTargets2(httpFallbackUrl);
|
|
3499
3570
|
console.log(`[discoverContexts] HTTP /json/list returned ${httpPages.length} pages`);
|
|
3500
3571
|
for (const p of httpPages) {
|
|
@@ -101,6 +101,7 @@ async function launchChrome(options = {}) {
|
|
|
101
101
|
];
|
|
102
102
|
if (headless) {
|
|
103
103
|
allArgs.push("--headless", "--hide-scrollbars", "--mute-audio");
|
|
104
|
+
allArgs.push("--autoplay-policy=no-user-gesture-required");
|
|
104
105
|
}
|
|
105
106
|
let tmpDir;
|
|
106
107
|
if (userDataDir) {
|
|
@@ -160,6 +161,15 @@ async function connectToCDP(rawEndpoint) {
|
|
|
160
161
|
}
|
|
161
162
|
return resolveEndpointFromHTTP(rawEndpoint);
|
|
162
163
|
}
|
|
164
|
+
function joinCdpHttpUrl(baseURL, path) {
|
|
165
|
+
try {
|
|
166
|
+
const u = new URL(baseURL);
|
|
167
|
+
u.pathname = (u.pathname.replace(/\/+$/, "") || "") + path;
|
|
168
|
+
return u.toString();
|
|
169
|
+
} catch {
|
|
170
|
+
return `${baseURL}${path}`;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
163
173
|
async function findFreePort() {
|
|
164
174
|
const { createServer } = await import("net");
|
|
165
175
|
return new Promise((resolve, reject) => {
|
|
@@ -193,7 +203,7 @@ async function waitForCDPReady(port, timeoutMs, child) {
|
|
|
193
203
|
throw new Error(`Chrome CDP not ready after ${timeoutMs}ms (port ${port})`);
|
|
194
204
|
}
|
|
195
205
|
async function resolveEndpointFromHTTP(baseURL) {
|
|
196
|
-
const url =
|
|
206
|
+
const url = joinCdpHttpUrl(baseURL, "/json/version");
|
|
197
207
|
const resp = await fetch(url, { signal: AbortSignal.timeout(3e3) });
|
|
198
208
|
if (!resp.ok) {
|
|
199
209
|
throw new Error(`CDP HTTP ${resp.status}: ${url}`);
|
|
@@ -205,7 +215,7 @@ async function resolveEndpointFromHTTP(baseURL) {
|
|
|
205
215
|
return data.webSocketDebuggerUrl;
|
|
206
216
|
}
|
|
207
217
|
async function getCDPTargets(baseURL) {
|
|
208
|
-
const url =
|
|
218
|
+
const url = joinCdpHttpUrl(baseURL, "/json/list");
|
|
209
219
|
const resp = await fetch(url, { signal: AbortSignal.timeout(5e3) });
|
|
210
220
|
if (!resp.ok) {
|
|
211
221
|
throw new Error(`CDP list HTTP ${resp.status}: ${url}`);
|
|
@@ -258,6 +268,7 @@ export {
|
|
|
258
268
|
findChrome,
|
|
259
269
|
launchChrome,
|
|
260
270
|
connectToCDP,
|
|
271
|
+
joinCdpHttpUrl,
|
|
261
272
|
getCDPTargets,
|
|
262
273
|
killChrome
|
|
263
274
|
};
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
connectToCDP,
|
|
7
7
|
launchChrome
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-3KZ34AUC.js";
|
|
9
9
|
import {
|
|
10
10
|
errMsg
|
|
11
11
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -381,6 +381,19 @@ function buildStealthInitScript() {
|
|
|
381
381
|
" document.fonts.add(ff);ff.load();}catch(e2){}",
|
|
382
382
|
" });",
|
|
383
383
|
" }catch(e){}",
|
|
384
|
+
// 3g. Notification.requestPermission 延迟(d62):headless 无原生横幅,
|
|
385
|
+
// request 瞬回 denied —— 真机 request 会 pending 在横幅上数秒到分钟。
|
|
386
|
+
// 延迟 2-6s 再 resolve,模拟横幅期(用户"看了下然后拒绝")。
|
|
387
|
+
" try{",
|
|
388
|
+
" if(window.Notification&&Notification.requestPermission){",
|
|
389
|
+
" var _nrp=Notification.requestPermission.bind(Notification);",
|
|
390
|
+
" Notification.requestPermission=function(cb){",
|
|
391
|
+
" return new Promise(function(res){",
|
|
392
|
+
" setTimeout(function(){_nrp().then(function(r){if(cb)try{cb(r)}catch(e){}res(r);});},2000+Math.random()*4000);",
|
|
393
|
+
" });",
|
|
394
|
+
" };",
|
|
395
|
+
" }",
|
|
396
|
+
" }catch(e){}",
|
|
384
397
|
// 3. toString disguise (name-list based)
|
|
385
398
|
" var _ts=Function.prototype.toString;",
|
|
386
399
|
" var _hf=document.hasFocus;",
|
|
@@ -526,6 +539,49 @@ var XBMouseImpl = class {
|
|
|
526
539
|
this._x = x;
|
|
527
540
|
this._y = y;
|
|
528
541
|
}
|
|
542
|
+
/**
|
|
543
|
+
* Drag from the CURRENT cursor position to (x, y): press, traverse a
|
|
544
|
+
* bezier trajectory with the button held, release. Drives the REAL
|
|
545
|
+
* HTML5 DnD pipeline — field-verified (d59): this sequence fires
|
|
546
|
+
* dragstart → dragover… → drop → dragend, all isTrusted=true. No
|
|
547
|
+
* Input.dispatchDragEvent needed.
|
|
548
|
+
*/
|
|
549
|
+
async drag(x, y, opts = {}) {
|
|
550
|
+
const stealth = process.env.XBROWSER_STEALTH !== "off";
|
|
551
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
552
|
+
type: "mousePressed",
|
|
553
|
+
x: this._x,
|
|
554
|
+
y: this._y,
|
|
555
|
+
button: "left",
|
|
556
|
+
clickCount: 1
|
|
557
|
+
});
|
|
558
|
+
this._button = "left";
|
|
559
|
+
const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
|
|
560
|
+
const fx = this._x, fy = this._y;
|
|
561
|
+
for (let i = 1; i <= steps; i++) {
|
|
562
|
+
if (stealth) await sleep2(rand(16, 28));
|
|
563
|
+
const t = i / steps;
|
|
564
|
+
this._x = fx + (x - fx) * t;
|
|
565
|
+
this._y = fy + (y - fy) * t;
|
|
566
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
567
|
+
type: "mouseMoved",
|
|
568
|
+
x: this._x,
|
|
569
|
+
y: this._y,
|
|
570
|
+
button: this._button
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
this._x = x;
|
|
574
|
+
this._y = y;
|
|
575
|
+
await sleep2(rand(60, 140));
|
|
576
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
577
|
+
type: "mouseReleased",
|
|
578
|
+
x,
|
|
579
|
+
y,
|
|
580
|
+
button: "left",
|
|
581
|
+
clickCount: 1
|
|
582
|
+
});
|
|
583
|
+
this._button = "none";
|
|
584
|
+
}
|
|
529
585
|
async wheel(deltaX, deltaY) {
|
|
530
586
|
await this.send("Input.dispatchMouseEvent", {
|
|
531
587
|
type: "mouseWheel",
|
|
@@ -1164,6 +1220,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1164
1220
|
`);
|
|
1165
1221
|
return selected;
|
|
1166
1222
|
}
|
|
1223
|
+
async dragAndDrop(source, target) {
|
|
1224
|
+
const boxes = await this.page.evaluate(`
|
|
1225
|
+
(function() {
|
|
1226
|
+
const s = ${this._q(source)}, t = ${this._q(target)};
|
|
1227
|
+
if (!s || !t) return null;
|
|
1228
|
+
const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
|
|
1229
|
+
return [c(s), c(t)];
|
|
1230
|
+
})()
|
|
1231
|
+
`);
|
|
1232
|
+
if (!boxes || !boxes[0] || !boxes[1]) {
|
|
1233
|
+
throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
|
|
1234
|
+
}
|
|
1235
|
+
await this.page.mouse.move(boxes[0].x, boxes[0].y);
|
|
1236
|
+
await this.page.mouse.drag(boxes[1].x, boxes[1].y);
|
|
1237
|
+
}
|
|
1167
1238
|
async screenshot(opts = {}) {
|
|
1168
1239
|
await waitForActionable(this.page, this.selector);
|
|
1169
1240
|
const box = await this.page.evaluate(`
|
|
@@ -3268,7 +3339,7 @@ var XBBrowserImpl = class {
|
|
|
3268
3339
|
this._exitHandler = null;
|
|
3269
3340
|
}
|
|
3270
3341
|
if (this.childProcess) {
|
|
3271
|
-
const { killChrome: killChrome2 } = await import("./launcher-
|
|
3342
|
+
const { killChrome: killChrome2 } = await import("./launcher-44STYRJC.js");
|
|
3272
3343
|
await killChrome2(this.childProcess, this.tmpDir);
|
|
3273
3344
|
}
|
|
3274
3345
|
await this.conn.close();
|
|
@@ -3403,7 +3474,7 @@ var XBBrowserImpl = class {
|
|
|
3403
3474
|
if (pageTargets.length === 0 && httpFallbackUrl) {
|
|
3404
3475
|
console.log(`[discoverContexts] Target.getTargets returned ${targetInfos.length} targets (0 page type). Falling back to HTTP /json/list at ${httpFallbackUrl}`);
|
|
3405
3476
|
try {
|
|
3406
|
-
const { getCDPTargets: getCDPTargets2 } = await import("./launcher-
|
|
3477
|
+
const { getCDPTargets: getCDPTargets2 } = await import("./launcher-44STYRJC.js");
|
|
3407
3478
|
const httpPages = await getCDPTargets2(httpFallbackUrl);
|
|
3408
3479
|
console.log(`[discoverContexts] HTTP /json/list returned ${httpPages.length} pages`);
|
|
3409
3480
|
for (const p of httpPages) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
launch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-LL37GYPP.js";
|
|
4
4
|
import {
|
|
5
5
|
errMsg
|
|
6
6
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -639,16 +639,40 @@ async function createSession(name, url, options) {
|
|
|
639
639
|
(t) => t.url && t.url !== "about:blank" && !t.url.startsWith("chrome://") && !t.url.startsWith("chrome-untrusted://") && !t.url.startsWith("chrome-error://") && (url ? t.url.includes(new URL(url).hostname) : true)
|
|
640
640
|
);
|
|
641
641
|
if (matchTarget && matchTarget.url) {
|
|
642
|
-
|
|
643
|
-
|
|
642
|
+
const existing2 = context.pages().find((p) => {
|
|
643
|
+
try {
|
|
644
|
+
return p.url() === matchTarget.url;
|
|
645
|
+
} catch {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
644
648
|
});
|
|
649
|
+
if (existing2) {
|
|
650
|
+
targetPage = existing2;
|
|
651
|
+
} else {
|
|
652
|
+
targetPage = await context.newPage();
|
|
653
|
+
await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
|
|
654
|
+
});
|
|
655
|
+
}
|
|
645
656
|
}
|
|
646
657
|
}
|
|
647
658
|
if (!targetPage) {
|
|
648
659
|
const pages = context.pages();
|
|
649
|
-
if (pages.length >
|
|
660
|
+
if (pages.length > 1) {
|
|
661
|
+
try {
|
|
662
|
+
for (const p of pages) {
|
|
663
|
+
const vis = await p.evaluate("document.visibilityState").catch(() => "hidden");
|
|
664
|
+
if (vis === "visible") {
|
|
665
|
+
targetPage = p;
|
|
666
|
+
break;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
} catch {
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
if (!targetPage && pages.length > 0) {
|
|
650
673
|
targetPage = pages[0];
|
|
651
|
-
}
|
|
674
|
+
}
|
|
675
|
+
if (!targetPage) {
|
|
652
676
|
targetPage = await context.newPage();
|
|
653
677
|
}
|
|
654
678
|
}
|
|
@@ -105,6 +105,7 @@ async function launchChrome(options = {}) {
|
|
|
105
105
|
];
|
|
106
106
|
if (headless) {
|
|
107
107
|
allArgs.push("--headless", "--hide-scrollbars", "--mute-audio");
|
|
108
|
+
allArgs.push("--autoplay-policy=no-user-gesture-required");
|
|
108
109
|
}
|
|
109
110
|
let tmpDir;
|
|
110
111
|
if (userDataDir) {
|
|
@@ -164,6 +165,15 @@ async function connectToCDP(rawEndpoint) {
|
|
|
164
165
|
}
|
|
165
166
|
return resolveEndpointFromHTTP(rawEndpoint);
|
|
166
167
|
}
|
|
168
|
+
function joinCdpHttpUrl(baseURL, path) {
|
|
169
|
+
try {
|
|
170
|
+
const u = new URL(baseURL);
|
|
171
|
+
u.pathname = (u.pathname.replace(/\/+$/, "") || "") + path;
|
|
172
|
+
return u.toString();
|
|
173
|
+
} catch {
|
|
174
|
+
return `${baseURL}${path}`;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
167
177
|
async function findFreePort() {
|
|
168
178
|
const { createServer } = await import("net");
|
|
169
179
|
return new Promise((resolve, reject) => {
|
|
@@ -197,7 +207,7 @@ async function waitForCDPReady(port, timeoutMs, child) {
|
|
|
197
207
|
throw new Error(`Chrome CDP not ready after ${timeoutMs}ms (port ${port})`);
|
|
198
208
|
}
|
|
199
209
|
async function resolveEndpointFromHTTP(baseURL) {
|
|
200
|
-
const url =
|
|
210
|
+
const url = joinCdpHttpUrl(baseURL, "/json/version");
|
|
201
211
|
const resp = await fetch(url, { signal: AbortSignal.timeout(3e3) });
|
|
202
212
|
if (!resp.ok) {
|
|
203
213
|
throw new Error(`CDP HTTP ${resp.status}: ${url}`);
|
|
@@ -209,7 +219,7 @@ async function resolveEndpointFromHTTP(baseURL) {
|
|
|
209
219
|
return data.webSocketDebuggerUrl;
|
|
210
220
|
}
|
|
211
221
|
async function getCDPTargets(baseURL) {
|
|
212
|
-
const url =
|
|
222
|
+
const url = joinCdpHttpUrl(baseURL, "/json/list");
|
|
213
223
|
const resp = await fetch(url, { signal: AbortSignal.timeout(5e3) });
|
|
214
224
|
if (!resp.ok) {
|
|
215
225
|
throw new Error(`CDP list HTTP ${resp.status}: ${url}`);
|
|
@@ -263,6 +273,7 @@ export {
|
|
|
263
273
|
findChrome,
|
|
264
274
|
launchChrome,
|
|
265
275
|
connectToCDP,
|
|
276
|
+
joinCdpHttpUrl,
|
|
266
277
|
getCDPTargets,
|
|
267
278
|
killChrome
|
|
268
279
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
connectToCDP,
|
|
3
3
|
launchChrome
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3KZ34AUC.js";
|
|
5
5
|
import {
|
|
6
6
|
errMsg
|
|
7
7
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -380,6 +380,19 @@ function buildStealthInitScript() {
|
|
|
380
380
|
" document.fonts.add(ff);ff.load();}catch(e2){}",
|
|
381
381
|
" });",
|
|
382
382
|
" }catch(e){}",
|
|
383
|
+
// 3g. Notification.requestPermission 延迟(d62):headless 无原生横幅,
|
|
384
|
+
// request 瞬回 denied —— 真机 request 会 pending 在横幅上数秒到分钟。
|
|
385
|
+
// 延迟 2-6s 再 resolve,模拟横幅期(用户"看了下然后拒绝")。
|
|
386
|
+
" try{",
|
|
387
|
+
" if(window.Notification&&Notification.requestPermission){",
|
|
388
|
+
" var _nrp=Notification.requestPermission.bind(Notification);",
|
|
389
|
+
" Notification.requestPermission=function(cb){",
|
|
390
|
+
" return new Promise(function(res){",
|
|
391
|
+
" setTimeout(function(){_nrp().then(function(r){if(cb)try{cb(r)}catch(e){}res(r);});},2000+Math.random()*4000);",
|
|
392
|
+
" });",
|
|
393
|
+
" };",
|
|
394
|
+
" }",
|
|
395
|
+
" }catch(e){}",
|
|
383
396
|
// 3. toString disguise (name-list based)
|
|
384
397
|
" var _ts=Function.prototype.toString;",
|
|
385
398
|
" var _hf=document.hasFocus;",
|
|
@@ -525,6 +538,49 @@ var XBMouseImpl = class {
|
|
|
525
538
|
this._x = x;
|
|
526
539
|
this._y = y;
|
|
527
540
|
}
|
|
541
|
+
/**
|
|
542
|
+
* Drag from the CURRENT cursor position to (x, y): press, traverse a
|
|
543
|
+
* bezier trajectory with the button held, release. Drives the REAL
|
|
544
|
+
* HTML5 DnD pipeline — field-verified (d59): this sequence fires
|
|
545
|
+
* dragstart → dragover… → drop → dragend, all isTrusted=true. No
|
|
546
|
+
* Input.dispatchDragEvent needed.
|
|
547
|
+
*/
|
|
548
|
+
async drag(x, y, opts = {}) {
|
|
549
|
+
const stealth = process.env.XBROWSER_STEALTH !== "off";
|
|
550
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
551
|
+
type: "mousePressed",
|
|
552
|
+
x: this._x,
|
|
553
|
+
y: this._y,
|
|
554
|
+
button: "left",
|
|
555
|
+
clickCount: 1
|
|
556
|
+
});
|
|
557
|
+
this._button = "left";
|
|
558
|
+
const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
|
|
559
|
+
const fx = this._x, fy = this._y;
|
|
560
|
+
for (let i = 1; i <= steps; i++) {
|
|
561
|
+
if (stealth) await sleep2(rand(16, 28));
|
|
562
|
+
const t = i / steps;
|
|
563
|
+
this._x = fx + (x - fx) * t;
|
|
564
|
+
this._y = fy + (y - fy) * t;
|
|
565
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
566
|
+
type: "mouseMoved",
|
|
567
|
+
x: this._x,
|
|
568
|
+
y: this._y,
|
|
569
|
+
button: this._button
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
this._x = x;
|
|
573
|
+
this._y = y;
|
|
574
|
+
await sleep2(rand(60, 140));
|
|
575
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
576
|
+
type: "mouseReleased",
|
|
577
|
+
x,
|
|
578
|
+
y,
|
|
579
|
+
button: "left",
|
|
580
|
+
clickCount: 1
|
|
581
|
+
});
|
|
582
|
+
this._button = "none";
|
|
583
|
+
}
|
|
528
584
|
async wheel(deltaX, deltaY) {
|
|
529
585
|
await this.send("Input.dispatchMouseEvent", {
|
|
530
586
|
type: "mouseWheel",
|
|
@@ -1265,6 +1321,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1265
1321
|
`);
|
|
1266
1322
|
return selected;
|
|
1267
1323
|
}
|
|
1324
|
+
async dragAndDrop(source, target) {
|
|
1325
|
+
const boxes = await this.page.evaluate(`
|
|
1326
|
+
(function() {
|
|
1327
|
+
const s = ${this._q(source)}, t = ${this._q(target)};
|
|
1328
|
+
if (!s || !t) return null;
|
|
1329
|
+
const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
|
|
1330
|
+
return [c(s), c(t)];
|
|
1331
|
+
})()
|
|
1332
|
+
`);
|
|
1333
|
+
if (!boxes || !boxes[0] || !boxes[1]) {
|
|
1334
|
+
throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
|
|
1335
|
+
}
|
|
1336
|
+
await this.page.mouse.move(boxes[0].x, boxes[0].y);
|
|
1337
|
+
await this.page.mouse.drag(boxes[1].x, boxes[1].y);
|
|
1338
|
+
}
|
|
1268
1339
|
async screenshot(opts = {}) {
|
|
1269
1340
|
await waitForActionable(this.page, this.selector);
|
|
1270
1341
|
const box = await this.page.evaluate(`
|
|
@@ -3369,7 +3440,7 @@ var XBBrowserImpl = class {
|
|
|
3369
3440
|
this._exitHandler = null;
|
|
3370
3441
|
}
|
|
3371
3442
|
if (this.childProcess) {
|
|
3372
|
-
const { killChrome: killChrome2 } = await import("./launcher-
|
|
3443
|
+
const { killChrome: killChrome2 } = await import("./launcher-44STYRJC.js");
|
|
3373
3444
|
await killChrome2(this.childProcess, this.tmpDir);
|
|
3374
3445
|
}
|
|
3375
3446
|
await this.conn.close();
|
|
@@ -3504,7 +3575,7 @@ var XBBrowserImpl = class {
|
|
|
3504
3575
|
if (pageTargets.length === 0 && httpFallbackUrl) {
|
|
3505
3576
|
console.log(`[discoverContexts] Target.getTargets returned ${targetInfos.length} targets (0 page type). Falling back to HTTP /json/list at ${httpFallbackUrl}`);
|
|
3506
3577
|
try {
|
|
3507
|
-
const { getCDPTargets: getCDPTargets2 } = await import("./launcher-
|
|
3578
|
+
const { getCDPTargets: getCDPTargets2 } = await import("./launcher-44STYRJC.js");
|
|
3508
3579
|
const httpPages = await getCDPTargets2(httpFallbackUrl);
|
|
3509
3580
|
console.log(`[discoverContexts] HTTP /json/list returned ${httpPages.length} pages`);
|
|
3510
3581
|
for (const p of httpPages) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createRuleEngine,
|
|
3
3
|
launch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DVKIL7H6.js";
|
|
5
5
|
import {
|
|
6
6
|
errMsg
|
|
7
7
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -1066,16 +1066,40 @@ async function createSession(name, url, options) {
|
|
|
1066
1066
|
(t) => t.url && t.url !== "about:blank" && !t.url.startsWith("chrome://") && !t.url.startsWith("chrome-untrusted://") && !t.url.startsWith("chrome-error://") && (url ? t.url.includes(new URL(url).hostname) : true)
|
|
1067
1067
|
);
|
|
1068
1068
|
if (matchTarget && matchTarget.url) {
|
|
1069
|
-
|
|
1070
|
-
|
|
1069
|
+
const existing2 = context.pages().find((p) => {
|
|
1070
|
+
try {
|
|
1071
|
+
return p.url() === matchTarget.url;
|
|
1072
|
+
} catch {
|
|
1073
|
+
return false;
|
|
1074
|
+
}
|
|
1071
1075
|
});
|
|
1076
|
+
if (existing2) {
|
|
1077
|
+
targetPage = existing2;
|
|
1078
|
+
} else {
|
|
1079
|
+
targetPage = await context.newPage();
|
|
1080
|
+
await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1072
1083
|
}
|
|
1073
1084
|
}
|
|
1074
1085
|
if (!targetPage) {
|
|
1075
1086
|
const pages = context.pages();
|
|
1076
|
-
if (pages.length >
|
|
1087
|
+
if (pages.length > 1) {
|
|
1088
|
+
try {
|
|
1089
|
+
for (const p of pages) {
|
|
1090
|
+
const vis = await p.evaluate("document.visibilityState").catch(() => "hidden");
|
|
1091
|
+
if (vis === "visible") {
|
|
1092
|
+
targetPage = p;
|
|
1093
|
+
break;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
} catch {
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
if (!targetPage && pages.length > 0) {
|
|
1077
1100
|
targetPage = pages[0];
|
|
1078
|
-
}
|
|
1101
|
+
}
|
|
1102
|
+
if (!targetPage) {
|
|
1079
1103
|
targetPage = await context.newPage();
|
|
1080
1104
|
}
|
|
1081
1105
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
connectToCDP,
|
|
3
3
|
launchChrome
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3KZ34AUC.js";
|
|
5
5
|
import {
|
|
6
6
|
errMsg
|
|
7
7
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -383,6 +383,19 @@ function buildStealthInitScript() {
|
|
|
383
383
|
" document.fonts.add(ff);ff.load();}catch(e2){}",
|
|
384
384
|
" });",
|
|
385
385
|
" }catch(e){}",
|
|
386
|
+
// 3g. Notification.requestPermission 延迟(d62):headless 无原生横幅,
|
|
387
|
+
// request 瞬回 denied —— 真机 request 会 pending 在横幅上数秒到分钟。
|
|
388
|
+
// 延迟 2-6s 再 resolve,模拟横幅期(用户"看了下然后拒绝")。
|
|
389
|
+
" try{",
|
|
390
|
+
" if(window.Notification&&Notification.requestPermission){",
|
|
391
|
+
" var _nrp=Notification.requestPermission.bind(Notification);",
|
|
392
|
+
" Notification.requestPermission=function(cb){",
|
|
393
|
+
" return new Promise(function(res){",
|
|
394
|
+
" setTimeout(function(){_nrp().then(function(r){if(cb)try{cb(r)}catch(e){}res(r);});},2000+Math.random()*4000);",
|
|
395
|
+
" });",
|
|
396
|
+
" };",
|
|
397
|
+
" }",
|
|
398
|
+
" }catch(e){}",
|
|
386
399
|
// 3. toString disguise (name-list based)
|
|
387
400
|
" var _ts=Function.prototype.toString;",
|
|
388
401
|
" var _hf=document.hasFocus;",
|
|
@@ -528,6 +541,49 @@ var XBMouseImpl = class {
|
|
|
528
541
|
this._x = x;
|
|
529
542
|
this._y = y;
|
|
530
543
|
}
|
|
544
|
+
/**
|
|
545
|
+
* Drag from the CURRENT cursor position to (x, y): press, traverse a
|
|
546
|
+
* bezier trajectory with the button held, release. Drives the REAL
|
|
547
|
+
* HTML5 DnD pipeline — field-verified (d59): this sequence fires
|
|
548
|
+
* dragstart → dragover… → drop → dragend, all isTrusted=true. No
|
|
549
|
+
* Input.dispatchDragEvent needed.
|
|
550
|
+
*/
|
|
551
|
+
async drag(x, y, opts = {}) {
|
|
552
|
+
const stealth = process.env.XBROWSER_STEALTH !== "off";
|
|
553
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
554
|
+
type: "mousePressed",
|
|
555
|
+
x: this._x,
|
|
556
|
+
y: this._y,
|
|
557
|
+
button: "left",
|
|
558
|
+
clickCount: 1
|
|
559
|
+
});
|
|
560
|
+
this._button = "left";
|
|
561
|
+
const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
|
|
562
|
+
const fx = this._x, fy = this._y;
|
|
563
|
+
for (let i = 1; i <= steps; i++) {
|
|
564
|
+
if (stealth) await sleep2(rand(16, 28));
|
|
565
|
+
const t = i / steps;
|
|
566
|
+
this._x = fx + (x - fx) * t;
|
|
567
|
+
this._y = fy + (y - fy) * t;
|
|
568
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
569
|
+
type: "mouseMoved",
|
|
570
|
+
x: this._x,
|
|
571
|
+
y: this._y,
|
|
572
|
+
button: this._button
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
this._x = x;
|
|
576
|
+
this._y = y;
|
|
577
|
+
await sleep2(rand(60, 140));
|
|
578
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
579
|
+
type: "mouseReleased",
|
|
580
|
+
x,
|
|
581
|
+
y,
|
|
582
|
+
button: "left",
|
|
583
|
+
clickCount: 1
|
|
584
|
+
});
|
|
585
|
+
this._button = "none";
|
|
586
|
+
}
|
|
531
587
|
async wheel(deltaX, deltaY) {
|
|
532
588
|
await this.send("Input.dispatchMouseEvent", {
|
|
533
589
|
type: "mouseWheel",
|
|
@@ -1268,6 +1324,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1268
1324
|
`);
|
|
1269
1325
|
return selected;
|
|
1270
1326
|
}
|
|
1327
|
+
async dragAndDrop(source, target) {
|
|
1328
|
+
const boxes = await this.page.evaluate(`
|
|
1329
|
+
(function() {
|
|
1330
|
+
const s = ${this._q(source)}, t = ${this._q(target)};
|
|
1331
|
+
if (!s || !t) return null;
|
|
1332
|
+
const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
|
|
1333
|
+
return [c(s), c(t)];
|
|
1334
|
+
})()
|
|
1335
|
+
`);
|
|
1336
|
+
if (!boxes || !boxes[0] || !boxes[1]) {
|
|
1337
|
+
throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
|
|
1338
|
+
}
|
|
1339
|
+
await this.page.mouse.move(boxes[0].x, boxes[0].y);
|
|
1340
|
+
await this.page.mouse.drag(boxes[1].x, boxes[1].y);
|
|
1341
|
+
}
|
|
1271
1342
|
async screenshot(opts = {}) {
|
|
1272
1343
|
await waitForActionable(this.page, this.selector);
|
|
1273
1344
|
const box = await this.page.evaluate(`
|
|
@@ -3372,7 +3443,7 @@ var XBBrowserImpl = class {
|
|
|
3372
3443
|
this._exitHandler = null;
|
|
3373
3444
|
}
|
|
3374
3445
|
if (this.childProcess) {
|
|
3375
|
-
const { killChrome: killChrome2 } = await import("./launcher-
|
|
3446
|
+
const { killChrome: killChrome2 } = await import("./launcher-44STYRJC.js");
|
|
3376
3447
|
await killChrome2(this.childProcess, this.tmpDir);
|
|
3377
3448
|
}
|
|
3378
3449
|
await this.conn.close();
|
|
@@ -3507,7 +3578,7 @@ var XBBrowserImpl = class {
|
|
|
3507
3578
|
if (pageTargets.length === 0 && httpFallbackUrl) {
|
|
3508
3579
|
console.log(`[discoverContexts] Target.getTargets returned ${targetInfos.length} targets (0 page type). Falling back to HTTP /json/list at ${httpFallbackUrl}`);
|
|
3509
3580
|
try {
|
|
3510
|
-
const { getCDPTargets: getCDPTargets3 } = await import("./launcher-
|
|
3581
|
+
const { getCDPTargets: getCDPTargets3 } = await import("./launcher-44STYRJC.js");
|
|
3511
3582
|
const httpPages = await getCDPTargets3(httpFallbackUrl);
|
|
3512
3583
|
console.log(`[discoverContexts] HTTP /json/list returned ${httpPages.length} pages`);
|
|
3513
3584
|
for (const p of httpPages) {
|
|
@@ -5873,16 +5944,40 @@ async function createSession(name, url, options) {
|
|
|
5873
5944
|
(t) => t.url && t.url !== "about:blank" && !t.url.startsWith("chrome://") && !t.url.startsWith("chrome-untrusted://") && !t.url.startsWith("chrome-error://") && (url ? t.url.includes(new URL(url).hostname) : true)
|
|
5874
5945
|
);
|
|
5875
5946
|
if (matchTarget && matchTarget.url) {
|
|
5876
|
-
|
|
5877
|
-
|
|
5947
|
+
const existing2 = context.pages().find((p) => {
|
|
5948
|
+
try {
|
|
5949
|
+
return p.url() === matchTarget.url;
|
|
5950
|
+
} catch {
|
|
5951
|
+
return false;
|
|
5952
|
+
}
|
|
5878
5953
|
});
|
|
5954
|
+
if (existing2) {
|
|
5955
|
+
targetPage = existing2;
|
|
5956
|
+
} else {
|
|
5957
|
+
targetPage = await context.newPage();
|
|
5958
|
+
await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
|
|
5959
|
+
});
|
|
5960
|
+
}
|
|
5879
5961
|
}
|
|
5880
5962
|
}
|
|
5881
5963
|
if (!targetPage) {
|
|
5882
5964
|
const pages = context.pages();
|
|
5883
|
-
if (pages.length >
|
|
5965
|
+
if (pages.length > 1) {
|
|
5966
|
+
try {
|
|
5967
|
+
for (const p of pages) {
|
|
5968
|
+
const vis = await p.evaluate("document.visibilityState").catch(() => "hidden");
|
|
5969
|
+
if (vis === "visible") {
|
|
5970
|
+
targetPage = p;
|
|
5971
|
+
break;
|
|
5972
|
+
}
|
|
5973
|
+
}
|
|
5974
|
+
} catch {
|
|
5975
|
+
}
|
|
5976
|
+
}
|
|
5977
|
+
if (!targetPage && pages.length > 0) {
|
|
5884
5978
|
targetPage = pages[0];
|
|
5885
|
-
}
|
|
5979
|
+
}
|
|
5980
|
+
if (!targetPage) {
|
|
5886
5981
|
targetPage = await context.newPage();
|
|
5887
5982
|
}
|
|
5888
5983
|
}
|
package/dist/cli.js
CHANGED
|
@@ -72,8 +72,8 @@ import {
|
|
|
72
72
|
setActivePage,
|
|
73
73
|
sleep,
|
|
74
74
|
wheelDelta
|
|
75
|
-
} from "./chunk-
|
|
76
|
-
import "./chunk-
|
|
75
|
+
} from "./chunk-OU335JBI.js";
|
|
76
|
+
import "./chunk-3KZ34AUC.js";
|
|
77
77
|
import {
|
|
78
78
|
errMsg
|
|
79
79
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -947,14 +947,14 @@ var mouseCommand = registerCommand({
|
|
|
947
947
|
description: "Control the mouse (move, click, etc.)",
|
|
948
948
|
scope: "page",
|
|
949
949
|
parameters: z6.object({
|
|
950
|
-
action: z6.enum(["move", "down", "up", "click", "dblclick"]),
|
|
950
|
+
action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
|
|
951
951
|
x: z6.coerce.number(),
|
|
952
952
|
y: z6.coerce.number(),
|
|
953
953
|
button: z6.enum(["left", "right", "middle"]).optional(),
|
|
954
954
|
steps: z6.coerce.number().optional()
|
|
955
955
|
}),
|
|
956
956
|
result: z6.object({
|
|
957
|
-
action: z6.enum(["move", "down", "up", "click", "dblclick"]),
|
|
957
|
+
action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
|
|
958
958
|
x: z6.number(),
|
|
959
959
|
y: z6.number()
|
|
960
960
|
}),
|
|
@@ -978,6 +978,9 @@ var mouseCommand = registerCommand({
|
|
|
978
978
|
case "dblclick":
|
|
979
979
|
await ctx.page.mouse.dblclick(p.x, p.y, { button });
|
|
980
980
|
break;
|
|
981
|
+
case "drag":
|
|
982
|
+
await ctx.page.mouse.drag(p.x, p.y, p.steps ? { steps: p.steps } : {});
|
|
983
|
+
break;
|
|
981
984
|
}
|
|
982
985
|
return ok6({ action: p.action, x: p.x, y: p.y });
|
|
983
986
|
}
|
|
@@ -7542,7 +7545,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7542
7545
|
}
|
|
7543
7546
|
let targetPageOverride = null;
|
|
7544
7547
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7545
|
-
const { findTargetPage } = await import("./browser-
|
|
7548
|
+
const { findTargetPage } = await import("./browser-W3Z4HPJN.js");
|
|
7546
7549
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7547
7550
|
if (!targetPageOverride) {
|
|
7548
7551
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -13717,7 +13720,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13717
13720
|
const targetPage = pages[cmdTabIndex];
|
|
13718
13721
|
await targetPage.bringToFront().catch(() => {
|
|
13719
13722
|
});
|
|
13720
|
-
const { setActivePage: setActivePage2 } = await import("./browser-
|
|
13723
|
+
const { setActivePage: setActivePage2 } = await import("./browser-W3Z4HPJN.js");
|
|
13721
13724
|
setActivePage2(session, targetPage);
|
|
13722
13725
|
}
|
|
13723
13726
|
}
|
|
@@ -13993,7 +13996,7 @@ async function main() {
|
|
|
13993
13996
|
const command = process.argv[2];
|
|
13994
13997
|
const isLongRunning = command === "preview" || command === "serve";
|
|
13995
13998
|
if (!isLongRunning) {
|
|
13996
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
13999
|
+
const { ensureProcessCanExit } = await import("./browser-W3Z4HPJN.js");
|
|
13997
14000
|
await ensureProcessCanExit().catch(() => {
|
|
13998
14001
|
});
|
|
13999
14002
|
process.exit(process.exitCode || exitCode);
|
package/dist/daemon-main.js
CHANGED
|
@@ -34,17 +34,17 @@ import {
|
|
|
34
34
|
resolveLaunchOpts,
|
|
35
35
|
saveSessionDiskMeta,
|
|
36
36
|
setActivePage
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-MMZCBUD3.js";
|
|
38
38
|
import {
|
|
39
39
|
createRuleEngine,
|
|
40
40
|
rand,
|
|
41
41
|
sleep,
|
|
42
42
|
wheelDelta
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-DVKIL7H6.js";
|
|
44
44
|
import {
|
|
45
45
|
queryJS
|
|
46
46
|
} from "./chunk-3FWLW7FS.js";
|
|
47
|
-
import "./chunk-
|
|
47
|
+
import "./chunk-3KZ34AUC.js";
|
|
48
48
|
import {
|
|
49
49
|
errMsg
|
|
50
50
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -907,14 +907,14 @@ var mouseCommand = registerCommand({
|
|
|
907
907
|
description: "Control the mouse (move, click, etc.)",
|
|
908
908
|
scope: "page",
|
|
909
909
|
parameters: z6.object({
|
|
910
|
-
action: z6.enum(["move", "down", "up", "click", "dblclick"]),
|
|
910
|
+
action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
|
|
911
911
|
x: z6.coerce.number(),
|
|
912
912
|
y: z6.coerce.number(),
|
|
913
913
|
button: z6.enum(["left", "right", "middle"]).optional(),
|
|
914
914
|
steps: z6.coerce.number().optional()
|
|
915
915
|
}),
|
|
916
916
|
result: z6.object({
|
|
917
|
-
action: z6.enum(["move", "down", "up", "click", "dblclick"]),
|
|
917
|
+
action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
|
|
918
918
|
x: z6.number(),
|
|
919
919
|
y: z6.number()
|
|
920
920
|
}),
|
|
@@ -938,6 +938,9 @@ var mouseCommand = registerCommand({
|
|
|
938
938
|
case "dblclick":
|
|
939
939
|
await ctx.page.mouse.dblclick(p.x, p.y, { button });
|
|
940
940
|
break;
|
|
941
|
+
case "drag":
|
|
942
|
+
await ctx.page.mouse.drag(p.x, p.y, p.steps ? { steps: p.steps } : {});
|
|
943
|
+
break;
|
|
941
944
|
}
|
|
942
945
|
return ok6({ action: p.action, x: p.x, y: p.y });
|
|
943
946
|
}
|
|
@@ -7060,7 +7063,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7060
7063
|
}
|
|
7061
7064
|
let targetPageOverride = null;
|
|
7062
7065
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7063
|
-
const { findTargetPage } = await import("./browser-
|
|
7066
|
+
const { findTargetPage } = await import("./browser-UPKOT3V6.js");
|
|
7064
7067
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7065
7068
|
if (!targetPageOverride) {
|
|
7066
7069
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -8879,7 +8882,7 @@ function createRPCHandler() {
|
|
|
8879
8882
|
if (isNewFormat) {
|
|
8880
8883
|
try {
|
|
8881
8884
|
const replayErrors = [];
|
|
8882
|
-
const { SessionReplayer } = await import("./session-replayer-
|
|
8885
|
+
const { SessionReplayer } = await import("./session-replayer-J4GXUULG.js");
|
|
8883
8886
|
const replayer = new SessionReplayer({
|
|
8884
8887
|
page: session.page,
|
|
8885
8888
|
stepDelay: slowMo * 500,
|
package/dist/index.d.ts
CHANGED
|
@@ -311,6 +311,10 @@ interface XBMouse {
|
|
|
311
311
|
steps?: number;
|
|
312
312
|
}): Promise<void>;
|
|
313
313
|
wheel(deltaX: number, deltaY: number): Promise<void>;
|
|
314
|
+
/** Drag from current position to (x,y) — drives the real HTML5 DnD pipeline */
|
|
315
|
+
drag(x: number, y: number, opts?: {
|
|
316
|
+
steps?: number;
|
|
317
|
+
}): Promise<void>;
|
|
314
318
|
}
|
|
315
319
|
interface XBKeyboard {
|
|
316
320
|
press(key: string, opts?: {
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
resolveLaunchOpts,
|
|
19
19
|
saveSessionDiskMeta,
|
|
20
20
|
setActivePage
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-EI2XZIDF.js";
|
|
22
22
|
import {
|
|
23
23
|
detectAntiBot,
|
|
24
24
|
formatDetectionMessage
|
|
@@ -86,8 +86,8 @@ import {
|
|
|
86
86
|
rand,
|
|
87
87
|
sleep,
|
|
88
88
|
wheelDelta
|
|
89
|
-
} from "./chunk-
|
|
90
|
-
import "./chunk-
|
|
89
|
+
} from "./chunk-LL37GYPP.js";
|
|
90
|
+
import "./chunk-3KZ34AUC.js";
|
|
91
91
|
import {
|
|
92
92
|
errMsg
|
|
93
93
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -981,14 +981,14 @@ var mouseCommand = registerCommand({
|
|
|
981
981
|
description: "Control the mouse (move, click, etc.)",
|
|
982
982
|
scope: "page",
|
|
983
983
|
parameters: z6.object({
|
|
984
|
-
action: z6.enum(["move", "down", "up", "click", "dblclick"]),
|
|
984
|
+
action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
|
|
985
985
|
x: z6.coerce.number(),
|
|
986
986
|
y: z6.coerce.number(),
|
|
987
987
|
button: z6.enum(["left", "right", "middle"]).optional(),
|
|
988
988
|
steps: z6.coerce.number().optional()
|
|
989
989
|
}),
|
|
990
990
|
result: z6.object({
|
|
991
|
-
action: z6.enum(["move", "down", "up", "click", "dblclick"]),
|
|
991
|
+
action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
|
|
992
992
|
x: z6.number(),
|
|
993
993
|
y: z6.number()
|
|
994
994
|
}),
|
|
@@ -1012,6 +1012,9 @@ var mouseCommand = registerCommand({
|
|
|
1012
1012
|
case "dblclick":
|
|
1013
1013
|
await ctx.page.mouse.dblclick(p.x, p.y, { button });
|
|
1014
1014
|
break;
|
|
1015
|
+
case "drag":
|
|
1016
|
+
await ctx.page.mouse.drag(p.x, p.y, p.steps ? { steps: p.steps } : {});
|
|
1017
|
+
break;
|
|
1015
1018
|
}
|
|
1016
1019
|
return ok6({ action: p.action, x: p.x, y: p.y });
|
|
1017
1020
|
}
|
|
@@ -7893,7 +7896,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7893
7896
|
}
|
|
7894
7897
|
let targetPageOverride = null;
|
|
7895
7898
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7896
|
-
const { findTargetPage } = await import("./browser-
|
|
7899
|
+
const { findTargetPage } = await import("./browser-SYE57VHU.js");
|
|
7897
7900
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7898
7901
|
if (!targetPageOverride) {
|
|
7899
7902
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -14106,7 +14109,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
14106
14109
|
const targetPage = pages[cmdTabIndex];
|
|
14107
14110
|
await targetPage.bringToFront().catch(() => {
|
|
14108
14111
|
});
|
|
14109
|
-
const { setActivePage: setActivePage2 } = await import("./browser-
|
|
14112
|
+
const { setActivePage: setActivePage2 } = await import("./browser-SYE57VHU.js");
|
|
14110
14113
|
setActivePage2(session, targetPage);
|
|
14111
14114
|
}
|
|
14112
14115
|
}
|
|
@@ -17279,7 +17282,7 @@ var DataCollector = class {
|
|
|
17279
17282
|
return results;
|
|
17280
17283
|
}
|
|
17281
17284
|
async createBrowserContext() {
|
|
17282
|
-
const { launch } = await import("./cdp-driver-
|
|
17285
|
+
const { launch } = await import("./cdp-driver-KT6HL33W.js");
|
|
17283
17286
|
const { browser } = await launch({
|
|
17284
17287
|
headless: true,
|
|
17285
17288
|
args: ["--no-sandbox", "--disable-setuid-sandbox"]
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
connectToCDP,
|
|
5
5
|
findChrome,
|
|
6
6
|
getCDPTargets,
|
|
7
|
+
joinCdpHttpUrl,
|
|
7
8
|
killChrome,
|
|
8
9
|
launchChrome
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-3KZ34AUC.js";
|
|
10
11
|
import "./chunk-GDKLH7ZY.js";
|
|
11
12
|
import "./chunk-KFQGP6VL.js";
|
|
12
13
|
export {
|
|
@@ -15,6 +16,7 @@ export {
|
|
|
15
16
|
connectToCDP,
|
|
16
17
|
findChrome,
|
|
17
18
|
getCDPTargets,
|
|
19
|
+
joinCdpHttpUrl,
|
|
18
20
|
killChrome,
|
|
19
21
|
launchChrome
|
|
20
22
|
};
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
connectToCDP,
|
|
5
5
|
findChrome,
|
|
6
6
|
getCDPTargets,
|
|
7
|
+
joinCdpHttpUrl,
|
|
7
8
|
killChrome,
|
|
8
9
|
launchChrome
|
|
9
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-IWVG4XYZ.js";
|
|
10
11
|
import "./chunk-3RG5ZIWI.js";
|
|
11
12
|
export {
|
|
12
13
|
ANTI_DETECT_ARGS,
|
|
@@ -14,6 +15,7 @@ export {
|
|
|
14
15
|
connectToCDP,
|
|
15
16
|
findChrome,
|
|
16
17
|
getCDPTargets,
|
|
18
|
+
joinCdpHttpUrl,
|
|
17
19
|
killChrome,
|
|
18
20
|
launchChrome
|
|
19
21
|
};
|
|
@@ -34,7 +34,7 @@ var SessionReplayer = class {
|
|
|
34
34
|
if (this.opts.page) {
|
|
35
35
|
this.page = this.opts.page;
|
|
36
36
|
} else if (this.opts.cdpUrl) {
|
|
37
|
-
const { launch } = await import("./cdp-driver-
|
|
37
|
+
const { launch } = await import("./cdp-driver-4UAV56SQ.js");
|
|
38
38
|
const { browser } = await launch({ cdpEndpoint: this.opts.cdpUrl });
|
|
39
39
|
let contexts = browser.contexts();
|
|
40
40
|
for (let i = 0; i < 10 && contexts.length === 0; i++) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.18.0",
|
|
4
4
|
"description": "Browser automation CLI for web scraping, headless browsing, SEO analysis, and AI agent workflows. A command-line alternative to Playwright, Puppeteer, and Selenium.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|