@opensteer/engine-playwright 0.7.0 → 0.8.1
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/index.cjs +482 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.js +482 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -831,6 +831,40 @@ interface ComputerUseBridge {
|
|
|
831
831
|
execute(input: ComputerUseBridgeInput): Promise<ComputerUseBridgeOutput>;
|
|
832
832
|
}
|
|
833
833
|
|
|
834
|
+
type MatchOperator = "exact" | "startsWith" | "contains";
|
|
835
|
+
interface AttributeMatchClause {
|
|
836
|
+
readonly kind: "attr";
|
|
837
|
+
readonly key: string;
|
|
838
|
+
readonly op?: MatchOperator;
|
|
839
|
+
readonly value?: string;
|
|
840
|
+
}
|
|
841
|
+
interface PositionMatchClause {
|
|
842
|
+
readonly kind: "position";
|
|
843
|
+
readonly axis: "nthOfType" | "nthChild";
|
|
844
|
+
}
|
|
845
|
+
type MatchClause = AttributeMatchClause | PositionMatchClause;
|
|
846
|
+
interface PathNodePosition {
|
|
847
|
+
readonly nthChild: number;
|
|
848
|
+
readonly nthOfType: number;
|
|
849
|
+
}
|
|
850
|
+
interface PathNode {
|
|
851
|
+
readonly tag: string;
|
|
852
|
+
readonly attrs: Readonly<Record<string, string>>;
|
|
853
|
+
readonly position: PathNodePosition;
|
|
854
|
+
readonly match: readonly MatchClause[];
|
|
855
|
+
}
|
|
856
|
+
interface ContextHop {
|
|
857
|
+
readonly kind: "iframe" | "shadow";
|
|
858
|
+
readonly host: readonly PathNode[];
|
|
859
|
+
}
|
|
860
|
+
interface ElementRouteBase {
|
|
861
|
+
readonly context: readonly ContextHop[];
|
|
862
|
+
readonly nodes: readonly PathNode[];
|
|
863
|
+
}
|
|
864
|
+
interface ReplayElementPath extends ElementRouteBase {
|
|
865
|
+
readonly resolution: "deterministic";
|
|
866
|
+
}
|
|
867
|
+
|
|
834
868
|
declare const OPENSTEER_DOM_ACTION_BRIDGE_SYMBOL: unique symbol;
|
|
835
869
|
type DomActionScrollAlignment = "start" | "center" | "end" | "nearest";
|
|
836
870
|
interface DomActionTargetInspection {
|
|
@@ -865,6 +899,7 @@ interface DomPointerHitAssessment {
|
|
|
865
899
|
readonly hitOwner?: NodeLocator;
|
|
866
900
|
}
|
|
867
901
|
interface DomActionBridge {
|
|
902
|
+
buildReplayPath(locator: NodeLocator): Promise<ReplayElementPath>;
|
|
868
903
|
inspectActionTarget(locator: NodeLocator): Promise<DomActionTargetInspection>;
|
|
869
904
|
canonicalizePointerTarget(locator: NodeLocator): Promise<NodeLocator>;
|
|
870
905
|
classifyPointerHit(input: {
|
|
@@ -1158,6 +1193,7 @@ declare class PlaywrightBrowserCoreEngine implements BrowserCoreEngine {
|
|
|
1158
1193
|
private requireSession;
|
|
1159
1194
|
private requirePage;
|
|
1160
1195
|
private requireFrame;
|
|
1196
|
+
private requireLiveFrame;
|
|
1161
1197
|
private requireDocument;
|
|
1162
1198
|
private cleanupPageController;
|
|
1163
1199
|
private isControllerAcceptingEvents;
|
|
@@ -1183,7 +1219,8 @@ declare function connectPlaywrightChromiumBrowser(input: {
|
|
|
1183
1219
|
readonly url: string;
|
|
1184
1220
|
readonly headers?: Readonly<Record<string, string>>;
|
|
1185
1221
|
}): Promise<Browser>;
|
|
1222
|
+
declare function disconnectPlaywrightChromiumBrowser(browser: Browser): Promise<void>;
|
|
1186
1223
|
|
|
1187
1224
|
declare function capturePlaywrightStorageOrigins(context: BrowserContext, origins: readonly string[]): Promise<StorageOriginSnapshot[]>;
|
|
1188
1225
|
|
|
1189
|
-
export { type AdoptedChromiumBrowser, type PlaywrightBrowserContextOptions, PlaywrightBrowserCoreEngine, type PlaywrightBrowserCoreEngineOptions, type PlaywrightChromiumLaunchOptions, capturePlaywrightStorageOrigins, connectPlaywrightChromiumBrowser, createPlaywrightBrowserCoreEngine };
|
|
1226
|
+
export { type AdoptedChromiumBrowser, type PlaywrightBrowserContextOptions, PlaywrightBrowserCoreEngine, type PlaywrightBrowserCoreEngineOptions, type PlaywrightChromiumLaunchOptions, capturePlaywrightStorageOrigins, connectPlaywrightChromiumBrowser, createPlaywrightBrowserCoreEngine, disconnectPlaywrightChromiumBrowser };
|
package/dist/index.d.ts
CHANGED
|
@@ -831,6 +831,40 @@ interface ComputerUseBridge {
|
|
|
831
831
|
execute(input: ComputerUseBridgeInput): Promise<ComputerUseBridgeOutput>;
|
|
832
832
|
}
|
|
833
833
|
|
|
834
|
+
type MatchOperator = "exact" | "startsWith" | "contains";
|
|
835
|
+
interface AttributeMatchClause {
|
|
836
|
+
readonly kind: "attr";
|
|
837
|
+
readonly key: string;
|
|
838
|
+
readonly op?: MatchOperator;
|
|
839
|
+
readonly value?: string;
|
|
840
|
+
}
|
|
841
|
+
interface PositionMatchClause {
|
|
842
|
+
readonly kind: "position";
|
|
843
|
+
readonly axis: "nthOfType" | "nthChild";
|
|
844
|
+
}
|
|
845
|
+
type MatchClause = AttributeMatchClause | PositionMatchClause;
|
|
846
|
+
interface PathNodePosition {
|
|
847
|
+
readonly nthChild: number;
|
|
848
|
+
readonly nthOfType: number;
|
|
849
|
+
}
|
|
850
|
+
interface PathNode {
|
|
851
|
+
readonly tag: string;
|
|
852
|
+
readonly attrs: Readonly<Record<string, string>>;
|
|
853
|
+
readonly position: PathNodePosition;
|
|
854
|
+
readonly match: readonly MatchClause[];
|
|
855
|
+
}
|
|
856
|
+
interface ContextHop {
|
|
857
|
+
readonly kind: "iframe" | "shadow";
|
|
858
|
+
readonly host: readonly PathNode[];
|
|
859
|
+
}
|
|
860
|
+
interface ElementRouteBase {
|
|
861
|
+
readonly context: readonly ContextHop[];
|
|
862
|
+
readonly nodes: readonly PathNode[];
|
|
863
|
+
}
|
|
864
|
+
interface ReplayElementPath extends ElementRouteBase {
|
|
865
|
+
readonly resolution: "deterministic";
|
|
866
|
+
}
|
|
867
|
+
|
|
834
868
|
declare const OPENSTEER_DOM_ACTION_BRIDGE_SYMBOL: unique symbol;
|
|
835
869
|
type DomActionScrollAlignment = "start" | "center" | "end" | "nearest";
|
|
836
870
|
interface DomActionTargetInspection {
|
|
@@ -865,6 +899,7 @@ interface DomPointerHitAssessment {
|
|
|
865
899
|
readonly hitOwner?: NodeLocator;
|
|
866
900
|
}
|
|
867
901
|
interface DomActionBridge {
|
|
902
|
+
buildReplayPath(locator: NodeLocator): Promise<ReplayElementPath>;
|
|
868
903
|
inspectActionTarget(locator: NodeLocator): Promise<DomActionTargetInspection>;
|
|
869
904
|
canonicalizePointerTarget(locator: NodeLocator): Promise<NodeLocator>;
|
|
870
905
|
classifyPointerHit(input: {
|
|
@@ -1158,6 +1193,7 @@ declare class PlaywrightBrowserCoreEngine implements BrowserCoreEngine {
|
|
|
1158
1193
|
private requireSession;
|
|
1159
1194
|
private requirePage;
|
|
1160
1195
|
private requireFrame;
|
|
1196
|
+
private requireLiveFrame;
|
|
1161
1197
|
private requireDocument;
|
|
1162
1198
|
private cleanupPageController;
|
|
1163
1199
|
private isControllerAcceptingEvents;
|
|
@@ -1183,7 +1219,8 @@ declare function connectPlaywrightChromiumBrowser(input: {
|
|
|
1183
1219
|
readonly url: string;
|
|
1184
1220
|
readonly headers?: Readonly<Record<string, string>>;
|
|
1185
1221
|
}): Promise<Browser>;
|
|
1222
|
+
declare function disconnectPlaywrightChromiumBrowser(browser: Browser): Promise<void>;
|
|
1186
1223
|
|
|
1187
1224
|
declare function capturePlaywrightStorageOrigins(context: BrowserContext, origins: readonly string[]): Promise<StorageOriginSnapshot[]>;
|
|
1188
1225
|
|
|
1189
|
-
export { type AdoptedChromiumBrowser, type PlaywrightBrowserContextOptions, PlaywrightBrowserCoreEngine, type PlaywrightBrowserCoreEngineOptions, type PlaywrightChromiumLaunchOptions, capturePlaywrightStorageOrigins, connectPlaywrightChromiumBrowser, createPlaywrightBrowserCoreEngine };
|
|
1226
|
+
export { type AdoptedChromiumBrowser, type PlaywrightBrowserContextOptions, PlaywrightBrowserCoreEngine, type PlaywrightBrowserCoreEngineOptions, type PlaywrightChromiumLaunchOptions, capturePlaywrightStorageOrigins, connectPlaywrightChromiumBrowser, createPlaywrightBrowserCoreEngine, disconnectPlaywrightChromiumBrowser };
|
package/dist/index.js
CHANGED
|
@@ -2371,8 +2371,421 @@ var CLASSIFY_POINTER_HIT_DECLARATION = String.raw`function(hitNode, point) {
|
|
|
2371
2371
|
ambiguous,
|
|
2372
2372
|
};
|
|
2373
2373
|
}`;
|
|
2374
|
+
var LIVE_REPLAY_PATH_MATCH_ATTRIBUTE_PRIORITY = [
|
|
2375
|
+
"class",
|
|
2376
|
+
"data-testid",
|
|
2377
|
+
"data-test",
|
|
2378
|
+
"data-qa",
|
|
2379
|
+
"data-cy",
|
|
2380
|
+
"name",
|
|
2381
|
+
"role",
|
|
2382
|
+
"type",
|
|
2383
|
+
"aria-label",
|
|
2384
|
+
"title",
|
|
2385
|
+
"placeholder",
|
|
2386
|
+
"for",
|
|
2387
|
+
"aria-controls",
|
|
2388
|
+
"aria-labelledby",
|
|
2389
|
+
"aria-describedby",
|
|
2390
|
+
"id",
|
|
2391
|
+
"href",
|
|
2392
|
+
"value",
|
|
2393
|
+
"src",
|
|
2394
|
+
"srcset",
|
|
2395
|
+
"imagesrcset",
|
|
2396
|
+
"ping",
|
|
2397
|
+
"alt"
|
|
2398
|
+
];
|
|
2399
|
+
var LIVE_REPLAY_PATH_STABLE_PRIMARY_ATTR_KEYS = [
|
|
2400
|
+
"data-testid",
|
|
2401
|
+
"data-test",
|
|
2402
|
+
"data-qa",
|
|
2403
|
+
"data-cy",
|
|
2404
|
+
"name",
|
|
2405
|
+
"role",
|
|
2406
|
+
"type",
|
|
2407
|
+
"aria-label",
|
|
2408
|
+
"title",
|
|
2409
|
+
"placeholder"
|
|
2410
|
+
];
|
|
2411
|
+
var LIVE_REPLAY_PATH_DEFERRED_MATCH_ATTR_KEYS = [
|
|
2412
|
+
"href",
|
|
2413
|
+
"src",
|
|
2414
|
+
"srcset",
|
|
2415
|
+
"imagesrcset",
|
|
2416
|
+
"ping",
|
|
2417
|
+
"value",
|
|
2418
|
+
"for",
|
|
2419
|
+
"aria-controls",
|
|
2420
|
+
"aria-labelledby",
|
|
2421
|
+
"aria-describedby"
|
|
2422
|
+
];
|
|
2423
|
+
var LIVE_REPLAY_PATH_POLICY = {
|
|
2424
|
+
matchAttributePriority: LIVE_REPLAY_PATH_MATCH_ATTRIBUTE_PRIORITY,
|
|
2425
|
+
stablePrimaryAttrKeys: LIVE_REPLAY_PATH_STABLE_PRIMARY_ATTR_KEYS,
|
|
2426
|
+
deferredMatchAttrKeys: LIVE_REPLAY_PATH_DEFERRED_MATCH_ATTR_KEYS
|
|
2427
|
+
};
|
|
2428
|
+
var BUILD_LIVE_REPLAY_PATH_DECLARATION = String.raw`function(policy, source) {
|
|
2429
|
+
const buildReplayPath = (0, eval)(source);
|
|
2430
|
+
return buildReplayPath(this, policy);
|
|
2431
|
+
}`;
|
|
2432
|
+
var BUILD_LIVE_REPLAY_PATH_SOURCE = String.raw`(target, policy) => {
|
|
2433
|
+
const MAX_ATTRIBUTE_VALUE_LENGTH = 300;
|
|
2434
|
+
|
|
2435
|
+
function isValidAttrKey(key) {
|
|
2436
|
+
const trimmed = String(key || "").trim();
|
|
2437
|
+
if (!trimmed) return false;
|
|
2438
|
+
if (/[\s"'<>/]/.test(trimmed)) return false;
|
|
2439
|
+
return /^[A-Za-z_][A-Za-z0-9_:\-.]*$/.test(trimmed);
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2442
|
+
function isMediaTag(tag) {
|
|
2443
|
+
return new Set(["img", "video", "source", "iframe"]).has(String(tag || "").toLowerCase());
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
function shouldKeepAttr(tag, key, value) {
|
|
2447
|
+
const normalized = String(key || "").trim().toLowerCase();
|
|
2448
|
+
if (!normalized || !String(value || "").trim()) return false;
|
|
2449
|
+
if (!isValidAttrKey(key)) return false;
|
|
2450
|
+
if (normalized === "c") return false;
|
|
2451
|
+
if (/^on[a-z]/i.test(normalized)) return false;
|
|
2452
|
+
if (new Set(["style", "nonce", "integrity", "crossorigin", "referrerpolicy", "autocomplete"]).has(normalized)) {
|
|
2453
|
+
return false;
|
|
2454
|
+
}
|
|
2455
|
+
if (normalized.startsWith("data-os-") || normalized.startsWith("data-opensteer-")) {
|
|
2456
|
+
return false;
|
|
2457
|
+
}
|
|
2458
|
+
if (
|
|
2459
|
+
isMediaTag(tag) &&
|
|
2460
|
+
new Set([
|
|
2461
|
+
"data-src",
|
|
2462
|
+
"data-lazy-src",
|
|
2463
|
+
"data-original",
|
|
2464
|
+
"data-lazy",
|
|
2465
|
+
"data-image",
|
|
2466
|
+
"data-url",
|
|
2467
|
+
"data-srcset",
|
|
2468
|
+
"data-lazy-srcset",
|
|
2469
|
+
"data-was-processed",
|
|
2470
|
+
]).has(normalized)
|
|
2471
|
+
) {
|
|
2472
|
+
return false;
|
|
2473
|
+
}
|
|
2474
|
+
return true;
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2477
|
+
function collectAttrs(node) {
|
|
2478
|
+
const tag = node.tagName.toLowerCase();
|
|
2479
|
+
const attrs = {};
|
|
2480
|
+
for (const attr of Array.from(node.attributes)) {
|
|
2481
|
+
if (!shouldKeepAttr(tag, attr.name, attr.value)) {
|
|
2482
|
+
continue;
|
|
2483
|
+
}
|
|
2484
|
+
const value = String(attr.value || "");
|
|
2485
|
+
if (!value.trim()) continue;
|
|
2486
|
+
if (value.length > MAX_ATTRIBUTE_VALUE_LENGTH) continue;
|
|
2487
|
+
attrs[attr.name] = value;
|
|
2488
|
+
}
|
|
2489
|
+
return attrs;
|
|
2490
|
+
}
|
|
2491
|
+
|
|
2492
|
+
function getSiblings(node, root) {
|
|
2493
|
+
if (node.parentElement) return Array.from(node.parentElement.children);
|
|
2494
|
+
return Array.from(root.children || []);
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2497
|
+
function toPosition(node, root) {
|
|
2498
|
+
const siblings = getSiblings(node, root);
|
|
2499
|
+
const tag = node.tagName.toLowerCase();
|
|
2500
|
+
const sameTag = siblings.filter((candidate) => candidate.tagName.toLowerCase() === tag);
|
|
2501
|
+
return {
|
|
2502
|
+
nthChild: siblings.indexOf(node) + 1,
|
|
2503
|
+
nthOfType: sameTag.indexOf(node) + 1,
|
|
2504
|
+
};
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
function buildChain(node) {
|
|
2508
|
+
const chain = [];
|
|
2509
|
+
let current = node;
|
|
2510
|
+
while (current) {
|
|
2511
|
+
chain.push(current);
|
|
2512
|
+
if (current.parentElement) {
|
|
2513
|
+
current = current.parentElement;
|
|
2514
|
+
continue;
|
|
2515
|
+
}
|
|
2516
|
+
break;
|
|
2517
|
+
}
|
|
2518
|
+
chain.reverse();
|
|
2519
|
+
return chain;
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
function sortAttributeKeys(keys) {
|
|
2523
|
+
const priority = Array.isArray(policy?.matchAttributePriority)
|
|
2524
|
+
? policy.matchAttributePriority.map((value) => String(value))
|
|
2525
|
+
: [];
|
|
2526
|
+
return [...keys].sort((left, right) => {
|
|
2527
|
+
const leftIndex = priority.indexOf(left);
|
|
2528
|
+
const rightIndex = priority.indexOf(right);
|
|
2529
|
+
const leftRank = leftIndex === -1 ? Number.MAX_SAFE_INTEGER : leftIndex;
|
|
2530
|
+
const rightRank = rightIndex === -1 ? Number.MAX_SAFE_INTEGER : rightIndex;
|
|
2531
|
+
if (leftRank !== rightRank) {
|
|
2532
|
+
return leftRank - rightRank;
|
|
2533
|
+
}
|
|
2534
|
+
return left.localeCompare(right);
|
|
2535
|
+
});
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
function tokenizeClassValue(value) {
|
|
2539
|
+
const seen = new Set();
|
|
2540
|
+
const out = [];
|
|
2541
|
+
for (const token of String(value || "").split(/\s+/)) {
|
|
2542
|
+
const normalized = token.trim();
|
|
2543
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
2544
|
+
seen.add(normalized);
|
|
2545
|
+
out.push(normalized);
|
|
2546
|
+
}
|
|
2547
|
+
return out;
|
|
2548
|
+
}
|
|
2549
|
+
|
|
2550
|
+
function clauseKey(clause) {
|
|
2551
|
+
return JSON.stringify(clause);
|
|
2552
|
+
}
|
|
2553
|
+
|
|
2554
|
+
function shouldDeferMatchAttribute(rawKey) {
|
|
2555
|
+
const key = String(rawKey || "").trim().toLowerCase();
|
|
2556
|
+
if (!key || key === "class") return false;
|
|
2557
|
+
if (key === "id" || /(?:^|[-_:])id$/.test(key)) return true;
|
|
2558
|
+
const deferred = new Set(
|
|
2559
|
+
Array.isArray(policy?.deferredMatchAttrKeys)
|
|
2560
|
+
? policy.deferredMatchAttrKeys.map((value) => String(value))
|
|
2561
|
+
: [],
|
|
2562
|
+
);
|
|
2563
|
+
if (deferred.has(key)) return true;
|
|
2564
|
+
const stablePrimary = new Set(
|
|
2565
|
+
Array.isArray(policy?.stablePrimaryAttrKeys)
|
|
2566
|
+
? policy.stablePrimaryAttrKeys.map((value) => String(value))
|
|
2567
|
+
: [],
|
|
2568
|
+
);
|
|
2569
|
+
if (key.startsWith("data-") && !stablePrimary.has(key)) return true;
|
|
2570
|
+
return !stablePrimary.has(key);
|
|
2571
|
+
}
|
|
2572
|
+
|
|
2573
|
+
function buildSegmentSelector(data) {
|
|
2574
|
+
let selector = String(data.tag || "*").toLowerCase();
|
|
2575
|
+
for (const clause of data.match || []) {
|
|
2576
|
+
if (clause.kind === "position") {
|
|
2577
|
+
if (clause.axis === "nthOfType") {
|
|
2578
|
+
selector += ":nth-of-type(" + Math.max(1, Number(data.position?.nthOfType || 1)) + ")";
|
|
2579
|
+
} else {
|
|
2580
|
+
selector += ":nth-child(" + Math.max(1, Number(data.position?.nthChild || 1)) + ")";
|
|
2581
|
+
}
|
|
2582
|
+
continue;
|
|
2583
|
+
}
|
|
2584
|
+
|
|
2585
|
+
const key = String(clause.key || "");
|
|
2586
|
+
const value = typeof clause.value === "string" ? clause.value : data.attrs?.[key];
|
|
2587
|
+
if (!key || !value) continue;
|
|
2588
|
+
if (key === "class" && (clause.op || "exact") === "exact") {
|
|
2589
|
+
for (const token of tokenizeClassValue(value)) {
|
|
2590
|
+
const escapedToken = String(token).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
2591
|
+
selector += '[class~="' + escapedToken + '"]';
|
|
2592
|
+
}
|
|
2593
|
+
continue;
|
|
2594
|
+
}
|
|
2595
|
+
const escaped = String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
2596
|
+
const op = clause.op || "exact";
|
|
2597
|
+
if (op === "startsWith") selector += "[" + key + '^="' + escaped + '"]';
|
|
2598
|
+
else if (op === "contains") selector += "[" + key + '*="' + escaped + '"]';
|
|
2599
|
+
else selector += "[" + key + '="' + escaped + '"]';
|
|
2600
|
+
}
|
|
2601
|
+
return selector;
|
|
2602
|
+
}
|
|
2603
|
+
|
|
2604
|
+
function buildCandidates(nodes) {
|
|
2605
|
+
const parts = nodes.map((node) => buildSegmentSelector(node));
|
|
2606
|
+
const out = [];
|
|
2607
|
+
const seen = new Set();
|
|
2608
|
+
for (let start = 0; start < parts.length; start += 1) {
|
|
2609
|
+
const selector = parts.slice(start).join(" ");
|
|
2610
|
+
if (!selector || seen.has(selector)) continue;
|
|
2611
|
+
seen.add(selector);
|
|
2612
|
+
out.push(selector);
|
|
2613
|
+
}
|
|
2614
|
+
return out;
|
|
2615
|
+
}
|
|
2616
|
+
|
|
2617
|
+
function selectReplayCandidate(nodes, root) {
|
|
2618
|
+
const selectors = buildCandidates(nodes);
|
|
2619
|
+
let fallback = null;
|
|
2620
|
+
let fallbackSelector = null;
|
|
2621
|
+
let fallbackCount = 0;
|
|
2622
|
+
for (const selector of selectors) {
|
|
2623
|
+
let matches = [];
|
|
2624
|
+
try {
|
|
2625
|
+
matches = Array.from(root.querySelectorAll(selector));
|
|
2626
|
+
} catch {
|
|
2627
|
+
matches = [];
|
|
2628
|
+
}
|
|
2629
|
+
if (!matches.length) continue;
|
|
2630
|
+
if (matches.length === 1) {
|
|
2631
|
+
return {
|
|
2632
|
+
element: matches[0],
|
|
2633
|
+
selector,
|
|
2634
|
+
count: 1,
|
|
2635
|
+
mode: "unique",
|
|
2636
|
+
};
|
|
2637
|
+
}
|
|
2638
|
+
if (!fallback) {
|
|
2639
|
+
fallback = matches[0];
|
|
2640
|
+
fallbackSelector = selector;
|
|
2641
|
+
fallbackCount = matches.length;
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
if (fallback && fallbackSelector) {
|
|
2645
|
+
return {
|
|
2646
|
+
element: fallback,
|
|
2647
|
+
selector: fallbackSelector,
|
|
2648
|
+
count: fallbackCount,
|
|
2649
|
+
mode: "fallback",
|
|
2650
|
+
};
|
|
2651
|
+
}
|
|
2652
|
+
return null;
|
|
2653
|
+
}
|
|
2654
|
+
|
|
2655
|
+
function buildClausePool(data) {
|
|
2656
|
+
const attrs = data.attrs || {};
|
|
2657
|
+
const pool = [];
|
|
2658
|
+
const deferred = [];
|
|
2659
|
+
const used = new Set();
|
|
2660
|
+
|
|
2661
|
+
const classValue = String(attrs.class || "").trim();
|
|
2662
|
+
if (classValue) {
|
|
2663
|
+
const clause = { kind: "attr", key: "class", op: "exact", value: classValue };
|
|
2664
|
+
used.add(clauseKey(clause));
|
|
2665
|
+
pool.push(clause);
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
for (const key of sortAttributeKeys(Object.keys(attrs))) {
|
|
2669
|
+
if (key === "class") continue;
|
|
2670
|
+
const value = attrs[key];
|
|
2671
|
+
if (!value || !String(value).trim()) continue;
|
|
2672
|
+
const clause = { kind: "attr", key, op: "exact" };
|
|
2673
|
+
const keyId = clauseKey(clause);
|
|
2674
|
+
if (used.has(keyId)) continue;
|
|
2675
|
+
used.add(keyId);
|
|
2676
|
+
if (shouldDeferMatchAttribute(key)) deferred.push(clause);
|
|
2677
|
+
else pool.push(clause);
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
for (const clause of [
|
|
2681
|
+
{ kind: "position", axis: "nthOfType" },
|
|
2682
|
+
{ kind: "position", axis: "nthChild" },
|
|
2683
|
+
]) {
|
|
2684
|
+
const keyId = clauseKey(clause);
|
|
2685
|
+
if (used.has(keyId)) continue;
|
|
2686
|
+
used.add(keyId);
|
|
2687
|
+
pool.push(clause);
|
|
2688
|
+
}
|
|
2689
|
+
|
|
2690
|
+
if (!pool.some((clause) => clause.kind === "attr")) {
|
|
2691
|
+
pool.push(...deferred);
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
return pool;
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2697
|
+
function finalizePath(elements, root) {
|
|
2698
|
+
if (!elements.length) return null;
|
|
2699
|
+
const nodes = elements.map((element) => ({
|
|
2700
|
+
tag: element.tagName.toLowerCase(),
|
|
2701
|
+
attrs: collectAttrs(element),
|
|
2702
|
+
position: toPosition(element, root),
|
|
2703
|
+
match: [],
|
|
2704
|
+
}));
|
|
2705
|
+
|
|
2706
|
+
const pools = nodes.map((node) => {
|
|
2707
|
+
node.match = [];
|
|
2708
|
+
return [...buildClausePool(node)];
|
|
2709
|
+
});
|
|
2710
|
+
|
|
2711
|
+
for (let index = 0; index < pools.length; index += 1) {
|
|
2712
|
+
const classIndex = pools[index].findIndex(
|
|
2713
|
+
(clause) => clause.kind === "attr" && clause.key === "class",
|
|
2714
|
+
);
|
|
2715
|
+
if (classIndex < 0) continue;
|
|
2716
|
+
const classClause = pools[index][classIndex];
|
|
2717
|
+
if (!classClause) continue;
|
|
2718
|
+
nodes[index].match.push(classClause);
|
|
2719
|
+
pools[index].splice(classIndex, 1);
|
|
2720
|
+
}
|
|
2721
|
+
|
|
2722
|
+
const expected = elements[elements.length - 1];
|
|
2723
|
+
const totalRemaining = pools.reduce((count, pool) => count + pool.length, 0);
|
|
2724
|
+
for (let iteration = 0; iteration <= totalRemaining; iteration += 1) {
|
|
2725
|
+
const chosen = selectReplayCandidate(nodes, root);
|
|
2726
|
+
if (chosen && chosen.mode === "unique" && chosen.element === expected) {
|
|
2727
|
+
return {
|
|
2728
|
+
nodes,
|
|
2729
|
+
selector: chosen.selector,
|
|
2730
|
+
};
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
let added = false;
|
|
2734
|
+
for (let index = pools.length - 1; index >= 0; index -= 1) {
|
|
2735
|
+
const next = pools[index][0];
|
|
2736
|
+
if (!next) continue;
|
|
2737
|
+
nodes[index].match.push(next);
|
|
2738
|
+
pools[index].shift();
|
|
2739
|
+
added = true;
|
|
2740
|
+
break;
|
|
2741
|
+
}
|
|
2742
|
+
if (!added) break;
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
return null;
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
if (!(target instanceof Element)) return null;
|
|
2749
|
+
|
|
2750
|
+
const context = [];
|
|
2751
|
+
let currentRoot = target.getRootNode() instanceof ShadowRoot ? target.getRootNode() : document;
|
|
2752
|
+
const targetChain = buildChain(target);
|
|
2753
|
+
const finalizedTarget = finalizePath(targetChain, currentRoot);
|
|
2754
|
+
if (!finalizedTarget) return null;
|
|
2755
|
+
|
|
2756
|
+
while (currentRoot instanceof ShadowRoot) {
|
|
2757
|
+
const host = currentRoot.host;
|
|
2758
|
+
const hostRoot =
|
|
2759
|
+
host.getRootNode() instanceof ShadowRoot ? host.getRootNode() : document;
|
|
2760
|
+
const hostChain = buildChain(host);
|
|
2761
|
+
const finalizedHost = finalizePath(hostChain, hostRoot);
|
|
2762
|
+
if (!finalizedHost) return null;
|
|
2763
|
+
context.unshift({
|
|
2764
|
+
kind: "shadow",
|
|
2765
|
+
host: finalizedHost.nodes,
|
|
2766
|
+
});
|
|
2767
|
+
currentRoot = hostRoot;
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
return {
|
|
2771
|
+
resolution: "deterministic",
|
|
2772
|
+
context,
|
|
2773
|
+
nodes: finalizedTarget.nodes,
|
|
2774
|
+
};
|
|
2775
|
+
}`;
|
|
2374
2776
|
function createPlaywrightDomActionBridge(context) {
|
|
2375
2777
|
return {
|
|
2778
|
+
buildReplayPath(locator) {
|
|
2779
|
+
return withLiveNode(context, locator, async ({ controller, document, backendNodeId }) => {
|
|
2780
|
+
const localPath = await buildLiveReplayPathForLocator(
|
|
2781
|
+
controller,
|
|
2782
|
+
document,
|
|
2783
|
+
locator,
|
|
2784
|
+
backendNodeId
|
|
2785
|
+
);
|
|
2786
|
+
return prefixIframeReplayPath(context, document.frameRef, localPath);
|
|
2787
|
+
});
|
|
2788
|
+
},
|
|
2376
2789
|
inspectActionTarget(locator) {
|
|
2377
2790
|
return withLiveNode(context, locator, async ({ controller, document, backendNodeId }) => {
|
|
2378
2791
|
const nodeId = await resolveFrontendNodeId(controller, document, locator, backendNodeId);
|
|
@@ -2666,6 +3079,58 @@ function normalizePointerHitAssessment(value, canonicalTarget) {
|
|
|
2666
3079
|
canonicalTarget
|
|
2667
3080
|
};
|
|
2668
3081
|
}
|
|
3082
|
+
async function buildLiveReplayPathForLocator(controller, document, locator, backendNodeId) {
|
|
3083
|
+
const raw = await callNodeFunction(controller, document, locator, backendNodeId, {
|
|
3084
|
+
functionDeclaration: BUILD_LIVE_REPLAY_PATH_DECLARATION,
|
|
3085
|
+
arguments: [{ value: LIVE_REPLAY_PATH_POLICY }, { value: BUILD_LIVE_REPLAY_PATH_SOURCE }],
|
|
3086
|
+
returnByValue: true
|
|
3087
|
+
});
|
|
3088
|
+
return requireReplayPath(raw, locator);
|
|
3089
|
+
}
|
|
3090
|
+
async function prefixIframeReplayPath(context, frameRef, localPath) {
|
|
3091
|
+
let currentPath = localPath;
|
|
3092
|
+
let currentFrame = context.requireFrame(frameRef);
|
|
3093
|
+
while (currentFrame.parentFrame() !== null) {
|
|
3094
|
+
const frameElement = await currentFrame.frameElement();
|
|
3095
|
+
try {
|
|
3096
|
+
const hostPath = await buildLiveReplayPathForHandle(frameElement);
|
|
3097
|
+
currentPath = {
|
|
3098
|
+
resolution: "deterministic",
|
|
3099
|
+
context: [
|
|
3100
|
+
...hostPath.context,
|
|
3101
|
+
{ kind: "iframe", host: hostPath.nodes },
|
|
3102
|
+
...currentPath.context
|
|
3103
|
+
],
|
|
3104
|
+
nodes: currentPath.nodes
|
|
3105
|
+
};
|
|
3106
|
+
} finally {
|
|
3107
|
+
await frameElement.dispose().catch(() => void 0);
|
|
3108
|
+
}
|
|
3109
|
+
currentFrame = currentFrame.parentFrame();
|
|
3110
|
+
}
|
|
3111
|
+
return currentPath;
|
|
3112
|
+
}
|
|
3113
|
+
async function buildLiveReplayPathForHandle(handle) {
|
|
3114
|
+
const raw = await handle.evaluate(
|
|
3115
|
+
(element, input) => {
|
|
3116
|
+
const buildReplayPath = (0, eval)(input.source);
|
|
3117
|
+
return buildReplayPath(element, input.policy);
|
|
3118
|
+
},
|
|
3119
|
+
{
|
|
3120
|
+
policy: LIVE_REPLAY_PATH_POLICY,
|
|
3121
|
+
source: BUILD_LIVE_REPLAY_PATH_SOURCE
|
|
3122
|
+
}
|
|
3123
|
+
);
|
|
3124
|
+
return requireReplayPath(raw);
|
|
3125
|
+
}
|
|
3126
|
+
function requireReplayPath(value, locator) {
|
|
3127
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || value.resolution !== "deterministic") {
|
|
3128
|
+
throw new Error(
|
|
3129
|
+
locator === void 0 ? "live DOM replay path builder returned an invalid result" : `live DOM replay path builder returned an invalid result for ${locator.nodeRef}`
|
|
3130
|
+
);
|
|
3131
|
+
}
|
|
3132
|
+
return value;
|
|
3133
|
+
}
|
|
2669
3134
|
function unionQuadBounds(quads) {
|
|
2670
3135
|
const bounds = quads.map((quad) => quadBounds(quad));
|
|
2671
3136
|
const minX = Math.min(...bounds.map((rect) => rect.x));
|
|
@@ -2958,6 +3423,7 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
2958
3423
|
document.documentEpoch,
|
|
2959
3424
|
this.nodeRefForBackendNode(document, backendNodeId)
|
|
2960
3425
|
),
|
|
3426
|
+
requireFrame: (frameRef) => this.requireLiveFrame(frameRef),
|
|
2961
3427
|
requireLiveNode: (locator) => this.requireLiveNode(locator)
|
|
2962
3428
|
});
|
|
2963
3429
|
return this.domActionBridge;
|
|
@@ -5104,6 +5570,18 @@ var PlaywrightBrowserCoreEngine = class _PlaywrightBrowserCoreEngine {
|
|
|
5104
5570
|
}
|
|
5105
5571
|
return frame;
|
|
5106
5572
|
}
|
|
5573
|
+
requireLiveFrame(frameRef) {
|
|
5574
|
+
const state = this.requireFrame(frameRef);
|
|
5575
|
+
const controller = this.requirePage(state.pageRef);
|
|
5576
|
+
for (const frame of controller.page.frames()) {
|
|
5577
|
+
if (controller.frameBindings.get(frame) === frameRef) {
|
|
5578
|
+
return frame;
|
|
5579
|
+
}
|
|
5580
|
+
}
|
|
5581
|
+
throw createBrowserCoreError("not-found", `frame ${frameRef} is not attached to a live page`, {
|
|
5582
|
+
details: { frameRef }
|
|
5583
|
+
});
|
|
5584
|
+
}
|
|
5107
5585
|
requireDocument(documentRef) {
|
|
5108
5586
|
const document = this.documents.get(documentRef);
|
|
5109
5587
|
if (!document) {
|
|
@@ -5305,6 +5783,9 @@ async function connectPlaywrightChromiumBrowser(input) {
|
|
|
5305
5783
|
...input.headers === void 0 ? {} : { headers: input.headers }
|
|
5306
5784
|
});
|
|
5307
5785
|
}
|
|
5786
|
+
async function disconnectPlaywrightChromiumBrowser(browser) {
|
|
5787
|
+
void browser.close().catch(() => void 0);
|
|
5788
|
+
}
|
|
5308
5789
|
function objectHeadersToEntries(headers) {
|
|
5309
5790
|
if (!headers) {
|
|
5310
5791
|
return [];
|
|
@@ -5458,6 +5939,6 @@ function withTimeout(promise, timeoutMs) {
|
|
|
5458
5939
|
]);
|
|
5459
5940
|
}
|
|
5460
5941
|
|
|
5461
|
-
export { PlaywrightBrowserCoreEngine, capturePlaywrightStorageOrigins, connectPlaywrightChromiumBrowser, createPlaywrightBrowserCoreEngine };
|
|
5942
|
+
export { PlaywrightBrowserCoreEngine, capturePlaywrightStorageOrigins, connectPlaywrightChromiumBrowser, createPlaywrightBrowserCoreEngine, disconnectPlaywrightChromiumBrowser };
|
|
5462
5943
|
//# sourceMappingURL=index.js.map
|
|
5463
5944
|
//# sourceMappingURL=index.js.map
|