@xbrowser/cli 1.9.7 → 1.9.9
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/{anti-bot-MCVM6IFB.js → anti-bot-DR56Y63V.js} +1 -1
- package/dist/{browser-JXIJF4VL.js → browser-FFYPFTBV.js} +1 -1
- package/dist/{browser-ALPLJNH2.js → browser-RHWUAMTB.js} +2 -2
- package/dist/{browser-ZPQP6VW7.js → browser-YCO4GJMZ.js} +2 -2
- package/dist/{cdp-driver-MI7VCE44.js → cdp-driver-2T4P4ZE2.js} +103 -2
- package/dist/{cdp-driver-6EVYLHL2.js → cdp-driver-J3YQ4LJV.js} +1 -1
- package/dist/chunk-3OD76SUE.js +20 -0
- package/dist/chunk-43TEMG4U.js +9 -0
- package/dist/{chunk-CH5ZQV64.js → chunk-4452SPFI.js} +928 -18
- package/dist/{chunk-C4O73DQL.js → chunk-5UGR6MUK.js} +928 -18
- package/dist/{chunk-37SHZSUR.js → chunk-6OZWKXSW.js} +15 -16
- package/dist/{chunk-7ZDWM6T2.js → chunk-BNO7OKO4.js} +5 -6
- package/dist/{chunk-24SY6PE5.js → chunk-CG3D3CHY.js} +1 -8
- package/dist/{chunk-ZJHQPMCY.js → chunk-DWDXEGVK.js} +5 -6
- package/dist/{chunk-74S7UUI2.js → chunk-GUTBIYFW.js} +117 -17
- package/dist/{chunk-DPJNCMLC.js → chunk-INTQPBYF.js} +7 -0
- package/dist/{human-interaction-OU7LZ6OZ.js → chunk-MWFHZUIY.js} +6 -7
- package/dist/chunk-Q2DFJQGS.js +128 -0
- package/dist/{chunk-VJNMAWPZ.js → chunk-RRBXV7KE.js} +103 -2
- package/dist/{chunk-5JSOGINQ.js → chunk-RZM5CNIY.js} +15 -16
- package/dist/{human-interaction-HJTXFVQS.js → chunk-SQHSZENE.js} +2 -2
- package/dist/chunk-TZPKFUBT.js +20 -0
- package/dist/{chunk-YAUG3NSI.js → chunk-YMUSHPU4.js} +16 -128
- package/dist/cli.js +41 -28
- package/dist/{daemon-client-4HJENICO.js → daemon-client-GKEPT4NY.js} +15 -3
- package/dist/{daemon-client-CMRAWXTN.js → daemon-client-O6BYVRXV.js} +4 -1
- package/dist/daemon-main.js +661 -70
- package/dist/human-interaction-5AO42MBA.js +8 -0
- package/dist/{human-interaction-2DZK4MW7.js → human-interaction-C5OEGXGO.js} +1 -1
- package/dist/human-interaction-ISXZTAYY.js +8 -0
- package/dist/index.d.ts +172 -2
- package/dist/index.js +173 -63
- package/dist/recovery-EF33LKRJ.js +77 -0
- package/dist/recovery-J2ISVGUL.js +77 -0
- package/dist/recovery-ZJVVHP7N.js +76 -0
- package/dist/{session-recorder-7GXI42FO.js → session-recorder-H3KEYU26.js} +1 -1
- package/dist/{session-recorder-RFOPX4SF.js → session-recorder-QRZMKFVL.js} +1 -1
- package/dist/{session-replayer-3HEIJBJ2.js → session-replayer-LJUC4TI7.js} +25 -8
- package/package.json +1 -1
|
@@ -288,6 +288,36 @@ function queryJS(selector) {
|
|
|
288
288
|
const xpath = JSON.stringify(selector.slice(6));
|
|
289
289
|
return `document.evaluate(${xpath}, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue`;
|
|
290
290
|
}
|
|
291
|
+
if (selector.startsWith("text=")) {
|
|
292
|
+
const raw = selector.slice(5);
|
|
293
|
+
const exact = raw.startsWith('"') && raw.endsWith('"');
|
|
294
|
+
const text = exact ? raw.slice(1, -1) : raw;
|
|
295
|
+
return `(() => {
|
|
296
|
+
const target = ${JSON.stringify(text)};
|
|
297
|
+
const exact = ${exact};
|
|
298
|
+
const els = [...document.querySelectorAll('*')].filter(e => {
|
|
299
|
+
if (e.children.length > 0) return false;
|
|
300
|
+
if (e.offsetParent === null) return false;
|
|
301
|
+
const t = (e.textContent || '').trim();
|
|
302
|
+
if (!t) return false;
|
|
303
|
+
return exact ? t === target : t.toLowerCase().includes(target.toLowerCase());
|
|
304
|
+
});
|
|
305
|
+
return els[0] || null;
|
|
306
|
+
})()`;
|
|
307
|
+
}
|
|
308
|
+
if (selector.startsWith("popup-text=")) {
|
|
309
|
+
const text = selector.slice("popup-text=".length);
|
|
310
|
+
return `(() => {
|
|
311
|
+
const target = ${JSON.stringify(text)};
|
|
312
|
+
const els = [...document.querySelectorAll('*')].filter(e => {
|
|
313
|
+
if (e.children.length > 0) return false;
|
|
314
|
+
if (e.offsetParent === null) return false;
|
|
315
|
+
if ((e.textContent || '').trim() !== target) return false;
|
|
316
|
+
return true;
|
|
317
|
+
});
|
|
318
|
+
return els[0] || null;
|
|
319
|
+
})()`;
|
|
320
|
+
}
|
|
291
321
|
return `document.querySelector(${JSON.stringify(selector)})`;
|
|
292
322
|
}
|
|
293
323
|
function queryAllJS(selector) {
|
|
@@ -295,6 +325,9 @@ function queryAllJS(selector) {
|
|
|
295
325
|
const xpath = JSON.stringify(selector.slice(6));
|
|
296
326
|
return `(() => { const it = document.evaluate(${xpath}, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); const r=[]; for(let i=0;i<it.snapshotLength;i++) r.push(it.snapshotItem(i)); return r; })()`;
|
|
297
327
|
}
|
|
328
|
+
if (selector.startsWith("text=") || selector.startsWith("popup-text=")) {
|
|
329
|
+
return `(() => { const el = ${queryJS(selector)}; return el ? [el] : []; })()`;
|
|
330
|
+
}
|
|
298
331
|
return `document.querySelectorAll(${JSON.stringify(selector)})`;
|
|
299
332
|
}
|
|
300
333
|
|
|
@@ -1332,7 +1365,22 @@ Last error: ${lastError.message}` : "";
|
|
|
1332
1365
|
return this._url;
|
|
1333
1366
|
}
|
|
1334
1367
|
async title() {
|
|
1335
|
-
|
|
1368
|
+
for (let i = 0; i < 20; i++) {
|
|
1369
|
+
try {
|
|
1370
|
+
this._title = await this.evaluate("document.title");
|
|
1371
|
+
if (this._title) return this._title;
|
|
1372
|
+
} catch {
|
|
1373
|
+
}
|
|
1374
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
1375
|
+
}
|
|
1376
|
+
try {
|
|
1377
|
+
const info = await this._cdpSend("Target.getTargetInfo", { targetId: this._targetId });
|
|
1378
|
+
if (info?.title) {
|
|
1379
|
+
this._title = info.title;
|
|
1380
|
+
return this._title;
|
|
1381
|
+
}
|
|
1382
|
+
} catch {
|
|
1383
|
+
}
|
|
1336
1384
|
return this._title;
|
|
1337
1385
|
}
|
|
1338
1386
|
async content() {
|
|
@@ -2742,11 +2790,52 @@ var CDPConnection = class extends EventEmitter4 {
|
|
|
2742
2790
|
this.setMaxListeners(0);
|
|
2743
2791
|
this.defaultSessionId = sessionId;
|
|
2744
2792
|
if (typeof wsOrUrl === "string") {
|
|
2745
|
-
|
|
2793
|
+
const wsOptions = /^wss:\/\/\d+\.\d+\.\d+\.\d+/.test(wsOrUrl) ? { rejectUnauthorized: false } : void 0;
|
|
2794
|
+
this.ws = new WebSocket(wsOrUrl, wsOptions);
|
|
2746
2795
|
} else {
|
|
2747
2796
|
this.ws = wsOrUrl;
|
|
2748
2797
|
}
|
|
2749
2798
|
this.bindWebSocket();
|
|
2799
|
+
this.startKeepalive();
|
|
2800
|
+
}
|
|
2801
|
+
/** Send periodic WS pings to prevent idle-timeout disconnects (e.g. CF's 100s).
|
|
2802
|
+
* Also detects dead connections: if a pong isn't received within 10s of a
|
|
2803
|
+
* ping, the connection is considered dead and forcibly closed. */
|
|
2804
|
+
keepaliveTimer = null;
|
|
2805
|
+
pongTimer = null;
|
|
2806
|
+
startKeepalive() {
|
|
2807
|
+
this.ws.on("pong", () => {
|
|
2808
|
+
if (this.pongTimer) {
|
|
2809
|
+
clearTimeout(this.pongTimer);
|
|
2810
|
+
this.pongTimer = null;
|
|
2811
|
+
}
|
|
2812
|
+
});
|
|
2813
|
+
this.keepaliveTimer = setInterval(() => {
|
|
2814
|
+
if (this.ws.readyState === WebSocket.OPEN) {
|
|
2815
|
+
if (!this.pongTimer) {
|
|
2816
|
+
this.pongTimer = setTimeout(() => {
|
|
2817
|
+
if (!this.closed) {
|
|
2818
|
+
this.closed = true;
|
|
2819
|
+
this.closeReason = "keepalive timeout (no pong in 10s)";
|
|
2820
|
+
try {
|
|
2821
|
+
this.ws.terminate();
|
|
2822
|
+
} catch {
|
|
2823
|
+
}
|
|
2824
|
+
for (const [, pending] of this.pending) {
|
|
2825
|
+
clearTimeout(pending.timeout);
|
|
2826
|
+
pending.reject(new Error("Connection dead: keepalive timeout"));
|
|
2827
|
+
}
|
|
2828
|
+
this.pending.clear();
|
|
2829
|
+
this.emit("disconnect");
|
|
2830
|
+
}
|
|
2831
|
+
}, 1e4);
|
|
2832
|
+
}
|
|
2833
|
+
this.ws.ping?.();
|
|
2834
|
+
} else if (this.closed) {
|
|
2835
|
+
if (this.keepaliveTimer) clearInterval(this.keepaliveTimer);
|
|
2836
|
+
this.keepaliveTimer = null;
|
|
2837
|
+
}
|
|
2838
|
+
}, 3e4);
|
|
2750
2839
|
}
|
|
2751
2840
|
/** Wait for the connection to be fully open */
|
|
2752
2841
|
async ready() {
|
|
@@ -2855,6 +2944,14 @@ var CDPConnection = class extends EventEmitter4 {
|
|
|
2855
2944
|
if (this.closed) return;
|
|
2856
2945
|
this.closed = true;
|
|
2857
2946
|
this.closeReason = "closed by caller";
|
|
2947
|
+
if (this.keepaliveTimer) {
|
|
2948
|
+
clearInterval(this.keepaliveTimer);
|
|
2949
|
+
this.keepaliveTimer = null;
|
|
2950
|
+
}
|
|
2951
|
+
if (this.pongTimer) {
|
|
2952
|
+
clearTimeout(this.pongTimer);
|
|
2953
|
+
this.pongTimer = null;
|
|
2954
|
+
}
|
|
2858
2955
|
for (const [id, pending] of this.pending) {
|
|
2859
2956
|
clearTimeout(pending.timeout);
|
|
2860
2957
|
pending.reject(new Error(`Connection closed: ${pending.method}`));
|
|
@@ -2896,6 +2993,10 @@ var CDPConnection = class extends EventEmitter4 {
|
|
|
2896
2993
|
if (this.closed) return;
|
|
2897
2994
|
this.closed = true;
|
|
2898
2995
|
this.closeReason = `WebSocket closed: ${code} ${reason?.toString() ?? ""}`.trim();
|
|
2996
|
+
if (this.keepaliveTimer) {
|
|
2997
|
+
clearInterval(this.keepaliveTimer);
|
|
2998
|
+
this.keepaliveTimer = null;
|
|
2999
|
+
}
|
|
2899
3000
|
for (const [id, pending] of this.pending) {
|
|
2900
3001
|
clearTimeout(pending.timeout);
|
|
2901
3002
|
pending.reject(new Error(`Connection closed: ${pending.method}`));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
launch
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-RRBXV7KE.js";
|
|
4
4
|
import {
|
|
5
5
|
errMsg
|
|
6
6
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -134,7 +134,7 @@ process.on("exit", () => {
|
|
|
134
134
|
if (session.isCDP) {
|
|
135
135
|
logSessionEvent("process_exit", `Session "${session.name}": CDP connection (not closing external browser).`);
|
|
136
136
|
} else {
|
|
137
|
-
logSessionEvent("process_exit", `Session "${session.name}": Closing browser.`);
|
|
137
|
+
logSessionEvent("process_exit", `Session "${session.name}": Closing self-launched browser.`);
|
|
138
138
|
try {
|
|
139
139
|
session.browser?.close();
|
|
140
140
|
} catch {
|
|
@@ -142,7 +142,7 @@ process.on("exit", () => {
|
|
|
142
142
|
}
|
|
143
143
|
}
|
|
144
144
|
if (_sharedBrowser) {
|
|
145
|
-
logSessionEvent("process_exit", "Closing shared browser.");
|
|
145
|
+
logSessionEvent("process_exit", "Closing shared browser (self-launched only, external CDP is safe).");
|
|
146
146
|
try {
|
|
147
147
|
_sharedBrowser.close();
|
|
148
148
|
} catch {
|
|
@@ -628,10 +628,6 @@ async function closeSessionByName(name) {
|
|
|
628
628
|
if (session.name === name || session.id === name) {
|
|
629
629
|
logSessionEvent("close_session", `name="${session.name}" id="${session.id}" url="${session.page.url()}"`);
|
|
630
630
|
if (session.isCDP) {
|
|
631
|
-
try {
|
|
632
|
-
await session.page.close();
|
|
633
|
-
} catch {
|
|
634
|
-
}
|
|
635
631
|
if (session.browser) {
|
|
636
632
|
await session.browser.close().catch(() => {
|
|
637
633
|
});
|
|
@@ -656,7 +652,7 @@ async function closeSessionByName(name) {
|
|
|
656
652
|
} catch {
|
|
657
653
|
}
|
|
658
654
|
try {
|
|
659
|
-
const { SessionRecorder } = await import("./session-recorder-
|
|
655
|
+
const { SessionRecorder } = await import("./session-recorder-QRZMKFVL.js");
|
|
660
656
|
SessionRecorder.cleanup(session.name);
|
|
661
657
|
} catch {
|
|
662
658
|
}
|
|
@@ -675,12 +671,17 @@ async function closeAllSessions() {
|
|
|
675
671
|
if (names) logSessionEvent("close_all_sessions", `Closing ${sessions.size} sessions: ${names}`);
|
|
676
672
|
for (const session of sessions.list()) {
|
|
677
673
|
try {
|
|
678
|
-
if (
|
|
674
|
+
if (session.isCDP) {
|
|
675
|
+
if (session.browser) {
|
|
676
|
+
await session.browser.close().catch(() => {
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
} else {
|
|
679
680
|
await session.context.close();
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
}
|
|
681
|
+
if (session.browser) {
|
|
682
|
+
await session.browser.close().catch(() => {
|
|
683
|
+
});
|
|
684
|
+
}
|
|
684
685
|
}
|
|
685
686
|
sessions.removeById(session.id);
|
|
686
687
|
} catch {
|
|
@@ -689,7 +690,7 @@ async function closeAllSessions() {
|
|
|
689
690
|
}
|
|
690
691
|
}
|
|
691
692
|
async function destroyBrowser() {
|
|
692
|
-
logSessionEvent("destroy_browser", `Sessions count: ${sessions.size}. Clearing idle timer and closing all
|
|
693
|
+
logSessionEvent("destroy_browser", `Sessions count: ${sessions.size}. Clearing idle timer and closing all sessions.`);
|
|
693
694
|
if (idleTimer) {
|
|
694
695
|
clearTimeout(idleTimer);
|
|
695
696
|
idleTimer = null;
|
|
@@ -725,8 +726,6 @@ async function ensureProcessCanExit() {
|
|
|
725
726
|
for (const session of sessions.list()) {
|
|
726
727
|
if (session.browser) {
|
|
727
728
|
if (session.isCDP) {
|
|
728
|
-
await session.browser.close().catch(() => {
|
|
729
|
-
});
|
|
730
729
|
} else {
|
|
731
730
|
await session.browser.close().catch(() => {
|
|
732
731
|
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ScreencastCapturer
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-KFQGP6VL.js";
|
|
3
|
+
} from "./chunk-BNO7OKO4.js";
|
|
5
4
|
|
|
6
5
|
// src/human-interaction.ts
|
|
7
6
|
import { execSync } from "child_process";
|
|
@@ -307,6 +306,7 @@ var HumanInteractionManager = class {
|
|
|
307
306
|
});
|
|
308
307
|
}
|
|
309
308
|
};
|
|
309
|
+
|
|
310
310
|
export {
|
|
311
311
|
HumanInteractionManager
|
|
312
312
|
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getDaemonConfig,
|
|
3
|
+
getDaemonProcessStatus
|
|
4
|
+
} from "./chunk-CG3D3CHY.js";
|
|
5
|
+
|
|
6
|
+
// src/utils/viewer-url.ts
|
|
7
|
+
function buildViewerUrl(sessionName = "default") {
|
|
8
|
+
try {
|
|
9
|
+
const status = getDaemonProcessStatus();
|
|
10
|
+
if (!status.running) return void 0;
|
|
11
|
+
const port = status.port || getDaemonConfig().basePort;
|
|
12
|
+
return `http://localhost:${port}/preview/${encodeURIComponent(sessionName)}`;
|
|
13
|
+
} catch {
|
|
14
|
+
return void 0;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
buildViewerUrl
|
|
20
|
+
};
|
|
@@ -1,128 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
startDaemonProcess,
|
|
3
|
+
stopDaemonProcess
|
|
4
|
+
} from "./chunk-Q2DFJQGS.js";
|
|
1
5
|
import {
|
|
2
6
|
errMsg
|
|
3
7
|
} from "./chunk-GDKLH7ZY.js";
|
|
4
8
|
|
|
5
|
-
// src/daemon/daemon.ts
|
|
6
|
-
import { spawn } from "child_process";
|
|
7
|
-
import { join, dirname } from "path";
|
|
8
|
-
import { homedir } from "os";
|
|
9
|
-
import { fileURLToPath } from "url";
|
|
10
|
-
import { writeFileSync, unlinkSync, mkdirSync } from "fs";
|
|
11
|
-
import { stopDaemon as xcliStopDaemon, isDaemonRunning, getDaemonStatus, killAllDaemon } from "@dyyz1993/xcli-core";
|
|
12
|
-
var CONFIG_DIR = join(homedir(), ".xbrowser");
|
|
13
|
-
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
14
|
-
var WORKER_PATH = join(__dirname, "daemon-main.js");
|
|
15
|
-
function getDaemonConfig() {
|
|
16
|
-
return {
|
|
17
|
-
configDir: CONFIG_DIR,
|
|
18
|
-
workerEntryPath: WORKER_PATH,
|
|
19
|
-
basePort: 9224
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
async function startDaemonProcess(port = 9224) {
|
|
23
|
-
const config = getDaemonConfig();
|
|
24
|
-
if (isDaemonRunning(config)) {
|
|
25
|
-
const status = getDaemonStatus(config);
|
|
26
|
-
if (status.port === port && status.pid) {
|
|
27
|
-
return { pid: status.pid, port: status.port, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
28
|
-
}
|
|
29
|
-
await xcliStopDaemon(config);
|
|
30
|
-
}
|
|
31
|
-
const lockFile = join(CONFIG_DIR, "daemon.lock");
|
|
32
|
-
try {
|
|
33
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
34
|
-
writeFileSync(lockFile, String(process.pid), { flag: "wx" });
|
|
35
|
-
} catch {
|
|
36
|
-
console.error("Another process is starting the daemon, waiting...");
|
|
37
|
-
for (let i = 0; i < 50; i++) {
|
|
38
|
-
await new Promise((r) => setTimeout(r, 200));
|
|
39
|
-
if (isDaemonRunning(config)) {
|
|
40
|
-
const s = getDaemonStatus(config);
|
|
41
|
-
if (s.port === port && s.pid) {
|
|
42
|
-
return { pid: s.pid, port: s.port, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
try {
|
|
47
|
-
unlinkSync(lockFile);
|
|
48
|
-
} catch {
|
|
49
|
-
}
|
|
50
|
-
try {
|
|
51
|
-
writeFileSync(lockFile, String(process.pid), { flag: "wx" });
|
|
52
|
-
} catch {
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
const child = spawn("node", [WORKER_PATH], {
|
|
56
|
-
detached: true,
|
|
57
|
-
stdio: "ignore",
|
|
58
|
-
env: {
|
|
59
|
-
...process.env,
|
|
60
|
-
XBROWSER_DAEMON_PORT: String(port)
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
child.unref();
|
|
64
|
-
return new Promise((resolve, reject) => {
|
|
65
|
-
let resolved = false;
|
|
66
|
-
const timeout = setTimeout(() => {
|
|
67
|
-
if (!resolved) {
|
|
68
|
-
resolved = true;
|
|
69
|
-
try {
|
|
70
|
-
unlinkSync(lockFile);
|
|
71
|
-
} catch {
|
|
72
|
-
}
|
|
73
|
-
reject(new Error("Daemon start timeout after 15s"));
|
|
74
|
-
}
|
|
75
|
-
}, 15e3);
|
|
76
|
-
const checkInterval = setInterval(() => {
|
|
77
|
-
if (isDaemonRunning(config)) {
|
|
78
|
-
const s = getDaemonStatus(config);
|
|
79
|
-
if (s.port === port && s.pid) {
|
|
80
|
-
resolved = true;
|
|
81
|
-
clearTimeout(timeout);
|
|
82
|
-
clearInterval(checkInterval);
|
|
83
|
-
try {
|
|
84
|
-
unlinkSync(lockFile);
|
|
85
|
-
} catch {
|
|
86
|
-
}
|
|
87
|
-
resolve({ pid: s.pid, port: s.port, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}, 200);
|
|
91
|
-
child.on("error", (err) => {
|
|
92
|
-
if (!resolved) {
|
|
93
|
-
resolved = true;
|
|
94
|
-
clearTimeout(timeout);
|
|
95
|
-
clearInterval(checkInterval);
|
|
96
|
-
try {
|
|
97
|
-
unlinkSync(lockFile);
|
|
98
|
-
} catch {
|
|
99
|
-
}
|
|
100
|
-
reject(err);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
async function stopDaemonProcess() {
|
|
106
|
-
await xcliStopDaemon(getDaemonConfig());
|
|
107
|
-
}
|
|
108
|
-
async function killAllDaemonProcesses() {
|
|
109
|
-
await killAllDaemon(getDaemonConfig());
|
|
110
|
-
}
|
|
111
|
-
function getDaemonProcessStatus() {
|
|
112
|
-
const config = getDaemonConfig();
|
|
113
|
-
const running = isDaemonRunning(config);
|
|
114
|
-
if (!running) {
|
|
115
|
-
return { running: false, pid: 0, port: 0, info: null };
|
|
116
|
-
}
|
|
117
|
-
const status = getDaemonStatus(config);
|
|
118
|
-
return {
|
|
119
|
-
running: true,
|
|
120
|
-
pid: status.pid,
|
|
121
|
-
port: status.port,
|
|
122
|
-
info: { pid: status.pid, port: status.port, startedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
9
|
// src/version.ts
|
|
127
10
|
import { createRequire } from "module";
|
|
128
11
|
var require2 = createRequire(import.meta.url);
|
|
@@ -201,7 +84,7 @@ async function rpcCall(method, params = {}, timeoutMs = 1e4) {
|
|
|
201
84
|
}
|
|
202
85
|
return resp.json();
|
|
203
86
|
}
|
|
204
|
-
async function
|
|
87
|
+
async function isDaemonRunning() {
|
|
205
88
|
try {
|
|
206
89
|
const resp = await fetch(`${DAEMON_BASE}/health`, { signal: AbortSignal.timeout(2e3) });
|
|
207
90
|
if (!resp.ok) return false;
|
|
@@ -238,6 +121,15 @@ async function forwardExec(command, params, session = "default", cdpEndpoint, ti
|
|
|
238
121
|
return { success: false, data: null, message: errMsg(e), duration: 0 };
|
|
239
122
|
}
|
|
240
123
|
}
|
|
124
|
+
async function forwardPluginExec(command, params, session = "default", cdpEndpoint, timeoutMs = 12e4) {
|
|
125
|
+
const rpcParams = { command, params, session };
|
|
126
|
+
if (cdpEndpoint) rpcParams.cdpEndpoint = cdpEndpoint;
|
|
127
|
+
try {
|
|
128
|
+
return await rpcCall("plugin:exec", rpcParams, timeoutMs);
|
|
129
|
+
} catch (e) {
|
|
130
|
+
return { success: false, data: null, message: errMsg(e), duration: 0 };
|
|
131
|
+
}
|
|
132
|
+
}
|
|
241
133
|
async function forwardChain(input, session = "default", cdpEndpoint) {
|
|
242
134
|
const params = { chain: input, session };
|
|
243
135
|
if (cdpEndpoint) params.cdpEndpoint = cdpEndpoint;
|
|
@@ -329,17 +221,13 @@ async function forwardViewerCheckSelector(name, selector) {
|
|
|
329
221
|
|
|
330
222
|
export {
|
|
331
223
|
version,
|
|
332
|
-
|
|
333
|
-
startDaemonProcess,
|
|
334
|
-
stopDaemonProcess,
|
|
335
|
-
killAllDaemonProcesses,
|
|
336
|
-
getDaemonProcessStatus,
|
|
337
|
-
isDaemonRunning2 as isDaemonRunning,
|
|
224
|
+
isDaemonRunning,
|
|
338
225
|
daemonPing,
|
|
339
226
|
forwardSessionCreate,
|
|
340
227
|
forwardSessionClose,
|
|
341
228
|
forwardSessionList,
|
|
342
229
|
forwardExec,
|
|
230
|
+
forwardPluginExec,
|
|
343
231
|
forwardChain,
|
|
344
232
|
forwardAgentObserve,
|
|
345
233
|
forwardAgentAct,
|
package/dist/cli.js
CHANGED
|
@@ -21,16 +21,21 @@ import {
|
|
|
21
21
|
forwardSessionClose,
|
|
22
22
|
forwardSessionList,
|
|
23
23
|
forwardViewerCheckSelector,
|
|
24
|
+
version
|
|
25
|
+
} from "./chunk-YMUSHPU4.js";
|
|
26
|
+
import {
|
|
27
|
+
buildViewerUrl
|
|
28
|
+
} from "./chunk-3OD76SUE.js";
|
|
29
|
+
import {
|
|
24
30
|
getDaemonConfig,
|
|
25
31
|
getDaemonProcessStatus,
|
|
26
32
|
killAllDaemonProcesses,
|
|
27
33
|
startDaemonProcess,
|
|
28
|
-
stopDaemonProcess
|
|
29
|
-
|
|
30
|
-
} from "./chunk-YAUG3NSI.js";
|
|
34
|
+
stopDaemonProcess
|
|
35
|
+
} from "./chunk-Q2DFJQGS.js";
|
|
31
36
|
import {
|
|
32
37
|
SessionRecorder
|
|
33
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-4452SPFI.js";
|
|
34
39
|
import {
|
|
35
40
|
addKnownIssue,
|
|
36
41
|
getKnowledgePath,
|
|
@@ -54,7 +59,7 @@ import {
|
|
|
54
59
|
resolveLaunchOpts,
|
|
55
60
|
saveSessionDiskMeta,
|
|
56
61
|
setActivePage
|
|
57
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-GUTBIYFW.js";
|
|
58
63
|
import "./chunk-TNEN6VQ2.js";
|
|
59
64
|
import {
|
|
60
65
|
errMsg
|
|
@@ -62,7 +67,7 @@ import {
|
|
|
62
67
|
import {
|
|
63
68
|
detectAntiBot,
|
|
64
69
|
formatDetectionMessage
|
|
65
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-INTQPBYF.js";
|
|
66
71
|
import {
|
|
67
72
|
NPM_REGISTRY_URL,
|
|
68
73
|
NPM_SCOPE,
|
|
@@ -5866,7 +5871,7 @@ function describeSelector(strategy, value, name) {
|
|
|
5866
5871
|
// src/context.ts
|
|
5867
5872
|
function attachDetectAntiBot(ctx) {
|
|
5868
5873
|
ctx.detectAntiBot = async (page, config) => {
|
|
5869
|
-
const { detectAntiBot: detectAntiBot2 } = await import("./anti-bot-
|
|
5874
|
+
const { detectAntiBot: detectAntiBot2 } = await import("./anti-bot-DR56Y63V.js");
|
|
5870
5875
|
return detectAntiBot2(page, config);
|
|
5871
5876
|
};
|
|
5872
5877
|
}
|
|
@@ -6313,18 +6318,6 @@ async function getPluginLoader() {
|
|
|
6313
6318
|
return pluginLoader;
|
|
6314
6319
|
}
|
|
6315
6320
|
|
|
6316
|
-
// src/utils/viewer-url.ts
|
|
6317
|
-
function buildViewerUrl(sessionName = "default") {
|
|
6318
|
-
try {
|
|
6319
|
-
const status = getDaemonProcessStatus();
|
|
6320
|
-
if (!status.running) return void 0;
|
|
6321
|
-
const port = status.port || getDaemonConfig().basePort;
|
|
6322
|
-
return `http://localhost:${port}/preview/${encodeURIComponent(sessionName)}`;
|
|
6323
|
-
} catch {
|
|
6324
|
-
return void 0;
|
|
6325
|
-
}
|
|
6326
|
-
}
|
|
6327
|
-
|
|
6328
6321
|
// src/plugin/login-guard.ts
|
|
6329
6322
|
async function checkPluginLoginRequired(options) {
|
|
6330
6323
|
const { site, command, commandName, ctx, page, sessionName } = options;
|
|
@@ -7058,7 +7051,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7058
7051
|
}
|
|
7059
7052
|
let targetPageOverride = null;
|
|
7060
7053
|
if (_target && extraOpts?.cdpEndpoint) {
|
|
7061
|
-
const { findTargetPage } = await import("./browser-
|
|
7054
|
+
const { findTargetPage } = await import("./browser-FFYPFTBV.js");
|
|
7062
7055
|
targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
|
|
7063
7056
|
if (!targetPageOverride) {
|
|
7064
7057
|
return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
|
|
@@ -7075,7 +7068,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7075
7068
|
params = result.data;
|
|
7076
7069
|
}
|
|
7077
7070
|
if (command.scope !== "cli" && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
7078
|
-
const { forwardExec } = await import("./daemon-client-
|
|
7071
|
+
const { forwardExec } = await import("./daemon-client-O6BYVRXV.js");
|
|
7079
7072
|
const result = await forwardExec(commandName, params, sessionName, extraOpts?.cdpEndpoint);
|
|
7080
7073
|
if (result) return result;
|
|
7081
7074
|
}
|
|
@@ -7263,6 +7256,26 @@ async function executeCommand(commandName, params, sessionName = "default", extr
|
|
|
7263
7256
|
const end = Date.now();
|
|
7264
7257
|
const duration = end - start;
|
|
7265
7258
|
const errorMessage = errMsg(err);
|
|
7259
|
+
if (session?.page && process.env.XBROWSER_RECOVERY && !extraOpts?._recoveryAttempted) {
|
|
7260
|
+
try {
|
|
7261
|
+
const { attemptRecovery } = await import("./recovery-J2ISVGUL.js");
|
|
7262
|
+
const recovery = await attemptRecovery(
|
|
7263
|
+
session.page,
|
|
7264
|
+
sessionName,
|
|
7265
|
+
commandName,
|
|
7266
|
+
errorMessage
|
|
7267
|
+
);
|
|
7268
|
+
if (recovery.recovered) {
|
|
7269
|
+
const retry = await executeCommand(commandName, params, sessionName, {
|
|
7270
|
+
...extraOpts,
|
|
7271
|
+
skipCleanup: true,
|
|
7272
|
+
_recoveryAttempted: true
|
|
7273
|
+
});
|
|
7274
|
+
return retry;
|
|
7275
|
+
}
|
|
7276
|
+
} catch {
|
|
7277
|
+
}
|
|
7278
|
+
}
|
|
7266
7279
|
if (session) {
|
|
7267
7280
|
streamCommandEvent(session.id, {
|
|
7268
7281
|
sessionId: session.id,
|
|
@@ -10551,7 +10564,7 @@ async function handlePlugin(args, options, mode) {
|
|
|
10551
10564
|
} catch {
|
|
10552
10565
|
}
|
|
10553
10566
|
try {
|
|
10554
|
-
const { daemonPing } = await import("./daemon-client-
|
|
10567
|
+
const { daemonPing } = await import("./daemon-client-O6BYVRXV.js");
|
|
10555
10568
|
if (await daemonPing()) {
|
|
10556
10569
|
await fetch("http://localhost:9224/rpc", {
|
|
10557
10570
|
method: "POST",
|
|
@@ -11117,7 +11130,7 @@ async function handleFilter(args, _mode, options) {
|
|
|
11117
11130
|
}
|
|
11118
11131
|
}
|
|
11119
11132
|
async function handleGeneratePlugin(sessionName, pluginName, outputDir) {
|
|
11120
|
-
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-
|
|
11133
|
+
const { SessionRecorder: SessionRecorder2 } = await import("./session-recorder-QRZMKFVL.js");
|
|
11121
11134
|
const { readSiteKnowledge: readSiteKnowledge2, toMarkdown } = await import("./site-knowledge-SYC6VCDB.js");
|
|
11122
11135
|
const { mkdirSync: mkdirSync10, writeFileSync: writeFileSync12 } = await import("fs");
|
|
11123
11136
|
const { join: join13 } = await import("path");
|
|
@@ -11354,7 +11367,7 @@ async function handleRun(filePath, options) {
|
|
|
11354
11367
|
|
|
11355
11368
|
// src/cli/viewer-routes.ts
|
|
11356
11369
|
async function handleViewer(_args, options, mode, _cdpEndpoint) {
|
|
11357
|
-
const name = options.
|
|
11370
|
+
const name = options.session || process.env.XBROWSER_SESSION || "default";
|
|
11358
11371
|
const selector = options.selector;
|
|
11359
11372
|
const userPort = options.port ? Number(options.port) : void 0;
|
|
11360
11373
|
let status = getDaemonProcessStatus();
|
|
@@ -13054,9 +13067,9 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13054
13067
|
}
|
|
13055
13068
|
const needsBrowser = cmdEntry.scope === "page" || cmdEntry.scope === "browser";
|
|
13056
13069
|
if (needsBrowser && !process.env.XBROWSER_DAEMON_WORKER) {
|
|
13057
|
-
const {
|
|
13070
|
+
const { forwardPluginExec } = await import("./daemon-client-O6BYVRXV.js");
|
|
13058
13071
|
const userTimeout = typeof params.timeout === "number" && params.timeout > 0 ? params.timeout * 1e3 + 3e4 : void 0;
|
|
13059
|
-
const result = await
|
|
13072
|
+
const result = await forwardPluginExec(`${command}.${subCommand}`, params, sessionName, cdpEndpoint, userTimeout);
|
|
13060
13073
|
const resultData = result && typeof result === "object" && "data" in result ? result.data : void 0;
|
|
13061
13074
|
if (result && result.success === false && resultData?.code === "LOGIN_REQUIRED") {
|
|
13062
13075
|
process.exitCode = 1;
|
|
@@ -13094,7 +13107,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
|
|
|
13094
13107
|
const targetPage = pages[cmdTabIndex];
|
|
13095
13108
|
await targetPage.bringToFront().catch(() => {
|
|
13096
13109
|
});
|
|
13097
|
-
const { setActivePage: setActivePage2 } = await import("./browser-
|
|
13110
|
+
const { setActivePage: setActivePage2 } = await import("./browser-FFYPFTBV.js");
|
|
13098
13111
|
setActivePage2(session, targetPage);
|
|
13099
13112
|
}
|
|
13100
13113
|
}
|
|
@@ -13370,7 +13383,7 @@ async function main() {
|
|
|
13370
13383
|
const command = process.argv[2];
|
|
13371
13384
|
const isLongRunning = command === "preview" || command === "serve";
|
|
13372
13385
|
if (!isLongRunning) {
|
|
13373
|
-
const { ensureProcessCanExit } = await import("./browser-
|
|
13386
|
+
const { ensureProcessCanExit } = await import("./browser-FFYPFTBV.js");
|
|
13374
13387
|
await ensureProcessCanExit().catch(() => {
|
|
13375
13388
|
});
|
|
13376
13389
|
process.exit(process.exitCode || exitCode);
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
startDaemonProcess,
|
|
3
|
-
stopDaemonProcess,
|
|
4
2
|
version
|
|
5
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-43TEMG4U.js";
|
|
4
|
+
import {
|
|
5
|
+
startDaemonProcess,
|
|
6
|
+
stopDaemonProcess
|
|
7
|
+
} from "./chunk-CG3D3CHY.js";
|
|
6
8
|
import {
|
|
7
9
|
errMsg
|
|
8
10
|
} from "./chunk-GDKLH7ZY.js";
|
|
@@ -117,6 +119,15 @@ async function forwardExec(command, params, session = "default", cdpEndpoint, ti
|
|
|
117
119
|
return { success: false, data: null, message: errMsg(e), duration: 0 };
|
|
118
120
|
}
|
|
119
121
|
}
|
|
122
|
+
async function forwardPluginExec(command, params, session = "default", cdpEndpoint, timeoutMs = 12e4) {
|
|
123
|
+
const rpcParams = { command, params, session };
|
|
124
|
+
if (cdpEndpoint) rpcParams.cdpEndpoint = cdpEndpoint;
|
|
125
|
+
try {
|
|
126
|
+
return await rpcCall("plugin:exec", rpcParams, timeoutMs);
|
|
127
|
+
} catch (e) {
|
|
128
|
+
return { success: false, data: null, message: errMsg(e), duration: 0 };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
120
131
|
async function forwardChain(input, session = "default", cdpEndpoint) {
|
|
121
132
|
const params = { chain: input, session };
|
|
122
133
|
if (cdpEndpoint) params.cdpEndpoint = cdpEndpoint;
|
|
@@ -224,6 +235,7 @@ export {
|
|
|
224
235
|
forwardNetworkList,
|
|
225
236
|
forwardNetworkReplay,
|
|
226
237
|
forwardNetworkTop,
|
|
238
|
+
forwardPluginExec,
|
|
227
239
|
forwardRecordCheckpoint,
|
|
228
240
|
forwardRecordStart,
|
|
229
241
|
forwardRecordStatus,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
forwardNetworkList,
|
|
18
18
|
forwardNetworkReplay,
|
|
19
19
|
forwardNetworkTop,
|
|
20
|
+
forwardPluginExec,
|
|
20
21
|
forwardRecordCheckpoint,
|
|
21
22
|
forwardRecordStart,
|
|
22
23
|
forwardRecordStatus,
|
|
@@ -29,7 +30,8 @@ import {
|
|
|
29
30
|
forwardSessionList,
|
|
30
31
|
forwardViewerCheckSelector,
|
|
31
32
|
isDaemonRunning
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-YMUSHPU4.js";
|
|
34
|
+
import "./chunk-Q2DFJQGS.js";
|
|
33
35
|
import "./chunk-GDKLH7ZY.js";
|
|
34
36
|
import "./chunk-KFQGP6VL.js";
|
|
35
37
|
export {
|
|
@@ -51,6 +53,7 @@ export {
|
|
|
51
53
|
forwardNetworkList,
|
|
52
54
|
forwardNetworkReplay,
|
|
53
55
|
forwardNetworkTop,
|
|
56
|
+
forwardPluginExec,
|
|
54
57
|
forwardRecordCheckpoint,
|
|
55
58
|
forwardRecordStart,
|
|
56
59
|
forwardRecordStatus,
|