@opensteer/engine-abp 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/README.md +4 -0
- package/dist/index.cjs +287 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +64 -1
- package/dist/index.d.ts +64 -1
- package/dist/index.js +282 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,3 +8,7 @@ building directly against the engine package.
|
|
|
8
8
|
```bash
|
|
9
9
|
pnpm add @opensteer/engine-abp
|
|
10
10
|
```
|
|
11
|
+
|
|
12
|
+
`agent-browser-protocol` downloads its bundled ABP browser during install. In offline
|
|
13
|
+
or custom environments, point Opensteer at an existing binary with
|
|
14
|
+
`launch.browserExecutablePath` or `ABP_BROWSER_PATH`.
|
package/dist/index.cjs
CHANGED
|
@@ -1776,6 +1776,9 @@ function resolveDefaultAbpWrapperExecutablePath() {
|
|
|
1776
1776
|
}
|
|
1777
1777
|
return resolveExecutablePath([path.join(root, "dist", "bin", "abp.js")]);
|
|
1778
1778
|
}
|
|
1779
|
+
function resolveDefaultAbpExecutablePath() {
|
|
1780
|
+
return resolveDefaultAbpBrowserExecutablePath() ?? resolveDefaultAbpWrapperExecutablePath();
|
|
1781
|
+
}
|
|
1779
1782
|
function buildAbpLaunchCommand(options) {
|
|
1780
1783
|
if (options.abpExecutablePath !== void 0 && options.browserExecutablePath !== void 0) {
|
|
1781
1784
|
throw createBrowserCoreError(
|
|
@@ -3171,8 +3174,260 @@ var CLASSIFY_POINTER_HIT_DECLARATION = String.raw`function(hitNode, point) {
|
|
|
3171
3174
|
ambiguous,
|
|
3172
3175
|
};
|
|
3173
3176
|
}`;
|
|
3177
|
+
var LIVE_REPLAY_PATH_MATCH_ATTRIBUTE_PRIORITY = {
|
|
3178
|
+
stablePrimaryExact: 150,
|
|
3179
|
+
stablePrimaryPrefix: 130,
|
|
3180
|
+
attrExact: 100,
|
|
3181
|
+
attrPrefix: 80,
|
|
3182
|
+
tagOnly: 10
|
|
3183
|
+
};
|
|
3184
|
+
var LIVE_REPLAY_PATH_STABLE_PRIMARY_ATTR_KEYS = [
|
|
3185
|
+
"data-testid",
|
|
3186
|
+
"data-test",
|
|
3187
|
+
"data-qa",
|
|
3188
|
+
"data-cy",
|
|
3189
|
+
"name",
|
|
3190
|
+
"role",
|
|
3191
|
+
"type",
|
|
3192
|
+
"aria-label",
|
|
3193
|
+
"title",
|
|
3194
|
+
"placeholder"
|
|
3195
|
+
];
|
|
3196
|
+
var LIVE_REPLAY_PATH_DEFERRED_MATCH_ATTR_KEYS = [
|
|
3197
|
+
"href",
|
|
3198
|
+
"src",
|
|
3199
|
+
"srcset",
|
|
3200
|
+
"imagesrcset",
|
|
3201
|
+
"ping",
|
|
3202
|
+
"value",
|
|
3203
|
+
"for",
|
|
3204
|
+
"aria-controls",
|
|
3205
|
+
"aria-labelledby",
|
|
3206
|
+
"aria-describedby"
|
|
3207
|
+
];
|
|
3208
|
+
var LIVE_REPLAY_PATH_POLICY = {
|
|
3209
|
+
matchAttributePriority: LIVE_REPLAY_PATH_MATCH_ATTRIBUTE_PRIORITY,
|
|
3210
|
+
stablePrimaryAttrKeys: LIVE_REPLAY_PATH_STABLE_PRIMARY_ATTR_KEYS,
|
|
3211
|
+
deferredMatchAttrKeys: LIVE_REPLAY_PATH_DEFERRED_MATCH_ATTR_KEYS
|
|
3212
|
+
};
|
|
3213
|
+
var BUILD_LIVE_REPLAY_PATH_DECLARATION = String.raw`function(policy, source) {
|
|
3214
|
+
const buildReplayPath = (0, eval)(source);
|
|
3215
|
+
return buildReplayPath(this, policy);
|
|
3216
|
+
}`;
|
|
3217
|
+
var BUILD_LIVE_REPLAY_PATH_SOURCE = String.raw`(target, policy) => {
|
|
3218
|
+
const MAX_ATTRIBUTE_VALUE_LENGTH = 300;
|
|
3219
|
+
|
|
3220
|
+
function isValidAttrKey(key) {
|
|
3221
|
+
const trimmed = String(key || "").trim();
|
|
3222
|
+
if (!trimmed) return false;
|
|
3223
|
+
if (/[\s"'<>/]/.test(trimmed)) return false;
|
|
3224
|
+
return /^[A-Za-z_][A-Za-z0-9_:\-.]*$/.test(trimmed);
|
|
3225
|
+
}
|
|
3226
|
+
|
|
3227
|
+
function isMediaTag(tag) {
|
|
3228
|
+
return new Set(["img", "video", "source", "iframe"]).has(String(tag || "").toLowerCase());
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
function shouldKeepAttr(tag, key, value) {
|
|
3232
|
+
const normalized = String(key || "").trim().toLowerCase();
|
|
3233
|
+
if (!normalized || !String(value || "").trim()) return false;
|
|
3234
|
+
if (!isValidAttrKey(key)) return false;
|
|
3235
|
+
if (normalized === "c") return false;
|
|
3236
|
+
if (/^on[a-z]/i.test(normalized)) return false;
|
|
3237
|
+
if (new Set(["style", "nonce", "integrity", "crossorigin", "referrerpolicy", "autocomplete"]).has(normalized)) {
|
|
3238
|
+
return false;
|
|
3239
|
+
}
|
|
3240
|
+
if (normalized.startsWith("data-os-") || normalized.startsWith("data-opensteer-")) {
|
|
3241
|
+
return false;
|
|
3242
|
+
}
|
|
3243
|
+
if (
|
|
3244
|
+
isMediaTag(tag) &&
|
|
3245
|
+
new Set([
|
|
3246
|
+
"data-src",
|
|
3247
|
+
"data-lazy-src",
|
|
3248
|
+
"data-original",
|
|
3249
|
+
"data-lazy",
|
|
3250
|
+
"data-image",
|
|
3251
|
+
"data-url",
|
|
3252
|
+
"data-srcset",
|
|
3253
|
+
"data-lazy-srcset",
|
|
3254
|
+
"data-was-processed",
|
|
3255
|
+
]).has(normalized)
|
|
3256
|
+
) {
|
|
3257
|
+
return false;
|
|
3258
|
+
}
|
|
3259
|
+
return true;
|
|
3260
|
+
}
|
|
3261
|
+
|
|
3262
|
+
function collectAttrs(node) {
|
|
3263
|
+
const tag = node.tagName.toLowerCase();
|
|
3264
|
+
const attrs = {};
|
|
3265
|
+
for (const attr of Array.from(node.attributes)) {
|
|
3266
|
+
if (!shouldKeepAttr(tag, attr.name, attr.value)) {
|
|
3267
|
+
continue;
|
|
3268
|
+
}
|
|
3269
|
+
const value = String(attr.value || "");
|
|
3270
|
+
if (!value.trim()) continue;
|
|
3271
|
+
if (value.length > MAX_ATTRIBUTE_VALUE_LENGTH) continue;
|
|
3272
|
+
attrs[attr.name] = value;
|
|
3273
|
+
}
|
|
3274
|
+
return attrs;
|
|
3275
|
+
}
|
|
3276
|
+
|
|
3277
|
+
function getSiblings(node, root) {
|
|
3278
|
+
if (node.parentElement) return Array.from(node.parentElement.children);
|
|
3279
|
+
return Array.from(root.children || []);
|
|
3280
|
+
}
|
|
3281
|
+
|
|
3282
|
+
function cssEscape(value) {
|
|
3283
|
+
return String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
3284
|
+
}
|
|
3285
|
+
|
|
3286
|
+
function stablePrimaryKey(attrs) {
|
|
3287
|
+
for (const key of policy.stablePrimaryAttrKeys || []) {
|
|
3288
|
+
if (attrs[key]) return key;
|
|
3289
|
+
}
|
|
3290
|
+
return null;
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
function countMatches(root, tag, attrKey, attrValue, mode) {
|
|
3294
|
+
const scope = root instanceof ShadowRoot ? root : root.ownerDocument;
|
|
3295
|
+
if (!scope || typeof scope.querySelectorAll !== "function") return 0;
|
|
3296
|
+
const escapedTag = String(tag || "*");
|
|
3297
|
+
let selector = escapedTag;
|
|
3298
|
+
if (attrKey && attrValue) {
|
|
3299
|
+
const operator = mode === "prefix" ? "^=" : "=";
|
|
3300
|
+
selector += "[" + attrKey + operator + "\\"" + cssEscape(attrValue) + "\\"]";
|
|
3301
|
+
}
|
|
3302
|
+
try {
|
|
3303
|
+
return scope.querySelectorAll(selector).length;
|
|
3304
|
+
} catch {
|
|
3305
|
+
return 0;
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
|
|
3309
|
+
function chooseAttribute(tag, attrs, root) {
|
|
3310
|
+
const stableKey = stablePrimaryKey(attrs);
|
|
3311
|
+
if (stableKey) {
|
|
3312
|
+
const exactCount = countMatches(root, tag, stableKey, attrs[stableKey], "exact");
|
|
3313
|
+
if (exactCount === 1) {
|
|
3314
|
+
return {
|
|
3315
|
+
key: stableKey,
|
|
3316
|
+
value: attrs[stableKey],
|
|
3317
|
+
match: "exact",
|
|
3318
|
+
};
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3322
|
+
const entries = Object.entries(attrs)
|
|
3323
|
+
.filter(([key]) => !policy.deferredMatchAttrKeys.includes(key))
|
|
3324
|
+
.concat(Object.entries(attrs).filter(([key]) => policy.deferredMatchAttrKeys.includes(key)));
|
|
3325
|
+
|
|
3326
|
+
for (const [key, value] of entries) {
|
|
3327
|
+
const exactCount = countMatches(root, tag, key, value, "exact");
|
|
3328
|
+
if (exactCount === 1) {
|
|
3329
|
+
return { key, value, match: "exact" };
|
|
3330
|
+
}
|
|
3331
|
+
if (value.length >= 4) {
|
|
3332
|
+
const prefixLength = Math.min(Math.max(4, Math.floor(value.length / 2)), value.length);
|
|
3333
|
+
const prefix = value.slice(0, prefixLength);
|
|
3334
|
+
const prefixCount = countMatches(root, tag, key, prefix, "prefix");
|
|
3335
|
+
if (prefixCount === 1) {
|
|
3336
|
+
return { key, value: prefix, match: "prefix" };
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
}
|
|
3340
|
+
|
|
3341
|
+
return null;
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
function buildChain(node) {
|
|
3345
|
+
const nodes = [];
|
|
3346
|
+
let current = node;
|
|
3347
|
+
while (current && current instanceof Element) {
|
|
3348
|
+
nodes.unshift(current);
|
|
3349
|
+
current = current.parentElement;
|
|
3350
|
+
}
|
|
3351
|
+
return nodes;
|
|
3352
|
+
}
|
|
3353
|
+
|
|
3354
|
+
function finalizePath(chain, root) {
|
|
3355
|
+
const result = [];
|
|
3356
|
+
for (const node of chain) {
|
|
3357
|
+
const tag = node.tagName.toLowerCase();
|
|
3358
|
+
const attrs = collectAttrs(node);
|
|
3359
|
+
const attribute = chooseAttribute(tag, attrs, root);
|
|
3360
|
+
if (attribute) {
|
|
3361
|
+
result.push({
|
|
3362
|
+
tag,
|
|
3363
|
+
attributes: [
|
|
3364
|
+
{
|
|
3365
|
+
name: attribute.key,
|
|
3366
|
+
value: attribute.value,
|
|
3367
|
+
match: attribute.match,
|
|
3368
|
+
},
|
|
3369
|
+
],
|
|
3370
|
+
});
|
|
3371
|
+
continue;
|
|
3372
|
+
}
|
|
3373
|
+
|
|
3374
|
+
const siblings = getSiblings(node, root).filter(
|
|
3375
|
+
(candidate) => candidate.tagName.toLowerCase() === tag,
|
|
3376
|
+
);
|
|
3377
|
+
const index = siblings.indexOf(node);
|
|
3378
|
+
result.push({
|
|
3379
|
+
tag,
|
|
3380
|
+
index: siblings.length <= 1 || index < 0 ? undefined : index,
|
|
3381
|
+
});
|
|
3382
|
+
}
|
|
3383
|
+
|
|
3384
|
+
return {
|
|
3385
|
+
nodes: result,
|
|
3386
|
+
};
|
|
3387
|
+
}
|
|
3388
|
+
|
|
3389
|
+
if (!(target instanceof Element)) return null;
|
|
3390
|
+
|
|
3391
|
+
const context = [];
|
|
3392
|
+
let currentRoot = target.getRootNode() instanceof ShadowRoot ? target.getRootNode() : document;
|
|
3393
|
+
const targetChain = buildChain(target);
|
|
3394
|
+
const finalizedTarget = finalizePath(targetChain, currentRoot);
|
|
3395
|
+
if (!finalizedTarget) return null;
|
|
3396
|
+
|
|
3397
|
+
while (currentRoot instanceof ShadowRoot) {
|
|
3398
|
+
const host = currentRoot.host;
|
|
3399
|
+
const hostRoot = host.getRootNode() instanceof ShadowRoot ? host.getRootNode() : document;
|
|
3400
|
+
const hostChain = buildChain(host);
|
|
3401
|
+
const finalizedHost = finalizePath(hostChain, hostRoot);
|
|
3402
|
+
if (!finalizedHost) return null;
|
|
3403
|
+
context.unshift({
|
|
3404
|
+
kind: "shadow",
|
|
3405
|
+
host: finalizedHost.nodes,
|
|
3406
|
+
});
|
|
3407
|
+
currentRoot = hostRoot;
|
|
3408
|
+
}
|
|
3409
|
+
|
|
3410
|
+
return {
|
|
3411
|
+
resolution: "deterministic",
|
|
3412
|
+
context,
|
|
3413
|
+
nodes: finalizedTarget.nodes,
|
|
3414
|
+
};
|
|
3415
|
+
}`;
|
|
3174
3416
|
function createAbpDomActionBridge(context) {
|
|
3175
3417
|
return {
|
|
3418
|
+
async buildReplayPath(locator) {
|
|
3419
|
+
const { controller, document, backendNodeId } = await prepareLiveNodeContext(
|
|
3420
|
+
context,
|
|
3421
|
+
locator
|
|
3422
|
+
);
|
|
3423
|
+
return withTemporaryExecutionResume(context, controller, async () => {
|
|
3424
|
+
const raw = await callNodeValueFunction(controller, document, locator, backendNodeId, {
|
|
3425
|
+
functionDeclaration: BUILD_LIVE_REPLAY_PATH_DECLARATION,
|
|
3426
|
+
arguments: [{ value: LIVE_REPLAY_PATH_POLICY }, { value: BUILD_LIVE_REPLAY_PATH_SOURCE }]
|
|
3427
|
+
});
|
|
3428
|
+
return requireReplayPath(raw, locator);
|
|
3429
|
+
});
|
|
3430
|
+
},
|
|
3176
3431
|
async inspectActionTarget(locator) {
|
|
3177
3432
|
const { controller, document, backendNodeId } = await prepareLiveNodeContext(
|
|
3178
3433
|
context,
|
|
@@ -3410,6 +3665,24 @@ async function callNodeFunctionWithNodeArgument(controller, document, locator, b
|
|
|
3410
3665
|
await releaseObject(controller, objectId);
|
|
3411
3666
|
}
|
|
3412
3667
|
}
|
|
3668
|
+
async function callNodeValueFunction(controller, document, locator, backendNodeId, input) {
|
|
3669
|
+
let objectId;
|
|
3670
|
+
try {
|
|
3671
|
+
objectId = await resolveNodeObjectId(controller, document, locator, backendNodeId);
|
|
3672
|
+
const evaluated = await controller.cdp.send("Runtime.callFunctionOn", {
|
|
3673
|
+
objectId,
|
|
3674
|
+
functionDeclaration: input.functionDeclaration,
|
|
3675
|
+
...input.arguments === void 0 ? {} : { arguments: [...input.arguments] },
|
|
3676
|
+
returnByValue: true,
|
|
3677
|
+
awaitPromise: true
|
|
3678
|
+
});
|
|
3679
|
+
return evaluated.result?.value;
|
|
3680
|
+
} catch (error) {
|
|
3681
|
+
rethrowNodeLookupError2(document, locator, error);
|
|
3682
|
+
} finally {
|
|
3683
|
+
await releaseObject(controller, objectId);
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3413
3686
|
async function resolveNodeObjectId(controller, document, locator, backendNodeId) {
|
|
3414
3687
|
try {
|
|
3415
3688
|
const resolved = await controller.cdp.send("DOM.resolveNode", {
|
|
@@ -3504,6 +3777,14 @@ function normalizePointerHitAssessment(value, canonicalTarget) {
|
|
|
3504
3777
|
canonicalTarget
|
|
3505
3778
|
};
|
|
3506
3779
|
}
|
|
3780
|
+
function requireReplayPath(value, locator) {
|
|
3781
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || value.resolution !== "deterministic") {
|
|
3782
|
+
throw new Error(
|
|
3783
|
+
`live DOM replay path builder returned an invalid result for ${locator.nodeRef}`
|
|
3784
|
+
);
|
|
3785
|
+
}
|
|
3786
|
+
return value;
|
|
3787
|
+
}
|
|
3507
3788
|
function rethrowNodeLookupError2(document, locator, error) {
|
|
3508
3789
|
if (error instanceof Error && /No node with given id found|Could not find node with given id|Cannot find context/i.test(
|
|
3509
3790
|
error.message
|
|
@@ -6533,6 +6814,12 @@ function resolveFallbackPageTarget(targets, tabMetadata) {
|
|
|
6533
6814
|
}
|
|
6534
6815
|
|
|
6535
6816
|
exports.AbpBrowserCoreEngine = AbpBrowserCoreEngine;
|
|
6817
|
+
exports.allocatePort = allocatePort;
|
|
6818
|
+
exports.buildAbpLaunchCommand = buildAbpLaunchCommand;
|
|
6536
6819
|
exports.createAbpBrowserCoreEngine = createAbpBrowserCoreEngine;
|
|
6820
|
+
exports.launchAbpProcess = launchAbpProcess;
|
|
6821
|
+
exports.resolveDefaultAbpBrowserExecutablePath = resolveDefaultAbpBrowserExecutablePath;
|
|
6822
|
+
exports.resolveDefaultAbpExecutablePath = resolveDefaultAbpExecutablePath;
|
|
6823
|
+
exports.resolveDefaultAbpWrapperExecutablePath = resolveDefaultAbpWrapperExecutablePath;
|
|
6537
6824
|
//# sourceMappingURL=index.cjs.map
|
|
6538
6825
|
//# sourceMappingURL=index.cjs.map
|