@xbrowser/cli 1.15.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-4FKHBUBJ.js → browser-GPRLH6P6.js} +2 -2
- package/dist/{browser-JNT2I73V.js → browser-HY7UXUQV.js} +1 -1
- package/dist/{browser-YYMKZWTU.js → browser-ZVNDI4TR.js} +2 -2
- package/dist/{cdp-driver-7RW4NY2X.js → cdp-driver-FIAUJTBZ.js} +1 -1
- package/dist/{cdp-driver-QX72T7SU.js → cdp-driver-GMDP4KDN.js} +1 -1
- package/dist/{cdp-driver-FTGIYCFO.js → cdp-driver-TPVLBEFT.js} +90 -0
- package/dist/{chunk-NTTFKS6T.js → chunk-3KUJOXUE.js} +90 -0
- package/dist/{chunk-HFP4QCZL.js → chunk-3LVR44KG.js} +126 -10
- package/dist/{chunk-K5E4CWRV.js → chunk-CE3L6HYV.js} +37 -11
- package/dist/{chunk-XQ4KOZ37.js → chunk-UQUJVBXE.js} +37 -11
- package/dist/{chunk-UXDGEDT7.js → chunk-W4JETHAD.js} +90 -0
- package/dist/cli.js +20 -17
- package/dist/clipboard-BOL2GP2E.js +58 -0
- package/dist/clipboard-XRP54ENE.js +58 -0
- package/dist/daemon-main.js +15 -12
- package/dist/index.d.ts +6 -0
- package/dist/index.js +41 -38
- package/dist/{session-replayer-DKHXF3DZ.js → session-replayer-NV65I6OQ.js} +1 -1
- package/package.json +1 -1
- package/dist/{recovery-Z3RDZENA.js → recovery-MDWAVXE4.js} +4 -4
- package/dist/{recovery-FTZGV6VY.js → recovery-NXC35EQN.js} +4 -4
|
@@ -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",
|
|
@@ -701,6 +744,26 @@ var XBKeyboardImpl = class {
|
|
|
701
744
|
...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
|
|
702
745
|
});
|
|
703
746
|
}
|
|
747
|
+
/**
|
|
748
|
+
* Shortcut combo press (modifier+key) with explicit per-event modifiers
|
|
749
|
+
* bitmask — plain down(mod)+press(key) inserts the raw character because
|
|
750
|
+
* CDP modifiers are per-event fields, not session state (d56: Meta,v
|
|
751
|
+
* typed a literal 'v'). keyDown type carries the default action so the
|
|
752
|
+
* browser's shortcut dispatcher sees the combo (e.g. native paste).
|
|
753
|
+
*/
|
|
754
|
+
async pressCombo(key, modifier) {
|
|
755
|
+
const MODBIT = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
|
|
756
|
+
const m = resolveKeyMapping(modifier);
|
|
757
|
+
const k = resolveKeyMapping(key);
|
|
758
|
+
const bits = MODBIT[modifier] ?? 0;
|
|
759
|
+
await this.dispatchKeyEvent({ type: "rawKeyDown", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: bits });
|
|
760
|
+
await this.dispatchKeyEvent({ type: "keyDown", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
761
|
+
if (process.env.XBROWSER_STEALTH !== "off") {
|
|
762
|
+
await sleep2(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
|
|
763
|
+
}
|
|
764
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
765
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: 0 });
|
|
766
|
+
}
|
|
704
767
|
async dispatchKeyEvent(params) {
|
|
705
768
|
await this.conn.send("Input.dispatchKeyEvent", params, this.sessionId);
|
|
706
769
|
}
|
|
@@ -1084,6 +1147,18 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1084
1147
|
await waitForActionable(this.page, this.selector, opts);
|
|
1085
1148
|
await scrollIntoView(this.page, this.selector);
|
|
1086
1149
|
await this.click({ ...opts });
|
|
1150
|
+
if (process.env.XBROWSER_STEALTH !== "off" && value.length >= 40 && process.env.XBROWSER_FILL_TYPE !== "type") {
|
|
1151
|
+
try {
|
|
1152
|
+
const { pasteViaClipboard, syntheticPaste } = await import("./clipboard-XRP54ENE.js");
|
|
1153
|
+
await pasteViaClipboard(this.page, value);
|
|
1154
|
+
const got = await this.page.evaluate(
|
|
1155
|
+
`(function(){ const el = ${this._q(this.selector)}; return el ? (el.value || '') : ''; })()`
|
|
1156
|
+
);
|
|
1157
|
+
if (got === value) return;
|
|
1158
|
+
if (await syntheticPaste(this.page, this._q(this.selector), value)) return;
|
|
1159
|
+
} catch {
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1087
1162
|
await this.page.keyboard.type(value, { stealth: true });
|
|
1088
1163
|
return;
|
|
1089
1164
|
await this.page.evaluate(`
|
|
@@ -1223,6 +1298,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1223
1298
|
`);
|
|
1224
1299
|
return selected;
|
|
1225
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
|
+
}
|
|
1226
1316
|
async screenshot(opts = {}) {
|
|
1227
1317
|
await waitForActionable(this.page, this.selector);
|
|
1228
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",
|
|
@@ -711,6 +754,26 @@ var XBKeyboardImpl = class {
|
|
|
711
754
|
...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
|
|
712
755
|
});
|
|
713
756
|
}
|
|
757
|
+
/**
|
|
758
|
+
* Shortcut combo press (modifier+key) with explicit per-event modifiers
|
|
759
|
+
* bitmask — plain down(mod)+press(key) inserts the raw character because
|
|
760
|
+
* CDP modifiers are per-event fields, not session state (d56: Meta,v
|
|
761
|
+
* typed a literal 'v'). keyDown type carries the default action so the
|
|
762
|
+
* browser's shortcut dispatcher sees the combo (e.g. native paste).
|
|
763
|
+
*/
|
|
764
|
+
async pressCombo(key, modifier) {
|
|
765
|
+
const MODBIT = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
|
|
766
|
+
const m = resolveKeyMapping(modifier);
|
|
767
|
+
const k = resolveKeyMapping(key);
|
|
768
|
+
const bits = MODBIT[modifier] ?? 0;
|
|
769
|
+
await this.dispatchKeyEvent({ type: "rawKeyDown", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: bits });
|
|
770
|
+
await this.dispatchKeyEvent({ type: "keyDown", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
771
|
+
if (process.env.XBROWSER_STEALTH !== "off") {
|
|
772
|
+
await sleep3(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
|
|
773
|
+
}
|
|
774
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
775
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: 0 });
|
|
776
|
+
}
|
|
714
777
|
async dispatchKeyEvent(params) {
|
|
715
778
|
await this.conn.send("Input.dispatchKeyEvent", params, this.sessionId);
|
|
716
779
|
}
|
|
@@ -1094,6 +1157,18 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1094
1157
|
await waitForActionable(this.page, this.selector, opts);
|
|
1095
1158
|
await scrollIntoView(this.page, this.selector);
|
|
1096
1159
|
await this.click({ ...opts });
|
|
1160
|
+
if (process.env.XBROWSER_STEALTH !== "off" && value.length >= 40 && process.env.XBROWSER_FILL_TYPE !== "type") {
|
|
1161
|
+
try {
|
|
1162
|
+
const { pasteViaClipboard, syntheticPaste } = await import("./clipboard-BOL2GP2E.js");
|
|
1163
|
+
await pasteViaClipboard(this.page, value);
|
|
1164
|
+
const got = await this.page.evaluate(
|
|
1165
|
+
`(function(){ const el = ${this._q(this.selector)}; return el ? (el.value || '') : ''; })()`
|
|
1166
|
+
);
|
|
1167
|
+
if (got === value) return;
|
|
1168
|
+
if (await syntheticPaste(this.page, this._q(this.selector), value)) return;
|
|
1169
|
+
} catch {
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1097
1172
|
await this.page.keyboard.type(value, { stealth: true });
|
|
1098
1173
|
return;
|
|
1099
1174
|
await this.page.evaluate(`
|
|
@@ -1233,6 +1308,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1233
1308
|
`);
|
|
1234
1309
|
return selected;
|
|
1235
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
|
+
}
|
|
1236
1326
|
async screenshot(opts = {}) {
|
|
1237
1327
|
await waitForActionable(this.page, this.selector);
|
|
1238
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",
|
|
@@ -714,6 +757,26 @@ var XBKeyboardImpl = class {
|
|
|
714
757
|
...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
|
|
715
758
|
});
|
|
716
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* Shortcut combo press (modifier+key) with explicit per-event modifiers
|
|
762
|
+
* bitmask — plain down(mod)+press(key) inserts the raw character because
|
|
763
|
+
* CDP modifiers are per-event fields, not session state (d56: Meta,v
|
|
764
|
+
* typed a literal 'v'). keyDown type carries the default action so the
|
|
765
|
+
* browser's shortcut dispatcher sees the combo (e.g. native paste).
|
|
766
|
+
*/
|
|
767
|
+
async pressCombo(key, modifier) {
|
|
768
|
+
const MODBIT = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
|
|
769
|
+
const m = resolveKeyMapping(modifier);
|
|
770
|
+
const k = resolveKeyMapping(key);
|
|
771
|
+
const bits = MODBIT[modifier] ?? 0;
|
|
772
|
+
await this.dispatchKeyEvent({ type: "rawKeyDown", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: bits });
|
|
773
|
+
await this.dispatchKeyEvent({ type: "keyDown", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
774
|
+
if (process.env.XBROWSER_STEALTH !== "off") {
|
|
775
|
+
await sleep3(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
|
|
776
|
+
}
|
|
777
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
778
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: 0 });
|
|
779
|
+
}
|
|
717
780
|
async dispatchKeyEvent(params) {
|
|
718
781
|
await this.conn.send("Input.dispatchKeyEvent", params, this.sessionId);
|
|
719
782
|
}
|
|
@@ -1097,6 +1160,18 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1097
1160
|
await waitForActionable(this.page, this.selector, opts);
|
|
1098
1161
|
await scrollIntoView(this.page, this.selector);
|
|
1099
1162
|
await this.click({ ...opts });
|
|
1163
|
+
if (process.env.XBROWSER_STEALTH !== "off" && value.length >= 40 && process.env.XBROWSER_FILL_TYPE !== "type") {
|
|
1164
|
+
try {
|
|
1165
|
+
const { pasteViaClipboard, syntheticPaste } = await import("./clipboard-BOL2GP2E.js");
|
|
1166
|
+
await pasteViaClipboard(this.page, value);
|
|
1167
|
+
const got = await this.page.evaluate(
|
|
1168
|
+
`(function(){ const el = ${this._q(this.selector)}; return el ? (el.value || '') : ''; })()`
|
|
1169
|
+
);
|
|
1170
|
+
if (got === value) return;
|
|
1171
|
+
if (await syntheticPaste(this.page, this._q(this.selector), value)) return;
|
|
1172
|
+
} catch {
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1100
1175
|
await this.page.keyboard.type(value, { stealth: true });
|
|
1101
1176
|
return;
|
|
1102
1177
|
await this.page.evaluate(`
|
|
@@ -1236,6 +1311,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1236
1311
|
`);
|
|
1237
1312
|
return selected;
|
|
1238
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
|
+
}
|
|
1239
1329
|
async screenshot(opts = {}) {
|
|
1240
1330
|
await waitForActionable(this.page, this.selector);
|
|
1241
1331
|
const box = await this.page.evaluate(`
|
|
@@ -5363,16 +5453,14 @@ process.on("exit", () => {
|
|
|
5363
5453
|
async function getCDPTargets2(cdpEndpoint) {
|
|
5364
5454
|
try {
|
|
5365
5455
|
const ep = String(cdpEndpoint);
|
|
5366
|
-
let
|
|
5367
|
-
let port = "9222";
|
|
5456
|
+
let url = "http://localhost:9222/json/list";
|
|
5368
5457
|
if (ep.startsWith("http://") || ep.startsWith("https://")) {
|
|
5369
5458
|
const u = new URL(ep);
|
|
5370
|
-
|
|
5371
|
-
|
|
5459
|
+
u.pathname = (u.pathname.replace(/\/+$/, "") || "") + "/json/list";
|
|
5460
|
+
url = u.toString();
|
|
5372
5461
|
} else if (/^\d+$/.test(ep)) {
|
|
5373
|
-
|
|
5462
|
+
url = `http://localhost:${ep}/json/list`;
|
|
5374
5463
|
}
|
|
5375
|
-
const url = `http://${host}:${port}/json/list`;
|
|
5376
5464
|
const resp = await fetch(url);
|
|
5377
5465
|
return await resp.json();
|
|
5378
5466
|
} catch {
|
|
@@ -5843,20 +5931,48 @@ async function createSession(name, url, options) {
|
|
|
5843
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)
|
|
5844
5932
|
);
|
|
5845
5933
|
if (matchTarget && matchTarget.url) {
|
|
5846
|
-
|
|
5847
|
-
|
|
5934
|
+
const existing2 = context.pages().find((p) => {
|
|
5935
|
+
try {
|
|
5936
|
+
return p.url() === matchTarget.url;
|
|
5937
|
+
} catch {
|
|
5938
|
+
return false;
|
|
5939
|
+
}
|
|
5848
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
|
+
}
|
|
5849
5948
|
}
|
|
5850
5949
|
}
|
|
5851
5950
|
if (!targetPage) {
|
|
5852
5951
|
const pages = context.pages();
|
|
5853
|
-
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) {
|
|
5854
5965
|
targetPage = pages[0];
|
|
5855
|
-
}
|
|
5966
|
+
}
|
|
5967
|
+
if (!targetPage) {
|
|
5856
5968
|
targetPage = await context.newPage();
|
|
5857
5969
|
}
|
|
5858
5970
|
}
|
|
5859
5971
|
page = targetPage;
|
|
5972
|
+
if (isCDP) {
|
|
5973
|
+
await Promise.resolve(targetPage.bringToFront?.()).catch(() => {
|
|
5974
|
+
});
|
|
5975
|
+
}
|
|
5860
5976
|
} else {
|
|
5861
5977
|
context = await b.newContext({ viewport: { width: 1920, height: 1080 } });
|
|
5862
5978
|
page = await context.newPage();
|
|
@@ -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";
|
|
@@ -161,16 +161,14 @@ process.on("exit", () => {
|
|
|
161
161
|
async function getCDPTargets(cdpEndpoint) {
|
|
162
162
|
try {
|
|
163
163
|
const ep = String(cdpEndpoint);
|
|
164
|
-
let
|
|
165
|
-
let port = "9222";
|
|
164
|
+
let url = "http://localhost:9222/json/list";
|
|
166
165
|
if (ep.startsWith("http://") || ep.startsWith("https://")) {
|
|
167
166
|
const u = new URL(ep);
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
u.pathname = (u.pathname.replace(/\/+$/, "") || "") + "/json/list";
|
|
168
|
+
url = u.toString();
|
|
170
169
|
} else if (/^\d+$/.test(ep)) {
|
|
171
|
-
|
|
170
|
+
url = `http://localhost:${ep}/json/list`;
|
|
172
171
|
}
|
|
173
|
-
const url = `http://${host}:${port}/json/list`;
|
|
174
172
|
const resp = await fetch(url);
|
|
175
173
|
return await resp.json();
|
|
176
174
|
} catch {
|
|
@@ -641,20 +639,48 @@ async function createSession(name, url, options) {
|
|
|
641
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)
|
|
642
640
|
);
|
|
643
641
|
if (matchTarget && matchTarget.url) {
|
|
644
|
-
|
|
645
|
-
|
|
642
|
+
const existing2 = context.pages().find((p) => {
|
|
643
|
+
try {
|
|
644
|
+
return p.url() === matchTarget.url;
|
|
645
|
+
} catch {
|
|
646
|
+
return false;
|
|
647
|
+
}
|
|
646
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
|
+
}
|
|
647
656
|
}
|
|
648
657
|
}
|
|
649
658
|
if (!targetPage) {
|
|
650
659
|
const pages = context.pages();
|
|
651
|
-
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) {
|
|
652
673
|
targetPage = pages[0];
|
|
653
|
-
}
|
|
674
|
+
}
|
|
675
|
+
if (!targetPage) {
|
|
654
676
|
targetPage = await context.newPage();
|
|
655
677
|
}
|
|
656
678
|
}
|
|
657
679
|
page = targetPage;
|
|
680
|
+
if (isCDP) {
|
|
681
|
+
await Promise.resolve(targetPage.bringToFront?.()).catch(() => {
|
|
682
|
+
});
|
|
683
|
+
}
|
|
658
684
|
} else {
|
|
659
685
|
context = await b.newContext({ viewport: { width: 1920, height: 1080 } });
|
|
660
686
|
page = await context.newPage();
|
|
@@ -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";
|
|
@@ -588,16 +588,14 @@ process.on("exit", () => {
|
|
|
588
588
|
async function getCDPTargets(cdpEndpoint) {
|
|
589
589
|
try {
|
|
590
590
|
const ep = String(cdpEndpoint);
|
|
591
|
-
let
|
|
592
|
-
let port = "9222";
|
|
591
|
+
let url = "http://localhost:9222/json/list";
|
|
593
592
|
if (ep.startsWith("http://") || ep.startsWith("https://")) {
|
|
594
593
|
const u = new URL(ep);
|
|
595
|
-
|
|
596
|
-
|
|
594
|
+
u.pathname = (u.pathname.replace(/\/+$/, "") || "") + "/json/list";
|
|
595
|
+
url = u.toString();
|
|
597
596
|
} else if (/^\d+$/.test(ep)) {
|
|
598
|
-
|
|
597
|
+
url = `http://localhost:${ep}/json/list`;
|
|
599
598
|
}
|
|
600
|
-
const url = `http://${host}:${port}/json/list`;
|
|
601
599
|
const resp = await fetch(url);
|
|
602
600
|
return await resp.json();
|
|
603
601
|
} catch {
|
|
@@ -1068,20 +1066,48 @@ async function createSession(name, url, options) {
|
|
|
1068
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)
|
|
1069
1067
|
);
|
|
1070
1068
|
if (matchTarget && matchTarget.url) {
|
|
1071
|
-
|
|
1072
|
-
|
|
1069
|
+
const existing2 = context.pages().find((p) => {
|
|
1070
|
+
try {
|
|
1071
|
+
return p.url() === matchTarget.url;
|
|
1072
|
+
} catch {
|
|
1073
|
+
return false;
|
|
1074
|
+
}
|
|
1073
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
|
+
}
|
|
1074
1083
|
}
|
|
1075
1084
|
}
|
|
1076
1085
|
if (!targetPage) {
|
|
1077
1086
|
const pages = context.pages();
|
|
1078
|
-
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) {
|
|
1079
1100
|
targetPage = pages[0];
|
|
1080
|
-
}
|
|
1101
|
+
}
|
|
1102
|
+
if (!targetPage) {
|
|
1081
1103
|
targetPage = await context.newPage();
|
|
1082
1104
|
}
|
|
1083
1105
|
}
|
|
1084
1106
|
page = targetPage;
|
|
1107
|
+
if (isCDP) {
|
|
1108
|
+
await Promise.resolve(targetPage.bringToFront?.()).catch(() => {
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1085
1111
|
} else {
|
|
1086
1112
|
context = await b.newContext({ viewport: { width: 1920, height: 1080 } });
|
|
1087
1113
|
page = await context.newPage();
|
|
@@ -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",
|
|
@@ -712,6 +755,26 @@ var XBKeyboardImpl = class {
|
|
|
712
755
|
...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
|
|
713
756
|
});
|
|
714
757
|
}
|
|
758
|
+
/**
|
|
759
|
+
* Shortcut combo press (modifier+key) with explicit per-event modifiers
|
|
760
|
+
* bitmask — plain down(mod)+press(key) inserts the raw character because
|
|
761
|
+
* CDP modifiers are per-event fields, not session state (d56: Meta,v
|
|
762
|
+
* typed a literal 'v'). keyDown type carries the default action so the
|
|
763
|
+
* browser's shortcut dispatcher sees the combo (e.g. native paste).
|
|
764
|
+
*/
|
|
765
|
+
async pressCombo(key, modifier) {
|
|
766
|
+
const MODBIT = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
|
|
767
|
+
const m = resolveKeyMapping(modifier);
|
|
768
|
+
const k = resolveKeyMapping(key);
|
|
769
|
+
const bits = MODBIT[modifier] ?? 0;
|
|
770
|
+
await this.dispatchKeyEvent({ type: "rawKeyDown", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: bits });
|
|
771
|
+
await this.dispatchKeyEvent({ type: "keyDown", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
772
|
+
if (process.env.XBROWSER_STEALTH !== "off") {
|
|
773
|
+
await sleep3(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
|
|
774
|
+
}
|
|
775
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
776
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: 0 });
|
|
777
|
+
}
|
|
715
778
|
async dispatchKeyEvent(params) {
|
|
716
779
|
await this.conn.send("Input.dispatchKeyEvent", params, this.sessionId);
|
|
717
780
|
}
|
|
@@ -993,6 +1056,18 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
993
1056
|
await waitForActionable(this.page, this.selector, opts);
|
|
994
1057
|
await scrollIntoView(this.page, this.selector);
|
|
995
1058
|
await this.click({ ...opts });
|
|
1059
|
+
if (process.env.XBROWSER_STEALTH !== "off" && value.length >= 40 && process.env.XBROWSER_FILL_TYPE !== "type") {
|
|
1060
|
+
try {
|
|
1061
|
+
const { pasteViaClipboard, syntheticPaste } = await import("./clipboard-BOL2GP2E.js");
|
|
1062
|
+
await pasteViaClipboard(this.page, value);
|
|
1063
|
+
const got = await this.page.evaluate(
|
|
1064
|
+
`(function(){ const el = ${this._q(this.selector)}; return el ? (el.value || '') : ''; })()`
|
|
1065
|
+
);
|
|
1066
|
+
if (got === value) return;
|
|
1067
|
+
if (await syntheticPaste(this.page, this._q(this.selector), value)) return;
|
|
1068
|
+
} catch {
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
996
1071
|
await this.page.keyboard.type(value, { stealth: true });
|
|
997
1072
|
return;
|
|
998
1073
|
await this.page.evaluate(`
|
|
@@ -1132,6 +1207,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1132
1207
|
`);
|
|
1133
1208
|
return selected;
|
|
1134
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
|
+
}
|
|
1135
1225
|
async screenshot(opts = {}) {
|
|
1136
1226
|
await waitForActionable(this.page, this.selector);
|
|
1137
1227
|
const box = await this.page.evaluate(`
|
package/dist/cli.js
CHANGED
|
@@ -26,6 +26,16 @@ import {
|
|
|
26
26
|
import {
|
|
27
27
|
buildViewerUrl
|
|
28
28
|
} from "./chunk-3OD76SUE.js";
|
|
29
|
+
import {
|
|
30
|
+
NPM_REGISTRY_URL,
|
|
31
|
+
NPM_SCOPE,
|
|
32
|
+
getConfigValue,
|
|
33
|
+
getMarketplaceUrl,
|
|
34
|
+
loadConfig,
|
|
35
|
+
resolveNpmPackageWithFallback,
|
|
36
|
+
resolveScreenshotsDir,
|
|
37
|
+
setConfigValue
|
|
38
|
+
} from "./chunk-ZTHE5RBZ.js";
|
|
29
39
|
import {
|
|
30
40
|
getDaemonConfig,
|
|
31
41
|
getDaemonProcessStatus,
|
|
@@ -62,7 +72,7 @@ import {
|
|
|
62
72
|
setActivePage,
|
|
63
73
|
sleep,
|
|
64
74
|
wheelDelta
|
|
65
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-3LVR44KG.js";
|
|
66
76
|
import "./chunk-TNEN6VQ2.js";
|
|
67
77
|
import {
|
|
68
78
|
errMsg
|
|
@@ -71,16 +81,6 @@ import {
|
|
|
71
81
|
detectAntiBot,
|
|
72
82
|
formatDetectionMessage
|
|
73
83
|
} from "./chunk-JKVUFP3G.js";
|
|
74
|
-
import {
|
|
75
|
-
NPM_REGISTRY_URL,
|
|
76
|
-
NPM_SCOPE,
|
|
77
|
-
getConfigValue,
|
|
78
|
-
getMarketplaceUrl,
|
|
79
|
-
loadConfig,
|
|
80
|
-
resolveNpmPackageWithFallback,
|
|
81
|
-
resolveScreenshotsDir,
|
|
82
|
-
setConfigValue
|
|
83
|
-
} from "./chunk-ZTHE5RBZ.js";
|
|
84
84
|
import "./chunk-KFQGP6VL.js";
|
|
85
85
|
|
|
86
86
|
// src/router.ts
|
|
@@ -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.`);
|
|
@@ -7756,7 +7759,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7756
7759
|
const errorMessage = errMsg(err);
|
|
7757
7760
|
if (session?.page && process.env.XBROWSER_RECOVERY && !extraOpts?._recoveryAttempted) {
|
|
7758
7761
|
try {
|
|
7759
|
-
const { attemptRecovery } = await import("./recovery-
|
|
7762
|
+
const { attemptRecovery } = await import("./recovery-NXC35EQN.js");
|
|
7760
7763
|
const recovery = await attemptRecovery(
|
|
7761
7764
|
session.page,
|
|
7762
7765
|
sessionName,
|
|
@@ -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);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import "./chunk-KFQGP6VL.js";
|
|
2
|
+
|
|
3
|
+
// src/utils/clipboard.ts
|
|
4
|
+
import { exec, execSync } from "child_process";
|
|
5
|
+
function writeClipboard(text) {
|
|
6
|
+
const plat = process.platform;
|
|
7
|
+
if (plat === "darwin") {
|
|
8
|
+
const p = exec("pbcopy");
|
|
9
|
+
if (!p.stdin) throw new Error("pbcopy stdin unavailable");
|
|
10
|
+
p.stdin.write(text);
|
|
11
|
+
p.stdin.end();
|
|
12
|
+
execSync("sleep 0.05");
|
|
13
|
+
} else if (plat === "linux") {
|
|
14
|
+
execSync("command -v xclip >/dev/null 2>&1 && echo ok", { stdio: "ignore" });
|
|
15
|
+
const p = exec("xclip -selection clipboard -in");
|
|
16
|
+
if (!p.stdin) throw new Error("xclip stdin unavailable");
|
|
17
|
+
p.stdin.write(text);
|
|
18
|
+
p.stdin.end();
|
|
19
|
+
execSync("sleep 0.05");
|
|
20
|
+
} else if (plat === "win32") {
|
|
21
|
+
const p = exec("clip");
|
|
22
|
+
if (!p.stdin) throw new Error("clip stdin unavailable");
|
|
23
|
+
p.stdin.write(text);
|
|
24
|
+
p.stdin.end();
|
|
25
|
+
execSync("timeout /t 1 /nobreak >nul");
|
|
26
|
+
} else {
|
|
27
|
+
throw new Error(`Unsupported platform for clipboard: ${plat}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function pasteViaClipboard(page, text) {
|
|
31
|
+
writeClipboard(text);
|
|
32
|
+
const kb = page.keyboard;
|
|
33
|
+
const mod = process.platform === "darwin" ? "Meta" : "Control";
|
|
34
|
+
await kb.pressCombo("v", mod);
|
|
35
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
36
|
+
}
|
|
37
|
+
async function syntheticPaste(page, selector, text) {
|
|
38
|
+
const result = await page.evaluate(`
|
|
39
|
+
(function() {
|
|
40
|
+
const el = ${"{SELECTOR}"};
|
|
41
|
+
if (!el) return false;
|
|
42
|
+
el.focus();
|
|
43
|
+
if (el.value) { el.select(); document.execCommand('delete'); }
|
|
44
|
+
try {
|
|
45
|
+
const dt = new DataTransfer();
|
|
46
|
+
dt.setData('text/plain', ${JSON.stringify(text)});
|
|
47
|
+
el.dispatchEvent(new ClipboardEvent('paste', { clipboardData: dt, bubbles: true, cancelable: true }));
|
|
48
|
+
} catch (e) { /* ClipboardEvent ctor guard */ }
|
|
49
|
+
const ok = document.execCommand('insertText', false, ${JSON.stringify(text)});
|
|
50
|
+
return ok === true && (el.value || '') === ${JSON.stringify(text)};
|
|
51
|
+
})()
|
|
52
|
+
`.replace("{SELECTOR}", selector));
|
|
53
|
+
return result === true;
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
pasteViaClipboard,
|
|
57
|
+
syntheticPaste
|
|
58
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import "./chunk-3RG5ZIWI.js";
|
|
2
|
+
|
|
3
|
+
// src/utils/clipboard.ts
|
|
4
|
+
import { exec, execSync } from "child_process";
|
|
5
|
+
function writeClipboard(text) {
|
|
6
|
+
const plat = process.platform;
|
|
7
|
+
if (plat === "darwin") {
|
|
8
|
+
const p = exec("pbcopy");
|
|
9
|
+
if (!p.stdin) throw new Error("pbcopy stdin unavailable");
|
|
10
|
+
p.stdin.write(text);
|
|
11
|
+
p.stdin.end();
|
|
12
|
+
execSync("sleep 0.05");
|
|
13
|
+
} else if (plat === "linux") {
|
|
14
|
+
execSync("command -v xclip >/dev/null 2>&1 && echo ok", { stdio: "ignore" });
|
|
15
|
+
const p = exec("xclip -selection clipboard -in");
|
|
16
|
+
if (!p.stdin) throw new Error("xclip stdin unavailable");
|
|
17
|
+
p.stdin.write(text);
|
|
18
|
+
p.stdin.end();
|
|
19
|
+
execSync("sleep 0.05");
|
|
20
|
+
} else if (plat === "win32") {
|
|
21
|
+
const p = exec("clip");
|
|
22
|
+
if (!p.stdin) throw new Error("clip stdin unavailable");
|
|
23
|
+
p.stdin.write(text);
|
|
24
|
+
p.stdin.end();
|
|
25
|
+
execSync("timeout /t 1 /nobreak >nul");
|
|
26
|
+
} else {
|
|
27
|
+
throw new Error(`Unsupported platform for clipboard: ${plat}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async function pasteViaClipboard(page, text) {
|
|
31
|
+
writeClipboard(text);
|
|
32
|
+
const kb = page.keyboard;
|
|
33
|
+
const mod = process.platform === "darwin" ? "Meta" : "Control";
|
|
34
|
+
await kb.pressCombo("v", mod);
|
|
35
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
36
|
+
}
|
|
37
|
+
async function syntheticPaste(page, selector, text) {
|
|
38
|
+
const result = await page.evaluate(`
|
|
39
|
+
(function() {
|
|
40
|
+
const el = ${"{SELECTOR}"};
|
|
41
|
+
if (!el) return false;
|
|
42
|
+
el.focus();
|
|
43
|
+
if (el.value) { el.select(); document.execCommand('delete'); }
|
|
44
|
+
try {
|
|
45
|
+
const dt = new DataTransfer();
|
|
46
|
+
dt.setData('text/plain', ${JSON.stringify(text)});
|
|
47
|
+
el.dispatchEvent(new ClipboardEvent('paste', { clipboardData: dt, bubbles: true, cancelable: true }));
|
|
48
|
+
} catch (e) { /* ClipboardEvent ctor guard */ }
|
|
49
|
+
const ok = document.execCommand('insertText', false, ${JSON.stringify(text)});
|
|
50
|
+
return ok === true && (el.value || '') === ${JSON.stringify(text)};
|
|
51
|
+
})()
|
|
52
|
+
`.replace("{SELECTOR}", selector));
|
|
53
|
+
return result === true;
|
|
54
|
+
}
|
|
55
|
+
export {
|
|
56
|
+
pasteViaClipboard,
|
|
57
|
+
syntheticPaste
|
|
58
|
+
};
|
package/dist/daemon-main.js
CHANGED
|
@@ -7,6 +7,10 @@ import {
|
|
|
7
7
|
import {
|
|
8
8
|
buildViewerUrl
|
|
9
9
|
} from "./chunk-TZPKFUBT.js";
|
|
10
|
+
import {
|
|
11
|
+
ScreencastCapturer,
|
|
12
|
+
resolveScreenshotsDir
|
|
13
|
+
} from "./chunk-HBMEFSTB.js";
|
|
10
14
|
import "./chunk-CG3D3CHY.js";
|
|
11
15
|
import {
|
|
12
16
|
commandLogStore,
|
|
@@ -30,13 +34,13 @@ import {
|
|
|
30
34
|
resolveLaunchOpts,
|
|
31
35
|
saveSessionDiskMeta,
|
|
32
36
|
setActivePage
|
|
33
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-UQUJVBXE.js";
|
|
34
38
|
import {
|
|
35
39
|
createRuleEngine,
|
|
36
40
|
rand,
|
|
37
41
|
sleep,
|
|
38
42
|
wheelDelta
|
|
39
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-W4JETHAD.js";
|
|
40
44
|
import {
|
|
41
45
|
queryJS
|
|
42
46
|
} from "./chunk-3FWLW7FS.js";
|
|
@@ -48,10 +52,6 @@ import {
|
|
|
48
52
|
detectAntiBot,
|
|
49
53
|
formatDetectionMessage
|
|
50
54
|
} from "./chunk-JKVUFP3G.js";
|
|
51
|
-
import {
|
|
52
|
-
ScreencastCapturer,
|
|
53
|
-
resolveScreenshotsDir
|
|
54
|
-
} from "./chunk-HBMEFSTB.js";
|
|
55
55
|
import "./chunk-KFQGP6VL.js";
|
|
56
56
|
|
|
57
57
|
// src/daemon/daemon-main.ts
|
|
@@ -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.`);
|
|
@@ -7274,7 +7277,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7274
7277
|
const errorMessage = errMsg(err);
|
|
7275
7278
|
if (session?.page && process.env.XBROWSER_RECOVERY && !extraOpts?._recoveryAttempted) {
|
|
7276
7279
|
try {
|
|
7277
|
-
const { attemptRecovery } = await import("./recovery-
|
|
7280
|
+
const { attemptRecovery } = await import("./recovery-MDWAVXE4.js");
|
|
7278
7281
|
const recovery = await attemptRecovery(
|
|
7279
7282
|
session.page,
|
|
7280
7283
|
sessionName,
|
|
@@ -8314,7 +8317,7 @@ function createRPCHandler() {
|
|
|
8314
8317
|
return result;
|
|
8315
8318
|
} catch (err) {
|
|
8316
8319
|
const errorMessage = errMsg(err);
|
|
8317
|
-
const { attemptRecovery } = await import("./recovery-
|
|
8320
|
+
const { attemptRecovery } = await import("./recovery-MDWAVXE4.js");
|
|
8318
8321
|
const recovery = await attemptRecovery(
|
|
8319
8322
|
session?.page,
|
|
8320
8323
|
sessionName,
|
|
@@ -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?: {
|
|
@@ -318,6 +322,8 @@ interface XBKeyboard {
|
|
|
318
322
|
}): Promise<void>;
|
|
319
323
|
/** Navigation key with CDP 'keyDown' type (carries browser default actions) */
|
|
320
324
|
pressNav(key: string): Promise<void>;
|
|
325
|
+
/** Shortcut combo (modifier+key) with explicit per-event modifiers bitmask */
|
|
326
|
+
pressCombo(key: string, modifier: 'Meta' | 'Control' | 'Alt' | 'Shift'): Promise<void>;
|
|
321
327
|
down(key: string): Promise<void>;
|
|
322
328
|
up(key: string): Promise<void>;
|
|
323
329
|
type(text: string, opts?: {
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
import {
|
|
2
|
+
filterRecording,
|
|
3
|
+
parseExcludeTypes
|
|
4
|
+
} from "./chunk-ANVL2ID2.js";
|
|
5
|
+
import {
|
|
6
|
+
closeAllSessions,
|
|
7
|
+
closeEphemeralContext,
|
|
8
|
+
closeSessionByName,
|
|
9
|
+
createEphemeralContext,
|
|
10
|
+
createSession,
|
|
11
|
+
destroyBrowser,
|
|
12
|
+
findOrRestoreSession,
|
|
13
|
+
findSession,
|
|
14
|
+
getAllSessions,
|
|
15
|
+
getBrowser,
|
|
16
|
+
getSessionById,
|
|
17
|
+
resetForTesting,
|
|
18
|
+
resolveLaunchOpts,
|
|
19
|
+
saveSessionDiskMeta,
|
|
20
|
+
setActivePage
|
|
21
|
+
} from "./chunk-CE3L6HYV.js";
|
|
1
22
|
import {
|
|
2
23
|
detectAntiBot,
|
|
3
24
|
formatDetectionMessage
|
|
@@ -61,43 +82,11 @@ import {
|
|
|
61
82
|
extractRecording,
|
|
62
83
|
printExtractSummary
|
|
63
84
|
} from "./chunk-X46HDAOT.js";
|
|
64
|
-
import {
|
|
65
|
-
filterRecording,
|
|
66
|
-
parseExcludeTypes
|
|
67
|
-
} from "./chunk-ANVL2ID2.js";
|
|
68
|
-
import {
|
|
69
|
-
SessionRecorder
|
|
70
|
-
} from "./chunk-NODRQGOK.js";
|
|
71
|
-
import {
|
|
72
|
-
addKnownIssue,
|
|
73
|
-
getKnowledgePath,
|
|
74
|
-
init_site_knowledge,
|
|
75
|
-
listSiteKnowledge,
|
|
76
|
-
readSiteKnowledge,
|
|
77
|
-
readSiteKnowledgeMarkdown
|
|
78
|
-
} from "./chunk-OZKD3W4X.js";
|
|
79
|
-
import {
|
|
80
|
-
closeAllSessions,
|
|
81
|
-
closeEphemeralContext,
|
|
82
|
-
closeSessionByName,
|
|
83
|
-
createEphemeralContext,
|
|
84
|
-
createSession,
|
|
85
|
-
destroyBrowser,
|
|
86
|
-
findOrRestoreSession,
|
|
87
|
-
findSession,
|
|
88
|
-
getAllSessions,
|
|
89
|
-
getBrowser,
|
|
90
|
-
getSessionById,
|
|
91
|
-
resetForTesting,
|
|
92
|
-
resolveLaunchOpts,
|
|
93
|
-
saveSessionDiskMeta,
|
|
94
|
-
setActivePage
|
|
95
|
-
} from "./chunk-K5E4CWRV.js";
|
|
96
85
|
import {
|
|
97
86
|
rand,
|
|
98
87
|
sleep,
|
|
99
88
|
wheelDelta
|
|
100
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-3KUJOXUE.js";
|
|
101
90
|
import "./chunk-TNEN6VQ2.js";
|
|
102
91
|
import {
|
|
103
92
|
errMsg
|
|
@@ -118,6 +107,17 @@ import {
|
|
|
118
107
|
networkAnomalyRule,
|
|
119
108
|
pageLifecycleRule
|
|
120
109
|
} from "./chunk-H2A5JUK5.js";
|
|
110
|
+
import {
|
|
111
|
+
SessionRecorder
|
|
112
|
+
} from "./chunk-NODRQGOK.js";
|
|
113
|
+
import {
|
|
114
|
+
addKnownIssue,
|
|
115
|
+
getKnowledgePath,
|
|
116
|
+
init_site_knowledge,
|
|
117
|
+
listSiteKnowledge,
|
|
118
|
+
readSiteKnowledge,
|
|
119
|
+
readSiteKnowledgeMarkdown
|
|
120
|
+
} from "./chunk-OZKD3W4X.js";
|
|
121
121
|
import {
|
|
122
122
|
__require
|
|
123
123
|
} from "./chunk-KFQGP6VL.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-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": {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildViewerUrl
|
|
3
|
-
} from "./chunk-TZPKFUBT.js";
|
|
4
|
-
import "./chunk-CG3D3CHY.js";
|
|
5
1
|
import {
|
|
6
2
|
HumanInteractionManager
|
|
7
3
|
} from "./chunk-OMU63E6J.js";
|
|
4
|
+
import {
|
|
5
|
+
buildViewerUrl
|
|
6
|
+
} from "./chunk-TZPKFUBT.js";
|
|
8
7
|
import "./chunk-HBMEFSTB.js";
|
|
8
|
+
import "./chunk-CG3D3CHY.js";
|
|
9
9
|
import "./chunk-KFQGP6VL.js";
|
|
10
10
|
|
|
11
11
|
// src/recovery.ts
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
buildViewerUrl
|
|
3
|
-
} from "./chunk-3OD76SUE.js";
|
|
4
|
-
import "./chunk-Q2DFJQGS.js";
|
|
5
1
|
import {
|
|
6
2
|
HumanInteractionManager
|
|
7
3
|
} from "./chunk-TEXCXIBW.js";
|
|
4
|
+
import {
|
|
5
|
+
buildViewerUrl
|
|
6
|
+
} from "./chunk-3OD76SUE.js";
|
|
8
7
|
import "./chunk-ZTHE5RBZ.js";
|
|
8
|
+
import "./chunk-Q2DFJQGS.js";
|
|
9
9
|
import "./chunk-KFQGP6VL.js";
|
|
10
10
|
|
|
11
11
|
// src/recovery.ts
|