browser-pilot 0.0.13 → 0.0.14
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 +59 -3
- package/dist/actions.cjs +418 -14
- package/dist/actions.d.cts +13 -3
- package/dist/actions.d.ts +13 -3
- package/dist/actions.mjs +1 -1
- package/dist/browser-LZTEHUDI.mjs +9 -0
- package/dist/browser.cjs +600 -20
- package/dist/browser.d.cts +12 -3
- package/dist/browser.d.ts +12 -3
- package/dist/browser.mjs +3 -3
- package/dist/cdp.cjs +31 -2
- package/dist/cdp.d.cts +1 -1
- package/dist/cdp.d.ts +1 -1
- package/dist/cdp.mjs +3 -1
- package/dist/chunk-7NDR6V7S.mjs +7788 -0
- package/dist/{chunk-VDAMDOS6.mjs → chunk-IN5HPAPB.mjs} +147 -7
- package/dist/{chunk-HP6R3W32.mjs → chunk-KIFB526Y.mjs} +44 -2
- package/dist/chunk-LUGLEMVR.mjs +11 -0
- package/dist/chunk-SPSZZH22.mjs +308 -0
- package/dist/{chunk-A2ZRAEO3.mjs → chunk-XMJABKCF.mjs} +408 -14
- package/dist/cli.mjs +1063 -7746
- package/dist/client-3AFV2IAF.mjs +10 -0
- package/dist/{client-DRqxBdHv.d.ts → client-Ck2nQksT.d.cts} +8 -6
- package/dist/{client-DRqxBdHv.d.cts → client-Ck2nQksT.d.ts} +8 -6
- package/dist/index.cjs +600 -20
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.mjs +3 -3
- package/dist/transport-WHEBAZUP.mjs +83 -0
- package/dist/{types-CzgQjai9.d.ts → types-BSoh5v1Y.d.cts} +62 -2
- package/dist/{types-BXMGFtnB.d.cts → types-CjT0vClo.d.ts} +62 -2
- package/package.json +2 -2
package/dist/browser.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/browser/index.ts
|
|
@@ -29,6 +39,24 @@ __export(browser_exports, {
|
|
|
29
39
|
});
|
|
30
40
|
module.exports = __toCommonJS(browser_exports);
|
|
31
41
|
|
|
42
|
+
// src/utils/json.ts
|
|
43
|
+
function isRecord(value) {
|
|
44
|
+
return typeof value === "object" && value !== null;
|
|
45
|
+
}
|
|
46
|
+
function stringifyUnknown(value) {
|
|
47
|
+
if (typeof value === "string") return value;
|
|
48
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
49
|
+
return String(value);
|
|
50
|
+
}
|
|
51
|
+
if (value === null) return "null";
|
|
52
|
+
if (value === void 0) return "undefined";
|
|
53
|
+
try {
|
|
54
|
+
return JSON.stringify(value);
|
|
55
|
+
} catch {
|
|
56
|
+
return Object.prototype.toString.call(value);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
32
60
|
// src/cdp/protocol.ts
|
|
33
61
|
var CDPError = class extends Error {
|
|
34
62
|
code;
|
|
@@ -144,8 +172,12 @@ function getReadyStateString(state) {
|
|
|
144
172
|
|
|
145
173
|
// src/cdp/client.ts
|
|
146
174
|
async function createCDPClient(wsUrl, options = {}) {
|
|
147
|
-
const {
|
|
175
|
+
const { timeout = 3e4 } = options;
|
|
148
176
|
const transport = await createTransport(wsUrl, { timeout });
|
|
177
|
+
return buildCDPClient(transport, options);
|
|
178
|
+
}
|
|
179
|
+
function buildCDPClient(transport, options = {}) {
|
|
180
|
+
const { debug = false, timeout = 3e4 } = options;
|
|
149
181
|
let messageId = 0;
|
|
150
182
|
let currentSessionId;
|
|
151
183
|
let connected = true;
|
|
@@ -155,7 +187,19 @@ async function createCDPClient(wsUrl, options = {}) {
|
|
|
155
187
|
transport.onMessage((raw) => {
|
|
156
188
|
let msg;
|
|
157
189
|
try {
|
|
158
|
-
|
|
190
|
+
const parsed = JSON.parse(raw);
|
|
191
|
+
if (!isRecord(parsed)) {
|
|
192
|
+
if (debug) console.error("[CDP] Ignoring non-object message:", raw);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if ("id" in parsed && typeof parsed["id"] === "number") {
|
|
196
|
+
msg = parsed;
|
|
197
|
+
} else if ("method" in parsed && typeof parsed["method"] === "string") {
|
|
198
|
+
msg = parsed;
|
|
199
|
+
} else {
|
|
200
|
+
if (debug) console.error("[CDP] Ignoring invalid message shape:", raw);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
159
203
|
} catch {
|
|
160
204
|
if (debug) console.error("[CDP] Failed to parse message:", raw);
|
|
161
205
|
return;
|
|
@@ -268,6 +312,9 @@ async function createCDPClient(wsUrl, options = {}) {
|
|
|
268
312
|
onAny(handler) {
|
|
269
313
|
anyEventHandlers.add(handler);
|
|
270
314
|
},
|
|
315
|
+
offAny(handler) {
|
|
316
|
+
anyEventHandlers.delete(handler);
|
|
317
|
+
},
|
|
271
318
|
async close() {
|
|
272
319
|
connected = false;
|
|
273
320
|
await transport.close();
|
|
@@ -472,6 +519,230 @@ function createProvider(options) {
|
|
|
472
519
|
}
|
|
473
520
|
}
|
|
474
521
|
|
|
522
|
+
// src/actions/executor.ts
|
|
523
|
+
var fs = __toESM(require("fs"), 1);
|
|
524
|
+
var import_node_path = require("path");
|
|
525
|
+
|
|
526
|
+
// src/recording/redaction.ts
|
|
527
|
+
var REDACTED_VALUE = "[REDACTED]";
|
|
528
|
+
var SENSITIVE_AUTOCOMPLETE_TOKENS = [
|
|
529
|
+
"current-password",
|
|
530
|
+
"new-password",
|
|
531
|
+
"one-time-code",
|
|
532
|
+
"cc-number",
|
|
533
|
+
"cc-csc",
|
|
534
|
+
"cc-exp",
|
|
535
|
+
"cc-exp-month",
|
|
536
|
+
"cc-exp-year"
|
|
537
|
+
];
|
|
538
|
+
function autocompleteTokens(autocomplete) {
|
|
539
|
+
if (!autocomplete) return [];
|
|
540
|
+
return autocomplete.toLowerCase().split(/\s+/).map((token) => token.trim()).filter(Boolean);
|
|
541
|
+
}
|
|
542
|
+
function isSensitiveFieldMetadata(metadata) {
|
|
543
|
+
if (!metadata) return false;
|
|
544
|
+
if (metadata.sensitiveValue) return true;
|
|
545
|
+
const inputType = metadata.inputType?.toLowerCase();
|
|
546
|
+
if (inputType === "password" || inputType === "hidden") {
|
|
547
|
+
return true;
|
|
548
|
+
}
|
|
549
|
+
const sensitiveAutocompleteTokens = new Set(SENSITIVE_AUTOCOMPLETE_TOKENS);
|
|
550
|
+
return autocompleteTokens(metadata.autocomplete).some(
|
|
551
|
+
(token) => sensitiveAutocompleteTokens.has(token)
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
function redactValueForRecording(value, metadata) {
|
|
555
|
+
if (value === void 0) return void 0;
|
|
556
|
+
return isSensitiveFieldMetadata(metadata) ? REDACTED_VALUE : value;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// src/browser/action-highlight.ts
|
|
560
|
+
var HIGHLIGHT_STYLES = {
|
|
561
|
+
click: { outline: "3px solid rgba(229,57,53,0.8)", badge: "#e53935", marker: "crosshair" },
|
|
562
|
+
fill: { outline: "3px solid rgba(33,150,243,0.8)", badge: "#2196f3" },
|
|
563
|
+
type: { outline: "3px solid rgba(33,150,243,0.6)", badge: "#2196f3" },
|
|
564
|
+
select: { outline: "3px solid rgba(156,39,176,0.8)", badge: "#9c27b0" },
|
|
565
|
+
hover: { outline: "2px dashed rgba(158,158,158,0.5)", badge: "#9e9e9e" },
|
|
566
|
+
scroll: { outline: "none", badge: "#607d8b", marker: "arrow" },
|
|
567
|
+
navigate: { outline: "none", badge: "#4caf50" },
|
|
568
|
+
submit: { outline: "3px solid rgba(255,152,0,0.8)", badge: "#ff9800" },
|
|
569
|
+
"assert-pass": { outline: "3px solid rgba(76,175,80,0.8)", badge: "#4caf50", marker: "check" },
|
|
570
|
+
"assert-fail": { outline: "3px solid rgba(244,67,54,0.8)", badge: "#f44336", marker: "cross" },
|
|
571
|
+
evaluate: { outline: "none", badge: "#ffc107" },
|
|
572
|
+
focus: { outline: "3px dotted rgba(33,150,243,0.6)", badge: "#2196f3" }
|
|
573
|
+
};
|
|
574
|
+
function buildHighlightScript(options) {
|
|
575
|
+
const style = HIGHLIGHT_STYLES[options.kind];
|
|
576
|
+
const label = options.label ? options.label.slice(0, 80) : void 0;
|
|
577
|
+
const escapedLabel = label ? label.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n") : "";
|
|
578
|
+
return `(function() {
|
|
579
|
+
// Remove any existing highlight
|
|
580
|
+
var existing = document.getElementById('__bp-action-highlight');
|
|
581
|
+
if (existing) existing.remove();
|
|
582
|
+
|
|
583
|
+
var container = document.createElement('div');
|
|
584
|
+
container.id = '__bp-action-highlight';
|
|
585
|
+
container.style.cssText = 'position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:99999;';
|
|
586
|
+
|
|
587
|
+
${options.bbox ? `
|
|
588
|
+
// Element outline
|
|
589
|
+
var outline = document.createElement('div');
|
|
590
|
+
outline.style.cssText = 'position:fixed;' +
|
|
591
|
+
'left:${options.bbox.x}px;top:${options.bbox.y}px;' +
|
|
592
|
+
'width:${options.bbox.width}px;height:${options.bbox.height}px;' +
|
|
593
|
+
'${style.outline !== "none" ? `outline:${style.outline};outline-offset:-1px;` : ""}' +
|
|
594
|
+
'pointer-events:none;box-sizing:border-box;';
|
|
595
|
+
container.appendChild(outline);
|
|
596
|
+
` : ""}
|
|
597
|
+
|
|
598
|
+
${options.point && style.marker === "crosshair" ? `
|
|
599
|
+
// Crosshair at click point
|
|
600
|
+
var hLine = document.createElement('div');
|
|
601
|
+
hLine.style.cssText = 'position:fixed;left:${options.point.x - 12}px;top:${options.point.y}px;' +
|
|
602
|
+
'width:24px;height:2px;background:${style.badge};pointer-events:none;';
|
|
603
|
+
var vLine = document.createElement('div');
|
|
604
|
+
vLine.style.cssText = 'position:fixed;left:${options.point.x}px;top:${options.point.y - 12}px;' +
|
|
605
|
+
'width:2px;height:24px;background:${style.badge};pointer-events:none;';
|
|
606
|
+
// Dot at center
|
|
607
|
+
var dot = document.createElement('div');
|
|
608
|
+
dot.style.cssText = 'position:fixed;left:${options.point.x - 4}px;top:${options.point.y - 4}px;' +
|
|
609
|
+
'width:8px;height:8px;border-radius:50%;background:${style.badge};pointer-events:none;';
|
|
610
|
+
container.appendChild(hLine);
|
|
611
|
+
container.appendChild(vLine);
|
|
612
|
+
container.appendChild(dot);
|
|
613
|
+
` : ""}
|
|
614
|
+
|
|
615
|
+
${label ? `
|
|
616
|
+
// Badge with label
|
|
617
|
+
var badge = document.createElement('div');
|
|
618
|
+
badge.style.cssText = 'position:fixed;' +
|
|
619
|
+
${options.bbox ? `'left:${options.bbox.x}px;top:${Math.max(0, options.bbox.y - 28)}px;'` : options.kind === "navigate" ? "'left:50%;top:8px;transform:translateX(-50%);'" : "'right:8px;top:8px;'"} +
|
|
620
|
+
'background:${style.badge};color:white;padding:4px 8px;' +
|
|
621
|
+
'font-family:monospace;font-size:12px;font-weight:bold;' +
|
|
622
|
+
'border-radius:3px;white-space:nowrap;max-width:400px;overflow:hidden;text-overflow:ellipsis;' +
|
|
623
|
+
'pointer-events:none;';
|
|
624
|
+
badge.textContent = '${escapedLabel}';
|
|
625
|
+
container.appendChild(badge);
|
|
626
|
+
` : ""}
|
|
627
|
+
|
|
628
|
+
${style.marker === "check" && options.bbox ? `
|
|
629
|
+
// Checkmark
|
|
630
|
+
var check = document.createElement('div');
|
|
631
|
+
check.style.cssText = 'position:fixed;left:${options.bbox.x + options.bbox.width / 2 - 10}px;' +
|
|
632
|
+
'top:${options.bbox.y + options.bbox.height / 2 - 10}px;' +
|
|
633
|
+
'width:20px;height:20px;font-size:18px;color:${style.badge};pointer-events:none;text-align:center;line-height:20px;';
|
|
634
|
+
check.textContent = '\\u2713';
|
|
635
|
+
container.appendChild(check);
|
|
636
|
+
` : ""}
|
|
637
|
+
|
|
638
|
+
${style.marker === "cross" && options.bbox ? `
|
|
639
|
+
// Cross mark
|
|
640
|
+
var cross = document.createElement('div');
|
|
641
|
+
cross.style.cssText = 'position:fixed;left:${options.bbox.x + options.bbox.width / 2 - 10}px;' +
|
|
642
|
+
'top:${options.bbox.y + options.bbox.height / 2 - 10}px;' +
|
|
643
|
+
'width:20px;height:20px;font-size:18px;color:${style.badge};pointer-events:none;text-align:center;line-height:20px;font-weight:bold;';
|
|
644
|
+
cross.textContent = '\\u2717';
|
|
645
|
+
container.appendChild(cross);
|
|
646
|
+
` : ""}
|
|
647
|
+
|
|
648
|
+
document.body.appendChild(container);
|
|
649
|
+
window.__bpRemoveActionHighlight = function() {
|
|
650
|
+
var el = document.getElementById('__bp-action-highlight');
|
|
651
|
+
if (el) el.remove();
|
|
652
|
+
delete window.__bpRemoveActionHighlight;
|
|
653
|
+
};
|
|
654
|
+
})();`;
|
|
655
|
+
}
|
|
656
|
+
async function injectActionHighlight(page, options) {
|
|
657
|
+
try {
|
|
658
|
+
await page.evaluate(buildHighlightScript(options));
|
|
659
|
+
} catch {
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
async function removeActionHighlight(page) {
|
|
663
|
+
try {
|
|
664
|
+
await page.evaluate(`(function() {
|
|
665
|
+
if (window.__bpRemoveActionHighlight) {
|
|
666
|
+
window.__bpRemoveActionHighlight();
|
|
667
|
+
}
|
|
668
|
+
})()`);
|
|
669
|
+
} catch {
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
function stepToHighlightKind(step) {
|
|
673
|
+
switch (step.action) {
|
|
674
|
+
case "click":
|
|
675
|
+
return "click";
|
|
676
|
+
case "fill":
|
|
677
|
+
return "fill";
|
|
678
|
+
case "type":
|
|
679
|
+
return "type";
|
|
680
|
+
case "select":
|
|
681
|
+
return "select";
|
|
682
|
+
case "hover":
|
|
683
|
+
return "hover";
|
|
684
|
+
case "scroll":
|
|
685
|
+
return "scroll";
|
|
686
|
+
case "goto":
|
|
687
|
+
return "navigate";
|
|
688
|
+
case "submit":
|
|
689
|
+
return "submit";
|
|
690
|
+
case "focus":
|
|
691
|
+
return "focus";
|
|
692
|
+
case "evaluate":
|
|
693
|
+
case "press":
|
|
694
|
+
case "shortcut":
|
|
695
|
+
return "evaluate";
|
|
696
|
+
case "assertVisible":
|
|
697
|
+
case "assertExists":
|
|
698
|
+
case "assertText":
|
|
699
|
+
case "assertUrl":
|
|
700
|
+
case "assertValue":
|
|
701
|
+
return step.success ? "assert-pass" : "assert-fail";
|
|
702
|
+
// Observation-only actions — no highlight
|
|
703
|
+
case "wait":
|
|
704
|
+
case "snapshot":
|
|
705
|
+
case "forms":
|
|
706
|
+
case "text":
|
|
707
|
+
case "screenshot":
|
|
708
|
+
case "newTab":
|
|
709
|
+
case "closeTab":
|
|
710
|
+
case "switchFrame":
|
|
711
|
+
case "switchToMain":
|
|
712
|
+
return null;
|
|
713
|
+
default:
|
|
714
|
+
return null;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
function getHighlightLabel(step, result, targetMetadata) {
|
|
718
|
+
switch (step.action) {
|
|
719
|
+
case "fill":
|
|
720
|
+
case "type":
|
|
721
|
+
return typeof step.value === "string" ? `"${redactValueForRecording(step.value, targetMetadata)}"` : void 0;
|
|
722
|
+
case "select":
|
|
723
|
+
return redactValueForRecording(
|
|
724
|
+
typeof step.value === "string" ? step.value : void 0,
|
|
725
|
+
targetMetadata
|
|
726
|
+
);
|
|
727
|
+
case "goto":
|
|
728
|
+
return step.url;
|
|
729
|
+
case "evaluate":
|
|
730
|
+
return "JS";
|
|
731
|
+
case "press":
|
|
732
|
+
return step.key;
|
|
733
|
+
case "shortcut":
|
|
734
|
+
return step.combo;
|
|
735
|
+
case "assertText":
|
|
736
|
+
case "assertUrl":
|
|
737
|
+
case "assertValue":
|
|
738
|
+
case "assertVisible":
|
|
739
|
+
case "assertExists":
|
|
740
|
+
return result.success ? "\u2713" : "\u2717";
|
|
741
|
+
default:
|
|
742
|
+
return void 0;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
475
746
|
// src/browser/actionability.ts
|
|
476
747
|
var ActionabilityError = class extends Error {
|
|
477
748
|
failureType;
|
|
@@ -1086,6 +1357,13 @@ var NavigationError = class extends Error {
|
|
|
1086
1357
|
|
|
1087
1358
|
// src/actions/executor.ts
|
|
1088
1359
|
var DEFAULT_TIMEOUT = 3e4;
|
|
1360
|
+
var DEFAULT_RECORDING_SKIP_ACTIONS = [
|
|
1361
|
+
"wait",
|
|
1362
|
+
"snapshot",
|
|
1363
|
+
"forms",
|
|
1364
|
+
"text",
|
|
1365
|
+
"screenshot"
|
|
1366
|
+
];
|
|
1089
1367
|
function classifyFailure(error) {
|
|
1090
1368
|
if (error instanceof ElementNotFoundError) {
|
|
1091
1369
|
return { reason: "missing" };
|
|
@@ -1165,6 +1443,9 @@ var BatchExecutor = class {
|
|
|
1165
1443
|
const { timeout = DEFAULT_TIMEOUT, onFail = "stop" } = options;
|
|
1166
1444
|
const results = [];
|
|
1167
1445
|
const startTime = Date.now();
|
|
1446
|
+
const recording = options.record ? this.createRecordingContext(options.record) : null;
|
|
1447
|
+
const startUrl = recording ? await this.getPageUrlSafe() : "";
|
|
1448
|
+
let stoppedAtIndex;
|
|
1168
1449
|
for (let i = 0; i < steps.length; i++) {
|
|
1169
1450
|
const step = steps[i];
|
|
1170
1451
|
const stepStart = Date.now();
|
|
@@ -1177,8 +1458,9 @@ var BatchExecutor = class {
|
|
|
1177
1458
|
await new Promise((resolve) => setTimeout(resolve, retryDelay));
|
|
1178
1459
|
}
|
|
1179
1460
|
try {
|
|
1461
|
+
this.page.resetLastActionPosition();
|
|
1180
1462
|
const result = await this.executeStep(step, timeout);
|
|
1181
|
-
|
|
1463
|
+
const stepResult = {
|
|
1182
1464
|
index: i,
|
|
1183
1465
|
action: step.action,
|
|
1184
1466
|
selector: step.selector,
|
|
@@ -1186,8 +1468,15 @@ var BatchExecutor = class {
|
|
|
1186
1468
|
success: true,
|
|
1187
1469
|
durationMs: Date.now() - stepStart,
|
|
1188
1470
|
result: result.value,
|
|
1189
|
-
text: result.text
|
|
1190
|
-
|
|
1471
|
+
text: result.text,
|
|
1472
|
+
timestamp: Date.now(),
|
|
1473
|
+
coordinates: this.page.getLastActionCoordinates() ?? void 0,
|
|
1474
|
+
boundingBox: this.page.getLastActionBoundingBox() ?? void 0
|
|
1475
|
+
};
|
|
1476
|
+
if (recording && !recording.skipActions.has(step.action)) {
|
|
1477
|
+
await this.captureRecordingFrame(step, stepResult, recording);
|
|
1478
|
+
}
|
|
1479
|
+
results.push(stepResult);
|
|
1191
1480
|
succeeded = true;
|
|
1192
1481
|
break;
|
|
1193
1482
|
} catch (error) {
|
|
@@ -1208,7 +1497,7 @@ var BatchExecutor = class {
|
|
|
1208
1497
|
} catch {
|
|
1209
1498
|
}
|
|
1210
1499
|
}
|
|
1211
|
-
|
|
1500
|
+
const failedResult = {
|
|
1212
1501
|
index: i,
|
|
1213
1502
|
action: step.action,
|
|
1214
1503
|
selector: step.selector,
|
|
@@ -1218,25 +1507,177 @@ var BatchExecutor = class {
|
|
|
1218
1507
|
hints,
|
|
1219
1508
|
failureReason: reason,
|
|
1220
1509
|
coveringElement,
|
|
1221
|
-
suggestion: getSuggestion(reason)
|
|
1222
|
-
|
|
1510
|
+
suggestion: getSuggestion(reason),
|
|
1511
|
+
timestamp: Date.now()
|
|
1512
|
+
};
|
|
1513
|
+
if (recording && !recording.skipActions.has(step.action)) {
|
|
1514
|
+
await this.captureRecordingFrame(step, failedResult, recording);
|
|
1515
|
+
}
|
|
1516
|
+
results.push(failedResult);
|
|
1223
1517
|
if (onFail === "stop" && !step.optional) {
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
stoppedAtIndex: i,
|
|
1227
|
-
steps: results,
|
|
1228
|
-
totalDurationMs: Date.now() - startTime
|
|
1229
|
-
};
|
|
1518
|
+
stoppedAtIndex = i;
|
|
1519
|
+
break;
|
|
1230
1520
|
}
|
|
1231
1521
|
}
|
|
1232
1522
|
}
|
|
1233
|
-
const
|
|
1523
|
+
const totalDurationMs = Date.now() - startTime;
|
|
1524
|
+
const allSuccess = stoppedAtIndex === void 0 && results.every((result) => result.success || steps[result.index]?.optional);
|
|
1525
|
+
let recordingManifest;
|
|
1526
|
+
if (recording) {
|
|
1527
|
+
recordingManifest = await this.writeRecordingManifest(
|
|
1528
|
+
recording,
|
|
1529
|
+
startTime,
|
|
1530
|
+
startUrl,
|
|
1531
|
+
allSuccess
|
|
1532
|
+
);
|
|
1533
|
+
}
|
|
1234
1534
|
return {
|
|
1235
1535
|
success: allSuccess,
|
|
1536
|
+
stoppedAtIndex,
|
|
1236
1537
|
steps: results,
|
|
1237
|
-
totalDurationMs
|
|
1538
|
+
totalDurationMs,
|
|
1539
|
+
recordingManifest
|
|
1238
1540
|
};
|
|
1239
1541
|
}
|
|
1542
|
+
createRecordingContext(record) {
|
|
1543
|
+
const baseDir = record.outputDir ?? (0, import_node_path.join)(process.cwd(), ".browser-pilot");
|
|
1544
|
+
const screenshotDir = (0, import_node_path.join)(baseDir, "screenshots");
|
|
1545
|
+
const manifestPath = (0, import_node_path.join)(baseDir, "recording.json");
|
|
1546
|
+
let existingFrames = [];
|
|
1547
|
+
try {
|
|
1548
|
+
const existing = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
1549
|
+
if (existing.frames && Array.isArray(existing.frames)) {
|
|
1550
|
+
existingFrames = existing.frames;
|
|
1551
|
+
}
|
|
1552
|
+
} catch {
|
|
1553
|
+
}
|
|
1554
|
+
fs.mkdirSync(screenshotDir, { recursive: true });
|
|
1555
|
+
return {
|
|
1556
|
+
baseDir,
|
|
1557
|
+
screenshotDir,
|
|
1558
|
+
sessionId: record.sessionId ?? this.page.targetId,
|
|
1559
|
+
frames: existingFrames,
|
|
1560
|
+
format: record.format ?? "webp",
|
|
1561
|
+
quality: Math.max(0, Math.min(100, record.quality ?? 40)),
|
|
1562
|
+
highlights: record.highlights !== false,
|
|
1563
|
+
skipActions: new Set(record.skipActions ?? DEFAULT_RECORDING_SKIP_ACTIONS)
|
|
1564
|
+
};
|
|
1565
|
+
}
|
|
1566
|
+
async getPageUrlSafe() {
|
|
1567
|
+
try {
|
|
1568
|
+
return await this.page.url();
|
|
1569
|
+
} catch {
|
|
1570
|
+
return "";
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Capture a recording screenshot frame with optional highlight overlay
|
|
1575
|
+
*/
|
|
1576
|
+
async captureRecordingFrame(step, stepResult, recording) {
|
|
1577
|
+
const targetMetadata = this.page.getLastActionTargetMetadata();
|
|
1578
|
+
let highlightInjected = false;
|
|
1579
|
+
try {
|
|
1580
|
+
const ts = Date.now();
|
|
1581
|
+
const seq = String(recording.frames.length + 1).padStart(4, "0");
|
|
1582
|
+
const filename = `${seq}-${ts}-${stepResult.action}.${recording.format}`;
|
|
1583
|
+
const filepath = (0, import_node_path.join)(recording.screenshotDir, filename);
|
|
1584
|
+
if (recording.highlights) {
|
|
1585
|
+
const kind = stepToHighlightKind(stepResult);
|
|
1586
|
+
if (kind) {
|
|
1587
|
+
await injectActionHighlight(this.page, {
|
|
1588
|
+
kind,
|
|
1589
|
+
bbox: stepResult.boundingBox,
|
|
1590
|
+
point: stepResult.coordinates,
|
|
1591
|
+
label: getHighlightLabel(step, stepResult, targetMetadata)
|
|
1592
|
+
});
|
|
1593
|
+
highlightInjected = true;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
const base64 = await this.page.screenshot({
|
|
1597
|
+
format: recording.format,
|
|
1598
|
+
quality: recording.quality
|
|
1599
|
+
});
|
|
1600
|
+
const buffer = Buffer.from(base64, "base64");
|
|
1601
|
+
fs.writeFileSync(filepath, buffer);
|
|
1602
|
+
stepResult.screenshotPath = filepath;
|
|
1603
|
+
let pageUrl;
|
|
1604
|
+
let pageTitle;
|
|
1605
|
+
try {
|
|
1606
|
+
pageUrl = await this.page.url();
|
|
1607
|
+
pageTitle = await this.page.title();
|
|
1608
|
+
} catch {
|
|
1609
|
+
}
|
|
1610
|
+
recording.frames.push({
|
|
1611
|
+
seq: recording.frames.length + 1,
|
|
1612
|
+
timestamp: ts,
|
|
1613
|
+
action: stepResult.action,
|
|
1614
|
+
selector: stepResult.selectorUsed ?? (Array.isArray(step.selector) ? step.selector[0] : step.selector),
|
|
1615
|
+
value: redactValueForRecording(
|
|
1616
|
+
typeof step.value === "string" ? step.value : void 0,
|
|
1617
|
+
targetMetadata
|
|
1618
|
+
),
|
|
1619
|
+
url: step.url,
|
|
1620
|
+
coordinates: stepResult.coordinates,
|
|
1621
|
+
boundingBox: stepResult.boundingBox,
|
|
1622
|
+
success: stepResult.success,
|
|
1623
|
+
durationMs: stepResult.durationMs,
|
|
1624
|
+
error: stepResult.error,
|
|
1625
|
+
screenshot: filename,
|
|
1626
|
+
pageUrl,
|
|
1627
|
+
pageTitle
|
|
1628
|
+
});
|
|
1629
|
+
} catch {
|
|
1630
|
+
} finally {
|
|
1631
|
+
if (recording.highlights || highlightInjected) {
|
|
1632
|
+
await removeActionHighlight(this.page);
|
|
1633
|
+
}
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
/**
|
|
1637
|
+
* Write recording manifest to disk
|
|
1638
|
+
*/
|
|
1639
|
+
async writeRecordingManifest(recording, startTime, startUrl, success) {
|
|
1640
|
+
let endUrl = startUrl;
|
|
1641
|
+
let viewport = { width: 1280, height: 720 };
|
|
1642
|
+
try {
|
|
1643
|
+
endUrl = await this.page.url();
|
|
1644
|
+
} catch {
|
|
1645
|
+
}
|
|
1646
|
+
try {
|
|
1647
|
+
const metrics = await this.page.cdpClient.send("Page.getLayoutMetrics");
|
|
1648
|
+
viewport = {
|
|
1649
|
+
width: metrics.cssVisualViewport.clientWidth,
|
|
1650
|
+
height: metrics.cssVisualViewport.clientHeight
|
|
1651
|
+
};
|
|
1652
|
+
} catch {
|
|
1653
|
+
}
|
|
1654
|
+
const manifestPath = (0, import_node_path.join)(recording.baseDir, "recording.json");
|
|
1655
|
+
let recordedAt = new Date(startTime).toISOString();
|
|
1656
|
+
let originalStartUrl = startUrl;
|
|
1657
|
+
try {
|
|
1658
|
+
const existing = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
1659
|
+
if (existing.recordedAt) recordedAt = existing.recordedAt;
|
|
1660
|
+
if (existing.startUrl) originalStartUrl = existing.startUrl;
|
|
1661
|
+
} catch {
|
|
1662
|
+
}
|
|
1663
|
+
const firstFrameTime = recording.frames[0]?.timestamp ?? startTime;
|
|
1664
|
+
const totalDurationMs = Date.now() - Math.min(firstFrameTime, startTime);
|
|
1665
|
+
const manifest = {
|
|
1666
|
+
version: 1,
|
|
1667
|
+
recordedAt,
|
|
1668
|
+
sessionId: recording.sessionId,
|
|
1669
|
+
startUrl: originalStartUrl,
|
|
1670
|
+
endUrl,
|
|
1671
|
+
viewport,
|
|
1672
|
+
format: recording.format,
|
|
1673
|
+
quality: recording.quality,
|
|
1674
|
+
totalDurationMs,
|
|
1675
|
+
success,
|
|
1676
|
+
frames: recording.frames
|
|
1677
|
+
};
|
|
1678
|
+
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
1679
|
+
return manifestPath;
|
|
1680
|
+
}
|
|
1240
1681
|
/**
|
|
1241
1682
|
* Execute a single step
|
|
1242
1683
|
*/
|
|
@@ -3766,6 +4207,9 @@ var Page = class {
|
|
|
3766
4207
|
brokenFrame = null;
|
|
3767
4208
|
/** Last matched selector from findElement (for selectorUsed tracking) */
|
|
3768
4209
|
_lastMatchedSelector;
|
|
4210
|
+
_lastActionCoordinates = null;
|
|
4211
|
+
_lastActionBoundingBox = null;
|
|
4212
|
+
_lastActionTargetMetadata = null;
|
|
3769
4213
|
/** Last snapshot for stale ref recovery */
|
|
3770
4214
|
lastSnapshot;
|
|
3771
4215
|
/** Audio input controller (lazy-initialized) */
|
|
@@ -3797,6 +4241,76 @@ var Page = class {
|
|
|
3797
4241
|
getLastMatchedSelector() {
|
|
3798
4242
|
return this._lastMatchedSelector;
|
|
3799
4243
|
}
|
|
4244
|
+
async getActionTargetMetadata(identifiers) {
|
|
4245
|
+
try {
|
|
4246
|
+
const objectId = identifiers.objectId ?? (identifiers.nodeId ? await this.resolveObjectId(identifiers.nodeId) : void 0);
|
|
4247
|
+
if (!objectId) return null;
|
|
4248
|
+
const response = await this.cdp.send("Runtime.callFunctionOn", {
|
|
4249
|
+
objectId,
|
|
4250
|
+
functionDeclaration: `function() {
|
|
4251
|
+
const tagName = this.tagName?.toLowerCase?.() || '';
|
|
4252
|
+
const inputType =
|
|
4253
|
+
tagName === 'input' && typeof this.type === 'string' ? this.type.toLowerCase() : '';
|
|
4254
|
+
const autocomplete =
|
|
4255
|
+
typeof this.autocomplete === 'string' ? this.autocomplete.toLowerCase() : '';
|
|
4256
|
+
return { tagName, inputType, autocomplete };
|
|
4257
|
+
}`,
|
|
4258
|
+
returnByValue: true
|
|
4259
|
+
});
|
|
4260
|
+
return response.result.value ?? null;
|
|
4261
|
+
} catch {
|
|
4262
|
+
return null;
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4265
|
+
async getElementPosition(identifiers) {
|
|
4266
|
+
try {
|
|
4267
|
+
const { quads } = await this.cdp.send(
|
|
4268
|
+
"DOM.getContentQuads",
|
|
4269
|
+
identifiers
|
|
4270
|
+
);
|
|
4271
|
+
if (quads?.length > 0) {
|
|
4272
|
+
const q = quads[0];
|
|
4273
|
+
const minX = Math.min(q[0], q[2], q[4], q[6]);
|
|
4274
|
+
const maxX = Math.max(q[0], q[2], q[4], q[6]);
|
|
4275
|
+
const minY = Math.min(q[1], q[3], q[5], q[7]);
|
|
4276
|
+
const maxY = Math.max(q[1], q[3], q[5], q[7]);
|
|
4277
|
+
return {
|
|
4278
|
+
center: { x: (minX + maxX) / 2, y: (minY + maxY) / 2 },
|
|
4279
|
+
bbox: { x: minX, y: minY, width: maxX - minX, height: maxY - minY }
|
|
4280
|
+
};
|
|
4281
|
+
}
|
|
4282
|
+
} catch {
|
|
4283
|
+
}
|
|
4284
|
+
if (identifiers.nodeId) {
|
|
4285
|
+
const box = await this.getBoxModel(identifiers.nodeId);
|
|
4286
|
+
if (box) {
|
|
4287
|
+
return {
|
|
4288
|
+
center: { x: box.content[0] + box.width / 2, y: box.content[1] + box.height / 2 },
|
|
4289
|
+
bbox: { x: box.content[0], y: box.content[1], width: box.width, height: box.height }
|
|
4290
|
+
};
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
return null;
|
|
4294
|
+
}
|
|
4295
|
+
setLastActionPosition(coords, bbox) {
|
|
4296
|
+
this._lastActionCoordinates = coords;
|
|
4297
|
+
this._lastActionBoundingBox = bbox;
|
|
4298
|
+
}
|
|
4299
|
+
getLastActionCoordinates() {
|
|
4300
|
+
return this._lastActionCoordinates;
|
|
4301
|
+
}
|
|
4302
|
+
getLastActionBoundingBox() {
|
|
4303
|
+
return this._lastActionBoundingBox;
|
|
4304
|
+
}
|
|
4305
|
+
getLastActionTargetMetadata() {
|
|
4306
|
+
return this._lastActionTargetMetadata;
|
|
4307
|
+
}
|
|
4308
|
+
/** Reset position tracking (call before each executor step) */
|
|
4309
|
+
resetLastActionPosition() {
|
|
4310
|
+
this._lastActionCoordinates = null;
|
|
4311
|
+
this._lastActionBoundingBox = null;
|
|
4312
|
+
this._lastActionTargetMetadata = null;
|
|
4313
|
+
}
|
|
3800
4314
|
/**
|
|
3801
4315
|
* Initialize the page (enable required CDP domains)
|
|
3802
4316
|
*/
|
|
@@ -3964,6 +4478,14 @@ var Page = class {
|
|
|
3964
4478
|
const quad = quads[0];
|
|
3965
4479
|
clickX = (quad[0] + quad[2] + quad[4] + quad[6]) / 4;
|
|
3966
4480
|
clickY = (quad[1] + quad[3] + quad[5] + quad[7]) / 4;
|
|
4481
|
+
const minX = Math.min(quad[0], quad[2], quad[4], quad[6]);
|
|
4482
|
+
const maxX = Math.max(quad[0], quad[2], quad[4], quad[6]);
|
|
4483
|
+
const minY = Math.min(quad[1], quad[3], quad[5], quad[7]);
|
|
4484
|
+
const maxY = Math.max(quad[1], quad[3], quad[5], quad[7]);
|
|
4485
|
+
this.setLastActionPosition(
|
|
4486
|
+
{ x: clickX, y: clickY },
|
|
4487
|
+
{ x: minX, y: minY, width: maxX - minX, height: maxY - minY }
|
|
4488
|
+
);
|
|
3967
4489
|
} else {
|
|
3968
4490
|
throw new Error("No quads");
|
|
3969
4491
|
}
|
|
@@ -3972,6 +4494,10 @@ var Page = class {
|
|
|
3972
4494
|
if (!box) throw new Error("Could not get element position");
|
|
3973
4495
|
clickX = box.content[0] + box.width / 2;
|
|
3974
4496
|
clickY = box.content[1] + box.height / 2;
|
|
4497
|
+
this.setLastActionPosition(
|
|
4498
|
+
{ x: clickX, y: clickY },
|
|
4499
|
+
{ x: box.content[0], y: box.content[1], width: box.width, height: box.height }
|
|
4500
|
+
);
|
|
3975
4501
|
}
|
|
3976
4502
|
const hitTargetCoordinates = this.currentFrame ? void 0 : { x: clickX, y: clickY };
|
|
3977
4503
|
const HIT_TARGET_RETRIES = 3;
|
|
@@ -4022,13 +4548,20 @@ var Page = class {
|
|
|
4022
4548
|
if (options.optional) return false;
|
|
4023
4549
|
throw e;
|
|
4024
4550
|
}
|
|
4551
|
+
const fillPos = await this.getElementPosition({ nodeId: element.nodeId });
|
|
4552
|
+
if (fillPos) this.setLastActionPosition(fillPos.center, fillPos.bbox);
|
|
4025
4553
|
const tagInfo = await this.cdp.send("Runtime.callFunctionOn", {
|
|
4026
4554
|
objectId,
|
|
4027
4555
|
functionDeclaration: `function() {
|
|
4028
|
-
return {
|
|
4556
|
+
return {
|
|
4557
|
+
tagName: this.tagName?.toLowerCase() || '',
|
|
4558
|
+
inputType: (this.type || '').toLowerCase(),
|
|
4559
|
+
autocomplete: typeof this.autocomplete === 'string' ? this.autocomplete.toLowerCase() : '',
|
|
4560
|
+
};
|
|
4029
4561
|
}`,
|
|
4030
4562
|
returnByValue: true
|
|
4031
4563
|
});
|
|
4564
|
+
this._lastActionTargetMetadata = tagInfo.result.value;
|
|
4032
4565
|
const { tagName, inputType } = tagInfo.result.value;
|
|
4033
4566
|
const specialInputTypes = /* @__PURE__ */ new Set([
|
|
4034
4567
|
"date",
|
|
@@ -4110,6 +4643,9 @@ var Page = class {
|
|
|
4110
4643
|
if (options.optional) return false;
|
|
4111
4644
|
throw e;
|
|
4112
4645
|
}
|
|
4646
|
+
const typePos = await this.getElementPosition({ nodeId: element.nodeId });
|
|
4647
|
+
if (typePos) this.setLastActionPosition(typePos.center, typePos.bbox);
|
|
4648
|
+
this._lastActionTargetMetadata = await this.getActionTargetMetadata({ objectId });
|
|
4113
4649
|
await this.cdp.send("DOM.focus", { nodeId: element.nodeId });
|
|
4114
4650
|
for (const char of text) {
|
|
4115
4651
|
const def = US_KEYBOARD[char];
|
|
@@ -4189,6 +4725,9 @@ var Page = class {
|
|
|
4189
4725
|
if (options.optional) return false;
|
|
4190
4726
|
throw e;
|
|
4191
4727
|
}
|
|
4728
|
+
const selectPos = await this.getElementPosition({ nodeId: element.nodeId });
|
|
4729
|
+
if (selectPos) this.setLastActionPosition(selectPos.center, selectPos.bbox);
|
|
4730
|
+
this._lastActionTargetMetadata = await this.getActionTargetMetadata({ objectId });
|
|
4192
4731
|
const metadata = await this.getNativeSelectMetadata(objectId, values);
|
|
4193
4732
|
if (!metadata.isSelect) {
|
|
4194
4733
|
throw new Error("select() target must be a native <select> element");
|
|
@@ -4325,6 +4864,8 @@ var Page = class {
|
|
|
4325
4864
|
if (options.optional) return false;
|
|
4326
4865
|
throw e;
|
|
4327
4866
|
}
|
|
4867
|
+
const checkPos = await this.getElementPosition({ nodeId: element.nodeId });
|
|
4868
|
+
if (checkPos) this.setLastActionPosition(checkPos.center, checkPos.bbox);
|
|
4328
4869
|
const before = await this.cdp.send("Runtime.callFunctionOn", {
|
|
4329
4870
|
objectId: object.objectId,
|
|
4330
4871
|
functionDeclaration: "function() { return !!this.checked; }",
|
|
@@ -4373,6 +4914,8 @@ var Page = class {
|
|
|
4373
4914
|
if (options.optional) return false;
|
|
4374
4915
|
throw e;
|
|
4375
4916
|
}
|
|
4917
|
+
const uncheckPos = await this.getElementPosition({ nodeId: element.nodeId });
|
|
4918
|
+
if (uncheckPos) this.setLastActionPosition(uncheckPos.center, uncheckPos.bbox);
|
|
4376
4919
|
const isRadio = await this.cdp.send(
|
|
4377
4920
|
"Runtime.callFunctionOn",
|
|
4378
4921
|
{
|
|
@@ -4428,6 +4971,8 @@ var Page = class {
|
|
|
4428
4971
|
throw new ElementNotFoundError(selector, hints);
|
|
4429
4972
|
}
|
|
4430
4973
|
const objectId = await this.resolveObjectId(element.nodeId);
|
|
4974
|
+
const submitPos = await this.getElementPosition({ nodeId: element.nodeId });
|
|
4975
|
+
if (submitPos) this.setLastActionPosition(submitPos.center, submitPos.bbox);
|
|
4431
4976
|
const isFormElement = await this.cdp.send(
|
|
4432
4977
|
"Runtime.callFunctionOn",
|
|
4433
4978
|
{
|
|
@@ -4524,6 +5069,8 @@ var Page = class {
|
|
|
4524
5069
|
const hints = await generateHints(this, selectorList, "focus");
|
|
4525
5070
|
throw new ElementNotFoundError(selector, hints);
|
|
4526
5071
|
}
|
|
5072
|
+
const focusPos = await this.getElementPosition({ nodeId: element.nodeId });
|
|
5073
|
+
if (focusPos) this.setLastActionPosition(focusPos.center, focusPos.bbox);
|
|
4527
5074
|
await this.cdp.send("DOM.focus", { nodeId: element.nodeId });
|
|
4528
5075
|
return true;
|
|
4529
5076
|
}
|
|
@@ -4559,6 +5106,14 @@ var Page = class {
|
|
|
4559
5106
|
const quad = quads[0];
|
|
4560
5107
|
x = (quad[0] + quad[2] + quad[4] + quad[6]) / 4;
|
|
4561
5108
|
y = (quad[1] + quad[3] + quad[5] + quad[7]) / 4;
|
|
5109
|
+
const minX = Math.min(quad[0], quad[2], quad[4], quad[6]);
|
|
5110
|
+
const maxX = Math.max(quad[0], quad[2], quad[4], quad[6]);
|
|
5111
|
+
const minY = Math.min(quad[1], quad[3], quad[5], quad[7]);
|
|
5112
|
+
const maxY = Math.max(quad[1], quad[3], quad[5], quad[7]);
|
|
5113
|
+
this.setLastActionPosition(
|
|
5114
|
+
{ x, y },
|
|
5115
|
+
{ x: minX, y: minY, width: maxX - minX, height: maxY - minY }
|
|
5116
|
+
);
|
|
4562
5117
|
} else {
|
|
4563
5118
|
throw new Error("No quads");
|
|
4564
5119
|
}
|
|
@@ -4570,6 +5125,10 @@ var Page = class {
|
|
|
4570
5125
|
}
|
|
4571
5126
|
x = box.content[0] + box.width / 2;
|
|
4572
5127
|
y = box.content[1] + box.height / 2;
|
|
5128
|
+
this.setLastActionPosition(
|
|
5129
|
+
{ x, y },
|
|
5130
|
+
{ x: box.content[0], y: box.content[1], width: box.width, height: box.height }
|
|
5131
|
+
);
|
|
4573
5132
|
}
|
|
4574
5133
|
await this.cdp.send("Input.dispatchMouseEvent", {
|
|
4575
5134
|
type: "mouseMoved",
|
|
@@ -4595,6 +5154,8 @@ var Page = class {
|
|
|
4595
5154
|
if (options.optional) return false;
|
|
4596
5155
|
throw new ElementNotFoundError(selector);
|
|
4597
5156
|
}
|
|
5157
|
+
const scrollPos = await this.getElementPosition({ nodeId: element.nodeId });
|
|
5158
|
+
if (scrollPos) this.setLastActionPosition(scrollPos.center, scrollPos.bbox);
|
|
4598
5159
|
await this.scrollIntoView(element.nodeId);
|
|
4599
5160
|
return true;
|
|
4600
5161
|
}
|
|
@@ -5356,7 +5917,7 @@ var Page = class {
|
|
|
5356
5917
|
return {
|
|
5357
5918
|
role,
|
|
5358
5919
|
name,
|
|
5359
|
-
value: value !== void 0 ?
|
|
5920
|
+
value: value !== void 0 ? stringifyUnknown(value) : void 0,
|
|
5360
5921
|
ref,
|
|
5361
5922
|
children: children.length > 0 ? children : void 0,
|
|
5362
5923
|
disabled,
|
|
@@ -5418,7 +5979,7 @@ var Page = class {
|
|
|
5418
5979
|
selector,
|
|
5419
5980
|
disabled,
|
|
5420
5981
|
checked,
|
|
5421
|
-
value: value !== void 0 ?
|
|
5982
|
+
value: value !== void 0 ? stringifyUnknown(value) : void 0
|
|
5422
5983
|
});
|
|
5423
5984
|
}
|
|
5424
5985
|
}
|
|
@@ -5888,7 +6449,7 @@ var Page = class {
|
|
|
5888
6449
|
*/
|
|
5889
6450
|
formatConsoleArgs(args) {
|
|
5890
6451
|
return args.map((arg) => {
|
|
5891
|
-
if (arg.value !== void 0) return
|
|
6452
|
+
if (arg.value !== void 0) return stringifyUnknown(arg.value);
|
|
5892
6453
|
if (arg.description) return arg.description;
|
|
5893
6454
|
return "[object]";
|
|
5894
6455
|
}).join(" ");
|
|
@@ -6677,6 +7238,25 @@ var Browser = class _Browser {
|
|
|
6677
7238
|
this.cdp = cdp;
|
|
6678
7239
|
this.providerSession = providerSession;
|
|
6679
7240
|
}
|
|
7241
|
+
/**
|
|
7242
|
+
* Create a Browser from an existing CDPClient (used by daemon fast-path).
|
|
7243
|
+
* The caller is responsible for the CDP connection lifecycle.
|
|
7244
|
+
*/
|
|
7245
|
+
static fromCDP(cdp, sessionInfo) {
|
|
7246
|
+
const providerSession = {
|
|
7247
|
+
wsUrl: sessionInfo.wsUrl,
|
|
7248
|
+
sessionId: sessionInfo.sessionId,
|
|
7249
|
+
async close() {
|
|
7250
|
+
}
|
|
7251
|
+
};
|
|
7252
|
+
const provider = {
|
|
7253
|
+
name: sessionInfo.provider ?? "daemon",
|
|
7254
|
+
async createSession() {
|
|
7255
|
+
return providerSession;
|
|
7256
|
+
}
|
|
7257
|
+
};
|
|
7258
|
+
return new _Browser(cdp, provider, providerSession, { provider: "generic" });
|
|
7259
|
+
}
|
|
6680
7260
|
/**
|
|
6681
7261
|
* Connect to a browser instance
|
|
6682
7262
|
*/
|