@xbrowser/cli 1.21.0 → 1.22.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/README.md +1 -0
- package/dist/{browser-CNBSH53B.js → browser-BVRFSUXU.js} +3 -2
- package/dist/{browser-C2VEOJC2.js → browser-DSYUAE7H.js} +5 -4
- package/dist/{browser-VZOOFLAH.js → browser-Q67BJTI2.js} +4 -3
- package/dist/{cdp-driver-KFX4A6WR.js → cdp-driver-DC7EIUG5.js} +4 -3
- package/dist/{cdp-driver-7Z6ZAT5E.js → cdp-driver-T7D6H2RW.js} +335 -546
- package/dist/{cdp-driver-26LGCHXV.js → cdp-driver-WWO2UZDR.js} +3 -2
- package/dist/{chunk-Z5RTK4GW.js → chunk-2Q3GQRUP.js} +2 -2
- package/dist/{chunk-CLYZPSDR.js → chunk-4OU37CXP.js} +354 -576
- package/dist/{chunk-HWWG2ISJ.js → chunk-7OP2ISEY.js} +353 -575
- package/dist/{chunk-3FWLW7FS.js → chunk-A7NEA4PA.js} +39 -1
- package/dist/chunk-GYB5BOSP.js +602 -0
- package/dist/{chunk-ESJYANQO.js → chunk-IFKJO2UR.js} +360 -582
- package/dist/{chunk-NODRQGOK.js → chunk-IR6C24P7.js} +97 -0
- package/dist/{chunk-3KZ34AUC.js → chunk-MYH6FIBZ.js} +2 -1
- package/dist/{chunk-AVSTNODR.js → chunk-T4WTKBWI.js} +2 -2
- package/dist/{chunk-HBHOKZPN.js → chunk-V6KGBU5J.js} +97 -0
- package/dist/{chunk-IWVG4XYZ.js → chunk-VCVDILH6.js} +2 -1
- package/dist/cli.js +25 -13
- package/dist/daemon-main.js +20 -14
- package/dist/index.d.ts +37 -1
- package/dist/index.js +26 -15
- package/dist/keep-awake-M4KJS4B4.js +29 -0
- package/dist/{launcher-44STYRJC.js → launcher-IK2FKW6T.js} +1 -1
- package/dist/{launcher-EXJHHAUL.js → launcher-LUOMMGZC.js} +1 -1
- package/dist/{session-recorder-SLDBENVF.js → session-recorder-563ISSJK.js} +1 -1
- package/dist/{session-recorder-3BEVWHOK.js → session-recorder-GEZVQBKW.js} +1 -1
- package/dist/session-replayer-XM5L7LFD.js +927 -0
- package/dist/stealth-2AA2FSNN.js +29 -0
- package/dist/stealth-JOXGV34D.js +29 -0
- package/package.json +1 -1
- package/dist/session-replayer-EVD4HZBB.js +0 -413
|
@@ -478,6 +478,55 @@ var ACTION_SIGNAL_SCRIPT = `
|
|
|
478
478
|
} catch(e) { /* skip */ }
|
|
479
479
|
}
|
|
480
480
|
|
|
481
|
+
// Ordinal address (r6): ancestor form's ordinal among sibling forms + element's
|
|
482
|
+
// ordinal among same-tag direct children of that form. Direct children only \u2014
|
|
483
|
+
// nested elements have no stable single-level address.
|
|
484
|
+
var ordinal = null;
|
|
485
|
+
try {
|
|
486
|
+
var ordForm = el.closest ? el.closest('form') : null;
|
|
487
|
+
if (ordForm && el.parentElement === ordForm) {
|
|
488
|
+
var ordParent = ordForm.parentElement;
|
|
489
|
+
var formSibs = ordParent
|
|
490
|
+
? Array.prototype.filter.call(ordParent.children, function(c) { return c.tagName === 'FORM'; })
|
|
491
|
+
: [ordForm];
|
|
492
|
+
var tagSibs = Array.prototype.filter.call(ordForm.children, function(c) { return c.tagName === el.tagName; });
|
|
493
|
+
ordinal = {
|
|
494
|
+
formNth: formSibs.indexOf(ordForm) + 1,
|
|
495
|
+
tagNth: tagSibs.indexOf(el) + 1,
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
} catch(e) { /* skip */ }
|
|
499
|
+
|
|
500
|
+
// Label text (r16): the <label> associated with the element (for= association or ancestor wrapper). In virtual list /
|
|
501
|
+
// form-row reordering scenarios, structural ordinals fail, but the label text moves in the same line as the
|
|
502
|
+
// control\u2014content moves, and the anchor follows the content.
|
|
503
|
+
var labelText = '';
|
|
504
|
+
try {
|
|
505
|
+
var lbl = null;
|
|
506
|
+
if (el.id) lbl = el.ownerDocument.querySelector('label[for="' + el.id + '"]');
|
|
507
|
+
if (!lbl && el.closest) lbl = el.closest('label');
|
|
508
|
+
if (lbl) labelText = (lbl.textContent || '').trim().substring(0, 40);
|
|
509
|
+
} catch(e) { /* skip */ }
|
|
510
|
+
|
|
511
|
+
// Element size (r25): rounded rect at record time \u2014 scoring signal for
|
|
512
|
+
// fingerprint disambiguation between same-fingerprint decoys.
|
|
513
|
+
var size = null;
|
|
514
|
+
try {
|
|
515
|
+
var szR = el.getBoundingClientRect();
|
|
516
|
+
if (szR.width > 0 || szR.height > 0) {
|
|
517
|
+
size = { w: Math.round(szR.width), h: Math.round(szR.height) };
|
|
518
|
+
}
|
|
519
|
+
} catch(e) { /* skip */ }
|
|
520
|
+
|
|
521
|
+
// Row text (r27): textContent of the closest table/list row. In virtual
|
|
522
|
+
// lists and sortable tables the row re-indexes \u2014 the row TEXT travels
|
|
523
|
+
// with the content, giving inputs a content anchor that survives reorder.
|
|
524
|
+
var rowText = '';
|
|
525
|
+
try {
|
|
526
|
+
var row = el.closest ? el.closest('tr,li') : null;
|
|
527
|
+
if (row) rowText = (row.textContent || '').trim().replace(/s+/g, ' ').substring(0, 40);
|
|
528
|
+
} catch(e) { /* skip */ }
|
|
529
|
+
|
|
481
530
|
return {
|
|
482
531
|
tag: tag,
|
|
483
532
|
selector: selector,
|
|
@@ -491,6 +540,10 @@ var ACTION_SIGNAL_SCRIPT = `
|
|
|
491
540
|
placeholder: el.getAttribute('placeholder') || undefined,
|
|
492
541
|
ariaLabel: el.getAttribute('aria-label') || undefined,
|
|
493
542
|
href: el.getAttribute('href') ? el.getAttribute('href').substring(0, 80) : undefined,
|
|
543
|
+
ordinal: ordinal || undefined,
|
|
544
|
+
labelText: labelText || undefined,
|
|
545
|
+
size: size || undefined,
|
|
546
|
+
rowText: rowText || undefined,
|
|
494
547
|
};
|
|
495
548
|
}
|
|
496
549
|
|
|
@@ -1128,6 +1181,50 @@ var ACTION_SIGNAL_SCRIPT = `
|
|
|
1128
1181
|
__xb_drag_start_pos = { x: e.clientX, y: e.clientY };
|
|
1129
1182
|
}, true);
|
|
1130
1183
|
document.addEventListener('drop', function(e) {
|
|
1184
|
+
// sup-s5: OS \u6587\u4EF6\u62D6\u5165\u6355\u83B7\u2014\u2014Dropzone/Uppy \u7C7B\u4E0A\u4F20\u533A\u65E0 input[type=file]\uFF0C
|
|
1185
|
+
// change \u6355\u83B7\u591F\u4E0D\u7740\uFF1BdataTransfer.files \u7ECF FileReader \u5185\u8054\uFF08\u4E0E
|
|
1186
|
+
// filechooser \u540C\u6784\uFF09\uFF0C\u56DE\u653E\u7AEF 'drop' \u52A8\u4F5C\u7ECF dropFiles \u91CD\u653E\u3002
|
|
1187
|
+
try {
|
|
1188
|
+
var dropped = (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0)
|
|
1189
|
+
? Array.prototype.slice.call(e.dataTransfer.files)
|
|
1190
|
+
: [];
|
|
1191
|
+
if (dropped.length > 0) {
|
|
1192
|
+
var zone = describe(resolveMeaningful(e));
|
|
1193
|
+
var names = dropped.map(function(f) { return f.name; });
|
|
1194
|
+
var readers = [];
|
|
1195
|
+
for (var i = 0; i < dropped.length; i++) {
|
|
1196
|
+
readers.push(new Promise(function(resolve) {
|
|
1197
|
+
var reader = new FileReader();
|
|
1198
|
+
reader.onload = function() { resolve(reader.result); };
|
|
1199
|
+
reader.onerror = function() { resolve(null); };
|
|
1200
|
+
reader.readAsDataURL(dropped[i]);
|
|
1201
|
+
}));
|
|
1202
|
+
}
|
|
1203
|
+
Promise.all(readers).then(function(contents) {
|
|
1204
|
+
var fileData = [];
|
|
1205
|
+
for (var j = 0; j < dropped.length; j++) {
|
|
1206
|
+
fileData.push({
|
|
1207
|
+
name: dropped[j].name,
|
|
1208
|
+
type: dropped[j].type,
|
|
1209
|
+
size: dropped[j].size,
|
|
1210
|
+
dataUrl: contents[j],
|
|
1211
|
+
});
|
|
1212
|
+
}
|
|
1213
|
+
pushAction('drop', {
|
|
1214
|
+
x: e.clientX,
|
|
1215
|
+
y: e.clientY,
|
|
1216
|
+
element: zone,
|
|
1217
|
+
value: names.join(', '),
|
|
1218
|
+
files: {
|
|
1219
|
+
names: names,
|
|
1220
|
+
count: dropped.length,
|
|
1221
|
+
isMultiple: dropped.length > 1,
|
|
1222
|
+
fileData: fileData,
|
|
1223
|
+
},
|
|
1224
|
+
});
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
} catch(_) { /* capture must not break the drag path */ }
|
|
1131
1228
|
if (__xb_drag_source && __xb_drag_start_pos) {
|
|
1132
1229
|
pushAction('drag', {
|
|
1133
1230
|
x: e.clientX,
|
|
@@ -93,10 +93,11 @@ async function launchChrome(options = {}) {
|
|
|
93
93
|
"--no-sandbox",
|
|
94
94
|
"--no-first-run",
|
|
95
95
|
"--no-default-browser-check",
|
|
96
|
+
"--disable-session-crashed-bubble",
|
|
96
97
|
"--disable-background-timer-throttling",
|
|
97
98
|
"--disable-backgrounding-occluded-windows",
|
|
98
99
|
"--disable-renderer-backgrounding",
|
|
99
|
-
"--disable-features=Translate",
|
|
100
|
+
"--disable-features=Translate,PasswordLeakDetection",
|
|
100
101
|
"--disable-popup-blocking"
|
|
101
102
|
];
|
|
102
103
|
if (headless) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createRuleEngine,
|
|
3
3
|
launch
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4OU37CXP.js";
|
|
5
5
|
import {
|
|
6
6
|
errMsg
|
|
7
7
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -1227,7 +1227,7 @@ async function closeSessionByName(name) {
|
|
|
1227
1227
|
} catch {
|
|
1228
1228
|
}
|
|
1229
1229
|
try {
|
|
1230
|
-
const { SessionRecorder } = await import("./session-recorder-
|
|
1230
|
+
const { SessionRecorder } = await import("./session-recorder-GEZVQBKW.js");
|
|
1231
1231
|
SessionRecorder.cleanup(session.name);
|
|
1232
1232
|
} catch {
|
|
1233
1233
|
}
|
|
@@ -875,6 +875,55 @@ var ACTION_SIGNAL_SCRIPT = `
|
|
|
875
875
|
} catch(e) { /* skip */ }
|
|
876
876
|
}
|
|
877
877
|
|
|
878
|
+
// Ordinal address (r6): ancestor form's ordinal among sibling forms + element's
|
|
879
|
+
// ordinal among same-tag direct children of that form. Direct children only \u2014
|
|
880
|
+
// nested elements have no stable single-level address.
|
|
881
|
+
var ordinal = null;
|
|
882
|
+
try {
|
|
883
|
+
var ordForm = el.closest ? el.closest('form') : null;
|
|
884
|
+
if (ordForm && el.parentElement === ordForm) {
|
|
885
|
+
var ordParent = ordForm.parentElement;
|
|
886
|
+
var formSibs = ordParent
|
|
887
|
+
? Array.prototype.filter.call(ordParent.children, function(c) { return c.tagName === 'FORM'; })
|
|
888
|
+
: [ordForm];
|
|
889
|
+
var tagSibs = Array.prototype.filter.call(ordForm.children, function(c) { return c.tagName === el.tagName; });
|
|
890
|
+
ordinal = {
|
|
891
|
+
formNth: formSibs.indexOf(ordForm) + 1,
|
|
892
|
+
tagNth: tagSibs.indexOf(el) + 1,
|
|
893
|
+
};
|
|
894
|
+
}
|
|
895
|
+
} catch(e) { /* skip */ }
|
|
896
|
+
|
|
897
|
+
// Label text (r16): the <label> associated with the element (for= association or ancestor wrapper). In virtual list /
|
|
898
|
+
// form-row reordering scenarios, structural ordinals fail, but the label text moves in the same line as the
|
|
899
|
+
// control\u2014content moves, and the anchor follows the content.
|
|
900
|
+
var labelText = '';
|
|
901
|
+
try {
|
|
902
|
+
var lbl = null;
|
|
903
|
+
if (el.id) lbl = el.ownerDocument.querySelector('label[for="' + el.id + '"]');
|
|
904
|
+
if (!lbl && el.closest) lbl = el.closest('label');
|
|
905
|
+
if (lbl) labelText = (lbl.textContent || '').trim().substring(0, 40);
|
|
906
|
+
} catch(e) { /* skip */ }
|
|
907
|
+
|
|
908
|
+
// Element size (r25): rounded rect at record time \u2014 scoring signal for
|
|
909
|
+
// fingerprint disambiguation between same-fingerprint decoys.
|
|
910
|
+
var size = null;
|
|
911
|
+
try {
|
|
912
|
+
var szR = el.getBoundingClientRect();
|
|
913
|
+
if (szR.width > 0 || szR.height > 0) {
|
|
914
|
+
size = { w: Math.round(szR.width), h: Math.round(szR.height) };
|
|
915
|
+
}
|
|
916
|
+
} catch(e) { /* skip */ }
|
|
917
|
+
|
|
918
|
+
// Row text (r27): textContent of the closest table/list row. In virtual
|
|
919
|
+
// lists and sortable tables the row re-indexes \u2014 the row TEXT travels
|
|
920
|
+
// with the content, giving inputs a content anchor that survives reorder.
|
|
921
|
+
var rowText = '';
|
|
922
|
+
try {
|
|
923
|
+
var row = el.closest ? el.closest('tr,li') : null;
|
|
924
|
+
if (row) rowText = (row.textContent || '').trim().replace(/s+/g, ' ').substring(0, 40);
|
|
925
|
+
} catch(e) { /* skip */ }
|
|
926
|
+
|
|
878
927
|
return {
|
|
879
928
|
tag: tag,
|
|
880
929
|
selector: selector,
|
|
@@ -888,6 +937,10 @@ var ACTION_SIGNAL_SCRIPT = `
|
|
|
888
937
|
placeholder: el.getAttribute('placeholder') || undefined,
|
|
889
938
|
ariaLabel: el.getAttribute('aria-label') || undefined,
|
|
890
939
|
href: el.getAttribute('href') ? el.getAttribute('href').substring(0, 80) : undefined,
|
|
940
|
+
ordinal: ordinal || undefined,
|
|
941
|
+
labelText: labelText || undefined,
|
|
942
|
+
size: size || undefined,
|
|
943
|
+
rowText: rowText || undefined,
|
|
891
944
|
};
|
|
892
945
|
}
|
|
893
946
|
|
|
@@ -1525,6 +1578,50 @@ var ACTION_SIGNAL_SCRIPT = `
|
|
|
1525
1578
|
__xb_drag_start_pos = { x: e.clientX, y: e.clientY };
|
|
1526
1579
|
}, true);
|
|
1527
1580
|
document.addEventListener('drop', function(e) {
|
|
1581
|
+
// sup-s5: OS \u6587\u4EF6\u62D6\u5165\u6355\u83B7\u2014\u2014Dropzone/Uppy \u7C7B\u4E0A\u4F20\u533A\u65E0 input[type=file]\uFF0C
|
|
1582
|
+
// change \u6355\u83B7\u591F\u4E0D\u7740\uFF1BdataTransfer.files \u7ECF FileReader \u5185\u8054\uFF08\u4E0E
|
|
1583
|
+
// filechooser \u540C\u6784\uFF09\uFF0C\u56DE\u653E\u7AEF 'drop' \u52A8\u4F5C\u7ECF dropFiles \u91CD\u653E\u3002
|
|
1584
|
+
try {
|
|
1585
|
+
var dropped = (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length > 0)
|
|
1586
|
+
? Array.prototype.slice.call(e.dataTransfer.files)
|
|
1587
|
+
: [];
|
|
1588
|
+
if (dropped.length > 0) {
|
|
1589
|
+
var zone = describe(resolveMeaningful(e));
|
|
1590
|
+
var names = dropped.map(function(f) { return f.name; });
|
|
1591
|
+
var readers = [];
|
|
1592
|
+
for (var i = 0; i < dropped.length; i++) {
|
|
1593
|
+
readers.push(new Promise(function(resolve) {
|
|
1594
|
+
var reader = new FileReader();
|
|
1595
|
+
reader.onload = function() { resolve(reader.result); };
|
|
1596
|
+
reader.onerror = function() { resolve(null); };
|
|
1597
|
+
reader.readAsDataURL(dropped[i]);
|
|
1598
|
+
}));
|
|
1599
|
+
}
|
|
1600
|
+
Promise.all(readers).then(function(contents) {
|
|
1601
|
+
var fileData = [];
|
|
1602
|
+
for (var j = 0; j < dropped.length; j++) {
|
|
1603
|
+
fileData.push({
|
|
1604
|
+
name: dropped[j].name,
|
|
1605
|
+
type: dropped[j].type,
|
|
1606
|
+
size: dropped[j].size,
|
|
1607
|
+
dataUrl: contents[j],
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1610
|
+
pushAction('drop', {
|
|
1611
|
+
x: e.clientX,
|
|
1612
|
+
y: e.clientY,
|
|
1613
|
+
element: zone,
|
|
1614
|
+
value: names.join(', '),
|
|
1615
|
+
files: {
|
|
1616
|
+
names: names,
|
|
1617
|
+
count: dropped.length,
|
|
1618
|
+
isMultiple: dropped.length > 1,
|
|
1619
|
+
fileData: fileData,
|
|
1620
|
+
},
|
|
1621
|
+
});
|
|
1622
|
+
});
|
|
1623
|
+
}
|
|
1624
|
+
} catch(_) { /* capture must not break the drag path */ }
|
|
1528
1625
|
if (__xb_drag_source && __xb_drag_start_pos) {
|
|
1529
1626
|
pushAction('drag', {
|
|
1530
1627
|
x: e.clientX,
|
|
@@ -97,10 +97,11 @@ async function launchChrome(options = {}) {
|
|
|
97
97
|
"--no-sandbox",
|
|
98
98
|
"--no-first-run",
|
|
99
99
|
"--no-default-browser-check",
|
|
100
|
+
"--disable-session-crashed-bubble",
|
|
100
101
|
"--disable-background-timer-throttling",
|
|
101
102
|
"--disable-backgrounding-occluded-windows",
|
|
102
103
|
"--disable-renderer-backgrounding",
|
|
103
|
-
"--disable-features=Translate",
|
|
104
|
+
"--disable-features=Translate,PasswordLeakDetection",
|
|
104
105
|
"--disable-popup-blocking"
|
|
105
106
|
];
|
|
106
107
|
if (headless) {
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
detectAntiBot,
|
|
4
|
+
formatDetectionMessage
|
|
5
|
+
} from "./chunk-JKVUFP3G.js";
|
|
2
6
|
import {
|
|
3
7
|
forwardCommandLog,
|
|
4
8
|
forwardNetworkAnalyze,
|
|
@@ -45,7 +49,7 @@ import {
|
|
|
45
49
|
} from "./chunk-Q2DFJQGS.js";
|
|
46
50
|
import {
|
|
47
51
|
SessionRecorder
|
|
48
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-IR6C24P7.js";
|
|
49
53
|
import {
|
|
50
54
|
addKnownIssue,
|
|
51
55
|
getKnowledgePath,
|
|
@@ -66,21 +70,19 @@ import {
|
|
|
66
70
|
getAllSessions,
|
|
67
71
|
getBrowser,
|
|
68
72
|
getSessionById,
|
|
69
|
-
rand,
|
|
70
73
|
resolveLaunchOpts,
|
|
71
74
|
saveSessionDiskMeta,
|
|
72
|
-
setActivePage
|
|
75
|
+
setActivePage
|
|
76
|
+
} from "./chunk-IFKJO2UR.js";
|
|
77
|
+
import {
|
|
78
|
+
rand,
|
|
73
79
|
sleep,
|
|
74
80
|
wheelDelta
|
|
75
|
-
} from "./chunk-
|
|
76
|
-
import "./chunk-
|
|
81
|
+
} from "./chunk-GYB5BOSP.js";
|
|
82
|
+
import "./chunk-MYH6FIBZ.js";
|
|
77
83
|
import {
|
|
78
84
|
errMsg
|
|
79
85
|
} from "./chunk-GDKLH7ZY.js";
|
|
80
|
-
import {
|
|
81
|
-
detectAntiBot,
|
|
82
|
-
formatDetectionMessage
|
|
83
|
-
} from "./chunk-JKVUFP3G.js";
|
|
84
86
|
import "./chunk-KFQGP6VL.js";
|
|
85
87
|
|
|
86
88
|
// src/router.ts
|
|
@@ -8248,7 +8250,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8248
8250
|
}
|
|
8249
8251
|
let targetPageOverride = null;
|
|
8250
8252
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
8251
|
-
const { findTargetPage } = await import("./browser-
|
|
8253
|
+
const { findTargetPage } = await import("./browser-BVRFSUXU.js");
|
|
8252
8254
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
8253
8255
|
if (!targetPageOverride) {
|
|
8254
8256
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -12292,6 +12294,16 @@ async function handleReplay(args, options, mode) {
|
|
|
12292
12294
|
}
|
|
12293
12295
|
return;
|
|
12294
12296
|
}
|
|
12297
|
+
if (result.ok && mode !== "json" && mode !== "yaml") {
|
|
12298
|
+
const healed = typeof result.healed === "number" ? result.healed : 0;
|
|
12299
|
+
if (healed > 0) {
|
|
12300
|
+
console.log(`
|
|
12301
|
+
Self-healed ${healed} action(s):`);
|
|
12302
|
+
for (const d of result.healedDetails ?? []) {
|
|
12303
|
+
console.log(` - step ${d.index + 1}: ${d.strategy}`);
|
|
12304
|
+
}
|
|
12305
|
+
}
|
|
12306
|
+
}
|
|
12295
12307
|
outputResult(result, mode);
|
|
12296
12308
|
}
|
|
12297
12309
|
async function handleConvert(args, _mode) {
|
|
@@ -12393,7 +12405,7 @@ async function handleFilter(args, _mode, options) {
|
|
|
12393
12405
|
}
|
|
12394
12406
|
}
|
|
12395
12407
|
async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
12396
|
-
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-
|
|
12408
|
+
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-563ISSJK.js");
|
|
12397
12409
|
const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
|
|
12398
12410
|
const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync12 } = await import("fs");
|
|
12399
12411
|
const { join: join15 } = await import("path");
|
|
@@ -14433,7 +14445,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
14433
14445
|
const targetPage = pages[cmdTabIndex];
|
|
14434
14446
|
await targetPage.bringToFront().catch(() => {
|
|
14435
14447
|
});
|
|
14436
|
-
const { setActivePage: setActivePage2 } = await import("./browser-
|
|
14448
|
+
const { setActivePage: setActivePage2 } = await import("./browser-BVRFSUXU.js");
|
|
14437
14449
|
setActivePage2(session, targetPage);
|
|
14438
14450
|
}
|
|
14439
14451
|
}
|
|
@@ -14709,7 +14721,7 @@ async function main() {
|
|
|
14709
14721
|
const command = process.argv[2];
|
|
14710
14722
|
const isLongRunning = command === "preview" || command === "serve";
|
|
14711
14723
|
if (!isLongRunning) {
|
|
14712
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
14724
|
+
const { ensureProcessCanExit } = await import("./browser-BVRFSUXU.js");
|
|
14713
14725
|
await ensureProcessCanExit().catch(() => {
|
|
14714
14726
|
});
|
|
14715
14727
|
process.exit(process.exitCode || exitCode);
|
package/dist/daemon-main.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
detectAntiBot,
|
|
3
|
+
formatDetectionMessage
|
|
4
|
+
} from "./chunk-JKVUFP3G.js";
|
|
1
5
|
import {
|
|
2
6
|
getPluginLoader
|
|
3
7
|
} from "./chunk-PIWNMC36.js";
|
|
@@ -19,7 +23,7 @@ import {
|
|
|
19
23
|
} from "./chunk-VEDJ5XSQ.js";
|
|
20
24
|
import {
|
|
21
25
|
SessionRecorder
|
|
22
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-V6KGBU5J.js";
|
|
23
27
|
import {
|
|
24
28
|
closeEphemeralContext,
|
|
25
29
|
closeSessionByName,
|
|
@@ -34,24 +38,22 @@ import {
|
|
|
34
38
|
resolveLaunchOpts,
|
|
35
39
|
saveSessionDiskMeta,
|
|
36
40
|
setActivePage
|
|
37
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-T4WTKBWI.js";
|
|
42
|
+
import {
|
|
43
|
+
createRuleEngine
|
|
44
|
+
} from "./chunk-4OU37CXP.js";
|
|
45
|
+
import {
|
|
46
|
+
queryJS
|
|
47
|
+
} from "./chunk-A7NEA4PA.js";
|
|
38
48
|
import {
|
|
39
|
-
createRuleEngine,
|
|
40
49
|
rand,
|
|
41
50
|
sleep,
|
|
42
51
|
wheelDelta
|
|
43
|
-
} from "./chunk-
|
|
44
|
-
import
|
|
45
|
-
queryJS
|
|
46
|
-
} from "./chunk-3FWLW7FS.js";
|
|
47
|
-
import "./chunk-3KZ34AUC.js";
|
|
52
|
+
} from "./chunk-GYB5BOSP.js";
|
|
53
|
+
import "./chunk-MYH6FIBZ.js";
|
|
48
54
|
import {
|
|
49
55
|
errMsg
|
|
50
56
|
} from "./chunk-GDKLH7ZY.js";
|
|
51
|
-
import {
|
|
52
|
-
detectAntiBot,
|
|
53
|
-
formatDetectionMessage
|
|
54
|
-
} from "./chunk-JKVUFP3G.js";
|
|
55
57
|
import "./chunk-KFQGP6VL.js";
|
|
56
58
|
|
|
57
59
|
// src/daemon/daemon-main.ts
|
|
@@ -7766,7 +7768,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7766
7768
|
}
|
|
7767
7769
|
let targetPageOverride = null;
|
|
7768
7770
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7769
|
-
const { findTargetPage } = await import("./browser-
|
|
7771
|
+
const { findTargetPage } = await import("./browser-DSYUAE7H.js");
|
|
7770
7772
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7771
7773
|
if (!targetPageOverride) {
|
|
7772
7774
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -9588,7 +9590,7 @@ function createRPCHandler() {
|
|
|
9588
9590
|
if (isNewFormat) {
|
|
9589
9591
|
try {
|
|
9590
9592
|
const replayErrors = [];
|
|
9591
|
-
const { SessionReplayer } = await import("./session-replayer-
|
|
9593
|
+
const { SessionReplayer } = await import("./session-replayer-XM5L7LFD.js");
|
|
9592
9594
|
const replayer = new SessionReplayer({
|
|
9593
9595
|
page: session.page,
|
|
9594
9596
|
stepDelay: slowMo * 500,
|
|
@@ -9613,6 +9615,8 @@ function createRPCHandler() {
|
|
|
9613
9615
|
duration,
|
|
9614
9616
|
eventsPlayed: result2.success,
|
|
9615
9617
|
totalEvents: result2.success + result2.failed + result2.skipped,
|
|
9618
|
+
healed: result2.healed,
|
|
9619
|
+
healedDetails: result2.healedDetails,
|
|
9616
9620
|
errors: replayErrors
|
|
9617
9621
|
});
|
|
9618
9622
|
} catch (e) {
|
|
@@ -9645,6 +9649,8 @@ function createRPCHandler() {
|
|
|
9645
9649
|
duration: typeof input.duration === "number" ? input.duration : 0,
|
|
9646
9650
|
eventsPlayed,
|
|
9647
9651
|
totalEvents,
|
|
9652
|
+
healed: typeof input.healed === "number" ? input.healed : 0,
|
|
9653
|
+
healedDetails: Array.isArray(input.healedDetails) ? input.healedDetails : [],
|
|
9648
9654
|
errors
|
|
9649
9655
|
};
|
|
9650
9656
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -137,6 +137,12 @@ interface XBContextOptions {
|
|
|
137
137
|
ignoreHTTPSErrors?: boolean;
|
|
138
138
|
/** S194: stealth 伪装配置(UA-CH 档案等)——经 context 传至 page 的注入层 */
|
|
139
139
|
stealthConfig?: Partial<StealthConfig>;
|
|
140
|
+
/** sup-s9: HTTP Basic/Digest 凭证——Fetch.authRequired 自动 ProvideCredentials;
|
|
141
|
+
* 缺省 CancelAuth(快速失败,不弹认证框不挂起) */
|
|
142
|
+
httpCredentials?: {
|
|
143
|
+
username: string;
|
|
144
|
+
password: string;
|
|
145
|
+
};
|
|
140
146
|
}
|
|
141
147
|
interface XBContext {
|
|
142
148
|
newPage(): Promise<XBPage>;
|
|
@@ -270,6 +276,8 @@ interface XBPage {
|
|
|
270
276
|
width: number;
|
|
271
277
|
height: number;
|
|
272
278
|
}): Promise<void>;
|
|
279
|
+
/** env-E2: 缩放变异——deviceScaleFactor 切换(CSS 视口尺寸不变) */
|
|
280
|
+
setDeviceScaleFactor(dsf: number): Promise<void>;
|
|
273
281
|
addInitScript(script: string): Promise<void>;
|
|
274
282
|
/** 覆盖当前页会话的 User-Agent(Network.setUserAgentOverride,会话级持久) */
|
|
275
283
|
setUserAgent(userAgent: string): Promise<void>;
|
|
@@ -286,6 +294,10 @@ interface XBPage {
|
|
|
286
294
|
route(url: string | RegExp, handler: (route: XBRoute) => Promise<void> | void): Promise<void>;
|
|
287
295
|
unroute(url: string | RegExp, handler?: (route: XBRoute) => Promise<void> | void): Promise<void>;
|
|
288
296
|
setInputFiles(selector: string, files: XBFilePayload | XBFilePayload[]): Promise<void>;
|
|
297
|
+
/** sup-s4: Dropzone 拖拽上传模拟——DataTransfer+File 派发 dragenter/dragover/drop */
|
|
298
|
+
dropFiles(selector: string, payload: XBFilePayload): Promise<void>;
|
|
299
|
+
/** sup-s11: beforeunload 自动应答语义(accept=离开默认 / dismiss=留守) */
|
|
300
|
+
setBeforeUnloadBehavior(mode: 'accept' | 'dismiss'): void;
|
|
289
301
|
dragAndDrop(source: string, target: string): Promise<void>;
|
|
290
302
|
on(event: string, handler: Function): void;
|
|
291
303
|
off(event: string, handler: Function): void;
|
|
@@ -1853,7 +1865,7 @@ interface HoverContext {
|
|
|
1853
1865
|
}
|
|
1854
1866
|
interface UserAction {
|
|
1855
1867
|
id: number;
|
|
1856
|
-
type: 'click' | 'input' | 'change' | 'keydown' | 'submit' | 'scroll' | 'navigation' | 'goto' | 'cdp-fill' | 'cdp-click' | 'cdp-eval' | 'filechooser' | 'dblclick' | 'contextmenu' | 'hover' | 'drag' | 'resize' | 'clipboard' | 'touch' | 'focus' | 'visibility' | 'popup_appear' | 'discovered_filters';
|
|
1868
|
+
type: 'click' | 'input' | 'change' | 'keydown' | 'submit' | 'scroll' | 'navigation' | 'goto' | 'cdp-fill' | 'cdp-click' | 'cdp-eval' | 'filechooser' | 'dblclick' | 'contextmenu' | 'hover' | 'drag' | 'resize' | 'clipboard' | 'touch' | 'focus' | 'visibility' | 'drop' | 'popup_appear' | 'discovered_filters';
|
|
1857
1869
|
timestamp: number;
|
|
1858
1870
|
url: string;
|
|
1859
1871
|
pageTitle: string;
|
|
@@ -1877,6 +1889,24 @@ interface UserAction {
|
|
|
1877
1889
|
placeholder?: string;
|
|
1878
1890
|
ariaLabel?: string;
|
|
1879
1891
|
href?: string;
|
|
1892
|
+
/** 结构地址(r6):祖先 form 在同级 form 中的序 + 元素在 form 内同 tag
|
|
1893
|
+
* 兄弟中的序(仅 form 直接子元素捕获)。布局位移后坐标失效时仍可定位。 */
|
|
1894
|
+
ordinal?: {
|
|
1895
|
+
formNth: number;
|
|
1896
|
+
tagNth: number;
|
|
1897
|
+
};
|
|
1898
|
+
/** 关联 label 的文本(r16):for= 关联或祖先 label 包裹。行重排/虚拟
|
|
1899
|
+
* 列表重建后结构序失效时的内容锚。 */
|
|
1900
|
+
labelText?: string;
|
|
1901
|
+
/** 元素尺寸(r25):录制时 rounded rect。同指纹诱饵消歧的评分信号
|
|
1902
|
+
* (仅加分不否决——响应式布局合法改变尺寸)。 */
|
|
1903
|
+
size?: {
|
|
1904
|
+
w: number;
|
|
1905
|
+
h: number;
|
|
1906
|
+
};
|
|
1907
|
+
/** 所在行文本(r27):closest('tr,li') 的 textContent 前 40 字符。
|
|
1908
|
+
* 表格/列表行重排后结构序失效时的内容锚(label 锚的行推广)。 */
|
|
1909
|
+
rowText?: string;
|
|
1880
1910
|
};
|
|
1881
1911
|
value?: string;
|
|
1882
1912
|
key?: string;
|
|
@@ -2277,6 +2307,12 @@ interface PlaybackResult {
|
|
|
2277
2307
|
event?: RecordedEvent;
|
|
2278
2308
|
error: string;
|
|
2279
2309
|
}>;
|
|
2310
|
+
/** r13: 自愈步数与明细(SessionReplayer 路径填充) */
|
|
2311
|
+
healed?: number;
|
|
2312
|
+
healedDetails?: Array<{
|
|
2313
|
+
index: number;
|
|
2314
|
+
strategy: string;
|
|
2315
|
+
}>;
|
|
2280
2316
|
}
|
|
2281
2317
|
/**
|
|
2282
2318
|
* Engine for playing back a recorded browser session.
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import {
|
|
2
|
+
extractAndSave,
|
|
3
|
+
extractRecording,
|
|
4
|
+
printExtractSummary
|
|
5
|
+
} from "./chunk-X46HDAOT.js";
|
|
1
6
|
import {
|
|
2
7
|
filterRecording,
|
|
3
8
|
parseExcludeTypes
|
|
4
9
|
} from "./chunk-ANVL2ID2.js";
|
|
10
|
+
import {
|
|
11
|
+
SessionRecorder
|
|
12
|
+
} from "./chunk-IR6C24P7.js";
|
|
5
13
|
import {
|
|
6
14
|
closeAllSessions,
|
|
7
15
|
closeEphemeralContext,
|
|
@@ -18,7 +26,7 @@ import {
|
|
|
18
26
|
resolveLaunchOpts,
|
|
19
27
|
saveSessionDiskMeta,
|
|
20
28
|
setActivePage
|
|
21
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-2Q3GQRUP.js";
|
|
22
30
|
import {
|
|
23
31
|
detectAntiBot,
|
|
24
32
|
formatDetectionMessage
|
|
@@ -77,17 +85,13 @@ import {
|
|
|
77
85
|
generateJSScript,
|
|
78
86
|
generatePythonScript
|
|
79
87
|
} from "./chunk-ETCO4SNK.js";
|
|
80
|
-
import
|
|
81
|
-
extractAndSave,
|
|
82
|
-
extractRecording,
|
|
83
|
-
printExtractSummary
|
|
84
|
-
} from "./chunk-X46HDAOT.js";
|
|
88
|
+
import "./chunk-7OP2ISEY.js";
|
|
85
89
|
import {
|
|
86
90
|
rand,
|
|
87
91
|
sleep,
|
|
88
92
|
wheelDelta
|
|
89
|
-
} from "./chunk-
|
|
90
|
-
import "./chunk-
|
|
93
|
+
} from "./chunk-GYB5BOSP.js";
|
|
94
|
+
import "./chunk-MYH6FIBZ.js";
|
|
91
95
|
import {
|
|
92
96
|
errMsg
|
|
93
97
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -107,9 +111,6 @@ import {
|
|
|
107
111
|
networkAnomalyRule,
|
|
108
112
|
pageLifecycleRule
|
|
109
113
|
} from "./chunk-75DNUI6M.js";
|
|
110
|
-
import {
|
|
111
|
-
SessionRecorder
|
|
112
|
-
} from "./chunk-NODRQGOK.js";
|
|
113
114
|
import {
|
|
114
115
|
addKnownIssue,
|
|
115
116
|
getKnowledgePath,
|
|
@@ -8599,7 +8600,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
8599
8600
|
}
|
|
8600
8601
|
let targetPageOverride = null;
|
|
8601
8602
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
8602
|
-
const { findTargetPage } = await import("./browser-
|
|
8603
|
+
const { findTargetPage } = await import("./browser-Q67BJTI2.js");
|
|
8603
8604
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
8604
8605
|
if (!targetPageOverride) {
|
|
8605
8606
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -12681,6 +12682,16 @@ async function handleReplay(args, options, mode) {
|
|
|
12681
12682
|
}
|
|
12682
12683
|
return;
|
|
12683
12684
|
}
|
|
12685
|
+
if (result.ok && mode !== "json" && mode !== "yaml") {
|
|
12686
|
+
const healed = typeof result.healed === "number" ? result.healed : 0;
|
|
12687
|
+
if (healed > 0) {
|
|
12688
|
+
console.log(`
|
|
12689
|
+
Self-healed ${healed} action(s):`);
|
|
12690
|
+
for (const d of result.healedDetails ?? []) {
|
|
12691
|
+
console.log(` - step ${d.index + 1}: ${d.strategy}`);
|
|
12692
|
+
}
|
|
12693
|
+
}
|
|
12694
|
+
}
|
|
12684
12695
|
outputResult(result, mode);
|
|
12685
12696
|
}
|
|
12686
12697
|
async function handleConvert(args, _mode) {
|
|
@@ -12782,7 +12793,7 @@ async function handleFilter(args, _mode, options) {
|
|
|
12782
12793
|
}
|
|
12783
12794
|
}
|
|
12784
12795
|
async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
12785
|
-
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-
|
|
12796
|
+
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-563ISSJK.js");
|
|
12786
12797
|
const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
|
|
12787
12798
|
const { mkdirSync: mkdirSync11, writeFileSync: writeFileSync13 } = await import("fs");
|
|
12788
12799
|
const { join: join16 } = await import("path");
|
|
@@ -14822,7 +14833,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
14822
14833
|
const targetPage = pages[cmdTabIndex];
|
|
14823
14834
|
await targetPage.bringToFront().catch(() => {
|
|
14824
14835
|
});
|
|
14825
|
-
const { setActivePage: setActivePage2 } = await import("./browser-
|
|
14836
|
+
const { setActivePage: setActivePage2 } = await import("./browser-Q67BJTI2.js");
|
|
14826
14837
|
setActivePage2(session, targetPage);
|
|
14827
14838
|
}
|
|
14828
14839
|
}
|
|
@@ -17995,7 +18006,7 @@ var DataCollector = class {
|
|
|
17995
18006
|
return results;
|
|
17996
18007
|
}
|
|
17997
18008
|
async createBrowserContext() {
|
|
17998
|
-
const { launch } = await import("./cdp-driver-
|
|
18009
|
+
const { launch } = await import("./cdp-driver-WWO2UZDR.js");
|
|
17999
18010
|
const { browser } = await launch({
|
|
18000
18011
|
headless: true,
|
|
18001
18012
|
args: ["--no-sandbox", "--disable-setuid-sandbox"]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import "./chunk-KFQGP6VL.js";
|
|
2
|
+
|
|
3
|
+
// src/utils/keep-awake.ts
|
|
4
|
+
import { spawn } from "child_process";
|
|
5
|
+
function startKeepAwake() {
|
|
6
|
+
if (process.platform !== "darwin") return { dispose: () => {
|
|
7
|
+
} };
|
|
8
|
+
try {
|
|
9
|
+
const child = spawn("caffeinate", ["-i", "-w", String(process.pid)], {
|
|
10
|
+
stdio: "ignore",
|
|
11
|
+
detached: false
|
|
12
|
+
});
|
|
13
|
+
return {
|
|
14
|
+
pid: child.pid,
|
|
15
|
+
dispose: () => {
|
|
16
|
+
try {
|
|
17
|
+
child.kill("SIGTERM");
|
|
18
|
+
} catch {
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
} catch {
|
|
23
|
+
return { dispose: () => {
|
|
24
|
+
} };
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
startKeepAwake
|
|
29
|
+
};
|