@xbrowser/cli 1.14.0 → 1.16.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-KJWBHGHX.js → browser-3KTEVTMU.js} +2 -2
- package/dist/{browser-5A6AL62M.js → browser-AOVQTGJ7.js} +2 -2
- package/dist/{browser-DI6UQN6Q.js → browser-KT4FOWBO.js} +1 -1
- package/dist/{cdp-driver-QXTXJZH7.js → cdp-driver-ALDP2CZT.js} +248 -49
- package/dist/{cdp-driver-4SFS6GNY.js → cdp-driver-DKNLIA6B.js} +1 -1
- package/dist/{cdp-driver-AHKUT57K.js → cdp-driver-OC37OT4B.js} +1 -1
- package/dist/{chunk-BTFKJD7Z.js → chunk-5EYOEB4R.js} +277 -65
- package/dist/{chunk-B753M33E.js → chunk-7V3B7VPX.js} +9 -7
- package/dist/{chunk-PYQGDBAF.js → chunk-A5HJ6IRE.js} +269 -59
- package/dist/{chunk-ZD4OSYOX.js → chunk-GWQ5NTVE.js} +9 -7
- package/dist/{chunk-UPAWITVM.js → chunk-LTBNQERK.js} +269 -59
- package/dist/cli.js +86 -32
- package/dist/clipboard-BOL2GP2E.js +58 -0
- package/dist/clipboard-XRP54ENE.js +58 -0
- package/dist/daemon-main.js +44 -22
- package/dist/index.d.ts +4 -0
- package/dist/index.js +106 -51
- package/dist/{session-replayer-I3PJFO3H.js → session-replayer-MJH5W7BB.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-7V3B7VPX.js";
|
|
24
|
+
import "./chunk-A5HJ6IRE.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-GWQ5NTVE.js";
|
|
24
|
+
import "./chunk-LTBNQERK.js";
|
|
25
25
|
import "./chunk-3FWLW7FS.js";
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import "./chunk-GDKLH7ZY.js";
|
|
@@ -24,7 +24,7 @@ var DEFAULT_STEALTH_CONFIG = {
|
|
|
24
24
|
bezierCurvature: [0.35, 0.6],
|
|
25
25
|
noiseAmplitude: 5.5,
|
|
26
26
|
overshootRange: [6, 14],
|
|
27
|
-
aimPause: [
|
|
27
|
+
aimPause: [80, 280],
|
|
28
28
|
pressDuration: [60, 140],
|
|
29
29
|
releaseDrift: [0.8, 2.5],
|
|
30
30
|
landingOffsetSmall: [0.3, 2.5],
|
|
@@ -92,6 +92,13 @@ function landingOffset(width, height, config = DEFAULT_STEALTH_CONFIG) {
|
|
|
92
92
|
const dy = rand(...range) * (Math.random() < 0.5 ? -1 : 1);
|
|
93
93
|
return { dx, dy };
|
|
94
94
|
}
|
|
95
|
+
function typingDelay(config = DEFAULT_STEALTH_CONFIG) {
|
|
96
|
+
const roll = Math.random();
|
|
97
|
+
const r = config.typingRhythm;
|
|
98
|
+
if (roll < r.pauseProb) return rand(...r.pauseRange);
|
|
99
|
+
if (roll < r.pauseProb + r.fastProb) return rand(...r.fastRange);
|
|
100
|
+
return rand(...r.normalRange);
|
|
101
|
+
}
|
|
95
102
|
var KEY_MAP = {};
|
|
96
103
|
for (let i = 97; i <= 122; i++) {
|
|
97
104
|
const ch = String.fromCharCode(i);
|
|
@@ -115,6 +122,7 @@ Object.assign(KEY_MAP, {
|
|
|
115
122
|
function buildStealthInitScript() {
|
|
116
123
|
return [
|
|
117
124
|
"(function(){",
|
|
125
|
+
' window.__xbStealthVer="57";',
|
|
118
126
|
// 1. AEL event proxy
|
|
119
127
|
" var o=EventTarget.prototype.addEventListener;",
|
|
120
128
|
" var fc=new InputDeviceCapabilities({firesTouchEvents:false});",
|
|
@@ -277,6 +285,70 @@ function buildStealthInitScript() {
|
|
|
277
285
|
' var _pto=Object.getOwnPropertyDescriptor(Performance.prototype,"timeOrigin");',
|
|
278
286
|
' if(_pto&&_pto.get){Object.defineProperty(performance,"timeOrigin",{get:function(){return _pto.get.call(performance);},configurable:true});}',
|
|
279
287
|
" }catch(e){}",
|
|
288
|
+
// 3f. getCoalescedEvents 合成(d47):真实鼠标 125Hz 采样被浏览器按帧合并,
|
|
289
|
+
// 快速移动时 pointermove.getCoalescedEvents() 返回 2~6 个事件(群内
|
|
290
|
+
// ≈8ms);CDP Input 逐事件派发不走合并管线,coalesced>1 恒为 0(结构性
|
|
291
|
+
// 暴露,间隔模拟救不了——实测 Chrome 帧对齐时 CDP 连发事件被直接丢弃
|
|
292
|
+
// 而非合并)。按 125Hz 物理插值合成 coalesced 群:期望样本数 = dt/8ms-1,
|
|
293
|
+
// 合成事件用真 PointerEvent 构造 + 实例级 isTrusted/timeStamp 遮蔽。
|
|
294
|
+
" try{",
|
|
295
|
+
" if(window.PointerEvent&&PointerEvent.prototype.getCoalescedEvents){",
|
|
296
|
+
" var _gce=PointerEvent.prototype.getCoalescedEvents;",
|
|
297
|
+
" var _lm=null;",
|
|
298
|
+
" var _gceH=function(){",
|
|
299
|
+
" var list=_gce.call(this);",
|
|
300
|
+
' if(this.type!=="pointermove"||!this.isTrusted)return list;',
|
|
301
|
+
" var cur={x:this.clientX,y:this.clientY,ts:this.timeStamp};",
|
|
302
|
+
" var out=null;",
|
|
303
|
+
" if((!list||list.length<2)&&_lm){",
|
|
304
|
+
" var dt=cur.ts-_lm.ts,dx=cur.x-_lm.x,dy=cur.y-_lm.y;",
|
|
305
|
+
// dt 长(帧丢弃后)不代表群覆盖整个 dt —— 真实 coalesced 群只覆盖
|
|
306
|
+
// 最后一帧窗口(≤16.7ms,群内 ≈8ms=125Hz)。合成群从自身往回推 8ms
|
|
307
|
+
// 链,位移取末端占比(span/dt,dt 远大于 span 时位移趋零=丢弃后实况)。
|
|
308
|
+
" var expN=Math.floor(dt/8)-1;",
|
|
309
|
+
// dt<12ms(不足一帧+采样周期)时真实浏览器不会产生合并群 ——
|
|
310
|
+
// 单采样帧 coalesced=1,强行合成会出现 ~2ms 的超物理群内间隔。
|
|
311
|
+
" if(expN>0&&dt>=12&&Math.random()>0.15){",
|
|
312
|
+
" var n=Math.min(4,expN+(Math.random()<0.3?1:0));",
|
|
313
|
+
" var span=Math.min(dt,n*8.3);",
|
|
314
|
+
" var frac=Math.min(1,span/Math.max(dt,1));",
|
|
315
|
+
" out=[];",
|
|
316
|
+
" for(var i=1;i<=n;i++){",
|
|
317
|
+
// k=距自身的步数(含自身共 n+1 个事件,相邻恒 ≈8.3ms=125Hz 周期)
|
|
318
|
+
" var k=n+1-i;",
|
|
319
|
+
' var ev=new PointerEvent("pointermove",{',
|
|
320
|
+
' pointerId:this.pointerId,pointerType:"mouse",isPrimary:this.isPrimary,',
|
|
321
|
+
" clientX:cur.x-dx*frac*(k/(n+1))+(Math.random()-0.5)*1.5,",
|
|
322
|
+
" clientY:cur.y-dy*frac*(k/(n+1))+(Math.random()-0.5)*1.5,",
|
|
323
|
+
" screenX:this.screenX,screenY:this.screenY,",
|
|
324
|
+
" buttons:this.buttons,button:this.button,",
|
|
325
|
+
" bubbles:true,cancelable:true,composed:true,",
|
|
326
|
+
" width:this.width,height:this.height,pressure:this.pressure,",
|
|
327
|
+
" tiltX:this.tiltX,tiltY:this.tiltY,twist:this.twist});",
|
|
328
|
+
" var tsV=cur.ts-k*8.3-Math.random()*1.2;",
|
|
329
|
+
// isTrusted/timeStamp 是实例不可配置属性(defineProperty 抛
|
|
330
|
+
// "Cannot redefine"),改 Proxy 包装:getPrototypeOf/ownKeys 透传,
|
|
331
|
+
// instanceof 与属性枚举行为与真事件一致。IIFE 捕获本次循环的 tsV
|
|
332
|
+
// 快照 —— var 提升会让所有 Proxy 闭包共享最后一次赋值(实测四个
|
|
333
|
+
// 合成事件同时间戳、群内间隔塌到 ~2ms)。
|
|
334
|
+
" out.push((function(e2,t2){return new Proxy(e2,{get:function(t,p){",
|
|
335
|
+
' if(p==="isTrusted")return true;',
|
|
336
|
+
' if(p==="timeStamp")return t2;',
|
|
337
|
+
' var v=Reflect.get(t,p);return typeof v==="function"?v.bind(t):v;',
|
|
338
|
+
" }});})(ev,tsV));",
|
|
339
|
+
" }",
|
|
340
|
+
" out.push(this);",
|
|
341
|
+
" }",
|
|
342
|
+
" }",
|
|
343
|
+
" _lm=cur;",
|
|
344
|
+
" return out||list;",
|
|
345
|
+
" };",
|
|
346
|
+
" PointerEvent.prototype.getCoalescedEvents=_gceH;",
|
|
347
|
+
// name 反查伪装:var _gceH=fn 的具名推断会暴露 hook(原生 name 是
|
|
348
|
+
// "getCoalescedEvents")——toString 白名单管不到 name 属性。
|
|
349
|
+
' try{Object.defineProperty(_gceH,"name",{value:"getCoalescedEvents"});}catch(e){}',
|
|
350
|
+
" }",
|
|
351
|
+
" }catch(e){}",
|
|
280
352
|
// 3d. Chrome object depth (d24): automation fakes usually only set
|
|
281
353
|
// window.chrome = {}; deep checks hit app.run/runtime/csi/loadTimes.
|
|
282
354
|
" try{",
|
|
@@ -311,6 +383,7 @@ function buildStealthInitScript() {
|
|
|
311
383
|
' if(this===HTMLCanvasElement.prototype.toDataURL)return"function toDataURL() { [native code] }";',
|
|
312
384
|
' if(this===AnalyserNode.prototype.getFloatFrequencyData)return"function getFloatFrequencyData() { [native code] }";',
|
|
313
385
|
' if(this===AudioBuffer.prototype.getChannelData)return"function getChannelData() { [native code] }";',
|
|
386
|
+
' if(this===_gceH)return"function getCoalescedEvents() { [native code] }";',
|
|
314
387
|
" return _ts.call(this);",
|
|
315
388
|
" };",
|
|
316
389
|
// 4. onclick prototype hijack (dual-stream consistency)
|
|
@@ -421,12 +494,14 @@ var XBMouseImpl = class {
|
|
|
421
494
|
});
|
|
422
495
|
}
|
|
423
496
|
async move(x, y, opts = {}) {
|
|
497
|
+
const stealth = opts.stealth ?? process.env.XBROWSER_STEALTH !== "off";
|
|
424
498
|
const steps = Math.max(1, opts.steps ?? 1);
|
|
425
499
|
const fromX = this._x;
|
|
426
500
|
const fromY = this._y;
|
|
427
501
|
const dx = x - fromX;
|
|
428
502
|
const dy = y - fromY;
|
|
429
503
|
for (let i = 1; i <= steps; i++) {
|
|
504
|
+
if (stealth) await sleep(rand(16, 28));
|
|
430
505
|
const t = i / steps;
|
|
431
506
|
this._x = fromX + dx * t;
|
|
432
507
|
this._y = fromY + dy * t;
|
|
@@ -541,44 +616,55 @@ var XBKeyboardImpl = class {
|
|
|
541
616
|
if (fixedDelay > 0) {
|
|
542
617
|
await sleep2(fixedDelay);
|
|
543
618
|
} else if (stealth) {
|
|
544
|
-
|
|
545
|
-
const cfg = DEFAULT_STEALTH_CONFIG.typingRhythm;
|
|
546
|
-
if (roll < cfg.pauseProb) {
|
|
547
|
-
await sleep2(rand(cfg.pauseRange[0], cfg.pauseRange[1]));
|
|
548
|
-
} else if (roll < cfg.pauseProb + cfg.fastProb) {
|
|
549
|
-
await sleep2(rand(cfg.fastRange[0], cfg.fastRange[1]));
|
|
550
|
-
} else {
|
|
551
|
-
await sleep2(rand(cfg.normalRange[0], cfg.normalRange[1]));
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
const mapping = resolveKeyMapping(char);
|
|
555
|
-
const downParams = {
|
|
556
|
-
type: "rawKeyDown",
|
|
557
|
-
key: mapping.key,
|
|
558
|
-
code: mapping.code
|
|
559
|
-
};
|
|
560
|
-
if (mapping.text) {
|
|
561
|
-
downParams.text = mapping.text;
|
|
562
|
-
downParams.unmodifiedText = mapping.text;
|
|
619
|
+
await sleep2(typingDelay());
|
|
563
620
|
}
|
|
564
|
-
if (
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
text: mapping.text
|
|
572
|
-
});
|
|
621
|
+
if (stealth && char.length === 1 && Math.random() < DEFAULT_STEALTH_CONFIG.typoProbability) {
|
|
622
|
+
const wrong = NEIGHBOR_KEYS[char];
|
|
623
|
+
if (wrong && wrong !== char) {
|
|
624
|
+
await this.dispatchKeySequence(resolveKeyMapping(wrong), stealth);
|
|
625
|
+
await sleep2(rand(120, 420));
|
|
626
|
+
await this.dispatchKeySequence(KEY_MAP2.Backspace, stealth);
|
|
627
|
+
}
|
|
573
628
|
}
|
|
574
|
-
await this.
|
|
575
|
-
type: "keyUp",
|
|
576
|
-
key: mapping.key,
|
|
577
|
-
code: mapping.code,
|
|
578
|
-
...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
|
|
579
|
-
});
|
|
629
|
+
await this.dispatchKeySequence(resolveKeyMapping(char), stealth);
|
|
580
630
|
}
|
|
581
631
|
}
|
|
632
|
+
/**
|
|
633
|
+
* Single-key event sequence: rawKeyDown → (char) → keyUp.
|
|
634
|
+
* Shared by press() and type() — two separate implementations drifted
|
|
635
|
+
* apart once already (S60: type() lost the keyPressDuration that press()
|
|
636
|
+
* had; d50 caught it as 33/33 keys with down→up of 2ms).
|
|
637
|
+
*/
|
|
638
|
+
async dispatchKeySequence(mapping, stealth) {
|
|
639
|
+
const downParams = {
|
|
640
|
+
type: "rawKeyDown",
|
|
641
|
+
key: mapping.key,
|
|
642
|
+
code: mapping.code
|
|
643
|
+
};
|
|
644
|
+
if (mapping.text) {
|
|
645
|
+
downParams.text = mapping.text;
|
|
646
|
+
downParams.unmodifiedText = mapping.text;
|
|
647
|
+
}
|
|
648
|
+
if (mapping.keyCode) {
|
|
649
|
+
downParams.windowsVirtualKeyCode = mapping.keyCode;
|
|
650
|
+
}
|
|
651
|
+
await this.dispatchKeyEvent(downParams);
|
|
652
|
+
if (mapping.text) {
|
|
653
|
+
await this.dispatchKeyEvent({ type: "char", text: mapping.text });
|
|
654
|
+
}
|
|
655
|
+
if (stealth) {
|
|
656
|
+
await sleep2(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
|
|
657
|
+
}
|
|
658
|
+
const upParams = {
|
|
659
|
+
type: "keyUp",
|
|
660
|
+
key: mapping.key,
|
|
661
|
+
code: mapping.code
|
|
662
|
+
};
|
|
663
|
+
if (mapping.keyCode) {
|
|
664
|
+
upParams.windowsVirtualKeyCode = mapping.keyCode;
|
|
665
|
+
}
|
|
666
|
+
await this.dispatchKeyEvent(upParams);
|
|
667
|
+
}
|
|
582
668
|
async insertText(text) {
|
|
583
669
|
await this.conn.send(
|
|
584
670
|
"Input.insertText",
|
|
@@ -586,6 +672,55 @@ var XBKeyboardImpl = class {
|
|
|
586
672
|
this.sessionId
|
|
587
673
|
);
|
|
588
674
|
}
|
|
675
|
+
/**
|
|
676
|
+
* Navigation key press using CDP type 'keyDown' (NOT rawKeyDown).
|
|
677
|
+
* rawKeyDown skips browser default actions — select option navigation,
|
|
678
|
+
* arrow-key scrolling etc. never fire under it (d53: ArrowDown on a
|
|
679
|
+
* focused <select> left the value unchanged). keyDown carries the
|
|
680
|
+
* default action.
|
|
681
|
+
*/
|
|
682
|
+
async pressNav(key) {
|
|
683
|
+
const mapping = resolveKeyMapping(key);
|
|
684
|
+
const downParams = {
|
|
685
|
+
type: "keyDown",
|
|
686
|
+
key: mapping.key,
|
|
687
|
+
code: mapping.code
|
|
688
|
+
};
|
|
689
|
+
if (mapping.keyCode) {
|
|
690
|
+
downParams.windowsVirtualKeyCode = mapping.keyCode;
|
|
691
|
+
downParams.nativeVirtualKeyCode = mapping.keyCode;
|
|
692
|
+
}
|
|
693
|
+
await this.dispatchKeyEvent(downParams);
|
|
694
|
+
if (process.env.XBROWSER_STEALTH !== "off") {
|
|
695
|
+
await sleep2(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
|
|
696
|
+
}
|
|
697
|
+
await this.dispatchKeyEvent({
|
|
698
|
+
type: "keyUp",
|
|
699
|
+
key: mapping.key,
|
|
700
|
+
code: mapping.code,
|
|
701
|
+
...mapping.keyCode ? { windowsVirtualKeyCode: mapping.keyCode } : {}
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Shortcut combo press (modifier+key) with explicit per-event modifiers
|
|
706
|
+
* bitmask — plain down(mod)+press(key) inserts the raw character because
|
|
707
|
+
* CDP modifiers are per-event fields, not session state (d56: Meta,v
|
|
708
|
+
* typed a literal 'v'). keyDown type carries the default action so the
|
|
709
|
+
* browser's shortcut dispatcher sees the combo (e.g. native paste).
|
|
710
|
+
*/
|
|
711
|
+
async pressCombo(key, modifier) {
|
|
712
|
+
const MODBIT = { Alt: 1, Control: 2, Meta: 4, Shift: 8 };
|
|
713
|
+
const m = resolveKeyMapping(modifier);
|
|
714
|
+
const k = resolveKeyMapping(key);
|
|
715
|
+
const bits = MODBIT[modifier] ?? 0;
|
|
716
|
+
await this.dispatchKeyEvent({ type: "rawKeyDown", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: bits });
|
|
717
|
+
await this.dispatchKeyEvent({ type: "keyDown", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
718
|
+
if (process.env.XBROWSER_STEALTH !== "off") {
|
|
719
|
+
await sleep2(rand(...DEFAULT_STEALTH_CONFIG.keyPressDuration));
|
|
720
|
+
}
|
|
721
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: k.key, code: k.code, ...k.keyCode ? { windowsVirtualKeyCode: k.keyCode } : {}, modifiers: bits });
|
|
722
|
+
await this.dispatchKeyEvent({ type: "keyUp", key: m.key, code: m.code, ...m.keyCode ? { windowsVirtualKeyCode: m.keyCode } : {}, modifiers: 0 });
|
|
723
|
+
}
|
|
589
724
|
async dispatchKeyEvent(params) {
|
|
590
725
|
await this.conn.send("Input.dispatchKeyEvent", params, this.sessionId);
|
|
591
726
|
}
|
|
@@ -640,6 +775,43 @@ var KEY_MAP2 = {
|
|
|
640
775
|
F11: { key: "F11", code: "F11", keyCode: 122 },
|
|
641
776
|
F12: { key: "F12", code: "F12", keyCode: 123 }
|
|
642
777
|
};
|
|
778
|
+
var NEIGHBOR_KEYS = {
|
|
779
|
+
a: "s",
|
|
780
|
+
b: "v",
|
|
781
|
+
c: "x",
|
|
782
|
+
d: "f",
|
|
783
|
+
e: "r",
|
|
784
|
+
f: "g",
|
|
785
|
+
g: "h",
|
|
786
|
+
h: "j",
|
|
787
|
+
i: "o",
|
|
788
|
+
j: "k",
|
|
789
|
+
k: "l",
|
|
790
|
+
l: "k",
|
|
791
|
+
m: "n",
|
|
792
|
+
n: "m",
|
|
793
|
+
o: "p",
|
|
794
|
+
p: "o",
|
|
795
|
+
q: "w",
|
|
796
|
+
r: "t",
|
|
797
|
+
s: "d",
|
|
798
|
+
t: "y",
|
|
799
|
+
u: "i",
|
|
800
|
+
v: "b",
|
|
801
|
+
w: "e",
|
|
802
|
+
x: "c",
|
|
803
|
+
y: "u",
|
|
804
|
+
z: "x",
|
|
805
|
+
"1": "2",
|
|
806
|
+
"2": "3",
|
|
807
|
+
"3": "4",
|
|
808
|
+
"4": "5",
|
|
809
|
+
"5": "6",
|
|
810
|
+
"6": "7",
|
|
811
|
+
"7": "8",
|
|
812
|
+
"8": "9",
|
|
813
|
+
"9": "0"
|
|
814
|
+
};
|
|
643
815
|
function sleep2(ms) {
|
|
644
816
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
645
817
|
}
|
|
@@ -932,6 +1104,18 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
932
1104
|
await waitForActionable(this.page, this.selector, opts);
|
|
933
1105
|
await scrollIntoView(this.page, this.selector);
|
|
934
1106
|
await this.click({ ...opts });
|
|
1107
|
+
if (process.env.XBROWSER_STEALTH !== "off" && value.length >= 40 && process.env.XBROWSER_FILL_TYPE !== "type") {
|
|
1108
|
+
try {
|
|
1109
|
+
const { pasteViaClipboard, syntheticPaste } = await import("./clipboard-XRP54ENE.js");
|
|
1110
|
+
await pasteViaClipboard(this.page, value);
|
|
1111
|
+
const got = await this.page.evaluate(
|
|
1112
|
+
`(function(){ const el = ${this._q(this.selector)}; return el ? (el.value || '') : ''; })()`
|
|
1113
|
+
);
|
|
1114
|
+
if (got === value) return;
|
|
1115
|
+
if (await syntheticPaste(this.page, this._q(this.selector), value)) return;
|
|
1116
|
+
} catch {
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
935
1119
|
await this.page.keyboard.type(value, { stealth: true });
|
|
936
1120
|
return;
|
|
937
1121
|
await this.page.evaluate(`
|
|
@@ -957,23 +1141,13 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
957
1141
|
async press(key, opts = {}) {
|
|
958
1142
|
await waitForActionable(this.page, this.selector, { timeout: opts.timeout });
|
|
959
1143
|
await scrollIntoView(this.page, this.selector);
|
|
960
|
-
await this.
|
|
961
|
-
(function() {
|
|
962
|
-
const el = ${this._q(this.selector)};
|
|
963
|
-
if (el) el.focus();
|
|
964
|
-
})()
|
|
965
|
-
`);
|
|
1144
|
+
await this.click({ timeout: opts.timeout });
|
|
966
1145
|
await this.page.keyboard.press(key);
|
|
967
1146
|
}
|
|
968
1147
|
async pressSequentially(text, opts = {}) {
|
|
969
1148
|
await waitForActionable(this.page, this.selector, { timeout: opts.timeout });
|
|
970
1149
|
await scrollIntoView(this.page, this.selector);
|
|
971
|
-
await this.
|
|
972
|
-
(function() {
|
|
973
|
-
const el = ${this._q(this.selector)};
|
|
974
|
-
if (el) el.focus();
|
|
975
|
-
})()
|
|
976
|
-
`);
|
|
1150
|
+
await this.click({ timeout: opts.timeout });
|
|
977
1151
|
await this.page.keyboard.type(text, { delay: opts.delay });
|
|
978
1152
|
}
|
|
979
1153
|
async hover(opts = {}) {
|
|
@@ -1028,11 +1202,36 @@ var XBLocatorImpl = class _XBLocatorImpl {
|
|
|
1028
1202
|
async selectOption(value) {
|
|
1029
1203
|
await waitForActionable(this.page, this.selector);
|
|
1030
1204
|
const values = Array.isArray(value) ? value : [value];
|
|
1031
|
-
const
|
|
1205
|
+
const info = await this.page.evaluate(`
|
|
1032
1206
|
(function() {
|
|
1033
1207
|
const el = ${this._q(this.selector)};
|
|
1034
1208
|
if (!el || el.tagName !== 'SELECT') throw new Error('Not a select element');
|
|
1035
|
-
|
|
1209
|
+
const values = ${JSON.stringify(values)};
|
|
1210
|
+
let target = -1, targetValue = '';
|
|
1211
|
+
outer:
|
|
1212
|
+
for (let i = 0; i < el.options.length; i++) {
|
|
1213
|
+
const opt = el.options[i];
|
|
1214
|
+
for (const v of values) {
|
|
1215
|
+
const hit = typeof v === 'object'
|
|
1216
|
+
? (v.label !== undefined ? opt.label === v.label
|
|
1217
|
+
: v.value !== undefined ? opt.value === v.value
|
|
1218
|
+
: opt.index === v.index)
|
|
1219
|
+
: (opt.value === v || opt.label === v);
|
|
1220
|
+
if (hit) { target = i; targetValue = opt.value; break outer; }
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
return { cur: el.selectedIndex, target: target, targetValue: targetValue, multiple: el.multiple };
|
|
1224
|
+
})()
|
|
1225
|
+
`);
|
|
1226
|
+
if (info.target < 0) {
|
|
1227
|
+
throw new Error(`Option not found: ${JSON.stringify(values)}`);
|
|
1228
|
+
}
|
|
1229
|
+
if (!info.multiple) {
|
|
1230
|
+
await this.click({ timeout: 5e3 });
|
|
1231
|
+
}
|
|
1232
|
+
const selected = await this.page.evaluate(`
|
|
1233
|
+
(function() {
|
|
1234
|
+
const el = ${this._q(this.selector)};
|
|
1036
1235
|
const values = ${JSON.stringify(values)};
|
|
1037
1236
|
const selectedValues = [];
|
|
1038
1237
|
|