@xbrowser/cli 1.0.0 → 1.0.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/README.md +17 -26
- package/dist/{browser-GURRY444.js → browser-GITRHHFO.js} +4 -3
- package/dist/{browser-DSVV4GHS.js → browser-R56O3CW6.js} +3 -3
- package/dist/{browser-53KUFEEM.js → browser-ZJOZB5CR.js} +4 -4
- package/dist/{cdp-driver-MNPR3HZH.js → cdp-driver-BE3FOMRN.js} +324 -58
- package/dist/{cdp-driver-SSXUGXP6.js → cdp-driver-TOPYJIFL.js} +3 -3
- package/dist/chunk-2SVQTI2O.js +2794 -0
- package/dist/{chunk-2MFXKN32.js → chunk-ACFE6PKF.js} +1013 -119
- package/dist/chunk-BBMRDUYQ.js +260 -0
- package/dist/{chunk-E4O5ZU3H.js → chunk-CAFNSGYM.js} +393 -95
- package/dist/{chunk-DTJRVA76.js → chunk-ETCO4SNK.js} +2 -2
- package/dist/{chunk-YKOHDEFV.js → chunk-JPA2ZT2R.js} +69 -36
- package/dist/{chunk-T4J4C2NZ.js → chunk-JPHCY4TC.js} +12 -2
- package/dist/chunk-KFQGP6VL.js +33 -0
- package/dist/{chunk-ITKPSIP7.js → chunk-MDAPTB7C.js} +6 -25
- package/dist/chunk-OZKD3W4X.js +417 -0
- package/dist/{chunk-42RPMJ76.js → chunk-PPG4D2EW.js} +325 -59
- package/dist/{chunk-IDVD44ED.js → chunk-Q4IGYTKR.js} +19 -7
- package/dist/{chunk-2BQZIT3S.js → chunk-QIK2I3VQ.js} +86 -2501
- package/dist/chunk-WJRE55TN.js +83 -0
- package/dist/cli.js +1435 -1077
- package/dist/{convert-EGFYNICZ.js → convert-LB3GJTLR.js} +3 -3
- package/dist/{convert-EKQVHKB4.js → convert-R3XXYKC6.js} +2 -2
- package/dist/{daemon-client-3VM7VU7O.js → daemon-client-DRCUMNHK.js} +25 -74
- package/dist/{daemon-client-YAVQ343A.js → daemon-client-UZZEHHIV.js} +2 -2
- package/dist/daemon-main.js +2200 -1691
- package/dist/{extract-JUOQQX4V.js → extract-2ZFW2MX7.js} +1 -1
- package/dist/{extract-L2IW3IUB.js → extract-BSYBM4MR.js} +1 -1
- package/dist/{filter-HC4RA7JY.js → filter-KCFO4RSV.js} +1 -1
- package/dist/{filter-VID2GGZ7.js → filter-T7DSZ2X7.js} +1 -1
- package/dist/{human-interaction-W753RVJB.js → human-interaction-UKAS5ZXV.js} +2 -2
- package/dist/index.d.ts +165 -108
- package/dist/index.js +2531 -1680
- package/dist/launcher-QUJ4M2VS.js +19 -0
- package/dist/{launcher-KA7J32K5.js → launcher-YARP45UY.js} +1 -1
- package/dist/{network-store-66A2RATI.js → network-store-XGZ25FFC.js} +1 -1
- package/dist/{network-store-BN6QEZ7R.js → network-store-YVDNUREI.js} +1 -1
- package/dist/{parse-action-dsl-T3DYC33D.js → parse-action-dsl-UM333TL2.js} +1 -1
- package/dist/{proxy-WKGUCH2C.js → proxy-LV4BJ5RC.js} +1 -1
- package/dist/session-recorder-RTDGURIJ.js +8 -0
- package/dist/session-recorder-YI7YYM36.js +7 -0
- package/dist/session-replayer-GLTUICSD.js +276 -0
- package/dist/site-knowledge-SYC6VCDB.js +23 -0
- package/package.json +5 -4
- package/dist/screenshot-CWAWMXVA.js +0 -28
- package/dist/session-recorder-MA75PKTQ.js +0 -7
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__require
|
|
3
|
+
} from "./chunk-KFQGP6VL.js";
|
|
4
|
+
|
|
5
|
+
// src/cdp-driver/launcher.ts
|
|
6
|
+
import { spawn } from "child_process";
|
|
7
|
+
import { existsSync as fsExistsSync } from "fs";
|
|
8
|
+
var DEFAULT_CHROME_PATHS = {
|
|
9
|
+
darwin: [
|
|
10
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
11
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
|
|
12
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
13
|
+
"/Applications/Brave Browser.app/Contents/MacOS/Brave Browser"
|
|
14
|
+
],
|
|
15
|
+
linux: [
|
|
16
|
+
"/usr/bin/google-chrome",
|
|
17
|
+
"/usr/bin/google-chrome-stable",
|
|
18
|
+
"/usr/bin/chromium",
|
|
19
|
+
"/usr/bin/chromium-browser",
|
|
20
|
+
"/usr/bin/microsoft-edge"
|
|
21
|
+
],
|
|
22
|
+
win32: [
|
|
23
|
+
"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
|
|
24
|
+
"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
|
|
25
|
+
"C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe"
|
|
26
|
+
]
|
|
27
|
+
};
|
|
28
|
+
var DEFAULT_ARGS = [
|
|
29
|
+
"--no-first-run",
|
|
30
|
+
"--no-default-browser-check",
|
|
31
|
+
"--no-sandbox",
|
|
32
|
+
"--disable-background-networking",
|
|
33
|
+
"--disable-background-timer-throttling",
|
|
34
|
+
"--disable-backgrounding-occluded-windows",
|
|
35
|
+
"--disable-breakpad",
|
|
36
|
+
"--disable-client-side-phishing-detection",
|
|
37
|
+
"--disable-default-apps",
|
|
38
|
+
"--disable-extensions",
|
|
39
|
+
"--disable-hang-monitor",
|
|
40
|
+
"--disable-ipc-flood-protection",
|
|
41
|
+
"--disable-popup-blocking",
|
|
42
|
+
"--disable-prompt-on-repost",
|
|
43
|
+
"--disable-renderer-backgrounding",
|
|
44
|
+
"--disable-sync",
|
|
45
|
+
"--disable-translate",
|
|
46
|
+
"--metrics-recording-only",
|
|
47
|
+
"--password-store=basic",
|
|
48
|
+
"--use-mock-keychain"
|
|
49
|
+
];
|
|
50
|
+
var ANTI_DETECT_ARGS = [
|
|
51
|
+
"--disable-blink-features=AutomationControlled",
|
|
52
|
+
"--disable-features=IsolateOrigins,site-per-process"
|
|
53
|
+
];
|
|
54
|
+
function findChrome() {
|
|
55
|
+
const platform = process.platform;
|
|
56
|
+
const paths = DEFAULT_CHROME_PATHS[platform] ?? [];
|
|
57
|
+
for (const p of paths) {
|
|
58
|
+
if (fsExistsSync(p)) return p;
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
async function launchChrome(options = {}) {
|
|
63
|
+
const {
|
|
64
|
+
executablePath,
|
|
65
|
+
headless = true,
|
|
66
|
+
args: extraArgs = [],
|
|
67
|
+
userDataDir,
|
|
68
|
+
timeout = 3e4,
|
|
69
|
+
env
|
|
70
|
+
} = options;
|
|
71
|
+
const chromePath = executablePath ?? findChrome();
|
|
72
|
+
if (!chromePath) {
|
|
73
|
+
throw new Error(
|
|
74
|
+
[
|
|
75
|
+
"Chrome/Chromium not found.",
|
|
76
|
+
"",
|
|
77
|
+
"\u63A8\u8350\uFF1A\u7528 cdp-tunnel \u590D\u7528\u4F60\u5DF2\u6709\u7684 Chrome\uFF08\u542B\u767B\u5F55\u6001\u3001\u53CD\u722C\u53CB\u597D\uFF09",
|
|
78
|
+
" npx cdp-tunnel setup # \u96F6\u5B89\u88C5\u4E00\u952E\u542F\u52A8\u4EE3\u7406 + \u52A0\u8F7D Chrome \u6269\u5C55",
|
|
79
|
+
" xbrowser goto https://example.com --cdp http://localhost:9221",
|
|
80
|
+
"",
|
|
81
|
+
"\u6216\u6307\u5B9A Chrome \u8DEF\u5F84\uFF1A",
|
|
82
|
+
' xbrowser config set browser.executablePath "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"'
|
|
83
|
+
].join("\n")
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const port = await findFreePort();
|
|
87
|
+
const allArgs = [
|
|
88
|
+
`--remote-debugging-port=${port}`,
|
|
89
|
+
"--remote-allow-origins=*",
|
|
90
|
+
"--no-sandbox",
|
|
91
|
+
"--no-first-run",
|
|
92
|
+
"--no-default-browser-check",
|
|
93
|
+
"--disable-background-timer-throttling",
|
|
94
|
+
"--disable-backgrounding-occluded-windows",
|
|
95
|
+
"--disable-renderer-backgrounding",
|
|
96
|
+
"--disable-features=Translate",
|
|
97
|
+
"--disable-popup-blocking"
|
|
98
|
+
];
|
|
99
|
+
if (headless) {
|
|
100
|
+
allArgs.push("--headless", "--hide-scrollbars", "--mute-audio");
|
|
101
|
+
}
|
|
102
|
+
let tmpDir;
|
|
103
|
+
if (userDataDir) {
|
|
104
|
+
allArgs.push(`--user-data-dir=${userDataDir}`);
|
|
105
|
+
} else {
|
|
106
|
+
const { mkdirSync } = await import("fs");
|
|
107
|
+
tmpDir = `/tmp/xbrowser-chrome-${process.pid}-${Date.now()}`;
|
|
108
|
+
mkdirSync(tmpDir, { recursive: true });
|
|
109
|
+
allArgs.push(`--user-data-dir=${tmpDir}`);
|
|
110
|
+
}
|
|
111
|
+
allArgs.push(...extraArgs, "about:blank");
|
|
112
|
+
const childEnv = {
|
|
113
|
+
...process.env,
|
|
114
|
+
...env
|
|
115
|
+
};
|
|
116
|
+
const quotedPath = chromePath.includes(" ") ? `"${chromePath}"` : chromePath;
|
|
117
|
+
const quotedArgs = allArgs.map((a) => {
|
|
118
|
+
if (a.includes(" ")) return `"${a}"`;
|
|
119
|
+
return a;
|
|
120
|
+
}).join(" ");
|
|
121
|
+
const fullCmd = `${quotedPath} ${quotedArgs}`;
|
|
122
|
+
const child = process.platform === "darwin" ? spawn("/bin/sh", ["-c", fullCmd], {
|
|
123
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
124
|
+
env: childEnv
|
|
125
|
+
}) : spawn(chromePath, allArgs, {
|
|
126
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
127
|
+
env: childEnv
|
|
128
|
+
});
|
|
129
|
+
const stderrLines = [];
|
|
130
|
+
child.stderr?.on("data", (data) => {
|
|
131
|
+
const line = data.toString().trim();
|
|
132
|
+
if (line) stderrLines.push(line);
|
|
133
|
+
});
|
|
134
|
+
child.stdout?.on("data", (data) => {
|
|
135
|
+
const line = data.toString().trim();
|
|
136
|
+
if (line) stderrLines.push(`[stdout] ${line}`);
|
|
137
|
+
});
|
|
138
|
+
child.on("error", (err) => {
|
|
139
|
+
if (!child.killed) {
|
|
140
|
+
console.error(`Chrome process error: ${err.message}`);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
try {
|
|
144
|
+
const wsEndpoint = await waitForCDPReady(port, timeout, child);
|
|
145
|
+
return { process: child, wsEndpoint, port, tmpDir };
|
|
146
|
+
} catch (err) {
|
|
147
|
+
const stderr = stderrLines.slice(-20).join("\n");
|
|
148
|
+
const exitInfo = child.exitCode !== null ? ` (exit code: ${child.exitCode})` : " (still running)";
|
|
149
|
+
throw new Error(`${err.message}${exitInfo}
|
|
150
|
+
Chrome stderr:
|
|
151
|
+
${stderr || "(empty)"}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function connectToCDP(rawEndpoint) {
|
|
155
|
+
if (rawEndpoint.startsWith("ws://") || rawEndpoint.startsWith("wss://")) {
|
|
156
|
+
return rawEndpoint;
|
|
157
|
+
}
|
|
158
|
+
return resolveEndpointFromHTTP(rawEndpoint);
|
|
159
|
+
}
|
|
160
|
+
async function findFreePort() {
|
|
161
|
+
const { createServer } = await import("net");
|
|
162
|
+
return new Promise((resolve, reject) => {
|
|
163
|
+
const srv = createServer();
|
|
164
|
+
srv.listen(0, "127.0.0.1", () => {
|
|
165
|
+
const addr = srv.address();
|
|
166
|
+
if (addr && typeof addr === "object") {
|
|
167
|
+
const port = addr.port;
|
|
168
|
+
srv.close(() => resolve(port));
|
|
169
|
+
} else {
|
|
170
|
+
srv.close();
|
|
171
|
+
reject(new Error("Failed to find free port"));
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
srv.on("error", reject);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
async function waitForCDPReady(port, timeoutMs, child) {
|
|
178
|
+
const deadline = Date.now() + timeoutMs;
|
|
179
|
+
while (Date.now() < deadline) {
|
|
180
|
+
if (child.exitCode !== null && child.exitCode !== 0) {
|
|
181
|
+
throw new Error(`Chrome exited with code ${child.exitCode} before CDP became ready`);
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
const wsEndpoint = await resolveEndpointFromHTTP(`http://127.0.0.1:${port}`);
|
|
185
|
+
return wsEndpoint;
|
|
186
|
+
} catch {
|
|
187
|
+
await sleep(200);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
throw new Error(`Chrome CDP not ready after ${timeoutMs}ms (port ${port})`);
|
|
191
|
+
}
|
|
192
|
+
async function resolveEndpointFromHTTP(baseURL) {
|
|
193
|
+
const url = `${baseURL}/json/version`;
|
|
194
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(3e3) });
|
|
195
|
+
if (!resp.ok) {
|
|
196
|
+
throw new Error(`CDP HTTP ${resp.status}: ${url}`);
|
|
197
|
+
}
|
|
198
|
+
const data = await resp.json();
|
|
199
|
+
if (!data.webSocketDebuggerUrl) {
|
|
200
|
+
throw new Error("No webSocketDebuggerUrl in CDP response");
|
|
201
|
+
}
|
|
202
|
+
return data.webSocketDebuggerUrl;
|
|
203
|
+
}
|
|
204
|
+
async function getCDPTargets(baseURL) {
|
|
205
|
+
const url = `${baseURL}/json/list`;
|
|
206
|
+
const resp = await fetch(url, { signal: AbortSignal.timeout(5e3) });
|
|
207
|
+
if (!resp.ok) {
|
|
208
|
+
throw new Error(`CDP list HTTP ${resp.status}: ${url}`);
|
|
209
|
+
}
|
|
210
|
+
const targets = await resp.json();
|
|
211
|
+
return targets;
|
|
212
|
+
}
|
|
213
|
+
async function killChrome(child, tmpDir) {
|
|
214
|
+
if (child.exitCode !== null) {
|
|
215
|
+
if (tmpDir) cleanupTmpDir(tmpDir);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
return new Promise((resolve) => {
|
|
219
|
+
const timer = setTimeout(() => {
|
|
220
|
+
try {
|
|
221
|
+
child.kill("SIGKILL");
|
|
222
|
+
} catch {
|
|
223
|
+
}
|
|
224
|
+
if (tmpDir) cleanupTmpDir(tmpDir);
|
|
225
|
+
resolve();
|
|
226
|
+
}, 5e3);
|
|
227
|
+
child.once("exit", () => {
|
|
228
|
+
clearTimeout(timer);
|
|
229
|
+
if (tmpDir) cleanupTmpDir(tmpDir);
|
|
230
|
+
resolve();
|
|
231
|
+
});
|
|
232
|
+
try {
|
|
233
|
+
child.kill("SIGTERM");
|
|
234
|
+
} catch {
|
|
235
|
+
clearTimeout(timer);
|
|
236
|
+
if (tmpDir) cleanupTmpDir(tmpDir);
|
|
237
|
+
resolve();
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
function cleanupTmpDir(dir) {
|
|
242
|
+
try {
|
|
243
|
+
const { rmSync } = __require("fs");
|
|
244
|
+
rmSync(dir, { recursive: true, force: true });
|
|
245
|
+
} catch {
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function sleep(ms) {
|
|
249
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export {
|
|
253
|
+
DEFAULT_ARGS,
|
|
254
|
+
ANTI_DETECT_ARGS,
|
|
255
|
+
findChrome,
|
|
256
|
+
launchChrome,
|
|
257
|
+
connectToCDP,
|
|
258
|
+
getCDPTargets,
|
|
259
|
+
killChrome
|
|
260
|
+
};
|