browserclaw 0.11.3 → 0.11.4

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 CHANGED
@@ -1319,7 +1319,10 @@ function normalizeCdpHttpBaseForJsonEndpoints(cdpUrl) {
1319
1319
  url.pathname = url.pathname.replace(/\/cdp$/, "");
1320
1320
  return url.toString().replace(/\/$/, "");
1321
1321
  } catch {
1322
- return cdpUrl.replace(/^ws:/, "http:").replace(/^wss:/, "https:").replace(/\/devtools\/browser\/.*$/, "").replace(/\/cdp$/, "").replace(/\/$/, "");
1322
+ let normalized = cdpUrl.replace(/^ws:/, "http:").replace(/^wss:/, "https:");
1323
+ const dtIdx = normalized.indexOf("/devtools/browser/");
1324
+ if (dtIdx >= 0) normalized = normalized.slice(0, dtIdx);
1325
+ return normalized.replace(/\/cdp$/, "").replace(/\/$/, "");
1323
1326
  }
1324
1327
  }
1325
1328
  function appendCdpPath(cdpUrl, cdpPath) {
@@ -1790,20 +1793,17 @@ var pageStates = /* @__PURE__ */ new WeakMap();
1790
1793
  var contextStates = /* @__PURE__ */ new WeakMap();
1791
1794
  var observedContexts = /* @__PURE__ */ new WeakSet();
1792
1795
  var observedPages = /* @__PURE__ */ new WeakSet();
1793
- var nextUploadArmId = 0;
1794
- var nextDialogArmId = 0;
1795
- var nextDownloadArmId = 0;
1796
- function bumpUploadArmId() {
1797
- nextUploadArmId += 1;
1798
- return nextUploadArmId;
1796
+ function bumpUploadArmId(state) {
1797
+ state.nextArmIdUpload += 1;
1798
+ return state.nextArmIdUpload;
1799
1799
  }
1800
- function bumpDialogArmId() {
1801
- nextDialogArmId += 1;
1802
- return nextDialogArmId;
1800
+ function bumpDialogArmId(state) {
1801
+ state.nextArmIdDialog += 1;
1802
+ return state.nextArmIdDialog;
1803
1803
  }
1804
- function bumpDownloadArmId() {
1805
- nextDownloadArmId += 1;
1806
- return nextDownloadArmId;
1804
+ function bumpDownloadArmId(state) {
1805
+ state.nextArmIdDownload += 1;
1806
+ return state.nextArmIdDownload;
1807
1807
  }
1808
1808
  function ensureContextState(context) {
1809
1809
  const existing = contextStates.get(context);
@@ -1833,7 +1833,10 @@ function ensurePageState(page) {
1833
1833
  nextRequestId: 0,
1834
1834
  armIdUpload: 0,
1835
1835
  armIdDialog: 0,
1836
- armIdDownload: 0
1836
+ armIdDownload: 0,
1837
+ nextArmIdUpload: 0,
1838
+ nextArmIdDialog: 0,
1839
+ nextArmIdDownload: 0
1837
1840
  };
1838
1841
  pageStates.set(page, state);
1839
1842
  if (!observedPages.has(page)) {
@@ -2162,51 +2165,41 @@ function isLoopbackCdpUrl(url) {
2162
2165
  return false;
2163
2166
  }
2164
2167
  }
2165
- var NoProxyLeaseManager = class {
2166
- leaseCount = 0;
2167
- snapshot = null;
2168
- acquire(url) {
2169
- if (!isLoopbackCdpUrl(url) || !hasProxyEnvConfigured()) return null;
2170
- if (this.leaseCount === 0 && !noProxyAlreadyCoversLocalhost()) {
2171
- const noProxy = process.env.NO_PROXY;
2172
- const noProxyLower = process.env.no_proxy;
2173
- const current = noProxy ?? noProxyLower ?? "";
2174
- const applied = current ? `${current},${LOOPBACK_ENTRIES}` : LOOPBACK_ENTRIES;
2175
- process.env.NO_PROXY = applied;
2176
- process.env.no_proxy = applied;
2177
- this.snapshot = { noProxy, noProxyLower, applied };
2178
- }
2179
- this.leaseCount += 1;
2180
- let released = false;
2181
- return () => {
2182
- if (released) return;
2183
- released = true;
2184
- this.release();
2185
- };
2186
- }
2187
- release() {
2188
- if (this.leaseCount <= 0) return;
2189
- this.leaseCount -= 1;
2190
- if (this.leaseCount > 0 || !this.snapshot) return;
2191
- const { noProxy, noProxyLower, applied } = this.snapshot;
2192
- const currentNoProxy = process.env.NO_PROXY;
2193
- const currentNoProxyLower = process.env.no_proxy;
2194
- if (currentNoProxy === applied && (currentNoProxyLower === applied || currentNoProxyLower === void 0)) {
2195
- if (noProxy !== void 0) process.env.NO_PROXY = noProxy;
2196
- else delete process.env.NO_PROXY;
2197
- if (noProxyLower !== void 0) process.env.no_proxy = noProxyLower;
2198
- else delete process.env.no_proxy;
2168
+ var envMutexPromise = Promise.resolve();
2169
+ async function withNoProxyForCdpUrl(url, fn) {
2170
+ if (!isLoopbackCdpUrl(url) || !hasProxyEnvConfigured()) return fn();
2171
+ const prev = envMutexPromise;
2172
+ let release = () => {
2173
+ };
2174
+ envMutexPromise = new Promise((r) => {
2175
+ release = r;
2176
+ });
2177
+ await prev;
2178
+ if (noProxyAlreadyCoversLocalhost()) {
2179
+ try {
2180
+ return await fn();
2181
+ } finally {
2182
+ release();
2199
2183
  }
2200
- this.snapshot = null;
2201
2184
  }
2202
- };
2203
- var noProxyLeaseManager = new NoProxyLeaseManager();
2204
- async function withNoProxyForCdpUrl(url, fn) {
2205
- const release = noProxyLeaseManager.acquire(url);
2185
+ const savedNoProxy = process.env.NO_PROXY;
2186
+ const savedNoProxyLower = process.env.no_proxy;
2187
+ const current = savedNoProxy ?? savedNoProxyLower ?? "";
2188
+ const applied = current ? `${current},${LOOPBACK_ENTRIES}` : LOOPBACK_ENTRIES;
2189
+ process.env.NO_PROXY = applied;
2190
+ process.env.no_proxy = applied;
2206
2191
  try {
2207
2192
  return await fn();
2208
2193
  } finally {
2209
- release?.();
2194
+ if (process.env.NO_PROXY === applied) {
2195
+ if (savedNoProxy !== void 0) process.env.NO_PROXY = savedNoProxy;
2196
+ else delete process.env.NO_PROXY;
2197
+ }
2198
+ if (process.env.no_proxy === applied) {
2199
+ if (savedNoProxyLower !== void 0) process.env.no_proxy = savedNoProxyLower;
2200
+ else delete process.env.no_proxy;
2201
+ }
2202
+ release();
2210
2203
  }
2211
2204
  }
2212
2205
  new http__default.default.Agent();
@@ -2436,7 +2429,7 @@ async function tryTerminateExecutionViaCdp(cdpUrl, targetId) {
2436
2429
  };
2437
2430
  });
2438
2431
  }
2439
- async function forceDisconnectPlaywrightForTarget(opts) {
2432
+ async function forceDisconnectPlaywrightConnection(opts) {
2440
2433
  const normalized = normalizeCdpUrl(opts.cdpUrl);
2441
2434
  const cur = cachedByCdpUrl.get(normalized);
2442
2435
  if (!cur) return;
@@ -2453,6 +2446,7 @@ async function forceDisconnectPlaywrightForTarget(opts) {
2453
2446
  cur.browser.close().catch(() => {
2454
2447
  });
2455
2448
  }
2449
+ var forceDisconnectPlaywrightForTarget = forceDisconnectPlaywrightConnection;
2456
2450
  function getAllPages(browser) {
2457
2451
  return browser.contexts().flatMap((c) => c.pages());
2458
2452
  }
@@ -2685,7 +2679,7 @@ async function evaluateViaPlaywright(opts) {
2685
2679
  }
2686
2680
  if (signal !== void 0) {
2687
2681
  const disconnect = () => {
2688
- forceDisconnectPlaywrightForTarget({
2682
+ forceDisconnectPlaywrightConnection({
2689
2683
  cdpUrl: opts.cdpUrl,
2690
2684
  targetId: opts.targetId}).catch(() => {
2691
2685
  });
@@ -2752,7 +2746,6 @@ function withBrowserNavigationPolicy(ssrfPolicy) {
2752
2746
  }
2753
2747
  var NETWORK_NAVIGATION_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
2754
2748
  var SAFE_NON_NETWORK_URLS = /* @__PURE__ */ new Set(["about:blank"]);
2755
- var PROXY_ENV_KEYS2 = ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "http_proxy", "https_proxy", "all_proxy"];
2756
2749
  var BLOCKED_HOSTNAMES = /* @__PURE__ */ new Set(["localhost", "localhost.localdomain", "metadata.google.internal"]);
2757
2750
  function isAllowedNonNetworkNavigationUrl(parsed) {
2758
2751
  return SAFE_NON_NETWORK_URLS.has(parsed.href);
@@ -2760,13 +2753,6 @@ function isAllowedNonNetworkNavigationUrl(parsed) {
2760
2753
  function isPrivateNetworkAllowedByPolicy(policy) {
2761
2754
  return policy?.dangerouslyAllowPrivateNetwork === true || policy?.allowPrivateNetwork === true;
2762
2755
  }
2763
- function hasProxyEnvConfigured2(env = process.env) {
2764
- for (const key of PROXY_ENV_KEYS2) {
2765
- const value = env[key];
2766
- if (typeof value === "string" && value.trim().length > 0) return true;
2767
- }
2768
- return false;
2769
- }
2770
2756
  function normalizeHostname(hostname) {
2771
2757
  let h = hostname.trim().toLowerCase();
2772
2758
  if (h.startsWith("[") && h.endsWith("]")) h = h.slice(1, -1);
@@ -3077,7 +3063,7 @@ async function assertBrowserNavigationAllowed(opts) {
3077
3063
  if (isAllowedNonNetworkNavigationUrl(parsed)) return;
3078
3064
  throw new InvalidBrowserNavigationUrlError(`Navigation blocked: unsupported protocol "${parsed.protocol}"`);
3079
3065
  }
3080
- if (hasProxyEnvConfigured2() && !isPrivateNetworkAllowedByPolicy(opts.ssrfPolicy)) {
3066
+ if (hasProxyEnvConfigured() && !isPrivateNetworkAllowedByPolicy(opts.ssrfPolicy)) {
3081
3067
  throw new InvalidBrowserNavigationUrlError(
3082
3068
  "Navigation blocked: strict browser SSRF policy cannot be enforced while env proxy variables are set"
3083
3069
  );
@@ -3532,7 +3518,7 @@ async function armDialogViaPlaywright(opts) {
3532
3518
  const page = await getPageForTargetId({ cdpUrl: opts.cdpUrl, targetId: opts.targetId });
3533
3519
  const state = ensurePageState(page);
3534
3520
  const timeout = normalizeTimeoutMs(opts.timeoutMs, 12e4);
3535
- state.armIdDialog = bumpDialogArmId();
3521
+ state.armIdDialog = bumpDialogArmId(state);
3536
3522
  const armId = state.armIdDialog;
3537
3523
  page.waitForEvent("dialog", { timeout }).then(async (dialog) => {
3538
3524
  if (state.armIdDialog !== armId) return;
@@ -3550,7 +3536,7 @@ async function armFileUploadViaPlaywright(opts) {
3550
3536
  const page = await getPageForTargetId({ cdpUrl: opts.cdpUrl, targetId: opts.targetId });
3551
3537
  const state = ensurePageState(page);
3552
3538
  const timeout = normalizeTimeoutMs(opts.timeoutMs, 12e4);
3553
- state.armIdUpload = bumpUploadArmId();
3539
+ state.armIdUpload = bumpUploadArmId(state);
3554
3540
  const armId = state.armIdUpload;
3555
3541
  page.waitForEvent("filechooser", { timeout }).then(async (fileChooser) => {
3556
3542
  if (state.armIdUpload !== armId) return;
@@ -3710,7 +3696,7 @@ async function navigateViaPlaywright(opts) {
3710
3696
  response = await navigate();
3711
3697
  } catch (err) {
3712
3698
  if (!isRetryableNavigateError(err)) throw err;
3713
- await forceDisconnectPlaywrightForTarget({
3699
+ await forceDisconnectPlaywrightConnection({
3714
3700
  cdpUrl: opts.cdpUrl,
3715
3701
  targetId: opts.targetId}).catch(() => {
3716
3702
  });
@@ -3852,18 +3838,12 @@ async function resizeViewportViaPlaywright(opts) {
3852
3838
 
3853
3839
  // src/actions/wait.ts
3854
3840
  var MAX_WAIT_TIME_MS = 3e4;
3855
- function resolveBoundedDelayMs2(value, label, maxMs) {
3856
- const normalized = Math.floor(value ?? 0);
3857
- if (!Number.isFinite(normalized) || normalized < 0) throw new Error(`${label} must be >= 0`);
3858
- if (normalized > maxMs) throw new Error(`${label} exceeds maximum of ${String(maxMs)}ms`);
3859
- return normalized;
3860
- }
3861
3841
  async function waitForViaPlaywright(opts) {
3862
3842
  const page = await getPageForTargetId({ cdpUrl: opts.cdpUrl, targetId: opts.targetId });
3863
3843
  ensurePageState(page);
3864
3844
  const timeout = normalizeTimeoutMs(opts.timeoutMs, 2e4);
3865
3845
  if (typeof opts.timeMs === "number" && Number.isFinite(opts.timeMs)) {
3866
- await page.waitForTimeout(resolveBoundedDelayMs2(opts.timeMs, "wait timeMs", MAX_WAIT_TIME_MS));
3846
+ await page.waitForTimeout(resolveBoundedDelayMs(opts.timeMs, "wait timeMs", MAX_WAIT_TIME_MS));
3867
3847
  }
3868
3848
  if (opts.text !== void 0 && opts.text !== "") {
3869
3849
  await page.waitForFunction((text) => (document.body?.innerText ?? "").includes(text), opts.text, { timeout });
@@ -4120,7 +4100,7 @@ async function downloadViaPlaywright(opts) {
4120
4100
  const timeout = normalizeTimeoutMs(opts.timeoutMs, 12e4);
4121
4101
  const outPath = opts.path.trim();
4122
4102
  if (!outPath) throw new Error("path is required");
4123
- state.armIdDownload = bumpDownloadArmId();
4103
+ state.armIdDownload = bumpDownloadArmId(state);
4124
4104
  const armId = state.armIdDownload;
4125
4105
  const waiter = createPageDownloadWaiter(page, timeout);
4126
4106
  try {
@@ -4140,7 +4120,7 @@ async function waitForDownloadViaPlaywright(opts) {
4140
4120
  const page = await getPageForTargetId({ cdpUrl: opts.cdpUrl, targetId: opts.targetId });
4141
4121
  const state = ensurePageState(page);
4142
4122
  const timeout = normalizeTimeoutMs(opts.timeoutMs, 12e4);
4143
- state.armIdDownload = bumpDownloadArmId();
4123
+ state.armIdDownload = bumpDownloadArmId(state);
4144
4124
  const armId = state.armIdDownload;
4145
4125
  const waiter = createPageDownloadWaiter(page, timeout);
4146
4126
  try {
@@ -6591,6 +6571,7 @@ exports.createPinnedLookup = createPinnedLookup;
6591
6571
  exports.detectChallengeViaPlaywright = detectChallengeViaPlaywright;
6592
6572
  exports.ensureContextState = ensureContextState;
6593
6573
  exports.executeSingleAction = executeSingleAction;
6574
+ exports.forceDisconnectPlaywrightConnection = forceDisconnectPlaywrightConnection;
6594
6575
  exports.forceDisconnectPlaywrightForTarget = forceDisconnectPlaywrightForTarget;
6595
6576
  exports.getChromeWebSocketUrl = getChromeWebSocketUrl;
6596
6577
  exports.getRestoredPageForTarget = getRestoredPageForTarget;