browserclaw 0.2.5 → 0.2.7

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 CHANGED
@@ -1,7 +1,9 @@
1
- # browserclaw
1
+ <h2 align="center">🦞 BrowserClaw — Standalone OpenClaw browser module</h1>
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/browserclaw.svg)](https://www.npmjs.com/package/browserclaw)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
3
+ <p align="center">
4
+ <a href="https://www.npmjs.com/package/browserclaw"><img src="https://img.shields.io/npm/v/browserclaw.svg" alt="npm version" /></a>
5
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="License: MIT" /></a>
6
+ </p>
5
7
 
6
8
  Extracted and refined from [OpenClaw](https://github.com/openclaw/openclaw)'s browser automation module. A standalone, typed library for AI-friendly browser control with **snapshot + ref targeting** — no CSS selectors, no XPath, no vision, just numbered refs that map to interactive elements.
7
9
 
package/dist/index.cjs CHANGED
@@ -408,7 +408,8 @@ async function launchChrome(opts = {}) {
408
408
  args.push("--no-sandbox", "--disable-setuid-sandbox");
409
409
  }
410
410
  if (process.platform === "linux") args.push("--disable-dev-shm-usage");
411
- if (opts.chromeArgs?.length) args.push(...opts.chromeArgs);
411
+ const extraArgs = Array.isArray(opts.chromeArgs) ? opts.chromeArgs.filter((a) => typeof a === "string" && a.trim().length > 0) : [];
412
+ if (extraArgs.length) args.push(...extraArgs);
412
413
  args.push("about:blank");
413
414
  return child_process.spawn(exe.path, args, {
414
415
  stdio: "pipe",
@@ -1405,7 +1406,76 @@ function assertSafeOutputPath(path2, allowedRoots) {
1405
1406
  }
1406
1407
  }
1407
1408
  }
1409
+ function expandIPv6(ip) {
1410
+ let normalized = ip;
1411
+ const v4Match = normalized.match(/^(.+:)(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/);
1412
+ if (v4Match) {
1413
+ const octets = v4Match[2].split(".").map(Number);
1414
+ if (octets.some((o) => o > 255)) return null;
1415
+ const hexHi = (octets[0] << 8 | octets[1]).toString(16).padStart(4, "0");
1416
+ const hexLo = (octets[2] << 8 | octets[3]).toString(16).padStart(4, "0");
1417
+ normalized = v4Match[1] + hexHi + ":" + hexLo;
1418
+ }
1419
+ const halves = normalized.split("::");
1420
+ if (halves.length > 2) return null;
1421
+ if (halves.length === 2) {
1422
+ const left = halves[0] !== "" ? halves[0].split(":") : [];
1423
+ const right = halves[1] !== "" ? halves[1].split(":") : [];
1424
+ const needed = 8 - left.length - right.length;
1425
+ if (needed < 0) return null;
1426
+ const groups2 = [...left, ...Array(needed).fill("0"), ...right];
1427
+ if (groups2.length !== 8) return null;
1428
+ return groups2.map((g) => g.padStart(4, "0")).join(":");
1429
+ }
1430
+ const groups = normalized.split(":");
1431
+ if (groups.length !== 8) return null;
1432
+ return groups.map((g) => g.padStart(4, "0")).join(":");
1433
+ }
1434
+ function hexToIPv4(hiHex, loHex) {
1435
+ const hi = parseInt(hiHex, 16);
1436
+ const lo = parseInt(loHex, 16);
1437
+ return `${hi >> 8 & 255}.${hi & 255}.${lo >> 8 & 255}.${lo & 255}`;
1438
+ }
1439
+ function extractEmbeddedIPv4(lower) {
1440
+ if (lower.startsWith("::ffff:")) {
1441
+ return lower.slice(7);
1442
+ }
1443
+ const expanded = expandIPv6(lower);
1444
+ if (expanded === null) return "";
1445
+ const groups = expanded.split(":");
1446
+ if (groups.length !== 8) return "";
1447
+ if (groups[0] === "0064" && groups[1] === "ff9b" && groups[2] === "0000" && groups[3] === "0000" && groups[4] === "0000" && groups[5] === "0000") {
1448
+ return hexToIPv4(groups[6], groups[7]);
1449
+ }
1450
+ if (groups[0] === "0064" && groups[1] === "ff9b" && groups[2] === "0001") {
1451
+ return hexToIPv4(groups[6], groups[7]);
1452
+ }
1453
+ if (groups[0] === "2002") {
1454
+ return hexToIPv4(groups[1], groups[2]);
1455
+ }
1456
+ if (groups[0] === "2001" && groups[1] === "0000") {
1457
+ const hiXored = (parseInt(groups[6], 16) ^ 65535).toString(16).padStart(4, "0");
1458
+ const loXored = (parseInt(groups[7], 16) ^ 65535).toString(16).padStart(4, "0");
1459
+ return hexToIPv4(hiXored, loXored);
1460
+ }
1461
+ return null;
1462
+ }
1463
+ function isStrictDecimalOctet(part) {
1464
+ if (!/^[0-9]+$/.test(part)) return false;
1465
+ const n = parseInt(part, 10);
1466
+ if (n < 0 || n > 255) return false;
1467
+ if (String(n) !== part) return false;
1468
+ return true;
1469
+ }
1470
+ function isUnsupportedIPv4Literal(ip) {
1471
+ if (/^[0-9]+$/.test(ip)) return true;
1472
+ const parts = ip.split(".");
1473
+ if (parts.length !== 4) return true;
1474
+ if (!parts.every(isStrictDecimalOctet)) return true;
1475
+ return false;
1476
+ }
1408
1477
  function isInternalIP(ip) {
1478
+ if (!ip.includes(":") && isUnsupportedIPv4Literal(ip)) return true;
1409
1479
  if (/^127\./.test(ip)) return true;
1410
1480
  if (/^10\./.test(ip)) return true;
1411
1481
  if (/^172\.(1[6-9]|2\d|3[01])\./.test(ip)) return true;
@@ -1417,9 +1487,10 @@ function isInternalIP(ip) {
1417
1487
  if (lower === "::1") return true;
1418
1488
  if (lower.startsWith("fe80:")) return true;
1419
1489
  if (lower.startsWith("fc") || lower.startsWith("fd")) return true;
1420
- if (lower.startsWith("::ffff:")) {
1421
- const v4 = lower.replace(/^::ffff:/, "");
1422
- return isInternalIP(v4);
1490
+ const embedded = extractEmbeddedIPv4(lower);
1491
+ if (embedded !== null) {
1492
+ if (embedded === "") return true;
1493
+ return isInternalIP(embedded);
1423
1494
  }
1424
1495
  return false;
1425
1496
  }