@xbrowser/cli 1.0.4 → 1.0.6
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/{browser-ITLZZDHJ.js → browser-AXCKBSWS.js} +2 -2
- package/dist/{browser-5CTOA2WS.js → browser-U4VWPTS2.js} +1 -1
- package/dist/{browser-IUJXXNBT.js → browser-X7OVRKJH.js} +2 -2
- package/dist/{cdp-driver-4X3DK6PS.js → cdp-driver-CWNZVWHX.js} +18 -4
- package/dist/{cdp-driver-D6WMSMWX.js → cdp-driver-ZAVN7GRB.js} +1 -1
- package/dist/{chunk-TWWOIJM7.js → chunk-5QAYN5EZ.js} +10 -1
- package/dist/{chunk-DKWR54XQ.js → chunk-7POCCXIB.js} +27 -4
- package/dist/{chunk-LRBSUKUZ.js → chunk-MXG2H3HJ.js} +10 -1
- package/dist/{chunk-N2JFPWMI.js → chunk-SEFIJY2M.js} +18 -4
- package/dist/cli.js +57 -17
- package/dist/daemon-main.js +15 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +58 -18
- package/dist/{session-replayer-MY27H4DX.js → session-replayer-GCGY6KFK.js} +1 -1
- package/package.json +1 -1
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
saveSessionDiskMeta,
|
|
21
21
|
setActivePage,
|
|
22
22
|
touchSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-MXG2H3HJ.js";
|
|
24
|
+
import "./chunk-SEFIJY2M.js";
|
|
25
25
|
import "./chunk-TNEN6VQ2.js";
|
|
26
26
|
import "./chunk-GDKLH7ZY.js";
|
|
27
27
|
import "./chunk-KFQGP6VL.js";
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
saveSessionDiskMeta,
|
|
21
21
|
setActivePage,
|
|
22
22
|
touchSession
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-5QAYN5EZ.js";
|
|
24
|
+
import "./chunk-SEFIJY2M.js";
|
|
25
25
|
import "./chunk-TNEN6VQ2.js";
|
|
26
26
|
import "./chunk-GDKLH7ZY.js";
|
|
27
27
|
import "./chunk-ABXMBNQ6.js";
|
|
@@ -2179,8 +2179,14 @@ var XBContextImpl = class {
|
|
|
2179
2179
|
// ── Cookies ─────────────────────────────────────────────────
|
|
2180
2180
|
async cookies(urls) {
|
|
2181
2181
|
const urlList = typeof urls === "string" ? [urls] : urls;
|
|
2182
|
-
const
|
|
2183
|
-
|
|
2182
|
+
const params = urlList ? { urls: urlList } : void 0;
|
|
2183
|
+
try {
|
|
2184
|
+
const result = await this.conn.send("Storage.getCookies", params);
|
|
2185
|
+
return result.cookies;
|
|
2186
|
+
} catch {
|
|
2187
|
+
const result = await this.conn.send("Network.getCookies", params);
|
|
2188
|
+
return result.cookies;
|
|
2189
|
+
}
|
|
2184
2190
|
}
|
|
2185
2191
|
async addCookies(cookies) {
|
|
2186
2192
|
const cdpCookies = cookies.map((c) => ({
|
|
@@ -2193,10 +2199,18 @@ var XBContextImpl = class {
|
|
|
2193
2199
|
secure: c.secure,
|
|
2194
2200
|
sameSite: c.sameSite
|
|
2195
2201
|
}));
|
|
2196
|
-
|
|
2202
|
+
try {
|
|
2203
|
+
await this.conn.send("Storage.setCookies", { cookies: cdpCookies });
|
|
2204
|
+
} catch {
|
|
2205
|
+
await this.conn.send("Network.setCookies", { cookies: cdpCookies });
|
|
2206
|
+
}
|
|
2197
2207
|
}
|
|
2198
2208
|
async clearCookies() {
|
|
2199
|
-
|
|
2209
|
+
try {
|
|
2210
|
+
await this.conn.send("Storage.clearCookies");
|
|
2211
|
+
} catch {
|
|
2212
|
+
await this.conn.send("Network.clearBrowserCookies");
|
|
2213
|
+
}
|
|
2200
2214
|
}
|
|
2201
2215
|
on(event, handler) {
|
|
2202
2216
|
this._emitter.on(event, handler);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
launch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SEFIJY2M.js";
|
|
4
4
|
import {
|
|
5
5
|
errMsg
|
|
6
6
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -36,6 +36,15 @@ async function fetchNoProxy(url) {
|
|
|
36
36
|
async function resolveCDPEndpoint(raw) {
|
|
37
37
|
if (raw === "auto") {
|
|
38
38
|
const httpResp = await fetchNoProxy("http://localhost:9222/json/version");
|
|
39
|
+
if (!httpResp.ok) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`CDP port 9222 responded with ${httpResp.status} ${httpResp.statusText}. \u53EF\u80FD\u539F\u56E0\uFF1A9222 \u88AB\u50F5\u6B7B\u7684 Chrome \u5360\u7528\uFF0C\u6216\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
|
|
42
|
+
\u89E3\u51B3\u65B9\u6CD5\uFF1A
|
|
43
|
+
1. \u6740\u6389\u6B8B\u7559 Chrome: pkill -f "remote-debugging-port"
|
|
44
|
+
2. \u91CD\u542F Chrome: npx cdp-tunnel setup
|
|
45
|
+
3. \u6216\u6307\u5B9A\u7AEF\u53E3: --cdp <port>`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
39
48
|
const data = await httpResp.json();
|
|
40
49
|
if (!data.webSocketDebuggerUrl) {
|
|
41
50
|
throw new Error("Could not auto-discover CDP endpoint from localhost:9222");
|
|
@@ -2184,8 +2184,14 @@ var XBContextImpl = class {
|
|
|
2184
2184
|
// ── Cookies ─────────────────────────────────────────────────
|
|
2185
2185
|
async cookies(urls) {
|
|
2186
2186
|
const urlList = typeof urls === "string" ? [urls] : urls;
|
|
2187
|
-
const
|
|
2188
|
-
|
|
2187
|
+
const params = urlList ? { urls: urlList } : void 0;
|
|
2188
|
+
try {
|
|
2189
|
+
const result = await this.conn.send("Storage.getCookies", params);
|
|
2190
|
+
return result.cookies;
|
|
2191
|
+
} catch {
|
|
2192
|
+
const result = await this.conn.send("Network.getCookies", params);
|
|
2193
|
+
return result.cookies;
|
|
2194
|
+
}
|
|
2189
2195
|
}
|
|
2190
2196
|
async addCookies(cookies) {
|
|
2191
2197
|
const cdpCookies = cookies.map((c) => ({
|
|
@@ -2198,10 +2204,18 @@ var XBContextImpl = class {
|
|
|
2198
2204
|
secure: c.secure,
|
|
2199
2205
|
sameSite: c.sameSite
|
|
2200
2206
|
}));
|
|
2201
|
-
|
|
2207
|
+
try {
|
|
2208
|
+
await this.conn.send("Storage.setCookies", { cookies: cdpCookies });
|
|
2209
|
+
} catch {
|
|
2210
|
+
await this.conn.send("Network.setCookies", { cookies: cdpCookies });
|
|
2211
|
+
}
|
|
2202
2212
|
}
|
|
2203
2213
|
async clearCookies() {
|
|
2204
|
-
|
|
2214
|
+
try {
|
|
2215
|
+
await this.conn.send("Storage.clearCookies");
|
|
2216
|
+
} catch {
|
|
2217
|
+
await this.conn.send("Network.clearBrowserCookies");
|
|
2218
|
+
}
|
|
2205
2219
|
}
|
|
2206
2220
|
on(event, handler) {
|
|
2207
2221
|
this._emitter.on(event, handler);
|
|
@@ -4129,6 +4143,15 @@ async function fetchNoProxy(url) {
|
|
|
4129
4143
|
async function resolveCDPEndpoint(raw) {
|
|
4130
4144
|
if (raw === "auto") {
|
|
4131
4145
|
const httpResp = await fetchNoProxy("http://localhost:9222/json/version");
|
|
4146
|
+
if (!httpResp.ok) {
|
|
4147
|
+
throw new Error(
|
|
4148
|
+
`CDP port 9222 responded with ${httpResp.status} ${httpResp.statusText}. \u53EF\u80FD\u539F\u56E0\uFF1A9222 \u88AB\u50F5\u6B7B\u7684 Chrome \u5360\u7528\uFF0C\u6216\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
|
|
4149
|
+
\u89E3\u51B3\u65B9\u6CD5\uFF1A
|
|
4150
|
+
1. \u6740\u6389\u6B8B\u7559 Chrome: pkill -f "remote-debugging-port"
|
|
4151
|
+
2. \u91CD\u542F Chrome: npx cdp-tunnel setup
|
|
4152
|
+
3. \u6216\u6307\u5B9A\u7AEF\u53E3: --cdp <port>`
|
|
4153
|
+
);
|
|
4154
|
+
}
|
|
4132
4155
|
const data = await httpResp.json();
|
|
4133
4156
|
if (!data.webSocketDebuggerUrl) {
|
|
4134
4157
|
throw new Error("Could not auto-discover CDP endpoint from localhost:9222");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
launch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SEFIJY2M.js";
|
|
4
4
|
import {
|
|
5
5
|
errMsg
|
|
6
6
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -1401,6 +1401,15 @@ async function fetchNoProxy(url) {
|
|
|
1401
1401
|
async function resolveCDPEndpoint(raw) {
|
|
1402
1402
|
if (raw === "auto") {
|
|
1403
1403
|
const httpResp = await fetchNoProxy("http://localhost:9222/json/version");
|
|
1404
|
+
if (!httpResp.ok) {
|
|
1405
|
+
throw new Error(
|
|
1406
|
+
`CDP port 9222 responded with ${httpResp.status} ${httpResp.statusText}. \u53EF\u80FD\u539F\u56E0\uFF1A9222 \u88AB\u50F5\u6B7B\u7684 Chrome \u5360\u7528\uFF0C\u6216\u6CA1\u6709 Chrome \u4EE5 --remote-debugging-port \u542F\u52A8\u3002
|
|
1407
|
+
\u89E3\u51B3\u65B9\u6CD5\uFF1A
|
|
1408
|
+
1. \u6740\u6389\u6B8B\u7559 Chrome: pkill -f "remote-debugging-port"
|
|
1409
|
+
2. \u91CD\u542F Chrome: npx cdp-tunnel setup
|
|
1410
|
+
3. \u6216\u6307\u5B9A\u7AEF\u53E3: --cdp <port>`
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1404
1413
|
const data = await httpResp.json();
|
|
1405
1414
|
if (!data.webSocketDebuggerUrl) {
|
|
1406
1415
|
throw new Error("Could not auto-discover CDP endpoint from localhost:9222");
|
|
@@ -2178,8 +2178,14 @@ var XBContextImpl = class {
|
|
|
2178
2178
|
// ── Cookies ─────────────────────────────────────────────────
|
|
2179
2179
|
async cookies(urls) {
|
|
2180
2180
|
const urlList = typeof urls === "string" ? [urls] : urls;
|
|
2181
|
-
const
|
|
2182
|
-
|
|
2181
|
+
const params = urlList ? { urls: urlList } : void 0;
|
|
2182
|
+
try {
|
|
2183
|
+
const result = await this.conn.send("Storage.getCookies", params);
|
|
2184
|
+
return result.cookies;
|
|
2185
|
+
} catch {
|
|
2186
|
+
const result = await this.conn.send("Network.getCookies", params);
|
|
2187
|
+
return result.cookies;
|
|
2188
|
+
}
|
|
2183
2189
|
}
|
|
2184
2190
|
async addCookies(cookies) {
|
|
2185
2191
|
const cdpCookies = cookies.map((c) => ({
|
|
@@ -2192,10 +2198,18 @@ var XBContextImpl = class {
|
|
|
2192
2198
|
secure: c.secure,
|
|
2193
2199
|
sameSite: c.sameSite
|
|
2194
2200
|
}));
|
|
2195
|
-
|
|
2201
|
+
try {
|
|
2202
|
+
await this.conn.send("Storage.setCookies", { cookies: cdpCookies });
|
|
2203
|
+
} catch {
|
|
2204
|
+
await this.conn.send("Network.setCookies", { cookies: cdpCookies });
|
|
2205
|
+
}
|
|
2196
2206
|
}
|
|
2197
2207
|
async clearCookies() {
|
|
2198
|
-
|
|
2208
|
+
try {
|
|
2209
|
+
await this.conn.send("Storage.clearCookies");
|
|
2210
|
+
} catch {
|
|
2211
|
+
await this.conn.send("Network.clearBrowserCookies");
|
|
2212
|
+
}
|
|
2199
2213
|
}
|
|
2200
2214
|
on(event, handler) {
|
|
2201
2215
|
this._emitter.on(event, handler);
|
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveLaunchOpts,
|
|
26
26
|
saveSessionDiskMeta,
|
|
27
27
|
setActivePage
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-7POCCXIB.js";
|
|
29
29
|
import "./chunk-TNEN6VQ2.js";
|
|
30
30
|
import {
|
|
31
31
|
forwardCommandLog,
|
|
@@ -346,8 +346,13 @@ var gotoCommand = registerCommand({
|
|
|
346
346
|
}),
|
|
347
347
|
handler: async (p, ctx) => {
|
|
348
348
|
let url = p.url;
|
|
349
|
-
|
|
350
|
-
|
|
349
|
+
const hasScheme = /^(https?|wss?|file|about|data|chrome|blob):/i.test(url);
|
|
350
|
+
if (!hasScheme) {
|
|
351
|
+
if (/^[\w-]+(\.[\w-]+)+/.test(url) || url.startsWith("localhost")) {
|
|
352
|
+
url = "https://" + url;
|
|
353
|
+
} else {
|
|
354
|
+
throw new Error(`Invalid URL: "${url}". Expected http(s)://, file://, about:, data:, or a domain name.`);
|
|
355
|
+
}
|
|
351
356
|
}
|
|
352
357
|
const response = await ctx.page.goto(url, {
|
|
353
358
|
waitUntil: p.waitUntil || "domcontentloaded"
|
|
@@ -402,7 +407,7 @@ var urlCommand = registerCommand({
|
|
|
402
407
|
scope: "page",
|
|
403
408
|
result: z.object({ url: z.string() }),
|
|
404
409
|
handler: async (_p, ctx) => {
|
|
405
|
-
return ok({ url: ctx.page.url() });
|
|
410
|
+
return ok({ url: ctx.page.url() || "about:blank" });
|
|
406
411
|
}
|
|
407
412
|
});
|
|
408
413
|
registerCommand({
|
|
@@ -565,7 +570,8 @@ var fillCommand = registerCommand({
|
|
|
565
570
|
}),
|
|
566
571
|
handler: async (p, ctx) => {
|
|
567
572
|
const page = ctx.page;
|
|
568
|
-
|
|
573
|
+
const shouldClear = p.clear !== false;
|
|
574
|
+
if (shouldClear) {
|
|
569
575
|
await page.fill(p.selector, "", { force: true, timeout: 1e4 });
|
|
570
576
|
}
|
|
571
577
|
const isReact = await page.evaluate(() => {
|
|
@@ -591,7 +597,7 @@ var fillCommand = registerCommand({
|
|
|
591
597
|
} else {
|
|
592
598
|
await page.fill(p.selector, p.value, { force: true, timeout: 1e4 });
|
|
593
599
|
}
|
|
594
|
-
return ok2({ selector: p.selector, value: p.value, cleared:
|
|
600
|
+
return ok2({ selector: p.selector, value: p.value, cleared: shouldClear, reactMode: !!isReact });
|
|
595
601
|
}
|
|
596
602
|
});
|
|
597
603
|
var typeCommand = registerCommand({
|
|
@@ -6960,7 +6966,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6960
6966
|
}
|
|
6961
6967
|
let targetPageOverride = null;
|
|
6962
6968
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6963
|
-
const { findTargetPage } = await import("./browser-
|
|
6969
|
+
const { findTargetPage } = await import("./browser-U4VWPTS2.js");
|
|
6964
6970
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6965
6971
|
if (!targetPageOverride) {
|
|
6966
6972
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -9497,10 +9503,10 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9497
9503
|
break;
|
|
9498
9504
|
}
|
|
9499
9505
|
case "press": {
|
|
9500
|
-
const key = parsed.value || parsed.remaining[1];
|
|
9501
|
-
if (!
|
|
9506
|
+
const key = parsed.value || (sel ? parsed.remaining[1] : parsed.remaining[0]);
|
|
9507
|
+
if (!key) outputError("Usage: xbrowser press [selector] <key>");
|
|
9502
9508
|
cmdName = "press";
|
|
9503
|
-
params = { ...sel ? { selector: sel } : {}, key
|
|
9509
|
+
params = { ...sel ? { selector: sel } : {}, key };
|
|
9504
9510
|
break;
|
|
9505
9511
|
}
|
|
9506
9512
|
case "select": {
|
|
@@ -9569,13 +9575,22 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9569
9575
|
params = { expression: args.join(" ") };
|
|
9570
9576
|
break;
|
|
9571
9577
|
case "scroll": {
|
|
9572
|
-
|
|
9573
|
-
|
|
9574
|
-
|
|
9578
|
+
let direction = "down";
|
|
9579
|
+
let distance;
|
|
9580
|
+
const firstArg = args[0];
|
|
9581
|
+
if (firstArg && ["up", "down", "left", "right"].includes(firstArg)) {
|
|
9582
|
+
direction = firstArg;
|
|
9583
|
+
if (args[1] && /^\d+$/.test(args[1])) distance = Number(args[1]);
|
|
9584
|
+
} else if (firstArg && /^\d+$/.test(firstArg)) {
|
|
9585
|
+
distance = Number(firstArg);
|
|
9586
|
+
} else if (firstArg) {
|
|
9587
|
+
outputError(`Invalid scroll argument: "${firstArg}". Use up/down/left/right or a pixel number.`);
|
|
9588
|
+
}
|
|
9589
|
+
distance = distance ?? (options.distance ? Number(options.distance) : options.amount ? Number(options.amount) : void 0);
|
|
9575
9590
|
cmdName = "scroll";
|
|
9576
9591
|
params = {
|
|
9577
9592
|
direction,
|
|
9578
|
-
distance
|
|
9593
|
+
distance,
|
|
9579
9594
|
selector: options.selector || options.s
|
|
9580
9595
|
};
|
|
9581
9596
|
break;
|
|
@@ -9588,6 +9603,14 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9588
9603
|
cmdName = "url";
|
|
9589
9604
|
params = {};
|
|
9590
9605
|
break;
|
|
9606
|
+
case "set-viewport": {
|
|
9607
|
+
const width = options.width ? Number(options.width) : args[0] ? Number(args[0]) : void 0;
|
|
9608
|
+
const height = options.height ? Number(options.height) : args[1] ? Number(args[1]) : void 0;
|
|
9609
|
+
if (!width || !height) outputError("Usage: xbrowser set-viewport <width> <height>");
|
|
9610
|
+
cmdName = "set-viewport";
|
|
9611
|
+
params = { width, height };
|
|
9612
|
+
break;
|
|
9613
|
+
}
|
|
9591
9614
|
case "html":
|
|
9592
9615
|
cmdName = "html";
|
|
9593
9616
|
params = { selector: options.selector || options.s };
|
|
@@ -9760,7 +9783,16 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9760
9783
|
} else if (!result.success) {
|
|
9761
9784
|
outputError(result.message || "Command failed");
|
|
9762
9785
|
} else {
|
|
9763
|
-
|
|
9786
|
+
const data = result.data;
|
|
9787
|
+
const isEmptyResult = data && typeof data === "object" && Object.values(data).every((v) => v === "" || v === null || v === void 0);
|
|
9788
|
+
if (isEmptyResult) {
|
|
9789
|
+
const hint = cdpEndpoint ? `\u53EF\u80FD\u672A\u8FDE\u63A5\u5230\u6D4F\u89C8\u5668\u3002\u8BF7\u786E\u8BA4 ${cdpEndpoint} \u4E0A\u6709 Chrome \u8FD0\u884C\uFF08--remote-debugging-port\uFF09\u3002` : "\u53EF\u80FD\u672A\u8FDE\u63A5\u5230\u6D4F\u89C8\u5668\u3002\u8BF7\u4F7F\u7528 --cdp <endpoint> \u8FDE\u63A5\uFF0C\u6216\u5B89\u88C5 cdp-tunnel \u590D\u7528\u5DF2\u6709 Chrome\u3002";
|
|
9790
|
+
outputResult(result.data, mode);
|
|
9791
|
+
console.error(`
|
|
9792
|
+
\u26A0\uFE0F ${hint}`);
|
|
9793
|
+
} else {
|
|
9794
|
+
outputResult(result.data, mode);
|
|
9795
|
+
}
|
|
9764
9796
|
}
|
|
9765
9797
|
}
|
|
9766
9798
|
|
|
@@ -12046,7 +12078,8 @@ async function handleChainInput(input, argv) {
|
|
|
12046
12078
|
}
|
|
12047
12079
|
if (!chainResult.success) throw new Error("Command failed");
|
|
12048
12080
|
}
|
|
12049
|
-
async function routeCommand(
|
|
12081
|
+
async function routeCommand(argvIn, stdinCommands) {
|
|
12082
|
+
let argv = argvIn;
|
|
12050
12083
|
try {
|
|
12051
12084
|
if (stdinCommands && stdinCommands.length > 0) {
|
|
12052
12085
|
await handleStdinMode(stdinCommands, argv);
|
|
@@ -12060,6 +12093,13 @@ async function routeCommand(argv, stdinCommands) {
|
|
|
12060
12093
|
await handleChainInput(argv[0], argv);
|
|
12061
12094
|
return;
|
|
12062
12095
|
}
|
|
12096
|
+
if (argv[0] && argv[0].includes(" ")) {
|
|
12097
|
+
const spaceIdx = argv[0].indexOf(" ");
|
|
12098
|
+
const possibleCmd = argv[0].substring(0, spaceIdx);
|
|
12099
|
+
if (/^[a-zA-Z][\w-]*$/.test(possibleCmd)) {
|
|
12100
|
+
argv = [possibleCmd, argv[0].substring(spaceIdx + 1), ...argv.slice(1)];
|
|
12101
|
+
}
|
|
12102
|
+
}
|
|
12063
12103
|
} catch (e) {
|
|
12064
12104
|
outputError(e instanceof Error ? e.message : String(e));
|
|
12065
12105
|
return;
|
|
@@ -12633,7 +12673,7 @@ async function main() {
|
|
|
12633
12673
|
const command = process.argv[2];
|
|
12634
12674
|
const isLongRunning = command === "preview" || command === "serve";
|
|
12635
12675
|
if (!isLongRunning) {
|
|
12636
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
12676
|
+
const { ensureProcessCanExit } = await import("./browser-U4VWPTS2.js");
|
|
12637
12677
|
await ensureProcessCanExit().catch(() => {
|
|
12638
12678
|
});
|
|
12639
12679
|
process.exit(exitCode);
|
package/dist/daemon-main.js
CHANGED
|
@@ -21,8 +21,8 @@ import {
|
|
|
21
21
|
resolveLaunchOpts,
|
|
22
22
|
saveSessionDiskMeta,
|
|
23
23
|
setActivePage
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-MXG2H3HJ.js";
|
|
25
|
+
import "./chunk-SEFIJY2M.js";
|
|
26
26
|
import "./chunk-TNEN6VQ2.js";
|
|
27
27
|
import {
|
|
28
28
|
getDaemonConfig,
|
|
@@ -304,8 +304,13 @@ var gotoCommand = registerCommand({
|
|
|
304
304
|
}),
|
|
305
305
|
handler: async (p, ctx) => {
|
|
306
306
|
let url = p.url;
|
|
307
|
-
|
|
308
|
-
|
|
307
|
+
const hasScheme = /^(https?|wss?|file|about|data|chrome|blob):/i.test(url);
|
|
308
|
+
if (!hasScheme) {
|
|
309
|
+
if (/^[\w-]+(\.[\w-]+)+/.test(url) || url.startsWith("localhost")) {
|
|
310
|
+
url = "https://" + url;
|
|
311
|
+
} else {
|
|
312
|
+
throw new Error(`Invalid URL: "${url}". Expected http(s)://, file://, about:, data:, or a domain name.`);
|
|
313
|
+
}
|
|
309
314
|
}
|
|
310
315
|
const response = await ctx.page.goto(url, {
|
|
311
316
|
waitUntil: p.waitUntil || "domcontentloaded"
|
|
@@ -360,7 +365,7 @@ var urlCommand = registerCommand({
|
|
|
360
365
|
scope: "page",
|
|
361
366
|
result: z.object({ url: z.string() }),
|
|
362
367
|
handler: async (_p, ctx) => {
|
|
363
|
-
return ok({ url: ctx.page.url() });
|
|
368
|
+
return ok({ url: ctx.page.url() || "about:blank" });
|
|
364
369
|
}
|
|
365
370
|
});
|
|
366
371
|
registerCommand({
|
|
@@ -523,7 +528,8 @@ var fillCommand = registerCommand({
|
|
|
523
528
|
}),
|
|
524
529
|
handler: async (p, ctx) => {
|
|
525
530
|
const page = ctx.page;
|
|
526
|
-
|
|
531
|
+
const shouldClear = p.clear !== false;
|
|
532
|
+
if (shouldClear) {
|
|
527
533
|
await page.fill(p.selector, "", { force: true, timeout: 1e4 });
|
|
528
534
|
}
|
|
529
535
|
const isReact = await page.evaluate(() => {
|
|
@@ -549,7 +555,7 @@ var fillCommand = registerCommand({
|
|
|
549
555
|
} else {
|
|
550
556
|
await page.fill(p.selector, p.value, { force: true, timeout: 1e4 });
|
|
551
557
|
}
|
|
552
|
-
return ok2({ selector: p.selector, value: p.value, cleared:
|
|
558
|
+
return ok2({ selector: p.selector, value: p.value, cleared: shouldClear, reactMode: !!isReact });
|
|
553
559
|
}
|
|
554
560
|
});
|
|
555
561
|
var typeCommand = registerCommand({
|
|
@@ -6918,7 +6924,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
6918
6924
|
}
|
|
6919
6925
|
let targetPageOverride = null;
|
|
6920
6926
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
6921
|
-
const { findTargetPage } = await import("./browser-
|
|
6927
|
+
const { findTargetPage } = await import("./browser-AXCKBSWS.js");
|
|
6922
6928
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
6923
6929
|
if (!targetPageOverride) {
|
|
6924
6930
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -8602,7 +8608,7 @@ function createRPCHandler() {
|
|
|
8602
8608
|
const isNewFormat = Array.isArray(parsed.actions);
|
|
8603
8609
|
if (isNewFormat) {
|
|
8604
8610
|
try {
|
|
8605
|
-
const { SessionReplayer } = await import("./session-replayer-
|
|
8611
|
+
const { SessionReplayer } = await import("./session-replayer-GCGY6KFK.js");
|
|
8606
8612
|
const replayer = new SessionReplayer({
|
|
8607
8613
|
page: session.page,
|
|
8608
8614
|
stepDelay: slowMo * 500,
|
package/dist/index.d.ts
CHANGED
|
@@ -1267,7 +1267,7 @@ interface AISearchResult {
|
|
|
1267
1267
|
* @param argv - Raw CLI argument array (typically `process.argv.slice(2)`).
|
|
1268
1268
|
* @param stdinCommands - Optional array of commands read from stdin.
|
|
1269
1269
|
*/
|
|
1270
|
-
declare function routeCommand(
|
|
1270
|
+
declare function routeCommand(argvIn: string[], stdinCommands?: string[]): Promise<void>;
|
|
1271
1271
|
|
|
1272
1272
|
/**
|
|
1273
1273
|
* Open a new browser session, navigate to the given URL, and persist session metadata.
|
package/dist/index.js
CHANGED
|
@@ -81,8 +81,8 @@ import {
|
|
|
81
81
|
resolveLaunchOpts,
|
|
82
82
|
saveSessionDiskMeta,
|
|
83
83
|
setActivePage
|
|
84
|
-
} from "./chunk-
|
|
85
|
-
import "./chunk-
|
|
84
|
+
} from "./chunk-5QAYN5EZ.js";
|
|
85
|
+
import "./chunk-SEFIJY2M.js";
|
|
86
86
|
import "./chunk-TNEN6VQ2.js";
|
|
87
87
|
import {
|
|
88
88
|
errMsg
|
|
@@ -386,8 +386,13 @@ var gotoCommand = registerCommand({
|
|
|
386
386
|
}),
|
|
387
387
|
handler: async (p, ctx) => {
|
|
388
388
|
let url = p.url;
|
|
389
|
-
|
|
390
|
-
|
|
389
|
+
const hasScheme = /^(https?|wss?|file|about|data|chrome|blob):/i.test(url);
|
|
390
|
+
if (!hasScheme) {
|
|
391
|
+
if (/^[\w-]+(\.[\w-]+)+/.test(url) || url.startsWith("localhost")) {
|
|
392
|
+
url = "https://" + url;
|
|
393
|
+
} else {
|
|
394
|
+
throw new Error(`Invalid URL: "${url}". Expected http(s)://, file://, about:, data:, or a domain name.`);
|
|
395
|
+
}
|
|
391
396
|
}
|
|
392
397
|
const response = await ctx.page.goto(url, {
|
|
393
398
|
waitUntil: p.waitUntil || "domcontentloaded"
|
|
@@ -442,7 +447,7 @@ var urlCommand = registerCommand({
|
|
|
442
447
|
scope: "page",
|
|
443
448
|
result: z.object({ url: z.string() }),
|
|
444
449
|
handler: async (_p, ctx) => {
|
|
445
|
-
return ok({ url: ctx.page.url() });
|
|
450
|
+
return ok({ url: ctx.page.url() || "about:blank" });
|
|
446
451
|
}
|
|
447
452
|
});
|
|
448
453
|
registerCommand({
|
|
@@ -605,7 +610,8 @@ var fillCommand = registerCommand({
|
|
|
605
610
|
}),
|
|
606
611
|
handler: async (p, ctx) => {
|
|
607
612
|
const page = ctx.page;
|
|
608
|
-
|
|
613
|
+
const shouldClear = p.clear !== false;
|
|
614
|
+
if (shouldClear) {
|
|
609
615
|
await page.fill(p.selector, "", { force: true, timeout: 1e4 });
|
|
610
616
|
}
|
|
611
617
|
const isReact = await page.evaluate(() => {
|
|
@@ -631,7 +637,7 @@ var fillCommand = registerCommand({
|
|
|
631
637
|
} else {
|
|
632
638
|
await page.fill(p.selector, p.value, { force: true, timeout: 1e4 });
|
|
633
639
|
}
|
|
634
|
-
return ok2({ selector: p.selector, value: p.value, cleared:
|
|
640
|
+
return ok2({ selector: p.selector, value: p.value, cleared: shouldClear, reactMode: !!isReact });
|
|
635
641
|
}
|
|
636
642
|
});
|
|
637
643
|
var typeCommand = registerCommand({
|
|
@@ -7280,7 +7286,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7280
7286
|
}
|
|
7281
7287
|
let targetPageOverride = null;
|
|
7282
7288
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7283
|
-
const { findTargetPage } = await import("./browser-
|
|
7289
|
+
const { findTargetPage } = await import("./browser-X7OVRKJH.js");
|
|
7284
7290
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7285
7291
|
if (!targetPageOverride) {
|
|
7286
7292
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -9837,10 +9843,10 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9837
9843
|
break;
|
|
9838
9844
|
}
|
|
9839
9845
|
case "press": {
|
|
9840
|
-
const key = parsed.value || parsed.remaining[1];
|
|
9841
|
-
if (!
|
|
9846
|
+
const key = parsed.value || (sel ? parsed.remaining[1] : parsed.remaining[0]);
|
|
9847
|
+
if (!key) outputError("Usage: xbrowser press [selector] <key>");
|
|
9842
9848
|
cmdName = "press";
|
|
9843
|
-
params = { ...sel ? { selector: sel } : {}, key
|
|
9849
|
+
params = { ...sel ? { selector: sel } : {}, key };
|
|
9844
9850
|
break;
|
|
9845
9851
|
}
|
|
9846
9852
|
case "select": {
|
|
@@ -9909,13 +9915,22 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9909
9915
|
params = { expression: args.join(" ") };
|
|
9910
9916
|
break;
|
|
9911
9917
|
case "scroll": {
|
|
9912
|
-
|
|
9913
|
-
|
|
9914
|
-
|
|
9918
|
+
let direction = "down";
|
|
9919
|
+
let distance;
|
|
9920
|
+
const firstArg = args[0];
|
|
9921
|
+
if (firstArg && ["up", "down", "left", "right"].includes(firstArg)) {
|
|
9922
|
+
direction = firstArg;
|
|
9923
|
+
if (args[1] && /^\d+$/.test(args[1])) distance = Number(args[1]);
|
|
9924
|
+
} else if (firstArg && /^\d+$/.test(firstArg)) {
|
|
9925
|
+
distance = Number(firstArg);
|
|
9926
|
+
} else if (firstArg) {
|
|
9927
|
+
outputError(`Invalid scroll argument: "${firstArg}". Use up/down/left/right or a pixel number.`);
|
|
9928
|
+
}
|
|
9929
|
+
distance = distance ?? (options.distance ? Number(options.distance) : options.amount ? Number(options.amount) : void 0);
|
|
9915
9930
|
cmdName = "scroll";
|
|
9916
9931
|
params = {
|
|
9917
9932
|
direction,
|
|
9918
|
-
distance
|
|
9933
|
+
distance,
|
|
9919
9934
|
selector: options.selector || options.s
|
|
9920
9935
|
};
|
|
9921
9936
|
break;
|
|
@@ -9928,6 +9943,14 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
9928
9943
|
cmdName = "url";
|
|
9929
9944
|
params = {};
|
|
9930
9945
|
break;
|
|
9946
|
+
case "set-viewport": {
|
|
9947
|
+
const width = options.width ? Number(options.width) : args[0] ? Number(args[0]) : void 0;
|
|
9948
|
+
const height = options.height ? Number(options.height) : args[1] ? Number(args[1]) : void 0;
|
|
9949
|
+
if (!width || !height) outputError("Usage: xbrowser set-viewport <width> <height>");
|
|
9950
|
+
cmdName = "set-viewport";
|
|
9951
|
+
params = { width, height };
|
|
9952
|
+
break;
|
|
9953
|
+
}
|
|
9931
9954
|
case "html":
|
|
9932
9955
|
cmdName = "html";
|
|
9933
9956
|
params = { selector: options.selector || options.s };
|
|
@@ -10100,7 +10123,16 @@ async function handleBrowserCommand(command, args, options, sessionName, mode, c
|
|
|
10100
10123
|
} else if (!result.success) {
|
|
10101
10124
|
outputError(result.message || "Command failed");
|
|
10102
10125
|
} else {
|
|
10103
|
-
|
|
10126
|
+
const data = result.data;
|
|
10127
|
+
const isEmptyResult = data && typeof data === "object" && Object.values(data).every((v) => v === "" || v === null || v === void 0);
|
|
10128
|
+
if (isEmptyResult) {
|
|
10129
|
+
const hint = cdpEndpoint ? `\u53EF\u80FD\u672A\u8FDE\u63A5\u5230\u6D4F\u89C8\u5668\u3002\u8BF7\u786E\u8BA4 ${cdpEndpoint} \u4E0A\u6709 Chrome \u8FD0\u884C\uFF08--remote-debugging-port\uFF09\u3002` : "\u53EF\u80FD\u672A\u8FDE\u63A5\u5230\u6D4F\u89C8\u5668\u3002\u8BF7\u4F7F\u7528 --cdp <endpoint> \u8FDE\u63A5\uFF0C\u6216\u5B89\u88C5 cdp-tunnel \u590D\u7528\u5DF2\u6709 Chrome\u3002";
|
|
10130
|
+
outputResult(result.data, mode);
|
|
10131
|
+
console.error(`
|
|
10132
|
+
\u26A0\uFE0F ${hint}`);
|
|
10133
|
+
} else {
|
|
10134
|
+
outputResult(result.data, mode);
|
|
10135
|
+
}
|
|
10104
10136
|
}
|
|
10105
10137
|
}
|
|
10106
10138
|
|
|
@@ -12386,7 +12418,8 @@ async function handleChainInput(input, argv) {
|
|
|
12386
12418
|
}
|
|
12387
12419
|
if (!chainResult.success) throw new Error("Command failed");
|
|
12388
12420
|
}
|
|
12389
|
-
async function routeCommand(
|
|
12421
|
+
async function routeCommand(argvIn, stdinCommands) {
|
|
12422
|
+
let argv = argvIn;
|
|
12390
12423
|
try {
|
|
12391
12424
|
if (stdinCommands && stdinCommands.length > 0) {
|
|
12392
12425
|
await handleStdinMode(stdinCommands, argv);
|
|
@@ -12400,6 +12433,13 @@ async function routeCommand(argv, stdinCommands) {
|
|
|
12400
12433
|
await handleChainInput(argv[0], argv);
|
|
12401
12434
|
return;
|
|
12402
12435
|
}
|
|
12436
|
+
if (argv[0] && argv[0].includes(" ")) {
|
|
12437
|
+
const spaceIdx = argv[0].indexOf(" ");
|
|
12438
|
+
const possibleCmd = argv[0].substring(0, spaceIdx);
|
|
12439
|
+
if (/^[a-zA-Z][\w-]*$/.test(possibleCmd)) {
|
|
12440
|
+
argv = [possibleCmd, argv[0].substring(spaceIdx + 1), ...argv.slice(1)];
|
|
12441
|
+
}
|
|
12442
|
+
}
|
|
12403
12443
|
} catch (e) {
|
|
12404
12444
|
outputError(e instanceof Error ? e.message : String(e));
|
|
12405
12445
|
return;
|
|
@@ -15760,7 +15800,7 @@ var DataCollector = class {
|
|
|
15760
15800
|
return results;
|
|
15761
15801
|
}
|
|
15762
15802
|
async createBrowserContext() {
|
|
15763
|
-
const { launch } = await import("./cdp-driver-
|
|
15803
|
+
const { launch } = await import("./cdp-driver-ZAVN7GRB.js");
|
|
15764
15804
|
const { browser } = await launch({
|
|
15765
15805
|
headless: true,
|
|
15766
15806
|
args: ["--no-sandbox", "--disable-setuid-sandbox"]
|
|
@@ -31,7 +31,7 @@ var SessionReplayer = class {
|
|
|
31
31
|
if (this.opts.page) {
|
|
32
32
|
this.page = this.opts.page;
|
|
33
33
|
} else if (this.opts.cdpUrl) {
|
|
34
|
-
const { launch } = await import("./cdp-driver-
|
|
34
|
+
const { launch } = await import("./cdp-driver-ZAVN7GRB.js");
|
|
35
35
|
const { browser } = await launch({ cdpEndpoint: this.opts.cdpUrl });
|
|
36
36
|
let contexts = browser.contexts();
|
|
37
37
|
for (let i = 0; i < 10 && contexts.length === 0; i++) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xbrowser/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "Browser automation CLI for web scraping, headless browsing, SEO analysis, and AI agent workflows. A command-line alternative to Playwright, Puppeteer, and Selenium.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|