browserclaw 0.11.4 → 0.11.6
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 +28 -28
- package/dist/index.cjs +69 -51
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -21
- package/dist/index.d.ts +45 -21
- package/dist/index.js +70 -54
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -15,16 +15,16 @@ The AI-native browser automation library — born from [OpenClaw](https://github
|
|
|
15
15
|
```typescript
|
|
16
16
|
import { BrowserClaw } from 'browserclaw';
|
|
17
17
|
|
|
18
|
-
const browser = await BrowserClaw.launch({ url: 'https://
|
|
18
|
+
const browser = await BrowserClaw.launch({ url: 'https://demo.playwright.dev/todomvc' });
|
|
19
19
|
const page = await browser.currentPage();
|
|
20
20
|
|
|
21
21
|
// Snapshot — the core feature
|
|
22
22
|
const { snapshot, refs } = await page.snapshot();
|
|
23
23
|
// snapshot: AI-readable text tree
|
|
24
|
-
// refs: { "e1": { role: "
|
|
24
|
+
// refs: { "e1": { role: "textbox", name: "What needs to be done?" }, "e2": { role: "link", name: "Playwright" } }
|
|
25
25
|
|
|
26
|
-
await page.
|
|
27
|
-
await page.
|
|
26
|
+
await page.type('e1', 'Buy groceries', { submit: true }); // Type by ref
|
|
27
|
+
await page.click('e2'); // Click by ref
|
|
28
28
|
await browser.stop();
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -102,20 +102,20 @@ Requires a Chromium-based browser installed on the system (Chrome, Brave, Edge,
|
|
|
102
102
|
## How It Works
|
|
103
103
|
|
|
104
104
|
```
|
|
105
|
-
┌─────────────┐ snapshot()
|
|
106
|
-
│ Web Page │ ──────────────► │ AI-readable text tree
|
|
107
|
-
│ │ │
|
|
108
|
-
│ [buttons] │ │ - heading "
|
|
109
|
-
│ [links] │ │ -
|
|
110
|
-
│ [inputs] │ │ - link "
|
|
111
|
-
└─────────────┘
|
|
105
|
+
┌─────────────┐ snapshot() ┌──────────────────────────────────────────┐
|
|
106
|
+
│ Web Page │ ──────────────► │ AI-readable text tree │
|
|
107
|
+
│ │ │ │
|
|
108
|
+
│ [buttons] │ │ - heading "todos" │
|
|
109
|
+
│ [links] │ │ - textbox "What needs to be done?" [e1] │
|
|
110
|
+
│ [inputs] │ │ - link "Playwright" [e2] │
|
|
111
|
+
└─────────────┘ └──────────────┬───────────────────────────┘
|
|
112
112
|
│
|
|
113
113
|
AI reads snapshot,
|
|
114
|
-
decides:
|
|
114
|
+
decides: type in e1
|
|
115
115
|
│
|
|
116
|
-
┌─────────────┐
|
|
116
|
+
┌─────────────┐ type('e1',...) ┌──────────────▼──────────────────┐
|
|
117
117
|
│ Web Page │ ◄────────────── │ Ref "e1" resolves to a │
|
|
118
|
-
│ (
|
|
118
|
+
│ (updated) │ │ Playwright locator — one ref, │
|
|
119
119
|
│ │ │ one exact element │
|
|
120
120
|
└─────────────┘ └─────────────────────────────────┘
|
|
121
121
|
```
|
|
@@ -133,7 +133,7 @@ Requires a Chromium-based browser installed on the system (Chrome, Brave, Edge,
|
|
|
133
133
|
```typescript
|
|
134
134
|
// Launch a new Chrome instance (auto-detects Chrome/Brave/Edge/Chromium)
|
|
135
135
|
const browser = await BrowserClaw.launch({
|
|
136
|
-
url: 'https://
|
|
136
|
+
url: 'https://demo.playwright.dev/todomvc', // navigate initial tab (no extra tabs)
|
|
137
137
|
headless: false, // default: false (visible window)
|
|
138
138
|
executablePath: '...', // optional: specific browser path
|
|
139
139
|
cdpPort: 9222, // default: 9222
|
|
@@ -159,7 +159,7 @@ const browser = await BrowserClaw.connect();
|
|
|
159
159
|
### Pages & Tabs
|
|
160
160
|
|
|
161
161
|
```typescript
|
|
162
|
-
const page = await browser.open('https://
|
|
162
|
+
const page = await browser.open('https://demo.playwright.dev/todomvc');
|
|
163
163
|
const current = await browser.currentPage(); // get active tab
|
|
164
164
|
const tabs = await browser.tabs(); // list all tabs
|
|
165
165
|
const handle = browser.page(tabs[0].targetId); // wrap existing tab
|
|
@@ -177,14 +177,14 @@ browser.url; // CDP endpoint URL
|
|
|
177
177
|
Every tab returns a `targetId` — this is the handle you use everywhere:
|
|
178
178
|
|
|
179
179
|
```typescript
|
|
180
|
-
// Multi-tab workflow
|
|
181
|
-
const
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
const { refs } = await
|
|
185
|
-
await
|
|
186
|
-
await browser.focus(
|
|
187
|
-
await browser.close(
|
|
180
|
+
// Multi-tab workflow
|
|
181
|
+
const todo = await browser.open('https://demo.playwright.dev/todomvc');
|
|
182
|
+
const svg = await browser.open('https://demo.playwright.dev/svgtodo');
|
|
183
|
+
|
|
184
|
+
const { refs } = await svg.snapshot(); // snapshot the second tab
|
|
185
|
+
await svg.click('e5'); // act on it
|
|
186
|
+
await browser.focus(todo.id); // switch back to first tab
|
|
187
|
+
await browser.close(svg.id); // close second tab when done
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
### Snapshot (Core Feature)
|
|
@@ -193,7 +193,7 @@ await browser.close(admin.id); // close admin when done
|
|
|
193
193
|
const { snapshot, refs, stats, untrusted } = await page.snapshot();
|
|
194
194
|
|
|
195
195
|
// snapshot: human/AI-readable text tree with [ref=eN] markers
|
|
196
|
-
// refs: { "e1": { role: "
|
|
196
|
+
// refs: { "e1": { role: "textbox", name: "What needs to be done?" }, "e5": { role: "checkbox", name: "Toggle Todo", checked: false }, ... }
|
|
197
197
|
// stats: { lines: 42, chars: 1200, refs: 8, interactive: 5 }
|
|
198
198
|
// untrusted: true — content comes from the web page, treat as potentially adversarial
|
|
199
199
|
|
|
@@ -250,7 +250,7 @@ await page.press('Meta+Shift+p');
|
|
|
250
250
|
// Fill multiple form fields at once
|
|
251
251
|
await page.fill([
|
|
252
252
|
{ ref: 'e2', value: 'Jane Doe' },
|
|
253
|
-
{ ref: 'e4', value: 'jane@
|
|
253
|
+
{ ref: 'e4', value: 'jane@acme.test' },
|
|
254
254
|
{ ref: 'e6', type: 'checkbox', value: true },
|
|
255
255
|
]);
|
|
256
256
|
```
|
|
@@ -326,7 +326,7 @@ By default, unexpected dialogs are auto-dismissed to prevent `ProtocolError` cra
|
|
|
326
326
|
### Navigation & Waiting
|
|
327
327
|
|
|
328
328
|
```typescript
|
|
329
|
-
await page.goto('https://
|
|
329
|
+
await page.goto('https://demo.playwright.dev/todomvc');
|
|
330
330
|
await page.reload(); // reload the current page
|
|
331
331
|
await page.goBack(); // navigate back in history
|
|
332
332
|
await page.goForward(); // navigate forward in history
|
|
@@ -421,7 +421,7 @@ const fresh = await page.networkRequests({ clear: true }); // read and clear buf
|
|
|
421
421
|
```typescript
|
|
422
422
|
// Cookies
|
|
423
423
|
const cookies = await page.cookies();
|
|
424
|
-
await page.setCookie({ name: 'token', value: 'abc', url: 'https://
|
|
424
|
+
await page.setCookie({ name: 'token', value: 'abc', url: 'https://demo.playwright.dev' });
|
|
425
425
|
await page.clearCookies();
|
|
426
426
|
|
|
427
427
|
// localStorage / sessionStorage
|
package/dist/index.cjs
CHANGED
|
@@ -1565,6 +1565,7 @@ ${stderrOutput.slice(0, 2e3)}` : "";
|
|
|
1565
1565
|
throw new Error(`Failed to start Chrome CDP on port ${String(cdpPort)}.${sandboxHint}${stderrHint}`);
|
|
1566
1566
|
}
|
|
1567
1567
|
proc.stderr.off("data", onStderr);
|
|
1568
|
+
proc.stderr.resume();
|
|
1568
1569
|
stderrChunks.length = 0;
|
|
1569
1570
|
return {
|
|
1570
1571
|
pid: proc.pid ?? -1,
|
|
@@ -1894,6 +1895,7 @@ function ensurePageState(page) {
|
|
|
1894
1895
|
page.on("dialog", (dialog) => {
|
|
1895
1896
|
if (state.armIdDialog > 0) return;
|
|
1896
1897
|
if (state.dialogHandler) {
|
|
1898
|
+
const handler = state.dialogHandler;
|
|
1897
1899
|
let handled = false;
|
|
1898
1900
|
const event = {
|
|
1899
1901
|
type: dialog.type(),
|
|
@@ -1908,7 +1910,7 @@ function ensurePageState(page) {
|
|
|
1908
1910
|
return dialog.dismiss();
|
|
1909
1911
|
}
|
|
1910
1912
|
};
|
|
1911
|
-
Promise.resolve(
|
|
1913
|
+
Promise.resolve().then(() => handler(event)).then(() => {
|
|
1912
1914
|
if (!handled) {
|
|
1913
1915
|
dialog.dismiss().catch((err) => {
|
|
1914
1916
|
console.warn(
|
|
@@ -2116,7 +2118,9 @@ async function fetchJsonForCdp(url, timeoutMs) {
|
|
|
2116
2118
|
const res = await fetch(url, { signal: ctrl.signal });
|
|
2117
2119
|
if (!res.ok) return null;
|
|
2118
2120
|
return await res.json();
|
|
2119
|
-
} catch {
|
|
2121
|
+
} catch (err) {
|
|
2122
|
+
if (process.env.DEBUG !== void 0 && process.env.DEBUG !== "")
|
|
2123
|
+
console.warn(`[browserclaw] fetchJsonForCdp ${url} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2120
2124
|
return null;
|
|
2121
2125
|
} finally {
|
|
2122
2126
|
clearTimeout(t);
|
|
@@ -2324,11 +2328,15 @@ async function disconnectBrowser() {
|
|
|
2324
2328
|
for (const p of connectingByCdpUrl.values()) {
|
|
2325
2329
|
try {
|
|
2326
2330
|
await p;
|
|
2327
|
-
} catch {
|
|
2331
|
+
} catch (err) {
|
|
2332
|
+
console.warn(
|
|
2333
|
+
`[browserclaw] disconnectBrowser: pending connect failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2334
|
+
);
|
|
2328
2335
|
}
|
|
2329
2336
|
}
|
|
2330
2337
|
}
|
|
2331
2338
|
for (const cur of cachedByCdpUrl.values()) {
|
|
2339
|
+
clearRoleRefsForCdpUrl(cur.cdpUrl);
|
|
2332
2340
|
if (cur.onDisconnected && typeof cur.browser.off === "function")
|
|
2333
2341
|
cur.browser.off("disconnected", cur.onDisconnected);
|
|
2334
2342
|
await cur.browser.close().catch(() => {
|
|
@@ -2450,12 +2458,17 @@ var forceDisconnectPlaywrightForTarget = forceDisconnectPlaywrightConnection;
|
|
|
2450
2458
|
function getAllPages(browser) {
|
|
2451
2459
|
return browser.contexts().flatMap((c) => c.pages());
|
|
2452
2460
|
}
|
|
2461
|
+
var pageTargetIdCache = /* @__PURE__ */ new WeakMap();
|
|
2453
2462
|
async function pageTargetId(page) {
|
|
2463
|
+
const cached = pageTargetIdCache.get(page);
|
|
2464
|
+
if (cached !== void 0) return cached;
|
|
2454
2465
|
const session = await page.context().newCDPSession(page);
|
|
2455
2466
|
try {
|
|
2456
2467
|
const info = await session.send("Target.getTargetInfo");
|
|
2457
2468
|
const targetInfo = info.targetInfo;
|
|
2458
|
-
|
|
2469
|
+
const id = (targetInfo?.targetId ?? "").trim() || null;
|
|
2470
|
+
if (id !== null) pageTargetIdCache.set(page, id);
|
|
2471
|
+
return id;
|
|
2459
2472
|
} finally {
|
|
2460
2473
|
await session.detach().catch(() => {
|
|
2461
2474
|
});
|
|
@@ -2485,17 +2498,19 @@ async function findPageByTargetIdViaTargetList(pages, targetId, cdpUrl) {
|
|
|
2485
2498
|
}
|
|
2486
2499
|
async function findPageByTargetId(browser, targetId, cdpUrl) {
|
|
2487
2500
|
const pages = getAllPages(browser);
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
}
|
|
2497
|
-
|
|
2498
|
-
}
|
|
2501
|
+
const results = await Promise.all(
|
|
2502
|
+
pages.map(async (page) => {
|
|
2503
|
+
try {
|
|
2504
|
+
const tid = await pageTargetId(page);
|
|
2505
|
+
return { page, tid };
|
|
2506
|
+
} catch {
|
|
2507
|
+
return { page, tid: null };
|
|
2508
|
+
}
|
|
2509
|
+
})
|
|
2510
|
+
);
|
|
2511
|
+
const resolvedViaCdp = results.some(({ tid }) => tid !== null);
|
|
2512
|
+
const matched = results.find(({ tid }) => tid !== null && tid !== "" && tid === targetId);
|
|
2513
|
+
if (matched) return matched.page;
|
|
2499
2514
|
if (cdpUrl !== void 0 && cdpUrl !== "") {
|
|
2500
2515
|
try {
|
|
2501
2516
|
return await findPageByTargetIdViaTargetList(pages, targetId, cdpUrl);
|
|
@@ -2551,9 +2566,6 @@ async function getPageForTargetId(opts) {
|
|
|
2551
2566
|
);
|
|
2552
2567
|
}
|
|
2553
2568
|
if (isBlockedPageRef(opts.cdpUrl, found)) throw new BlockedBrowserTargetError();
|
|
2554
|
-
const foundTargetId = await pageTargetId(found).catch(() => null);
|
|
2555
|
-
if (foundTargetId !== null && foundTargetId !== "" && isBlockedTarget(opts.cdpUrl, foundTargetId))
|
|
2556
|
-
throw new BlockedBrowserTargetError();
|
|
2557
2569
|
return found;
|
|
2558
2570
|
}
|
|
2559
2571
|
async function resolvePageByTargetIdOrThrow(opts) {
|
|
@@ -3206,7 +3218,7 @@ async function writeViaSiblingTempPath(params) {
|
|
|
3206
3218
|
const requestedTargetPath = path.resolve(params.targetPath);
|
|
3207
3219
|
const targetPath = await promises$1.realpath(path.dirname(requestedTargetPath)).then((realDir) => path.join(realDir, path.basename(requestedTargetPath))).catch(() => requestedTargetPath);
|
|
3208
3220
|
const relativeTargetPath = path.relative(rootDir, targetPath);
|
|
3209
|
-
if (!relativeTargetPath || relativeTargetPath === ".." || relativeTargetPath.startsWith(`..${path.sep}`) || isAbsolute(relativeTargetPath)) {
|
|
3221
|
+
if (!relativeTargetPath || relativeTargetPath === ".." || relativeTargetPath.startsWith(`..${path.sep}`) || path.isAbsolute(relativeTargetPath)) {
|
|
3210
3222
|
throw new Error("Target path is outside the allowed root");
|
|
3211
3223
|
}
|
|
3212
3224
|
const tempPath = buildSiblingTempPath(targetPath);
|
|
@@ -3221,9 +3233,6 @@ async function writeViaSiblingTempPath(params) {
|
|
|
3221
3233
|
});
|
|
3222
3234
|
}
|
|
3223
3235
|
}
|
|
3224
|
-
function isAbsolute(p) {
|
|
3225
|
-
return p.startsWith("/") || /^[a-zA-Z]:/.test(p);
|
|
3226
|
-
}
|
|
3227
3236
|
async function assertBrowserNavigationResultAllowed(opts) {
|
|
3228
3237
|
const rawUrl = opts.url.trim();
|
|
3229
3238
|
if (rawUrl === "") return;
|
|
@@ -3264,7 +3273,6 @@ async function setCheckedViaEvaluate(locator, checked) {
|
|
|
3264
3273
|
else input.checked = desired;
|
|
3265
3274
|
input.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3266
3275
|
input.dispatchEvent(new Event("change", { bubbles: true }));
|
|
3267
|
-
input.click();
|
|
3268
3276
|
}, checked);
|
|
3269
3277
|
}
|
|
3270
3278
|
function resolveLocator(page, resolved) {
|
|
@@ -3441,7 +3449,10 @@ async function fillFormViaPlaywright(opts) {
|
|
|
3441
3449
|
const checked = rawValue === true || rawValue === 1 || rawValue === "1" || rawValue === "true";
|
|
3442
3450
|
try {
|
|
3443
3451
|
await locator.setChecked(checked, { timeout, force: true });
|
|
3444
|
-
} catch {
|
|
3452
|
+
} catch (setCheckedErr) {
|
|
3453
|
+
console.warn(
|
|
3454
|
+
`[browserclaw] setChecked fallback for ref "${ref}": ${setCheckedErr instanceof Error ? setCheckedErr.message : String(setCheckedErr)}`
|
|
3455
|
+
);
|
|
3445
3456
|
try {
|
|
3446
3457
|
await setCheckedViaEvaluate(locator, checked);
|
|
3447
3458
|
} catch (err) {
|
|
@@ -3553,6 +3564,7 @@ async function armFileUploadViaPlaywright(opts) {
|
|
|
3553
3564
|
scopeLabel: `uploads directory (${DEFAULT_UPLOAD_DIR})`
|
|
3554
3565
|
});
|
|
3555
3566
|
if (!uploadPathsResult.ok) {
|
|
3567
|
+
console.warn(`[browserclaw] armFileUpload: path validation failed: ${uploadPathsResult.error}`);
|
|
3556
3568
|
try {
|
|
3557
3569
|
await page.keyboard.press("Escape");
|
|
3558
3570
|
} catch {
|
|
@@ -4602,14 +4614,17 @@ async function traceStopViaPlaywright(opts) {
|
|
|
4602
4614
|
if (!ctxState.traceActive) {
|
|
4603
4615
|
throw new Error("No active trace. Start a trace before stopping it.");
|
|
4604
4616
|
}
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
4610
|
-
|
|
4611
|
-
|
|
4612
|
-
|
|
4617
|
+
try {
|
|
4618
|
+
await writeViaSiblingTempPath({
|
|
4619
|
+
rootDir: path.dirname(opts.path),
|
|
4620
|
+
targetPath: opts.path,
|
|
4621
|
+
writeTemp: async (tempPath) => {
|
|
4622
|
+
await context.tracing.stop({ path: tempPath });
|
|
4623
|
+
}
|
|
4624
|
+
});
|
|
4625
|
+
} finally {
|
|
4626
|
+
ctxState.traceActive = false;
|
|
4627
|
+
}
|
|
4613
4628
|
}
|
|
4614
4629
|
|
|
4615
4630
|
// src/snapshot/ref-map.ts
|
|
@@ -4808,7 +4823,7 @@ function buildRoleSnapshotFromAriaSnapshot(ariaSnapshot, options = {}) {
|
|
|
4808
4823
|
const isInteractive = INTERACTIVE_ROLES.has(role);
|
|
4809
4824
|
const isContent = CONTENT_ROLES.has(role);
|
|
4810
4825
|
const isStructural = STRUCTURAL_ROLES.has(role);
|
|
4811
|
-
if (options.compact === true && isStructural && name
|
|
4826
|
+
if (options.compact === true && isStructural && !name) continue;
|
|
4812
4827
|
if (!(isInteractive || isContent && name !== "")) {
|
|
4813
4828
|
result.push(line);
|
|
4814
4829
|
continue;
|
|
@@ -4819,7 +4834,7 @@ function buildRoleSnapshotFromAriaSnapshot(ariaSnapshot, options = {}) {
|
|
|
4819
4834
|
const state = parseStateFromSuffix(suffix);
|
|
4820
4835
|
refs[ref] = { role, name, nth, ...state };
|
|
4821
4836
|
let enhanced = `${prefix}${roleRaw}`;
|
|
4822
|
-
if (name
|
|
4837
|
+
if (name) enhanced += ` "${name}"`;
|
|
4823
4838
|
enhanced += ` [ref=${ref}]`;
|
|
4824
4839
|
if (nth > 0) enhanced += ` [nth=${String(nth)}]`;
|
|
4825
4840
|
if (suffix !== "") enhanced += suffix;
|
|
@@ -4897,7 +4912,7 @@ function buildRoleSnapshotFromAiSnapshot(aiSnapshot, options = {}) {
|
|
|
4897
4912
|
}
|
|
4898
4913
|
const role = roleRaw.toLowerCase();
|
|
4899
4914
|
const isStructural = STRUCTURAL_ROLES.has(role);
|
|
4900
|
-
if (options.compact === true && isStructural && name
|
|
4915
|
+
if (options.compact === true && isStructural && !name) continue;
|
|
4901
4916
|
const ref = parseAiSnapshotRef(suffix);
|
|
4902
4917
|
const state = parseStateFromSuffix(suffix);
|
|
4903
4918
|
if (ref !== null) {
|
|
@@ -4905,9 +4920,9 @@ function buildRoleSnapshotFromAiSnapshot(aiSnapshot, options = {}) {
|
|
|
4905
4920
|
out.push(line);
|
|
4906
4921
|
} else if (INTERACTIVE_ROLES.has(role)) {
|
|
4907
4922
|
const generatedRef = nextGeneratedRef();
|
|
4908
|
-
refs[generatedRef] = { role, ...name
|
|
4923
|
+
refs[generatedRef] = { role, ...name ? { name } : {}, ...state };
|
|
4909
4924
|
let enhanced = `${prefix}${roleRaw}`;
|
|
4910
|
-
if (name
|
|
4925
|
+
if (name) enhanced += ` "${name}"`;
|
|
4911
4926
|
enhanced += ` [ref=${generatedRef}]`;
|
|
4912
4927
|
if (suffix.trim() !== "") enhanced += suffix;
|
|
4913
4928
|
out.push(enhanced);
|
|
@@ -4988,7 +5003,7 @@ async function snapshotRole(opts) {
|
|
|
4988
5003
|
if (!maybe._snapshotForAI) {
|
|
4989
5004
|
throw new Error("refs=aria requires Playwright _snapshotForAI support.");
|
|
4990
5005
|
}
|
|
4991
|
-
const result = await maybe._snapshotForAI({ timeout: 5e3, track: "response" });
|
|
5006
|
+
const result = await maybe._snapshotForAI({ timeout: normalizeTimeoutMs(opts.timeoutMs, 5e3), track: "response" });
|
|
4992
5007
|
const built2 = buildRoleSnapshotFromAiSnapshot(String(result.full), opts.options);
|
|
4993
5008
|
storeRoleRefsForTarget({
|
|
4994
5009
|
page,
|
|
@@ -5498,7 +5513,7 @@ var CrawlPage = class {
|
|
|
5498
5513
|
* ```ts
|
|
5499
5514
|
* await page.fill([
|
|
5500
5515
|
* { ref: 'e2', type: 'text', value: 'Jane Doe' },
|
|
5501
|
-
* { ref: 'e4', type: 'text', value: 'jane@
|
|
5516
|
+
* { ref: 'e4', type: 'text', value: 'jane@acme.test' },
|
|
5502
5517
|
* { ref: 'e6', type: 'checkbox', value: true },
|
|
5503
5518
|
* ]);
|
|
5504
5519
|
* ```
|
|
@@ -5551,17 +5566,18 @@ var CrawlPage = class {
|
|
|
5551
5566
|
});
|
|
5552
5567
|
}
|
|
5553
5568
|
/**
|
|
5554
|
-
* Arm a one-shot dialog handler (alert, confirm, prompt).
|
|
5569
|
+
* Arm a one-shot dialog handler (alert, confirm, prompt). Fire-and-forget:
|
|
5570
|
+
* returns immediately once the arm is registered. The dialog is handled in
|
|
5571
|
+
* the background when it fires.
|
|
5555
5572
|
*
|
|
5556
|
-
*
|
|
5573
|
+
* Call this BEFORE triggering the action that opens the dialog.
|
|
5557
5574
|
*
|
|
5558
5575
|
* @param opts - Dialog options (accept/dismiss, prompt text, timeout)
|
|
5559
5576
|
*
|
|
5560
5577
|
* @example
|
|
5561
5578
|
* ```ts
|
|
5562
|
-
*
|
|
5563
|
-
* await page.click('e5');
|
|
5564
|
-
* await dialogDone; // wait for dialog to be handled
|
|
5579
|
+
* await page.armDialog({ accept: true }); // registers the handler, returns immediately
|
|
5580
|
+
* await page.click('e5'); // triggers confirm() — handled in background
|
|
5565
5581
|
* ```
|
|
5566
5582
|
*/
|
|
5567
5583
|
async armDialog(opts) {
|
|
@@ -6043,7 +6059,7 @@ var CrawlPage = class {
|
|
|
6043
6059
|
* await page.setCookie({
|
|
6044
6060
|
* name: 'token',
|
|
6045
6061
|
* value: 'abc123',
|
|
6046
|
-
* url: 'https://
|
|
6062
|
+
* url: 'https://demo.playwright.dev/todomvc',
|
|
6047
6063
|
* });
|
|
6048
6064
|
* ```
|
|
6049
6065
|
*/
|
|
@@ -6295,7 +6311,7 @@ var CrawlPage = class {
|
|
|
6295
6311
|
*
|
|
6296
6312
|
* @example
|
|
6297
6313
|
* ```ts
|
|
6298
|
-
* await page.goto('https://
|
|
6314
|
+
* await page.goto('https://demo.playwright.dev/todomvc');
|
|
6299
6315
|
* const challenge = await page.detectChallenge();
|
|
6300
6316
|
* if (challenge?.kind === 'cloudflare-js') {
|
|
6301
6317
|
* const { resolved } = await page.waitForChallenge({ timeoutMs: 20000 });
|
|
@@ -6356,7 +6372,7 @@ var CrawlPage = class {
|
|
|
6356
6372
|
*
|
|
6357
6373
|
* // Use Playwright selectors
|
|
6358
6374
|
* const input = await page.locator('input[name="email"]');
|
|
6359
|
-
* await input.fill('test@
|
|
6375
|
+
* await input.fill('test@acme.test');
|
|
6360
6376
|
* ```
|
|
6361
6377
|
*/
|
|
6362
6378
|
async locator(selector) {
|
|
@@ -6387,14 +6403,14 @@ var BrowserClaw = class _BrowserClaw {
|
|
|
6387
6403
|
* @example
|
|
6388
6404
|
* ```ts
|
|
6389
6405
|
* // Launch and navigate to a URL
|
|
6390
|
-
* const browser = await BrowserClaw.launch({ url: 'https://
|
|
6406
|
+
* const browser = await BrowserClaw.launch({ url: 'https://demo.playwright.dev/todomvc' });
|
|
6391
6407
|
*
|
|
6392
6408
|
* // Headless mode
|
|
6393
|
-
* const browser = await BrowserClaw.launch({ url: 'https://
|
|
6409
|
+
* const browser = await BrowserClaw.launch({ url: 'https://demo.playwright.dev/todomvc', headless: true });
|
|
6394
6410
|
*
|
|
6395
6411
|
* // Specific browser
|
|
6396
6412
|
* const browser = await BrowserClaw.launch({
|
|
6397
|
-
* url: 'https://
|
|
6413
|
+
* url: 'https://demo.playwright.dev/todomvc',
|
|
6398
6414
|
* executablePath: '/usr/bin/google-chrome',
|
|
6399
6415
|
* });
|
|
6400
6416
|
* ```
|
|
@@ -6450,7 +6466,7 @@ var BrowserClaw = class _BrowserClaw {
|
|
|
6450
6466
|
*
|
|
6451
6467
|
* @example
|
|
6452
6468
|
* ```ts
|
|
6453
|
-
* const page = await browser.open('https://
|
|
6469
|
+
* const page = await browser.open('https://demo.playwright.dev/todomvc');
|
|
6454
6470
|
* const { snapshot, refs } = await page.snapshot();
|
|
6455
6471
|
* ```
|
|
6456
6472
|
*/
|
|
@@ -6557,6 +6573,7 @@ var BrowserClaw = class _BrowserClaw {
|
|
|
6557
6573
|
}
|
|
6558
6574
|
};
|
|
6559
6575
|
|
|
6576
|
+
exports.BlockedBrowserTargetError = BlockedBrowserTargetError;
|
|
6560
6577
|
exports.BrowserClaw = BrowserClaw;
|
|
6561
6578
|
exports.BrowserTabNotFoundError = BrowserTabNotFoundError;
|
|
6562
6579
|
exports.CrawlPage = CrawlPage;
|
|
@@ -6587,6 +6604,7 @@ exports.resolveBoundedDelayMs = resolveBoundedDelayMs;
|
|
|
6587
6604
|
exports.resolveInteractionTimeoutMs = resolveInteractionTimeoutMs;
|
|
6588
6605
|
exports.resolvePageByTargetIdOrThrow = resolvePageByTargetIdOrThrow;
|
|
6589
6606
|
exports.resolvePinnedHostnameWithPolicy = resolvePinnedHostnameWithPolicy;
|
|
6607
|
+
exports.resolveStrictExistingPathsWithinRoot = resolveStrictExistingPathsWithinRoot;
|
|
6590
6608
|
exports.resolveStrictExistingUploadPaths = resolveStrictExistingUploadPaths;
|
|
6591
6609
|
exports.sanitizeUntrustedFileName = sanitizeUntrustedFileName;
|
|
6592
6610
|
exports.setDialogHandler = setDialogHandler;
|