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 +58 -77
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.js +58 -78
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
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
|
-
|
|
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
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
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
|
-
|
|
1802
|
-
return
|
|
1800
|
+
function bumpDialogArmId(state) {
|
|
1801
|
+
state.nextArmIdDialog += 1;
|
|
1802
|
+
return state.nextArmIdDialog;
|
|
1803
1803
|
}
|
|
1804
|
-
function bumpDownloadArmId() {
|
|
1805
|
-
|
|
1806
|
-
return
|
|
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
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
}
|
|
2179
|
-
|
|
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
|
-
|
|
2204
|
-
|
|
2205
|
-
const
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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 (
|
|
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
|
|
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(
|
|
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;
|