browserclaw 0.8.0 → 0.8.2
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 +173 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +124 -2
- package/dist/index.d.ts +124 -2
- package/dist/index.js +173 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1929,6 +1929,41 @@ function ensurePageState(page) {
|
|
|
1929
1929
|
});
|
|
1930
1930
|
page.on("dialog", (dialog) => {
|
|
1931
1931
|
if (state.armIdDialog > 0) return;
|
|
1932
|
+
if (state.dialogHandler) {
|
|
1933
|
+
let handled = false;
|
|
1934
|
+
const event = {
|
|
1935
|
+
type: dialog.type(),
|
|
1936
|
+
message: dialog.message(),
|
|
1937
|
+
defaultValue: dialog.defaultValue(),
|
|
1938
|
+
accept: (promptText) => {
|
|
1939
|
+
handled = true;
|
|
1940
|
+
return dialog.accept(promptText);
|
|
1941
|
+
},
|
|
1942
|
+
dismiss: () => {
|
|
1943
|
+
handled = true;
|
|
1944
|
+
return dialog.dismiss();
|
|
1945
|
+
}
|
|
1946
|
+
};
|
|
1947
|
+
Promise.resolve(state.dialogHandler(event)).then(() => {
|
|
1948
|
+
if (!handled) {
|
|
1949
|
+
dialog.dismiss().catch((err) => {
|
|
1950
|
+
console.warn(
|
|
1951
|
+
`[browserclaw] Failed to auto-dismiss dialog: ${err instanceof Error ? err.message : String(err)}`
|
|
1952
|
+
);
|
|
1953
|
+
});
|
|
1954
|
+
}
|
|
1955
|
+
}).catch((err) => {
|
|
1956
|
+
console.warn(`[browserclaw] onDialog handler error: ${err instanceof Error ? err.message : String(err)}`);
|
|
1957
|
+
if (!handled) {
|
|
1958
|
+
dialog.dismiss().catch((dismissErr) => {
|
|
1959
|
+
console.warn(
|
|
1960
|
+
`[browserclaw] Failed to dismiss dialog after handler error: ${dismissErr instanceof Error ? dismissErr.message : String(dismissErr)}`
|
|
1961
|
+
);
|
|
1962
|
+
});
|
|
1963
|
+
}
|
|
1964
|
+
});
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1932
1967
|
dialog.dismiss().catch((err) => {
|
|
1933
1968
|
console.warn(`[browserclaw] Failed to dismiss dialog: ${err instanceof Error ? err.message : String(err)}`);
|
|
1934
1969
|
});
|
|
@@ -1940,6 +1975,11 @@ function ensurePageState(page) {
|
|
|
1940
1975
|
}
|
|
1941
1976
|
return state;
|
|
1942
1977
|
}
|
|
1978
|
+
async function setDialogHandler(opts) {
|
|
1979
|
+
const page = await getPageForTargetId({ cdpUrl: opts.cdpUrl, targetId: opts.targetId });
|
|
1980
|
+
const state = ensurePageState(page);
|
|
1981
|
+
state.dialogHandler = opts.handler;
|
|
1982
|
+
}
|
|
1943
1983
|
function applyStealthToPage(page) {
|
|
1944
1984
|
page.evaluate(STEALTH_SCRIPT).catch((e) => {
|
|
1945
1985
|
if (process.env.DEBUG !== void 0 && process.env.DEBUG !== "")
|
|
@@ -2543,7 +2583,17 @@ var BLOCKED_IPV4_RANGES = /* @__PURE__ */ new Set([
|
|
|
2543
2583
|
"private",
|
|
2544
2584
|
"reserved"
|
|
2545
2585
|
]);
|
|
2546
|
-
var BLOCKED_IPV6_RANGES = /* @__PURE__ */ new Set([
|
|
2586
|
+
var BLOCKED_IPV6_RANGES = /* @__PURE__ */ new Set([
|
|
2587
|
+
"unspecified",
|
|
2588
|
+
"loopback",
|
|
2589
|
+
"linkLocal",
|
|
2590
|
+
"uniqueLocal",
|
|
2591
|
+
"multicast",
|
|
2592
|
+
"reserved",
|
|
2593
|
+
"benchmarking",
|
|
2594
|
+
"discard",
|
|
2595
|
+
"orchid2"
|
|
2596
|
+
]);
|
|
2547
2597
|
var RFC2544_BENCHMARK_PREFIX = [ipaddr.IPv4.parse("198.18.0.0"), 15];
|
|
2548
2598
|
var EMBEDDED_IPV4_SENTINEL_RULES = [
|
|
2549
2599
|
// IPv4-compatible (::a.b.c.d)
|
|
@@ -4207,6 +4257,7 @@ var CONTENT_ROLES = /* @__PURE__ */ new Set([
|
|
|
4207
4257
|
var STRUCTURAL_ROLES = /* @__PURE__ */ new Set([
|
|
4208
4258
|
"generic",
|
|
4209
4259
|
"group",
|
|
4260
|
+
"ignored",
|
|
4210
4261
|
"list",
|
|
4211
4262
|
"table",
|
|
4212
4263
|
"row",
|
|
@@ -4822,6 +4873,32 @@ var CrawlPage = class {
|
|
|
4822
4873
|
timeoutMs: opts?.timeoutMs
|
|
4823
4874
|
});
|
|
4824
4875
|
}
|
|
4876
|
+
/**
|
|
4877
|
+
* Click an element by CSS selector (no snapshot/ref needed).
|
|
4878
|
+
*
|
|
4879
|
+
* Finds and clicks atomically — no stale ref problem.
|
|
4880
|
+
*
|
|
4881
|
+
* @param selector - CSS selector (e.g. `'#submit-btn'`, `'.modal button'`)
|
|
4882
|
+
* @param opts - Click options (double-click, button, modifiers)
|
|
4883
|
+
*
|
|
4884
|
+
* @example
|
|
4885
|
+
* ```ts
|
|
4886
|
+
* await page.clickBySelector('#submit-btn');
|
|
4887
|
+
* await page.clickBySelector('.modal .close', { button: 'right' });
|
|
4888
|
+
* ```
|
|
4889
|
+
*/
|
|
4890
|
+
async clickBySelector(selector, opts) {
|
|
4891
|
+
return clickViaPlaywright({
|
|
4892
|
+
cdpUrl: this.cdpUrl,
|
|
4893
|
+
targetId: this.targetId,
|
|
4894
|
+
selector,
|
|
4895
|
+
doubleClick: opts?.doubleClick,
|
|
4896
|
+
button: opts?.button,
|
|
4897
|
+
modifiers: opts?.modifiers,
|
|
4898
|
+
delayMs: opts?.delayMs,
|
|
4899
|
+
timeoutMs: opts?.timeoutMs
|
|
4900
|
+
});
|
|
4901
|
+
}
|
|
4825
4902
|
/**
|
|
4826
4903
|
* Click at specific page coordinates.
|
|
4827
4904
|
*
|
|
@@ -5065,6 +5142,48 @@ var CrawlPage = class {
|
|
|
5065
5142
|
timeoutMs: opts.timeoutMs
|
|
5066
5143
|
});
|
|
5067
5144
|
}
|
|
5145
|
+
/**
|
|
5146
|
+
* Register a persistent dialog handler for all dialogs (alert, confirm, prompt, beforeunload).
|
|
5147
|
+
*
|
|
5148
|
+
* Unlike `armDialog()` which handles a single expected dialog, `onDialog()` handles
|
|
5149
|
+
* every dialog that appears until cleared. This prevents unexpected dialogs from
|
|
5150
|
+
* blocking the page.
|
|
5151
|
+
*
|
|
5152
|
+
* The handler receives a `DialogEvent` with `accept()` and `dismiss()` methods.
|
|
5153
|
+
* If the handler throws or doesn't call either, the dialog is auto-dismissed.
|
|
5154
|
+
*
|
|
5155
|
+
* Pass `undefined` or `null` to clear the handler and restore default auto-dismiss.
|
|
5156
|
+
*
|
|
5157
|
+
* Note: `armDialog()` takes priority — if a one-shot handler is armed, it handles
|
|
5158
|
+
* the next dialog instead of the persistent handler.
|
|
5159
|
+
*
|
|
5160
|
+
* @param handler - Callback for dialog events, or `undefined`/`null` to clear
|
|
5161
|
+
*
|
|
5162
|
+
* @example
|
|
5163
|
+
* ```ts
|
|
5164
|
+
* // Accept all confirm dialogs, dismiss everything else
|
|
5165
|
+
* page.onDialog((event) => {
|
|
5166
|
+
* if (event.type === 'confirm') event.accept();
|
|
5167
|
+
* else event.dismiss();
|
|
5168
|
+
* });
|
|
5169
|
+
*
|
|
5170
|
+
* // Log and auto-accept all dialogs
|
|
5171
|
+
* page.onDialog(async (event) => {
|
|
5172
|
+
* console.log(`Dialog: ${event.type} — ${event.message}`);
|
|
5173
|
+
* await event.accept();
|
|
5174
|
+
* });
|
|
5175
|
+
*
|
|
5176
|
+
* // Clear the handler (restore default auto-dismiss)
|
|
5177
|
+
* page.onDialog(undefined);
|
|
5178
|
+
* ```
|
|
5179
|
+
*/
|
|
5180
|
+
async onDialog(handler) {
|
|
5181
|
+
return setDialogHandler({
|
|
5182
|
+
cdpUrl: this.cdpUrl,
|
|
5183
|
+
targetId: this.targetId,
|
|
5184
|
+
handler: handler ?? void 0
|
|
5185
|
+
});
|
|
5186
|
+
}
|
|
5068
5187
|
/**
|
|
5069
5188
|
* Arm a one-shot file chooser handler.
|
|
5070
5189
|
*
|
|
@@ -5732,6 +5851,58 @@ var CrawlPage = class {
|
|
|
5732
5851
|
pollMs: opts?.pollMs
|
|
5733
5852
|
});
|
|
5734
5853
|
}
|
|
5854
|
+
// ── Playwright Escape Hatches ─────────────────────────────────
|
|
5855
|
+
/**
|
|
5856
|
+
* Get the underlying Playwright `Page` object for this tab.
|
|
5857
|
+
*
|
|
5858
|
+
* Use this when browserclaw's API doesn't cover your use case and you need
|
|
5859
|
+
* direct access to Playwright's full API (custom locator strategies,
|
|
5860
|
+
* frame manipulation, request interception, etc.).
|
|
5861
|
+
*
|
|
5862
|
+
* **Warning:** Modifications made via the raw Playwright page may conflict
|
|
5863
|
+
* with browserclaw's internal state (e.g. ref tracking). Use with care.
|
|
5864
|
+
*
|
|
5865
|
+
* @returns The Playwright `Page` instance
|
|
5866
|
+
*
|
|
5867
|
+
* @example
|
|
5868
|
+
* ```ts
|
|
5869
|
+
* const pwPage = await page.playwrightPage();
|
|
5870
|
+
*
|
|
5871
|
+
* // Use Playwright's full API directly
|
|
5872
|
+
* await pwPage.locator('.my-component').waitFor({ state: 'visible' });
|
|
5873
|
+
* await pwPage.route('**\/api/**', route => route.fulfill({ body: '{}' }));
|
|
5874
|
+
*
|
|
5875
|
+
* // Access frames
|
|
5876
|
+
* const frame = pwPage.frameLocator('#my-iframe');
|
|
5877
|
+
* ```
|
|
5878
|
+
*/
|
|
5879
|
+
async playwrightPage() {
|
|
5880
|
+
return getRestoredPageForTarget({ cdpUrl: this.cdpUrl, targetId: this.targetId });
|
|
5881
|
+
}
|
|
5882
|
+
/**
|
|
5883
|
+
* Create a Playwright `Locator` for a CSS selector on this page.
|
|
5884
|
+
*
|
|
5885
|
+
* Convenience method that returns a Playwright locator without needing
|
|
5886
|
+
* to first obtain the Page object. Useful for one-off Playwright operations.
|
|
5887
|
+
*
|
|
5888
|
+
* @param selector - CSS selector or Playwright selector string
|
|
5889
|
+
* @returns A Playwright `Locator` instance
|
|
5890
|
+
*
|
|
5891
|
+
* @example
|
|
5892
|
+
* ```ts
|
|
5893
|
+
* const loc = await page.locator('.modal-dialog button.confirm');
|
|
5894
|
+
* await loc.waitFor({ state: 'visible' });
|
|
5895
|
+
* await loc.click();
|
|
5896
|
+
*
|
|
5897
|
+
* // Use Playwright selectors
|
|
5898
|
+
* const input = await page.locator('input[name="email"]');
|
|
5899
|
+
* await input.fill('test@example.com');
|
|
5900
|
+
* ```
|
|
5901
|
+
*/
|
|
5902
|
+
async locator(selector) {
|
|
5903
|
+
const pwPage = await getRestoredPageForTarget({ cdpUrl: this.cdpUrl, targetId: this.targetId });
|
|
5904
|
+
return pwPage.locator(selector);
|
|
5905
|
+
}
|
|
5735
5906
|
};
|
|
5736
5907
|
var BrowserClaw = class _BrowserClaw {
|
|
5737
5908
|
cdpUrl;
|
|
@@ -5925,6 +6096,7 @@ exports.resolvePageByTargetIdOrThrow = resolvePageByTargetIdOrThrow;
|
|
|
5925
6096
|
exports.resolvePinnedHostnameWithPolicy = resolvePinnedHostnameWithPolicy;
|
|
5926
6097
|
exports.resolveStrictExistingUploadPaths = resolveStrictExistingUploadPaths;
|
|
5927
6098
|
exports.sanitizeUntrustedFileName = sanitizeUntrustedFileName;
|
|
6099
|
+
exports.setDialogHandler = setDialogHandler;
|
|
5928
6100
|
exports.waitForChallengeViaPlaywright = waitForChallengeViaPlaywright;
|
|
5929
6101
|
exports.withBrowserNavigationPolicy = withBrowserNavigationPolicy;
|
|
5930
6102
|
exports.withPageScopedCdpClient = withPageScopedCdpClient;
|