browserclaw 0.9.7 → 0.10.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 +58 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +58 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1407,6 +1407,9 @@ async function launchChrome(opts = {}) {
|
|
|
1407
1407
|
if (opts.noSandbox === true) {
|
|
1408
1408
|
args.push("--no-sandbox", "--disable-setuid-sandbox");
|
|
1409
1409
|
}
|
|
1410
|
+
if (opts.ignoreHTTPSErrors === true) {
|
|
1411
|
+
args.push("--ignore-certificate-errors");
|
|
1412
|
+
}
|
|
1410
1413
|
if (process.platform === "linux") args.push("--disable-dev-shm-usage");
|
|
1411
1414
|
const extraArgs = Array.isArray(opts.chromeArgs) ? opts.chromeArgs.filter((a) => typeof a === "string" && a.trim().length > 0) : [];
|
|
1412
1415
|
if (extraArgs.length) args.push(...extraArgs);
|
|
@@ -2375,7 +2378,14 @@ function toAIFriendlyError(error, selector) {
|
|
|
2375
2378
|
`Element "${selector}" is not interactable (hidden or covered). Try scrolling it into view, closing overlays, or re-snapshotting.`
|
|
2376
2379
|
);
|
|
2377
2380
|
}
|
|
2378
|
-
|
|
2381
|
+
const timeoutMatch = /Timeout (\d+)ms exceeded/.exec(message);
|
|
2382
|
+
if (timeoutMatch) {
|
|
2383
|
+
return new Error(
|
|
2384
|
+
`Element "${selector}" timed out after ${timeoutMatch[1]}ms \u2014 element may be hidden or not interactable. Run a new snapshot to see current page elements.`
|
|
2385
|
+
);
|
|
2386
|
+
}
|
|
2387
|
+
const cleaned = message.replace(/locator\([^)]*\)\./g, "").replace(/waiting for locator\([^)]*\)/g, "").trim();
|
|
2388
|
+
return new Error(cleaned || message);
|
|
2379
2389
|
}
|
|
2380
2390
|
function normalizeTimeoutMs(timeoutMs, fallback, maxMs = 12e4) {
|
|
2381
2391
|
return Math.max(500, Math.min(maxMs, timeoutMs ?? fallback));
|
|
@@ -3073,6 +3083,7 @@ function requiresInspectableBrowserNavigationRedirects(ssrfPolicy) {
|
|
|
3073
3083
|
|
|
3074
3084
|
// src/actions/interaction.ts
|
|
3075
3085
|
var MAX_CLICK_DELAY_MS = 5e3;
|
|
3086
|
+
var DEFAULT_SCROLL_TIMEOUT_MS = 2e4;
|
|
3076
3087
|
var CHECKABLE_ROLES = /* @__PURE__ */ new Set(["menuitemcheckbox", "menuitemradio", "checkbox", "switch"]);
|
|
3077
3088
|
function resolveLocator(page, resolved) {
|
|
3078
3089
|
if (resolved.ref !== void 0 && resolved.ref !== "") return refLocator(page, resolved.ref);
|
|
@@ -3107,8 +3118,9 @@ async function pressAndHoldViaCdp(opts) {
|
|
|
3107
3118
|
async function clickByTextViaPlaywright(opts) {
|
|
3108
3119
|
const page = await getRestoredPageForTarget(opts);
|
|
3109
3120
|
const timeout = resolveInteractionTimeoutMs(opts.timeoutMs);
|
|
3121
|
+
const locator = page.getByText(opts.text, { exact: opts.exact }).and(page.locator(":visible")).or(page.getByTitle(opts.text, { exact: opts.exact })).first();
|
|
3110
3122
|
try {
|
|
3111
|
-
await
|
|
3123
|
+
await locator.click({ timeout, button: opts.button, modifiers: opts.modifiers });
|
|
3112
3124
|
} catch (err) {
|
|
3113
3125
|
throw toAIFriendlyError(err, `text="${opts.text}"`);
|
|
3114
3126
|
}
|
|
@@ -3116,13 +3128,12 @@ async function clickByTextViaPlaywright(opts) {
|
|
|
3116
3128
|
async function clickByRoleViaPlaywright(opts) {
|
|
3117
3129
|
const page = await getRestoredPageForTarget(opts);
|
|
3118
3130
|
const timeout = resolveInteractionTimeoutMs(opts.timeoutMs);
|
|
3131
|
+
const label = `role=${opts.role}${opts.name !== void 0 && opts.name !== "" ? ` name="${opts.name}"` : ""}`;
|
|
3132
|
+
const locator = page.getByRole(opts.role, { name: opts.name }).nth(opts.index ?? 0);
|
|
3119
3133
|
try {
|
|
3120
|
-
await
|
|
3134
|
+
await locator.click({ timeout, button: opts.button, modifiers: opts.modifiers });
|
|
3121
3135
|
} catch (err) {
|
|
3122
|
-
throw toAIFriendlyError(
|
|
3123
|
-
err,
|
|
3124
|
-
`role=${opts.role}${opts.name !== void 0 && opts.name !== "" ? ` name="${opts.name}"` : ""}`
|
|
3125
|
-
);
|
|
3136
|
+
throw toAIFriendlyError(err, label);
|
|
3126
3137
|
}
|
|
3127
3138
|
}
|
|
3128
3139
|
async function clickViaPlaywright(opts) {
|
|
@@ -3143,7 +3154,7 @@ async function clickViaPlaywright(opts) {
|
|
|
3143
3154
|
try {
|
|
3144
3155
|
const delayMs = resolveBoundedDelayMs(opts.delayMs, "click delayMs", MAX_CLICK_DELAY_MS);
|
|
3145
3156
|
if (delayMs > 0) {
|
|
3146
|
-
await locator.hover({ timeout });
|
|
3157
|
+
await locator.hover({ timeout, force: opts.force });
|
|
3147
3158
|
await new Promise((resolve2) => setTimeout(resolve2, delayMs));
|
|
3148
3159
|
}
|
|
3149
3160
|
let ariaCheckedBefore;
|
|
@@ -3151,9 +3162,9 @@ async function clickViaPlaywright(opts) {
|
|
|
3151
3162
|
ariaCheckedBefore = await locator.getAttribute("aria-checked", { timeout }).catch(() => void 0);
|
|
3152
3163
|
}
|
|
3153
3164
|
if (opts.doubleClick === true) {
|
|
3154
|
-
await locator.dblclick({ timeout, button: opts.button, modifiers: opts.modifiers });
|
|
3165
|
+
await locator.dblclick({ timeout, button: opts.button, modifiers: opts.modifiers, force: opts.force });
|
|
3155
3166
|
} else {
|
|
3156
|
-
await locator.click({ timeout, button: opts.button, modifiers: opts.modifiers });
|
|
3167
|
+
await locator.click({ timeout, button: opts.button, modifiers: opts.modifiers, force: opts.force });
|
|
3157
3168
|
}
|
|
3158
3169
|
if (checkableRole && opts.doubleClick !== true && ariaCheckedBefore !== void 0) {
|
|
3159
3170
|
const POLL_INTERVAL_MS = 50;
|
|
@@ -3247,7 +3258,7 @@ async function fillFormViaPlaywright(opts) {
|
|
|
3247
3258
|
if (type === "checkbox" || type === "radio") {
|
|
3248
3259
|
const checked = rawValue === true || rawValue === 1 || rawValue === "1" || rawValue === "true";
|
|
3249
3260
|
try {
|
|
3250
|
-
await locator.setChecked(checked, { timeout });
|
|
3261
|
+
await locator.setChecked(checked, { timeout, force: true });
|
|
3251
3262
|
} catch (err) {
|
|
3252
3263
|
throw toAIFriendlyError(err, ref);
|
|
3253
3264
|
}
|
|
@@ -3266,7 +3277,13 @@ async function scrollIntoViewViaPlaywright(opts) {
|
|
|
3266
3277
|
const label = resolved.ref ?? resolved.selector ?? "";
|
|
3267
3278
|
const locator = resolveLocator(page, resolved);
|
|
3268
3279
|
try {
|
|
3269
|
-
await locator.
|
|
3280
|
+
await locator.waitFor({
|
|
3281
|
+
state: "attached",
|
|
3282
|
+
timeout: normalizeTimeoutMs(opts.timeoutMs, DEFAULT_SCROLL_TIMEOUT_MS)
|
|
3283
|
+
});
|
|
3284
|
+
await locator.evaluate((el) => {
|
|
3285
|
+
el.scrollIntoView({ block: "center", behavior: "instant" });
|
|
3286
|
+
});
|
|
3270
3287
|
} catch (err) {
|
|
3271
3288
|
throw toAIFriendlyError(err, label);
|
|
3272
3289
|
}
|
|
@@ -3542,9 +3559,13 @@ async function waitForViaPlaywright(opts) {
|
|
|
3542
3559
|
if (opts.loadState !== void 0) {
|
|
3543
3560
|
await page.waitForLoadState(opts.loadState, { timeout });
|
|
3544
3561
|
}
|
|
3545
|
-
if (opts.fn !== void 0
|
|
3546
|
-
|
|
3547
|
-
|
|
3562
|
+
if (opts.fn !== void 0) {
|
|
3563
|
+
if (typeof opts.fn === "function") {
|
|
3564
|
+
await page.waitForFunction(opts.fn, { timeout });
|
|
3565
|
+
} else {
|
|
3566
|
+
const fn = opts.fn.trim();
|
|
3567
|
+
if (fn !== "") await page.waitForFunction(fn, void 0, { timeout });
|
|
3568
|
+
}
|
|
3548
3569
|
}
|
|
3549
3570
|
}
|
|
3550
3571
|
|
|
@@ -4254,6 +4275,13 @@ async function traceStopViaPlaywright(opts) {
|
|
|
4254
4275
|
}
|
|
4255
4276
|
|
|
4256
4277
|
// src/snapshot/ref-map.ts
|
|
4278
|
+
function parseStateFromSuffix(suffix) {
|
|
4279
|
+
const state = {};
|
|
4280
|
+
if (/\[disabled\]/i.test(suffix)) state.disabled = true;
|
|
4281
|
+
if (/\[checked\s*=\s*"?mixed"?\]/i.test(suffix)) state.checked = "mixed";
|
|
4282
|
+
else if (/\[checked\]/i.test(suffix)) state.checked = true;
|
|
4283
|
+
return state;
|
|
4284
|
+
}
|
|
4257
4285
|
var INTERACTIVE_ROLES = /* @__PURE__ */ new Set([
|
|
4258
4286
|
"button",
|
|
4259
4287
|
"link",
|
|
@@ -4412,7 +4440,8 @@ function buildRoleSnapshotFromAriaSnapshot(ariaSnapshot, options = {}) {
|
|
|
4412
4440
|
const ref = nextRef();
|
|
4413
4441
|
const nth = tracker.getNextIndex(role, name);
|
|
4414
4442
|
tracker.trackRef(role, name, ref);
|
|
4415
|
-
|
|
4443
|
+
const state = parseStateFromSuffix(suffix);
|
|
4444
|
+
refs[ref] = { role, name, nth, ...state };
|
|
4416
4445
|
let enhanced = `${prefix}${roleRaw}`;
|
|
4417
4446
|
if (name !== void 0 && name !== "") enhanced += ` "${name}"`;
|
|
4418
4447
|
enhanced += ` [ref=${ref}]`;
|
|
@@ -4449,7 +4478,8 @@ function buildRoleSnapshotFromAriaSnapshot(ariaSnapshot, options = {}) {
|
|
|
4449
4478
|
const ref = nextRef();
|
|
4450
4479
|
const nth = tracker.getNextIndex(role, name);
|
|
4451
4480
|
tracker.trackRef(role, name, ref);
|
|
4452
|
-
|
|
4481
|
+
const state = parseStateFromSuffix(suffix);
|
|
4482
|
+
refs[ref] = { role, name, nth, ...state };
|
|
4453
4483
|
let enhanced = `${prefix}${roleRaw}`;
|
|
4454
4484
|
if (name !== "") enhanced += ` "${name}"`;
|
|
4455
4485
|
enhanced += ` [ref=${ref}]`;
|
|
@@ -4487,12 +4517,13 @@ function buildRoleSnapshotFromAiSnapshot(aiSnapshot, options = {}) {
|
|
|
4487
4517
|
if (!INTERACTIVE_ROLES.has(role)) continue;
|
|
4488
4518
|
const ref = parseAiSnapshotRef(suffix);
|
|
4489
4519
|
const prefix = /^(\s*-\s*)/.exec(line)?.[1] ?? "";
|
|
4520
|
+
const state = parseStateFromSuffix(suffix);
|
|
4490
4521
|
if (ref !== null) {
|
|
4491
|
-
refs[ref] = { role, ...name !== void 0 && name !== "" ? { name } : {} };
|
|
4522
|
+
refs[ref] = { role, ...name !== void 0 && name !== "" ? { name } : {}, ...state };
|
|
4492
4523
|
out2.push(`${prefix}${roleRaw}${name !== void 0 && name !== "" ? ` "${name}"` : ""}${suffix}`);
|
|
4493
4524
|
} else {
|
|
4494
4525
|
const generatedRef = nextInteractiveRef();
|
|
4495
|
-
refs[generatedRef] = { role, ...name !== void 0 && name !== "" ? { name } : {} };
|
|
4526
|
+
refs[generatedRef] = { role, ...name !== void 0 && name !== "" ? { name } : {}, ...state };
|
|
4496
4527
|
let enhanced = `${prefix}${roleRaw}`;
|
|
4497
4528
|
if (name !== void 0 && name !== "") enhanced += ` "${name}"`;
|
|
4498
4529
|
enhanced += ` [ref=${generatedRef}]`;
|
|
@@ -4530,12 +4561,13 @@ function buildRoleSnapshotFromAiSnapshot(aiSnapshot, options = {}) {
|
|
|
4530
4561
|
const isStructural = STRUCTURAL_ROLES.has(role);
|
|
4531
4562
|
if (options.compact === true && isStructural && name === "") continue;
|
|
4532
4563
|
const ref = parseAiSnapshotRef(suffix);
|
|
4564
|
+
const state = parseStateFromSuffix(suffix);
|
|
4533
4565
|
if (ref !== null) {
|
|
4534
|
-
refs[ref] = { role, ...name !== "" ? { name } : {} };
|
|
4566
|
+
refs[ref] = { role, ...name !== "" ? { name } : {}, ...state };
|
|
4535
4567
|
out.push(line);
|
|
4536
4568
|
} else if (INTERACTIVE_ROLES.has(role)) {
|
|
4537
4569
|
const generatedRef = nextGeneratedRef();
|
|
4538
|
-
refs[generatedRef] = { role, ...name !== "" ? { name } : {} };
|
|
4570
|
+
refs[generatedRef] = { role, ...name !== "" ? { name } : {}, ...state };
|
|
4539
4571
|
let enhanced = `${prefix}${roleRaw}`;
|
|
4540
4572
|
if (name !== "") enhanced += ` "${name}"`;
|
|
4541
4573
|
enhanced += ` [ref=${generatedRef}]`;
|
|
@@ -4901,7 +4933,8 @@ var CrawlPage = class {
|
|
|
4901
4933
|
button: opts?.button,
|
|
4902
4934
|
modifiers: opts?.modifiers,
|
|
4903
4935
|
delayMs: opts?.delayMs,
|
|
4904
|
-
timeoutMs: opts?.timeoutMs
|
|
4936
|
+
timeoutMs: opts?.timeoutMs,
|
|
4937
|
+
force: opts?.force
|
|
4905
4938
|
});
|
|
4906
4939
|
}
|
|
4907
4940
|
/**
|
|
@@ -4927,7 +4960,8 @@ var CrawlPage = class {
|
|
|
4927
4960
|
button: opts?.button,
|
|
4928
4961
|
modifiers: opts?.modifiers,
|
|
4929
4962
|
delayMs: opts?.delayMs,
|
|
4930
|
-
timeoutMs: opts?.timeoutMs
|
|
4963
|
+
timeoutMs: opts?.timeoutMs,
|
|
4964
|
+
force: opts?.force
|
|
4931
4965
|
});
|
|
4932
4966
|
}
|
|
4933
4967
|
/**
|
|
@@ -5030,6 +5064,7 @@ var CrawlPage = class {
|
|
|
5030
5064
|
targetId: this.targetId,
|
|
5031
5065
|
role,
|
|
5032
5066
|
name,
|
|
5067
|
+
index: opts?.index,
|
|
5033
5068
|
button: opts?.button,
|
|
5034
5069
|
modifiers: opts?.modifiers,
|
|
5035
5070
|
timeoutMs: opts?.timeoutMs
|