@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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
connectToCDP,
|
|
3
3
|
launchChrome
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BBMRDUYQ.js";
|
|
5
5
|
import {
|
|
6
6
|
__require
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KFQGP6VL.js";
|
|
8
8
|
|
|
9
9
|
// src/browser.ts
|
|
10
10
|
import { randomUUID } from "crypto";
|
|
@@ -250,36 +250,36 @@ function resolveKeyMapping(key) {
|
|
|
250
250
|
return { key, code: key };
|
|
251
251
|
}
|
|
252
252
|
var KEY_MAP = {
|
|
253
|
-
Enter: { key: "Enter", code: "Enter", text: "\r" },
|
|
254
|
-
Tab: { key: "Tab", code: "Tab", text: " " },
|
|
255
|
-
Escape: { key: "Escape", code: "Escape" },
|
|
256
|
-
Backspace: { key: "Backspace", code: "Backspace" },
|
|
257
|
-
Delete: { key: "Delete", code: "Delete" },
|
|
258
|
-
Space: { key: " ", code: "Space", text: " " },
|
|
259
|
-
ArrowUp: { key: "ArrowUp", code: "ArrowUp" },
|
|
260
|
-
ArrowDown: { key: "ArrowDown", code: "ArrowDown" },
|
|
261
|
-
ArrowLeft: { key: "ArrowLeft", code: "ArrowLeft" },
|
|
262
|
-
ArrowRight: { key: "ArrowRight", code: "ArrowRight" },
|
|
263
|
-
Home: { key: "Home", code: "Home" },
|
|
264
|
-
End: { key: "End", code: "End" },
|
|
265
|
-
PageUp: { key: "PageUp", code: "PageUp" },
|
|
266
|
-
PageDown: { key: "PageDown", code: "PageDown" },
|
|
267
|
-
Control: { key: "Control", code: "ControlLeft" },
|
|
268
|
-
Shift: { key: "Shift", code: "ShiftLeft" },
|
|
269
|
-
Alt: { key: "Alt", code: "AltLeft" },
|
|
270
|
-
Meta: { key: "Meta", code: "MetaLeft" },
|
|
271
|
-
F1: { key: "F1", code: "F1" },
|
|
272
|
-
F2: { key: "F2", code: "F2" },
|
|
273
|
-
F3: { key: "F3", code: "F3" },
|
|
274
|
-
F4: { key: "F4", code: "F4" },
|
|
275
|
-
F5: { key: "F5", code: "F5" },
|
|
276
|
-
F6: { key: "F6", code: "F6" },
|
|
277
|
-
F7: { key: "F7", code: "F7" },
|
|
278
|
-
F8: { key: "F8", code: "F8" },
|
|
279
|
-
F9: { key: "F9", code: "F9" },
|
|
280
|
-
F10: { key: "F10", code: "F10" },
|
|
281
|
-
F11: { key: "F11", code: "F11" },
|
|
282
|
-
F12: { key: "F12", code: "F12" }
|
|
253
|
+
Enter: { key: "Enter", code: "Enter", text: "\r", keyCode: 13 },
|
|
254
|
+
Tab: { key: "Tab", code: "Tab", text: " ", keyCode: 9 },
|
|
255
|
+
Escape: { key: "Escape", code: "Escape", keyCode: 27 },
|
|
256
|
+
Backspace: { key: "Backspace", code: "Backspace", keyCode: 8 },
|
|
257
|
+
Delete: { key: "Delete", code: "Delete", keyCode: 46 },
|
|
258
|
+
Space: { key: " ", code: "Space", text: " ", keyCode: 32 },
|
|
259
|
+
ArrowUp: { key: "ArrowUp", code: "ArrowUp", keyCode: 38 },
|
|
260
|
+
ArrowDown: { key: "ArrowDown", code: "ArrowDown", keyCode: 40 },
|
|
261
|
+
ArrowLeft: { key: "ArrowLeft", code: "ArrowLeft", keyCode: 37 },
|
|
262
|
+
ArrowRight: { key: "ArrowRight", code: "ArrowRight", keyCode: 39 },
|
|
263
|
+
Home: { key: "Home", code: "Home", keyCode: 36 },
|
|
264
|
+
End: { key: "End", code: "End", keyCode: 35 },
|
|
265
|
+
PageUp: { key: "PageUp", code: "PageUp", keyCode: 33 },
|
|
266
|
+
PageDown: { key: "PageDown", code: "PageDown", keyCode: 34 },
|
|
267
|
+
Control: { key: "Control", code: "ControlLeft", keyCode: 17 },
|
|
268
|
+
Shift: { key: "Shift", code: "ShiftLeft", keyCode: 16 },
|
|
269
|
+
Alt: { key: "Alt", code: "AltLeft", keyCode: 18 },
|
|
270
|
+
Meta: { key: "Meta", code: "MetaLeft", keyCode: 91 },
|
|
271
|
+
F1: { key: "F1", code: "F1", keyCode: 112 },
|
|
272
|
+
F2: { key: "F2", code: "F2", keyCode: 113 },
|
|
273
|
+
F3: { key: "F3", code: "F3", keyCode: 114 },
|
|
274
|
+
F4: { key: "F4", code: "F4", keyCode: 115 },
|
|
275
|
+
F5: { key: "F5", code: "F5", keyCode: 116 },
|
|
276
|
+
F6: { key: "F6", code: "F6", keyCode: 117 },
|
|
277
|
+
F7: { key: "F7", code: "F7", keyCode: 118 },
|
|
278
|
+
F8: { key: "F8", code: "F8", keyCode: 119 },
|
|
279
|
+
F9: { key: "F9", code: "F9", keyCode: 120 },
|
|
280
|
+
F10: { key: "F10", code: "F10", keyCode: 121 },
|
|
281
|
+
F11: { key: "F11", code: "F11", keyCode: 122 },
|
|
282
|
+
F12: { key: "F12", code: "F12", keyCode: 123 }
|
|
283
283
|
};
|
|
284
284
|
function sleep2(ms) {
|
|
285
285
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -974,7 +974,7 @@ function createXBRequest(page, data) {
|
|
|
974
974
|
}
|
|
975
975
|
};
|
|
976
976
|
}
|
|
977
|
-
function createXBRouteFetch(conn, sessionId, params) {
|
|
977
|
+
function createXBRouteFetch(conn, sessionId, params, emitter) {
|
|
978
978
|
const request = createXBRequest(null, {
|
|
979
979
|
requestId: params.requestId,
|
|
980
980
|
url: params.request.url,
|
|
@@ -1012,6 +1012,16 @@ function createXBRouteFetch(conn, sessionId, params) {
|
|
|
1012
1012
|
responseHeaders: Object.entries(headers).map(([k, v]) => ({ name: k, value: v })),
|
|
1013
1013
|
body: bodyBytes.toString("base64")
|
|
1014
1014
|
}, sessionId);
|
|
1015
|
+
if (emitter) {
|
|
1016
|
+
const responseData = {
|
|
1017
|
+
requestId: params.requestId,
|
|
1018
|
+
status: opts.status ?? 200,
|
|
1019
|
+
url: params.request.url,
|
|
1020
|
+
headers
|
|
1021
|
+
};
|
|
1022
|
+
const response = createXBResponse(responseData, conn, sessionId);
|
|
1023
|
+
emitter.emit("response", response);
|
|
1024
|
+
}
|
|
1015
1025
|
}
|
|
1016
1026
|
};
|
|
1017
1027
|
}
|
|
@@ -1233,6 +1243,25 @@ Last error: ${lastError.message}` : "";
|
|
|
1233
1243
|
}
|
|
1234
1244
|
return result.result?.value;
|
|
1235
1245
|
}
|
|
1246
|
+
/** evaluateHandle — evaluates fn and returns a handle for element bounding box */
|
|
1247
|
+
async evaluateHandle(fn, ...args) {
|
|
1248
|
+
let expression;
|
|
1249
|
+
if (typeof fn === "string") {
|
|
1250
|
+
expression = fn;
|
|
1251
|
+
} else {
|
|
1252
|
+
const argStr = args.length > 0 ? `...${JSON.stringify(args)}` : "";
|
|
1253
|
+
expression = `(()=>{const __fn=(${fn.toString()});const __el=__fn(${argStr});if(__el&&typeof __el.getBoundingClientRect==='function'){const r=__el.getBoundingClientRect();return JSON.parse(JSON.stringify({x:r.x,y:r.y,w:r.width,h:r.height}));}return null;})()`;
|
|
1254
|
+
}
|
|
1255
|
+
const result = await this.conn.send("Runtime.evaluate", { expression, returnByValue: true }).catch(() => ({ result: { value: null } }));
|
|
1256
|
+
let box = null;
|
|
1257
|
+
try {
|
|
1258
|
+
box = JSON.parse(result.result?.value);
|
|
1259
|
+
} catch {
|
|
1260
|
+
}
|
|
1261
|
+
return {
|
|
1262
|
+
asElement: () => box ? { boundingBox: async () => box } : null
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1236
1265
|
async $eval(selector, fn, ...args) {
|
|
1237
1266
|
const fnBody = typeof fn === "function" ? fn.toString() : fn;
|
|
1238
1267
|
return this.evaluate(
|
|
@@ -1448,6 +1477,26 @@ Last error: ${lastError.message}` : "";
|
|
|
1448
1477
|
off(event, handler) {
|
|
1449
1478
|
this._emitter.off(event, handler);
|
|
1450
1479
|
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Wait for a one-shot event (Playwright-compatible subset).
|
|
1482
|
+
* Used to listen for 'filechooser', 'dialog', 'popup', 'framenavigated', etc.
|
|
1483
|
+
*/
|
|
1484
|
+
async waitForEvent(event, opts = {}) {
|
|
1485
|
+
const timeout = opts.timeout ?? 3e4;
|
|
1486
|
+
return new Promise((resolve, reject) => {
|
|
1487
|
+
const timer = setTimeout(() => {
|
|
1488
|
+
this._emitter.off(event, handler);
|
|
1489
|
+
reject(new Error(`waitForEvent('${event}') timeout after ${timeout}ms`));
|
|
1490
|
+
}, timeout);
|
|
1491
|
+
const handler = (...args) => {
|
|
1492
|
+
if (opts.predicate && !opts.predicate(...args)) return;
|
|
1493
|
+
clearTimeout(timer);
|
|
1494
|
+
this._emitter.off(event, handler);
|
|
1495
|
+
resolve(args.length === 1 ? args[0] : args);
|
|
1496
|
+
};
|
|
1497
|
+
this._emitter.on(event, handler);
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1451
1500
|
// ── Lifecycle ───────────────────────────────────────────────
|
|
1452
1501
|
async close() {
|
|
1453
1502
|
if (this._closed) return;
|
|
@@ -1611,6 +1660,40 @@ Last error: ${lastError.message}` : "";
|
|
|
1611
1660
|
this._emit("dialog", dialog);
|
|
1612
1661
|
})
|
|
1613
1662
|
);
|
|
1663
|
+
this._subscriptions.push(
|
|
1664
|
+
this.conn.subscribe("Page.fileChooserOpened", this.sessionId, async (params) => {
|
|
1665
|
+
const p = params;
|
|
1666
|
+
let selector = "";
|
|
1667
|
+
try {
|
|
1668
|
+
const result = await this.conn.send("DOM.describeNode", { backendNodeId: p.backendNodeId }, this.sessionId);
|
|
1669
|
+
const attrs = result.node?.attributes || [];
|
|
1670
|
+
const idIdx = attrs.indexOf("id");
|
|
1671
|
+
if (idIdx >= 0) selector = "#" + attrs[idIdx + 1];
|
|
1672
|
+
} catch {
|
|
1673
|
+
}
|
|
1674
|
+
if (!selector) {
|
|
1675
|
+
try {
|
|
1676
|
+
const result = await this.conn.send("DOM.resolveNode", { backendNodeId: p.backendNodeId }, this.sessionId);
|
|
1677
|
+
const evalResult = await this.conn.send("Runtime.callFunctionOn", {
|
|
1678
|
+
objectId: result.objectId,
|
|
1679
|
+
functionDeclaration: 'function() { return this.id || this.name || "" }',
|
|
1680
|
+
returnByValue: true
|
|
1681
|
+
}, this.sessionId);
|
|
1682
|
+
if (evalResult.result?.value) selector = "#" + evalResult.result.value;
|
|
1683
|
+
} catch {
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
const fileChooser = {
|
|
1687
|
+
selector,
|
|
1688
|
+
isMultiple: p.mode === "selectMultiple",
|
|
1689
|
+
setFiles: async (files) => {
|
|
1690
|
+
const fileArray = Array.isArray(files) ? files : [files];
|
|
1691
|
+
await this.setInputFiles(selector || 'input[type="file"]', fileArray);
|
|
1692
|
+
}
|
|
1693
|
+
};
|
|
1694
|
+
this._emit("filechooser", fileChooser);
|
|
1695
|
+
})
|
|
1696
|
+
);
|
|
1614
1697
|
}
|
|
1615
1698
|
setupNetworkEvents() {
|
|
1616
1699
|
this._subscriptions.push(
|
|
@@ -1624,7 +1707,17 @@ Last error: ${lastError.message}` : "";
|
|
|
1624
1707
|
postData: p.request.postData ?? null,
|
|
1625
1708
|
resourceType: p.type
|
|
1626
1709
|
});
|
|
1627
|
-
this._emit("request",
|
|
1710
|
+
this._emit("request", createXBRequest(
|
|
1711
|
+
null,
|
|
1712
|
+
{
|
|
1713
|
+
requestId: p.requestId,
|
|
1714
|
+
url: p.request.url,
|
|
1715
|
+
method: p.request.method,
|
|
1716
|
+
headers: p.request.headers,
|
|
1717
|
+
postData: p.request.postData ?? null,
|
|
1718
|
+
resourceType: p.type
|
|
1719
|
+
}
|
|
1720
|
+
));
|
|
1628
1721
|
this.checkNetworkIdle();
|
|
1629
1722
|
})
|
|
1630
1723
|
);
|
|
@@ -1636,7 +1729,11 @@ Last error: ${lastError.message}` : "";
|
|
|
1636
1729
|
url: p.response.url,
|
|
1637
1730
|
headers: p.response.headers
|
|
1638
1731
|
});
|
|
1639
|
-
this._emit("response",
|
|
1732
|
+
this._emit("response", createXBResponse(
|
|
1733
|
+
{ requestId: p.requestId, status: p.response.status, url: p.response.url, headers: p.response.headers },
|
|
1734
|
+
this.conn,
|
|
1735
|
+
this.sessionId
|
|
1736
|
+
));
|
|
1640
1737
|
})
|
|
1641
1738
|
);
|
|
1642
1739
|
this._subscriptions.push(
|
|
@@ -1722,14 +1819,21 @@ Last error: ${lastError.message}` : "";
|
|
|
1722
1819
|
reject(new Error(`waitForResponse timed out after ${timeout}ms`));
|
|
1723
1820
|
}, timeout);
|
|
1724
1821
|
const handler = (params) => {
|
|
1725
|
-
|
|
1726
|
-
const
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1822
|
+
let response;
|
|
1823
|
+
const respObj = params;
|
|
1824
|
+
if (respObj.response) {
|
|
1825
|
+
const data = {
|
|
1826
|
+
requestId: respObj.requestId || "",
|
|
1827
|
+
status: respObj.response.status || 0,
|
|
1828
|
+
url: respObj.response.url || "",
|
|
1829
|
+
headers: respObj.response.headers || {}
|
|
1830
|
+
};
|
|
1831
|
+
response = createXBResponse(data, this.conn, this.sessionId);
|
|
1832
|
+
} else if (typeof params.status === "function") {
|
|
1833
|
+
response = params;
|
|
1834
|
+
} else {
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1733
1837
|
if (predicate(response)) {
|
|
1734
1838
|
clearTimeout(timer);
|
|
1735
1839
|
this._emitter.removeListener("response", handler);
|
|
@@ -1753,16 +1857,22 @@ Last error: ${lastError.message}` : "";
|
|
|
1753
1857
|
reject(new Error(`waitForRequest timed out after ${timeout}ms`));
|
|
1754
1858
|
}, timeout);
|
|
1755
1859
|
const handler = (params) => {
|
|
1756
|
-
|
|
1757
|
-
const
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1860
|
+
let request;
|
|
1861
|
+
const reqObj = params;
|
|
1862
|
+
if (reqObj.request) {
|
|
1863
|
+
request = createXBRequest(this, {
|
|
1864
|
+
requestId: reqObj.requestId || "",
|
|
1865
|
+
url: reqObj.request.url || "",
|
|
1866
|
+
method: reqObj.request.method || "",
|
|
1867
|
+
headers: reqObj.request.headers || {},
|
|
1868
|
+
postData: reqObj.request.postData ?? null,
|
|
1869
|
+
resourceType: reqObj.type || ""
|
|
1870
|
+
});
|
|
1871
|
+
} else if (typeof params.url === "function") {
|
|
1872
|
+
request = params;
|
|
1873
|
+
} else {
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1766
1876
|
if (predicate(request)) {
|
|
1767
1877
|
clearTimeout(timer);
|
|
1768
1878
|
this._emitter.removeListener("request", handler);
|
|
@@ -1823,7 +1933,18 @@ Last error: ${lastError.message}` : "";
|
|
|
1823
1933
|
const requestUrl = params.request.url;
|
|
1824
1934
|
for (const { regex, handler } of this._routeHandlers) {
|
|
1825
1935
|
if (regex.test(requestUrl)) {
|
|
1826
|
-
|
|
1936
|
+
this._emit("request", createXBRequest(
|
|
1937
|
+
null,
|
|
1938
|
+
{
|
|
1939
|
+
requestId: params.requestId,
|
|
1940
|
+
url: params.request.url,
|
|
1941
|
+
method: params.request.method,
|
|
1942
|
+
headers: params.request.headers,
|
|
1943
|
+
postData: params.request.postData ?? null,
|
|
1944
|
+
resourceType: params.resourceType
|
|
1945
|
+
}
|
|
1946
|
+
));
|
|
1947
|
+
const route = createXBRouteFetch(this.conn, this.sessionId, params, this._emitter);
|
|
1827
1948
|
try {
|
|
1828
1949
|
await handler(route);
|
|
1829
1950
|
} catch {
|
|
@@ -1990,6 +2111,7 @@ var XBContextImpl = class {
|
|
|
1990
2111
|
const page = new XBPageImpl(this.conn, sessionId, targetId, this, this._browser);
|
|
1991
2112
|
await page._init();
|
|
1992
2113
|
this._pages.push(page);
|
|
2114
|
+
this.forwardPageEvents(page);
|
|
1993
2115
|
if (this.options.viewport) {
|
|
1994
2116
|
await page.setViewportSize(this.options.viewport).catch(() => {
|
|
1995
2117
|
});
|
|
@@ -2031,7 +2153,10 @@ var XBContextImpl = class {
|
|
|
2031
2153
|
}
|
|
2032
2154
|
this._browser._removeContext(this.contextId);
|
|
2033
2155
|
}
|
|
2034
|
-
async newCDPSession(
|
|
2156
|
+
async newCDPSession(page) {
|
|
2157
|
+
if (page instanceof XBPageImpl) {
|
|
2158
|
+
return new XBCDPSessionImpl(this.conn, page.sessionId);
|
|
2159
|
+
}
|
|
2035
2160
|
return new XBCDPSessionImpl(this.conn);
|
|
2036
2161
|
}
|
|
2037
2162
|
async addInitScript(script) {
|
|
@@ -2068,7 +2193,31 @@ var XBContextImpl = class {
|
|
|
2068
2193
|
off(event, handler) {
|
|
2069
2194
|
this._emitter.off(event, handler);
|
|
2070
2195
|
}
|
|
2196
|
+
/**
|
|
2197
|
+
* Register a page that was attached to an existing target (discovered via
|
|
2198
|
+
* Target.getTargets). Used by XBBrowserImpl.discoverContexts() to wire up
|
|
2199
|
+
* pages from the user's existing browser session into the context wrapper
|
|
2200
|
+
* so they appear in `context.pages()` and can be reused by plugins.
|
|
2201
|
+
*/
|
|
2202
|
+
_addDiscoveredPage(page) {
|
|
2203
|
+
const exists = this._pages.some((p) => p._targetId === page._targetId);
|
|
2204
|
+
if (exists) return;
|
|
2205
|
+
this._pages.push(page);
|
|
2206
|
+
this.forwardPageEvents(page);
|
|
2207
|
+
}
|
|
2071
2208
|
// ── Private ─────────────────────────────────────────────────
|
|
2209
|
+
/** Forward page-level events (request, response, etc.) to context listeners */
|
|
2210
|
+
forwardPageEvents(page) {
|
|
2211
|
+
const forward = (event) => {
|
|
2212
|
+
page.on(event, (...args) => {
|
|
2213
|
+
this._emitter.emit(event, ...args);
|
|
2214
|
+
});
|
|
2215
|
+
};
|
|
2216
|
+
forward("request");
|
|
2217
|
+
forward("response");
|
|
2218
|
+
forward("requestfailed");
|
|
2219
|
+
forward("requestfinished");
|
|
2220
|
+
}
|
|
2072
2221
|
setupAutoAttach() {
|
|
2073
2222
|
this.targetAttachedHandler = (paramsRaw) => {
|
|
2074
2223
|
const params = paramsRaw;
|
|
@@ -2093,6 +2242,7 @@ var XBContextImpl = class {
|
|
|
2093
2242
|
});
|
|
2094
2243
|
}
|
|
2095
2244
|
this._pages.push(page);
|
|
2245
|
+
this.forwardPageEvents(page);
|
|
2096
2246
|
this._emitter.emit("page", page);
|
|
2097
2247
|
});
|
|
2098
2248
|
};
|
|
@@ -2109,10 +2259,17 @@ var XBBrowserImpl = class {
|
|
|
2109
2259
|
childProcess = null;
|
|
2110
2260
|
tmpDir;
|
|
2111
2261
|
_exitHandler = null;
|
|
2112
|
-
|
|
2262
|
+
/**
|
|
2263
|
+
* Original CDP endpoint (HTTP or ws URL) used to construct this browser.
|
|
2264
|
+
* Used by discoverContexts() as a fallback to HTTP /json/list when
|
|
2265
|
+
* Target.getTargets doesn't return page-type targets (e.g. cdp-tunnel proxy).
|
|
2266
|
+
*/
|
|
2267
|
+
cdpEndpoint;
|
|
2268
|
+
constructor(conn, childProcess, tmpDir, cdpEndpoint) {
|
|
2113
2269
|
this.conn = conn;
|
|
2114
2270
|
this.childProcess = childProcess ?? null;
|
|
2115
2271
|
this.tmpDir = tmpDir;
|
|
2272
|
+
this.cdpEndpoint = cdpEndpoint;
|
|
2116
2273
|
conn.on("disconnect", () => {
|
|
2117
2274
|
this._disconnected = true;
|
|
2118
2275
|
this._emitter.emit("disconnected");
|
|
@@ -2156,7 +2313,7 @@ var XBBrowserImpl = class {
|
|
|
2156
2313
|
this._exitHandler = null;
|
|
2157
2314
|
}
|
|
2158
2315
|
if (this.childProcess) {
|
|
2159
|
-
const { killChrome: killChrome2 } = await import("./launcher-
|
|
2316
|
+
const { killChrome: killChrome2 } = await import("./launcher-QUJ4M2VS.js");
|
|
2160
2317
|
await killChrome2(this.childProcess, this.tmpDir);
|
|
2161
2318
|
}
|
|
2162
2319
|
await this.conn.close();
|
|
@@ -2186,6 +2343,10 @@ var XBBrowserImpl = class {
|
|
|
2186
2343
|
contextId,
|
|
2187
2344
|
context
|
|
2188
2345
|
});
|
|
2346
|
+
if (this.childProcess) {
|
|
2347
|
+
this._enableAutoAttach().catch(() => {
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2189
2350
|
return context;
|
|
2190
2351
|
}
|
|
2191
2352
|
contexts() {
|
|
@@ -2214,6 +2375,23 @@ var XBBrowserImpl = class {
|
|
|
2214
2375
|
async _detachFromTarget(sessionId) {
|
|
2215
2376
|
await this.conn.send("Target.detachFromTarget", { sessionId });
|
|
2216
2377
|
}
|
|
2378
|
+
/**
|
|
2379
|
+
* Derive the HTTP /json base URL from the original cdpEndpoint for use
|
|
2380
|
+
* as a fallback when Target.getTargets doesn't return page targets.
|
|
2381
|
+
* Supports both http:// and ws:// input formats.
|
|
2382
|
+
*/
|
|
2383
|
+
_httpFallbackURL() {
|
|
2384
|
+
if (!this.cdpEndpoint) return void 0;
|
|
2385
|
+
if (this.cdpEndpoint.startsWith("http://") || this.cdpEndpoint.startsWith("https://")) {
|
|
2386
|
+
return this.cdpEndpoint;
|
|
2387
|
+
}
|
|
2388
|
+
if (this.cdpEndpoint.startsWith("ws://") || this.cdpEndpoint.startsWith("wss://")) {
|
|
2389
|
+
const url = this.cdpEndpoint.replace(/^ws/, "http");
|
|
2390
|
+
const slashIdx = url.indexOf("/", url.indexOf("//") + 2);
|
|
2391
|
+
return slashIdx >= 0 ? url.substring(0, slashIdx) : url;
|
|
2392
|
+
}
|
|
2393
|
+
return void 0;
|
|
2394
|
+
}
|
|
2217
2395
|
/** Create a new page target within a browser context */
|
|
2218
2396
|
async _createTarget(contextId, url = "about:blank") {
|
|
2219
2397
|
const params = { url };
|
|
@@ -2230,10 +2408,97 @@ var XBBrowserImpl = class {
|
|
|
2230
2408
|
async _enableAutoAttach() {
|
|
2231
2409
|
await this.conn.send("Target.setAutoAttach", {
|
|
2232
2410
|
autoAttach: true,
|
|
2233
|
-
waitForDebuggerOnStart:
|
|
2411
|
+
waitForDebuggerOnStart: false,
|
|
2234
2412
|
flatten: true
|
|
2235
2413
|
});
|
|
2236
2414
|
}
|
|
2415
|
+
/**
|
|
2416
|
+
* Discover existing browser contexts and pages via Target.getTargets.
|
|
2417
|
+
*
|
|
2418
|
+
* For CDP tunnel connections (cdp-tunnel, attach scenarios), the
|
|
2419
|
+
* Target.attachedToTarget auto-attach flow is unreliable. Without this
|
|
2420
|
+
* call, `b.contexts()` would return [] and callers would fall back to
|
|
2421
|
+
* `b.newContext()` — which creates an isolated context with NO cookies
|
|
2422
|
+
* shared with the user's existing browser session (causing login failures).
|
|
2423
|
+
*
|
|
2424
|
+
* This method:
|
|
2425
|
+
* 1. Queries Target.getTargets to enumerate all page targets
|
|
2426
|
+
* 2. Groups them by browserContextId
|
|
2427
|
+
* 3. Attaches to each existing page via Target.attachToTarget
|
|
2428
|
+
* 4. Wraps the discovered pages in a XBContextImpl and registers it in
|
|
2429
|
+
* this._contexts so `contexts()` returns the user's actual contexts
|
|
2430
|
+
* 5. Enables Target.setAutoAttach for future pages
|
|
2431
|
+
*
|
|
2432
|
+
* No-op for self-launched browsers (they already populated contexts via
|
|
2433
|
+
* newContext() + childProcess-gated auto-attach).
|
|
2434
|
+
*/
|
|
2435
|
+
async discoverContexts() {
|
|
2436
|
+
if (this._disconnected) return;
|
|
2437
|
+
let targetInfos = [];
|
|
2438
|
+
try {
|
|
2439
|
+
const result = await this.conn.send(
|
|
2440
|
+
"Target.getTargets"
|
|
2441
|
+
);
|
|
2442
|
+
targetInfos = result.targetInfos ?? [];
|
|
2443
|
+
} catch {
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2446
|
+
const pageTargets = targetInfos.filter((t) => t.type === "page");
|
|
2447
|
+
const httpFallbackUrl = this._httpFallbackURL();
|
|
2448
|
+
if (pageTargets.length === 0 && httpFallbackUrl) {
|
|
2449
|
+
console.log(`[discoverContexts] Target.getTargets returned ${targetInfos.length} targets (0 page type). Falling back to HTTP /json/list at ${httpFallbackUrl}`);
|
|
2450
|
+
try {
|
|
2451
|
+
const { getCDPTargets: getCDPTargets3 } = await import("./launcher-QUJ4M2VS.js");
|
|
2452
|
+
const httpPages = await getCDPTargets3(httpFallbackUrl);
|
|
2453
|
+
console.log(`[discoverContexts] HTTP /json/list returned ${httpPages.length} pages`);
|
|
2454
|
+
for (const p of httpPages) {
|
|
2455
|
+
if (p.type !== "page") continue;
|
|
2456
|
+
if (!p.url || p.url.startsWith("chrome://") || p.url.startsWith("devtools://")) continue;
|
|
2457
|
+
targetInfos.push({
|
|
2458
|
+
targetId: p.id,
|
|
2459
|
+
type: "page",
|
|
2460
|
+
url: p.url,
|
|
2461
|
+
title: p.title
|
|
2462
|
+
});
|
|
2463
|
+
}
|
|
2464
|
+
console.log(`[discoverContexts] After HTTP fallback: ${targetInfos.length} total targets, ${targetInfos.filter((t) => t.type === "page").length} pages`);
|
|
2465
|
+
} catch (err) {
|
|
2466
|
+
console.log(`[discoverContexts] HTTP fallback failed: ${err.message}`);
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
const pagesByContext = /* @__PURE__ */ new Map();
|
|
2470
|
+
for (const t of targetInfos) {
|
|
2471
|
+
if (t.type !== "page") continue;
|
|
2472
|
+
if (!t.url || t.url.startsWith("chrome://") || t.url.startsWith("devtools://")) {
|
|
2473
|
+
continue;
|
|
2474
|
+
}
|
|
2475
|
+
const ctxId = t.browserContextId || "default";
|
|
2476
|
+
if (!pagesByContext.has(ctxId)) pagesByContext.set(ctxId, []);
|
|
2477
|
+
pagesByContext.get(ctxId).push(t);
|
|
2478
|
+
}
|
|
2479
|
+
for (const [ctxId, pages] of pagesByContext) {
|
|
2480
|
+
if (this._contexts.has(ctxId)) continue;
|
|
2481
|
+
const context = new XBContextImpl(this.conn, ctxId, this, {});
|
|
2482
|
+
for (const p of pages) {
|
|
2483
|
+
try {
|
|
2484
|
+
const sessionId = await this._attachToTarget(p.targetId);
|
|
2485
|
+
const page = new XBPageImpl(this.conn, sessionId, p.targetId, context, this);
|
|
2486
|
+
await page._init();
|
|
2487
|
+
context._addDiscoveredPage(page);
|
|
2488
|
+
} catch {
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
this._contexts.set(ctxId, { contextId: ctxId, context });
|
|
2492
|
+
}
|
|
2493
|
+
try {
|
|
2494
|
+
await this.conn.send("Target.setAutoAttach", {
|
|
2495
|
+
autoAttach: true,
|
|
2496
|
+
waitForDebuggerOnStart: false,
|
|
2497
|
+
flatten: true
|
|
2498
|
+
});
|
|
2499
|
+
} catch {
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2237
2502
|
};
|
|
2238
2503
|
|
|
2239
2504
|
// src/cdp-driver/connection.ts
|
|
@@ -2453,7 +2718,8 @@ async function launch(options = {}) {
|
|
|
2453
2718
|
}
|
|
2454
2719
|
const conn = new CDPConnection(wsEndpoint);
|
|
2455
2720
|
await conn.ready();
|
|
2456
|
-
const
|
|
2721
|
+
const httpEndpoint = options.cdpEndpoint && !options.cdpEndpoint.startsWith("ws") ? options.cdpEndpoint : void 0;
|
|
2722
|
+
const browser = new XBBrowserImpl(conn, childProcess, tmpDir, httpEndpoint);
|
|
2457
2723
|
return { browser, wsEndpoint };
|
|
2458
2724
|
}
|
|
2459
2725
|
|
|
@@ -3879,6 +4145,7 @@ async function resolveCDPEndpoint(raw) {
|
|
|
3879
4145
|
}
|
|
3880
4146
|
|
|
3881
4147
|
// src/browser.ts
|
|
4148
|
+
import { SessionStore } from "@dyyz1993/xcli-core";
|
|
3882
4149
|
function logSessionEvent(event, details) {
|
|
3883
4150
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19);
|
|
3884
4151
|
const pid = process.pid;
|
|
@@ -3891,7 +4158,7 @@ function sessionFile(name) {
|
|
|
3891
4158
|
function ensureSessionDir() {
|
|
3892
4159
|
mkdirSync(SESSION_DIR, { recursive: true });
|
|
3893
4160
|
}
|
|
3894
|
-
var sessions =
|
|
4161
|
+
var sessions = new SessionStore();
|
|
3895
4162
|
var _sharedBrowser = null;
|
|
3896
4163
|
var _sharedCdpProxy = null;
|
|
3897
4164
|
var IDLE_TIMEOUT_MS = (process.env.XBROWSER_IDLE_TIMEOUT ? parseInt(process.env.XBROWSER_IDLE_TIMEOUT, 10) : 30) * 60 * 1e3;
|
|
@@ -3902,7 +4169,7 @@ function resetIdleTimer() {
|
|
|
3902
4169
|
const now = Date.now();
|
|
3903
4170
|
let allIdle = true;
|
|
3904
4171
|
const idleSessions = [];
|
|
3905
|
-
for (const
|
|
4172
|
+
for (const s of sessions) {
|
|
3906
4173
|
if (now - s.lastActivityAt < IDLE_TIMEOUT_MS) {
|
|
3907
4174
|
allIdle = false;
|
|
3908
4175
|
} else {
|
|
@@ -3925,7 +4192,7 @@ function touchSession(id) {
|
|
|
3925
4192
|
resetIdleTimer();
|
|
3926
4193
|
}
|
|
3927
4194
|
process.on("exit", () => {
|
|
3928
|
-
for (const session of sessions.
|
|
4195
|
+
for (const session of sessions.list()) {
|
|
3929
4196
|
if (session.isCDP) {
|
|
3930
4197
|
logSessionEvent("process_exit", `Session "${session.name}": CDP connection (not closing external browser).`);
|
|
3931
4198
|
} else {
|
|
@@ -4015,6 +4282,9 @@ async function createBrowser(options) {
|
|
|
4015
4282
|
return browser3;
|
|
4016
4283
|
}
|
|
4017
4284
|
const { browser: browser2 } = await launch({ cdpEndpoint: realEndpoint });
|
|
4285
|
+
await browser2.discoverContexts().catch((err) => {
|
|
4286
|
+
console.error(`[browser] discoverContexts failed: ${err.message}`);
|
|
4287
|
+
});
|
|
4018
4288
|
return browser2;
|
|
4019
4289
|
}
|
|
4020
4290
|
const executablePath = options?.executablePath || process.env.XBROWSER_CHROMIUM_PATH || discoverChromiumPath();
|
|
@@ -4029,10 +4299,7 @@ async function getBrowser(options) {
|
|
|
4029
4299
|
return _sharedBrowser;
|
|
4030
4300
|
}
|
|
4031
4301
|
function findSession(name) {
|
|
4032
|
-
|
|
4033
|
-
if (session.name === name) return session;
|
|
4034
|
-
}
|
|
4035
|
-
return void 0;
|
|
4302
|
+
return sessions.find(name);
|
|
4036
4303
|
}
|
|
4037
4304
|
function getSessionById(id) {
|
|
4038
4305
|
return sessions.get(id);
|
|
@@ -4136,9 +4403,14 @@ async function findOrRestoreSession(name, cdpEndpoint) {
|
|
|
4136
4403
|
return void 0;
|
|
4137
4404
|
}
|
|
4138
4405
|
const targetUrl = meta.conversationUrl || meta.url;
|
|
4139
|
-
if (targetUrl && page.url() !== targetUrl
|
|
4140
|
-
|
|
4141
|
-
|
|
4406
|
+
if (targetUrl && page.url() !== targetUrl) {
|
|
4407
|
+
try {
|
|
4408
|
+
if (!page.url().includes(new URL(targetUrl).hostname)) {
|
|
4409
|
+
await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 3e4 }).catch(() => {
|
|
4410
|
+
});
|
|
4411
|
+
}
|
|
4412
|
+
} catch {
|
|
4413
|
+
}
|
|
4142
4414
|
}
|
|
4143
4415
|
const session = {
|
|
4144
4416
|
id: meta.id || randomUUID(),
|
|
@@ -4151,13 +4423,13 @@ async function findOrRestoreSession(name, cdpEndpoint) {
|
|
|
4151
4423
|
isCDP: true,
|
|
4152
4424
|
cdpEndpoint: ep
|
|
4153
4425
|
};
|
|
4154
|
-
for (const
|
|
4426
|
+
for (const existingSession of sessions.list()) {
|
|
4155
4427
|
if (existingSession.name === name) {
|
|
4156
|
-
logSessionEvent("remove_stale", `Removing stale session name="${name}" id="${
|
|
4157
|
-
sessions.
|
|
4428
|
+
logSessionEvent("remove_stale", `Removing stale session name="${name}" id="${existingSession.id}" during restore`);
|
|
4429
|
+
sessions.removeById(existingSession.id);
|
|
4158
4430
|
}
|
|
4159
4431
|
}
|
|
4160
|
-
sessions.set(session
|
|
4432
|
+
sessions.set(session);
|
|
4161
4433
|
resetIdleTimer();
|
|
4162
4434
|
await installNetworkCapture(page, name);
|
|
4163
4435
|
return session;
|
|
@@ -4173,7 +4445,12 @@ async function createEphemeralContext(options) {
|
|
|
4173
4445
|
const { browser: b2 } = await launch({ cdpEndpoint: endpoint });
|
|
4174
4446
|
const contexts = b2.contexts();
|
|
4175
4447
|
const ctx = contexts[0] || await b2.newContext();
|
|
4176
|
-
const
|
|
4448
|
+
const allPages = ctx.pages();
|
|
4449
|
+
const existingPages = allPages.filter((p) => {
|
|
4450
|
+
const url = p.url();
|
|
4451
|
+
return url !== "about:blank" && !url.startsWith("chrome://");
|
|
4452
|
+
});
|
|
4453
|
+
const page2 = existingPages.length > 0 ? existingPages[0] : allPages.length > 0 ? allPages[0] : await ctx.newPage();
|
|
4177
4454
|
resetIdleTimer();
|
|
4178
4455
|
ephemeralConnections.set(page2, b2);
|
|
4179
4456
|
return { context: ctx, page: page2 };
|
|
@@ -4205,11 +4482,11 @@ async function closeEphemeralContext(context) {
|
|
|
4205
4482
|
}
|
|
4206
4483
|
}
|
|
4207
4484
|
function getAllSessions() {
|
|
4208
|
-
return
|
|
4485
|
+
return sessions.list();
|
|
4209
4486
|
}
|
|
4210
4487
|
async function installNetworkCapture(page, sessionName) {
|
|
4211
4488
|
if (process.env.XBROWSER_DAEMON_WORKER !== "1") return;
|
|
4212
|
-
const { networkStore } = await import("./network-store-
|
|
4489
|
+
const { networkStore } = await import("./network-store-YVDNUREI.js");
|
|
4213
4490
|
const requestData = /* @__PURE__ */ new Map();
|
|
4214
4491
|
const responseMeta = /* @__PURE__ */ new Map();
|
|
4215
4492
|
const xbPage = page;
|
|
@@ -4330,16 +4607,38 @@ async function createSession(name, url, options) {
|
|
|
4330
4607
|
}
|
|
4331
4608
|
context = contexts[0] || await b.newContext();
|
|
4332
4609
|
let targetPage = null;
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4610
|
+
const targetHostname = url ? (() => {
|
|
4611
|
+
try {
|
|
4612
|
+
return new URL(url).hostname;
|
|
4613
|
+
} catch {
|
|
4614
|
+
return "";
|
|
4615
|
+
}
|
|
4616
|
+
})() : "";
|
|
4617
|
+
if (targetHostname) {
|
|
4618
|
+
for (const ctx of contexts) {
|
|
4619
|
+
const pages = ctx.pages();
|
|
4620
|
+
for (const p of pages) {
|
|
4621
|
+
const pUrl = p.url();
|
|
4622
|
+
if (pUrl && pUrl !== "about:blank" && !pUrl.startsWith("chrome://") && pUrl.includes(targetHostname)) {
|
|
4623
|
+
targetPage = p;
|
|
4624
|
+
break;
|
|
4625
|
+
}
|
|
4626
|
+
}
|
|
4627
|
+
if (targetPage) break;
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
if (!targetPage) {
|
|
4631
|
+
for (const ctx of contexts) {
|
|
4632
|
+
const pages = ctx.pages();
|
|
4633
|
+
for (const p of pages) {
|
|
4634
|
+
const pUrl = p.url();
|
|
4635
|
+
if (pUrl && pUrl !== "about:blank" && !pUrl.startsWith("chrome://")) {
|
|
4636
|
+
targetPage = p;
|
|
4637
|
+
break;
|
|
4638
|
+
}
|
|
4340
4639
|
}
|
|
4640
|
+
if (targetPage) break;
|
|
4341
4641
|
}
|
|
4342
|
-
if (targetPage) break;
|
|
4343
4642
|
}
|
|
4344
4643
|
if (!targetPage && options?.cdpEndpoint) {
|
|
4345
4644
|
const targets = await getCDPTargets2(options.cdpEndpoint);
|
|
@@ -4380,14 +4679,14 @@ async function createSession(name, url, options) {
|
|
|
4380
4679
|
isCDP,
|
|
4381
4680
|
cdpEndpoint: options?.cdpEndpoint
|
|
4382
4681
|
};
|
|
4383
|
-
sessions.set(session
|
|
4682
|
+
sessions.set(session);
|
|
4384
4683
|
logSessionEvent("create_session", `name="${name}" id="${session.id}" url="${url || "(no url)"}" isCDP=${isCDP} cdpEndpoint=${options?.cdpEndpoint || "(none)"}`);
|
|
4385
4684
|
resetIdleTimer();
|
|
4386
4685
|
await installNetworkCapture(page, name);
|
|
4387
4686
|
return session;
|
|
4388
4687
|
}
|
|
4389
4688
|
async function closeSessionByName(name) {
|
|
4390
|
-
for (const
|
|
4689
|
+
for (const session of sessions) {
|
|
4391
4690
|
if (session.name === name || session.id === name) {
|
|
4392
4691
|
logSessionEvent("close_session", `name="${session.name}" id="${session.id}" url="${session.page.url()}"`);
|
|
4393
4692
|
if (session.isCDP) {
|
|
@@ -4406,20 +4705,20 @@ async function closeSessionByName(name) {
|
|
|
4406
4705
|
});
|
|
4407
4706
|
}
|
|
4408
4707
|
}
|
|
4409
|
-
sessions.
|
|
4708
|
+
sessions.removeById(session.id);
|
|
4410
4709
|
const file2 = sessionFile(session.name);
|
|
4411
4710
|
try {
|
|
4412
4711
|
unlinkSync(file2);
|
|
4413
4712
|
} catch {
|
|
4414
4713
|
}
|
|
4415
4714
|
try {
|
|
4416
|
-
const { networkStore, commandLogStore } = await import("./network-store-
|
|
4715
|
+
const { networkStore, commandLogStore } = await import("./network-store-YVDNUREI.js");
|
|
4417
4716
|
networkStore.clear(session.name);
|
|
4418
4717
|
commandLogStore.clear(session.name);
|
|
4419
4718
|
} catch {
|
|
4420
4719
|
}
|
|
4421
4720
|
try {
|
|
4422
|
-
const { SessionRecorder } = await import("./session-recorder-
|
|
4721
|
+
const { SessionRecorder } = await import("./session-recorder-RTDGURIJ.js");
|
|
4423
4722
|
SessionRecorder.cleanup(session.name);
|
|
4424
4723
|
} catch {
|
|
4425
4724
|
}
|
|
@@ -4434,9 +4733,9 @@ async function closeSessionByName(name) {
|
|
|
4434
4733
|
return false;
|
|
4435
4734
|
}
|
|
4436
4735
|
async function closeAllSessions() {
|
|
4437
|
-
const names =
|
|
4736
|
+
const names = sessions.list().map((s) => `${s.name}(${s.page.url()})`).join(", ");
|
|
4438
4737
|
if (names) logSessionEvent("close_all_sessions", `Closing ${sessions.size} sessions: ${names}`);
|
|
4439
|
-
for (const
|
|
4738
|
+
for (const session of sessions.list()) {
|
|
4440
4739
|
try {
|
|
4441
4740
|
if (!session.isCDP) {
|
|
4442
4741
|
await session.context.close();
|
|
@@ -4445,9 +4744,9 @@ async function closeAllSessions() {
|
|
|
4445
4744
|
await session.browser.close().catch(() => {
|
|
4446
4745
|
});
|
|
4447
4746
|
}
|
|
4448
|
-
sessions.
|
|
4747
|
+
sessions.removeById(session.id);
|
|
4449
4748
|
} catch {
|
|
4450
|
-
sessions.
|
|
4749
|
+
sessions.removeById(session.id);
|
|
4451
4750
|
}
|
|
4452
4751
|
}
|
|
4453
4752
|
}
|
|
@@ -4485,7 +4784,7 @@ async function ensureProcessCanExit() {
|
|
|
4485
4784
|
clearTimeout(idleTimer);
|
|
4486
4785
|
idleTimer = null;
|
|
4487
4786
|
}
|
|
4488
|
-
for (const session of sessions.
|
|
4787
|
+
for (const session of sessions.list()) {
|
|
4489
4788
|
if (session.browser) {
|
|
4490
4789
|
if (session.isCDP) {
|
|
4491
4790
|
await session.browser.close().catch(() => {
|
|
@@ -4511,7 +4810,6 @@ async function ensureProcessCanExit() {
|
|
|
4511
4810
|
|
|
4512
4811
|
export {
|
|
4513
4812
|
createRuleEngine,
|
|
4514
|
-
resolveCDPEndpoint,
|
|
4515
4813
|
touchSession,
|
|
4516
4814
|
findTargetPage,
|
|
4517
4815
|
resolveLaunchOpts,
|