browserclaw 0.3.0 → 0.3.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.d.cts CHANGED
@@ -151,6 +151,13 @@ interface SnapshotOptions {
151
151
  * - `'role'` — uses Playwright's `ariaSnapshot()` + `getByRole()` resolution
152
152
  */
153
153
  mode?: 'role' | 'aria';
154
+ /**
155
+ * How refs are stored for role-mode snapshots.
156
+ * - `'role'` (default) — refs resolved via `getByRole()`
157
+ * - `'aria'` — refs resolved via aria snapshot index
158
+ * Only applies when `mode: 'role'`.
159
+ */
160
+ refsMode?: 'role' | 'aria';
154
161
  }
155
162
  /** A node in the raw ARIA accessibility tree. */
156
163
  interface AriaNode {
package/dist/index.d.ts CHANGED
@@ -151,6 +151,13 @@ interface SnapshotOptions {
151
151
  * - `'role'` — uses Playwright's `ariaSnapshot()` + `getByRole()` resolution
152
152
  */
153
153
  mode?: 'role' | 'aria';
154
+ /**
155
+ * How refs are stored for role-mode snapshots.
156
+ * - `'role'` (default) — refs resolved via `getByRole()`
157
+ * - `'aria'` — refs resolved via aria snapshot index
158
+ * Only applies when `mode: 'role'`.
159
+ */
160
+ refsMode?: 'role' | 'aria';
154
161
  }
155
162
  /** A node in the raw ARIA accessibility tree. */
156
163
  interface AriaNode {
package/dist/index.js CHANGED
@@ -1104,7 +1104,7 @@ async function snapshotRole(opts) {
1104
1104
  targetId: opts.targetId,
1105
1105
  refs: built.refs,
1106
1106
  frameSelector: frameSelector || void 0,
1107
- mode: "role"
1107
+ mode: opts.refsMode ?? "role"
1108
1108
  });
1109
1109
  return {
1110
1110
  snapshot: built.snapshot,
@@ -1387,7 +1387,20 @@ var InvalidBrowserNavigationUrlError = class extends Error {
1387
1387
  function withBrowserNavigationPolicy(ssrfPolicy) {
1388
1388
  return { ssrfPolicy };
1389
1389
  }
1390
+ var NETWORK_NAVIGATION_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
1391
+ var SAFE_NON_NETWORK_URLS = /* @__PURE__ */ new Set(["about:blank"]);
1390
1392
  async function assertBrowserNavigationAllowed(opts) {
1393
+ const rawUrl = String(opts.url ?? "").trim();
1394
+ let parsed;
1395
+ try {
1396
+ parsed = new URL(rawUrl);
1397
+ } catch {
1398
+ throw new InvalidBrowserNavigationUrlError(`Invalid URL: "${rawUrl}"`);
1399
+ }
1400
+ if (!NETWORK_NAVIGATION_PROTOCOLS.has(parsed.protocol)) {
1401
+ if (SAFE_NON_NETWORK_URLS.has(parsed.href)) return;
1402
+ throw new InvalidBrowserNavigationUrlError(`Navigation blocked: unsupported protocol "${parsed.protocol}"`);
1403
+ }
1391
1404
  const policy = opts.ssrfPolicy;
1392
1405
  if (policy?.allowPrivateNetwork) return;
1393
1406
  const allowedHostnames = [
@@ -1395,18 +1408,12 @@ async function assertBrowserNavigationAllowed(opts) {
1395
1408
  ...policy?.hostnameAllowlist ?? []
1396
1409
  ];
1397
1410
  if (allowedHostnames.length) {
1398
- let parsed;
1399
- try {
1400
- parsed = new URL(opts.url);
1401
- } catch {
1402
- throw new InvalidBrowserNavigationUrlError(`Invalid URL: "${opts.url}"`);
1403
- }
1404
1411
  const hostname = parsed.hostname.toLowerCase();
1405
1412
  if (allowedHostnames.some((h) => h.toLowerCase() === hostname)) return;
1406
1413
  }
1407
- if (await isInternalUrlResolved(opts.url, opts.lookupFn)) {
1414
+ if (await isInternalUrlResolved(rawUrl, opts.lookupFn)) {
1408
1415
  throw new InvalidBrowserNavigationUrlError(
1409
- `Navigation to internal/loopback address blocked: "${opts.url}". Use ssrfPolicy: { allowPrivateNetwork: true } if this is intentional.`
1416
+ `Navigation to internal/loopback address blocked: "${rawUrl}". Use ssrfPolicy: { allowPrivateNetwork: true } if this is intentional.`
1410
1417
  );
1411
1418
  }
1412
1419
  }
@@ -2136,6 +2143,7 @@ var CrawlPage = class {
2136
2143
  targetId: this.targetId,
2137
2144
  selector: opts.selector,
2138
2145
  frameSelector: opts.frameSelector,
2146
+ refsMode: opts.refsMode,
2139
2147
  options: {
2140
2148
  interactive: opts.interactive,
2141
2149
  compact: opts.compact,