@xbrowser/cli 1.16.0 → 1.17.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-GPRLH6P6.js} +2 -2
- package/dist/{browser-KT4FOWBO.js → browser-HY7UXUQV.js} +1 -1
- package/dist/{browser-AOVQTGJ7.js → browser-ZVNDI4TR.js} +2 -2
- package/dist/{cdp-driver-DKNLIA6B.js → cdp-driver-FIAUJTBZ.js} +1 -1
- package/dist/{cdp-driver-OC37OT4B.js → cdp-driver-GMDP4KDN.js} +1 -1
- package/dist/{cdp-driver-ALDP2CZT.js → cdp-driver-TPVLBEFT.js} +58 -0
- package/dist/{chunk-A5HJ6IRE.js → chunk-3KUJOXUE.js} +58 -0
- package/dist/{chunk-5EYOEB4R.js → chunk-3LVR44KG.js} +86 -4
- package/dist/{chunk-7V3B7VPX.js → chunk-CE3L6HYV.js} +29 -5
- package/dist/{chunk-GWQ5NTVE.js → chunk-UQUJVBXE.js} +29 -5
- package/dist/{chunk-LTBNQERK.js → chunk-W4JETHAD.js} +58 -0
- package/dist/cli.js +9 -6
- package/dist/daemon-main.js +9 -6
- package/dist/index.d.ts +4 -0
- package/dist/index.js +10 -7
- package/dist/{session-replayer-MJH5W7BB.js → session-replayer-NV65I6OQ.js} +1 -1
- package/package.json +1 -1
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
saveSessionDiskMeta,
|
|
21
21
|
setActivePage,
|
|
22
22
|
touchSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-CE3L6HYV.js";
|
|
24
|
+
import "./chunk-3KUJOXUE.js";
|
|
25
25
|
import "./chunk-TNEN6VQ2.js";
|
|
26
26
|
import "./chunk-GDKLH7ZY.js";
|
|
27
27
|
import "./chunk-A6LPGFAL.js";
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
saveSessionDiskMeta,
|
|
21
21
|
setActivePage,
|
|
22
22
|
touchSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-UQUJVBXE.js";
|
|
24
|
+
import "./chunk-W4JETHAD.js";
|
|
25
25
|
import "./chunk-3FWLW7FS.js";
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import "./chunk-GDKLH7ZY.js";
|
|
@@ -515,6 +515,49 @@ var XBMouseImpl = class {
|
|
|
515
515
|
this._x = x;
|
|
516
516
|
this._y = y;
|
|
517
517
|
}
|
|
518
|
+
/**
|
|
519
|
+
* Drag from the CURRENT cursor position to (x, y): press, traverse a
|
|
520
|
+
* bezier trajectory with the button held, release. Drives the REAL
|
|
521
|
+
* HTML5 DnD pipeline — field-verified (d59): this sequence fires
|
|
522
|
+
* dragstart → dragover… → drop → dragend, all isTrusted=true. No
|
|
523
|
+
* Input.dispatchDragEvent needed.
|
|
524
|
+
*/
|
|
525
|
+
async drag(x, y, opts = {}) {
|
|
526
|
+
const stealth = process.env.XBROWSER_STEALTH !== "off";
|
|
527
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
528
|
+
type: "mousePressed",
|
|
529
|
+
x: this._x,
|
|
530
|
+
y: this._y,
|
|
531
|
+
button: "left",
|
|
532
|
+
clickCount: 1
|
|
533
|
+
});
|
|
534
|
+
this._button = "left";
|
|
535
|
+
const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
|
|
536
|
+
const fx = this._x, fy = this._y;
|
|
537
|
+
for (let i = 1; i <= steps; i++) {
|
|
538
|
+
if (stealth) await sleep(rand(16, 28));
|
|
539
|
+
const t = i / steps;
|
|
540
|
+
this._x = fx + (x - fx) * t;
|
|
541
|
+
this._y = fy + (y - fy) * t;
|
|
542
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
543
|
+
type: "mouseMoved",
|
|
544
|
+
x: this._x,
|
|
545
|
+
y: this._y,
|
|
546
|
+
button: this._button
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
this._x = x;
|
|
550
|
+
this._y = y;
|
|
551
|
+
await sleep(rand(60, 140));
|
|
552
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
553
|
+
type: "mouseReleased",
|
|
554
|
+
x,
|
|
555
|
+
y,
|
|
556
|
+
button: "left",
|
|
557
|
+
clickCount: 1
|
|
558
|
+
});
|
|
559
|
+
this._button = "none";
|
|
560
|
+
}
|
|
518
561
|
async wheel(deltaX, deltaY) {
|
|
519
562
|
await this.send("Input.dispatchMouseEvent", {
|
|
520
563
|
type: "mouseWheel",
|
|
@@ -1255,6 +1298,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1255
1298
|
`);
|
|
1256
1299
|
return selected;
|
|
1257
1300
|
}
|
|
1301
|
+
async dragAndDrop(source, target) {
|
|
1302
|
+
const boxes = await this.page.evaluate(`
|
|
1303
|
+
(function() {
|
|
1304
|
+
const s = ${this._q(source)}, t = ${this._q(target)};
|
|
1305
|
+
if (!s || !t) return null;
|
|
1306
|
+
const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
|
|
1307
|
+
return [c(s), c(t)];
|
|
1308
|
+
})()
|
|
1309
|
+
`);
|
|
1310
|
+
if (!boxes || !boxes[0] || !boxes[1]) {
|
|
1311
|
+
throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
|
|
1312
|
+
}
|
|
1313
|
+
await this.page.mouse.move(boxes[0].x, boxes[0].y);
|
|
1314
|
+
await this.page.mouse.drag(boxes[1].x, boxes[1].y);
|
|
1315
|
+
}
|
|
1258
1316
|
async screenshot(opts = {}) {
|
|
1259
1317
|
await waitForActionable(this.page, this.selector);
|
|
1260
1318
|
const box = await this.page.evaluate(`
|
|
@@ -525,6 +525,49 @@ var XBMouseImpl = class {
|
|
|
525
525
|
this._x = x;
|
|
526
526
|
this._y = y;
|
|
527
527
|
}
|
|
528
|
+
/**
|
|
529
|
+
* Drag from the CURRENT cursor position to (x, y): press, traverse a
|
|
530
|
+
* bezier trajectory with the button held, release. Drives the REAL
|
|
531
|
+
* HTML5 DnD pipeline — field-verified (d59): this sequence fires
|
|
532
|
+
* dragstart → dragover… → drop → dragend, all isTrusted=true. No
|
|
533
|
+
* Input.dispatchDragEvent needed.
|
|
534
|
+
*/
|
|
535
|
+
async drag(x, y, opts = {}) {
|
|
536
|
+
const stealth = process.env.XBROWSER_STEALTH !== "off";
|
|
537
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
538
|
+
type: "mousePressed",
|
|
539
|
+
x: this._x,
|
|
540
|
+
y: this._y,
|
|
541
|
+
button: "left",
|
|
542
|
+
clickCount: 1
|
|
543
|
+
});
|
|
544
|
+
this._button = "left";
|
|
545
|
+
const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
|
|
546
|
+
const fx = this._x, fy = this._y;
|
|
547
|
+
for (let i = 1; i <= steps; i++) {
|
|
548
|
+
if (stealth) await sleep2(rand(16, 28));
|
|
549
|
+
const t = i / steps;
|
|
550
|
+
this._x = fx + (x - fx) * t;
|
|
551
|
+
this._y = fy + (y - fy) * t;
|
|
552
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
553
|
+
type: "mouseMoved",
|
|
554
|
+
x: this._x,
|
|
555
|
+
y: this._y,
|
|
556
|
+
button: this._button
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
this._x = x;
|
|
560
|
+
this._y = y;
|
|
561
|
+
await sleep2(rand(60, 140));
|
|
562
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
563
|
+
type: "mouseReleased",
|
|
564
|
+
x,
|
|
565
|
+
y,
|
|
566
|
+
button: "left",
|
|
567
|
+
clickCount: 1
|
|
568
|
+
});
|
|
569
|
+
this._button = "none";
|
|
570
|
+
}
|
|
528
571
|
async wheel(deltaX, deltaY) {
|
|
529
572
|
await this.send("Input.dispatchMouseEvent", {
|
|
530
573
|
type: "mouseWheel",
|
|
@@ -1265,6 +1308,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1265
1308
|
`);
|
|
1266
1309
|
return selected;
|
|
1267
1310
|
}
|
|
1311
|
+
async dragAndDrop(source, target) {
|
|
1312
|
+
const boxes = await this.page.evaluate(`
|
|
1313
|
+
(function() {
|
|
1314
|
+
const s = ${this._q(source)}, t = ${this._q(target)};
|
|
1315
|
+
if (!s || !t) return null;
|
|
1316
|
+
const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
|
|
1317
|
+
return [c(s), c(t)];
|
|
1318
|
+
})()
|
|
1319
|
+
`);
|
|
1320
|
+
if (!boxes || !boxes[0] || !boxes[1]) {
|
|
1321
|
+
throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
|
|
1322
|
+
}
|
|
1323
|
+
await this.page.mouse.move(boxes[0].x, boxes[0].y);
|
|
1324
|
+
await this.page.mouse.drag(boxes[1].x, boxes[1].y);
|
|
1325
|
+
}
|
|
1268
1326
|
async screenshot(opts = {}) {
|
|
1269
1327
|
await waitForActionable(this.page, this.selector);
|
|
1270
1328
|
const box = await this.page.evaluate(`
|
|
@@ -528,6 +528,49 @@ var XBMouseImpl = class {
|
|
|
528
528
|
this._x = x;
|
|
529
529
|
this._y = y;
|
|
530
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 sleep2(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 sleep2(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
|
+
}
|
|
531
574
|
async wheel(deltaX, deltaY) {
|
|
532
575
|
await this.send("Input.dispatchMouseEvent", {
|
|
533
576
|
type: "mouseWheel",
|
|
@@ -1268,6 +1311,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1268
1311
|
`);
|
|
1269
1312
|
return selected;
|
|
1270
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
|
+
}
|
|
1271
1329
|
async screenshot(opts = {}) {
|
|
1272
1330
|
await waitForActionable(this.page, this.selector);
|
|
1273
1331
|
const box = await this.page.evaluate(`
|
|
@@ -5873,16 +5931,40 @@ async function createSession(name, url, options) {
|
|
|
5873
5931
|
(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
5932
|
);
|
|
5875
5933
|
if (matchTarget && matchTarget.url) {
|
|
5876
|
-
|
|
5877
|
-
|
|
5934
|
+
const existing2 = context.pages().find((p) => {
|
|
5935
|
+
try {
|
|
5936
|
+
return p.url() === matchTarget.url;
|
|
5937
|
+
} catch {
|
|
5938
|
+
return false;
|
|
5939
|
+
}
|
|
5878
5940
|
});
|
|
5941
|
+
if (existing2) {
|
|
5942
|
+
targetPage = existing2;
|
|
5943
|
+
} else {
|
|
5944
|
+
targetPage = await context.newPage();
|
|
5945
|
+
await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
|
|
5946
|
+
});
|
|
5947
|
+
}
|
|
5879
5948
|
}
|
|
5880
5949
|
}
|
|
5881
5950
|
if (!targetPage) {
|
|
5882
5951
|
const pages = context.pages();
|
|
5883
|
-
if (pages.length >
|
|
5952
|
+
if (pages.length > 1) {
|
|
5953
|
+
try {
|
|
5954
|
+
for (const p of pages) {
|
|
5955
|
+
const vis = await p.evaluate("document.visibilityState").catch(() => "hidden");
|
|
5956
|
+
if (vis === "visible") {
|
|
5957
|
+
targetPage = p;
|
|
5958
|
+
break;
|
|
5959
|
+
}
|
|
5960
|
+
}
|
|
5961
|
+
} catch {
|
|
5962
|
+
}
|
|
5963
|
+
}
|
|
5964
|
+
if (!targetPage && pages.length > 0) {
|
|
5884
5965
|
targetPage = pages[0];
|
|
5885
|
-
}
|
|
5966
|
+
}
|
|
5967
|
+
if (!targetPage) {
|
|
5886
5968
|
targetPage = await context.newPage();
|
|
5887
5969
|
}
|
|
5888
5970
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
launch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-3KUJOXUE.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
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createRuleEngine,
|
|
3
3
|
launch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-W4JETHAD.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
|
}
|
|
@@ -526,6 +526,49 @@ var XBMouseImpl = class {
|
|
|
526
526
|
this._x = x;
|
|
527
527
|
this._y = y;
|
|
528
528
|
}
|
|
529
|
+
/**
|
|
530
|
+
* Drag from the CURRENT cursor position to (x, y): press, traverse a
|
|
531
|
+
* bezier trajectory with the button held, release. Drives the REAL
|
|
532
|
+
* HTML5 DnD pipeline — field-verified (d59): this sequence fires
|
|
533
|
+
* dragstart → dragover… → drop → dragend, all isTrusted=true. No
|
|
534
|
+
* Input.dispatchDragEvent needed.
|
|
535
|
+
*/
|
|
536
|
+
async drag(x, y, opts = {}) {
|
|
537
|
+
const stealth = process.env.XBROWSER_STEALTH !== "off";
|
|
538
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
539
|
+
type: "mousePressed",
|
|
540
|
+
x: this._x,
|
|
541
|
+
y: this._y,
|
|
542
|
+
button: "left",
|
|
543
|
+
clickCount: 1
|
|
544
|
+
});
|
|
545
|
+
this._button = "left";
|
|
546
|
+
const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
|
|
547
|
+
const fx = this._x, fy = this._y;
|
|
548
|
+
for (let i = 1; i <= steps; i++) {
|
|
549
|
+
if (stealth) await sleep2(rand(16, 28));
|
|
550
|
+
const t = i / steps;
|
|
551
|
+
this._x = fx + (x - fx) * t;
|
|
552
|
+
this._y = fy + (y - fy) * t;
|
|
553
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
554
|
+
type: "mouseMoved",
|
|
555
|
+
x: this._x,
|
|
556
|
+
y: this._y,
|
|
557
|
+
button: this._button
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
this._x = x;
|
|
561
|
+
this._y = y;
|
|
562
|
+
await sleep2(rand(60, 140));
|
|
563
|
+
await this.send("Input.dispatchMouseEvent", {
|
|
564
|
+
type: "mouseReleased",
|
|
565
|
+
x,
|
|
566
|
+
y,
|
|
567
|
+
button: "left",
|
|
568
|
+
clickCount: 1
|
|
569
|
+
});
|
|
570
|
+
this._button = "none";
|
|
571
|
+
}
|
|
529
572
|
async wheel(deltaX, deltaY) {
|
|
530
573
|
await this.send("Input.dispatchMouseEvent", {
|
|
531
574
|
type: "mouseWheel",
|
|
@@ -1164,6 +1207,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1164
1207
|
`);
|
|
1165
1208
|
return selected;
|
|
1166
1209
|
}
|
|
1210
|
+
async dragAndDrop(source, target) {
|
|
1211
|
+
const boxes = await this.page.evaluate(`
|
|
1212
|
+
(function() {
|
|
1213
|
+
const s = ${this._q(source)}, t = ${this._q(target)};
|
|
1214
|
+
if (!s || !t) return null;
|
|
1215
|
+
const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
|
|
1216
|
+
return [c(s), c(t)];
|
|
1217
|
+
})()
|
|
1218
|
+
`);
|
|
1219
|
+
if (!boxes || !boxes[0] || !boxes[1]) {
|
|
1220
|
+
throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
|
|
1221
|
+
}
|
|
1222
|
+
await this.page.mouse.move(boxes[0].x, boxes[0].y);
|
|
1223
|
+
await this.page.mouse.drag(boxes[1].x, boxes[1].y);
|
|
1224
|
+
}
|
|
1167
1225
|
async screenshot(opts = {}) {
|
|
1168
1226
|
await waitForActionable(this.page, this.selector);
|
|
1169
1227
|
const box = await this.page.evaluate(`
|
package/dist/cli.js
CHANGED
|
@@ -72,7 +72,7 @@ import {
|
|
|
72
72
|
setActivePage,
|
|
73
73
|
sleep,
|
|
74
74
|
wheelDelta
|
|
75
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-3LVR44KG.js";
|
|
76
76
|
import "./chunk-TNEN6VQ2.js";
|
|
77
77
|
import {
|
|
78
78
|
errMsg
|
|
@@ -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-HY7UXUQV.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-HY7UXUQV.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-HY7UXUQV.js");
|
|
13997
14000
|
await ensureProcessCanExit().catch(() => {
|
|
13998
14001
|
});
|
|
13999
14002
|
process.exit(process.exitCode || exitCode);
|
package/dist/daemon-main.js
CHANGED
|
@@ -34,13 +34,13 @@ import {
|
|
|
34
34
|
resolveLaunchOpts,
|
|
35
35
|
saveSessionDiskMeta,
|
|
36
36
|
setActivePage
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-UQUJVBXE.js";
|
|
38
38
|
import {
|
|
39
39
|
createRuleEngine,
|
|
40
40
|
rand,
|
|
41
41
|
sleep,
|
|
42
42
|
wheelDelta
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-W4JETHAD.js";
|
|
44
44
|
import {
|
|
45
45
|
queryJS
|
|
46
46
|
} from "./chunk-3FWLW7FS.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-ZVNDI4TR.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-NV65I6OQ.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-CE3L6HYV.js";
|
|
22
22
|
import {
|
|
23
23
|
detectAntiBot,
|
|
24
24
|
formatDetectionMessage
|
|
@@ -86,7 +86,7 @@ import {
|
|
|
86
86
|
rand,
|
|
87
87
|
sleep,
|
|
88
88
|
wheelDelta
|
|
89
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-3KUJOXUE.js";
|
|
90
90
|
import "./chunk-TNEN6VQ2.js";
|
|
91
91
|
import {
|
|
92
92
|
errMsg
|
|
@@ -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-GPRLH6P6.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-GPRLH6P6.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-GMDP4KDN.js");
|
|
17283
17286
|
const { browser } = await launch({
|
|
17284
17287
|
headless: true,
|
|
17285
17288
|
args: ["--no-sandbox", "--disable-setuid-sandbox"]
|
|
@@ -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-FIAUJTBZ.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.17.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": {
|