@xbrowser/cli 1.16.0 → 1.18.0

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.
@@ -20,9 +20,9 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-7V3B7VPX.js";
24
- import "./chunk-A5HJ6IRE.js";
25
- import "./chunk-TNEN6VQ2.js";
23
+ } from "./chunk-EI2XZIDF.js";
24
+ import "./chunk-LL37GYPP.js";
25
+ import "./chunk-3KZ34AUC.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-A6LPGFAL.js";
28
28
  import "./chunk-H2A5JUK5.js";
@@ -20,10 +20,10 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-GWQ5NTVE.js";
24
- import "./chunk-LTBNQERK.js";
23
+ } from "./chunk-MMZCBUD3.js";
24
+ import "./chunk-DVKIL7H6.js";
25
25
  import "./chunk-3FWLW7FS.js";
26
- import "./chunk-TNEN6VQ2.js";
26
+ import "./chunk-3KZ34AUC.js";
27
27
  import "./chunk-GDKLH7ZY.js";
28
28
  import "./chunk-KFQGP6VL.js";
29
29
  export {
@@ -20,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-5EYOEB4R.js";
24
- import "./chunk-TNEN6VQ2.js";
23
+ } from "./chunk-OU335JBI.js";
24
+ import "./chunk-3KZ34AUC.js";
25
25
  import "./chunk-GDKLH7ZY.js";
26
26
  import "./chunk-KFQGP6VL.js";
27
27
  export {
@@ -14,7 +14,7 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-LTBNQERK.js";
17
+ } from "./chunk-DVKIL7H6.js";
18
18
  import "./chunk-3FWLW7FS.js";
19
19
  import {
20
20
  connectToCDP,
@@ -22,7 +22,7 @@ import {
22
22
  getCDPTargets,
23
23
  killChrome,
24
24
  launchChrome
25
- } from "./chunk-TNEN6VQ2.js";
25
+ } from "./chunk-3KZ34AUC.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-KFQGP6VL.js";
28
28
  export {
@@ -14,14 +14,14 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-A5HJ6IRE.js";
17
+ } from "./chunk-LL37GYPP.js";
18
18
  import {
19
19
  connectToCDP,
20
20
  findChrome,
21
21
  getCDPTargets,
22
22
  killChrome,
23
23
  launchChrome
24
- } from "./chunk-TNEN6VQ2.js";
24
+ } from "./chunk-3KZ34AUC.js";
25
25
  import "./chunk-GDKLH7ZY.js";
26
26
  import "./chunk-H2A5JUK5.js";
27
27
  import "./chunk-KFQGP6VL.js";
@@ -5,7 +5,7 @@ import {
5
5
  getCDPTargets,
6
6
  killChrome,
7
7
  launchChrome
8
- } from "./chunk-AMI64BSD.js";
8
+ } from "./chunk-IWVG4XYZ.js";
9
9
  import {
10
10
  __require
11
11
  } from "./chunk-3RG5ZIWI.js";
@@ -370,6 +370,19 @@ function buildStealthInitScript() {
370
370
  " document.fonts.add(ff);ff.load();}catch(e2){}",
371
371
  " });",
372
372
  " }catch(e){}",
373
+ // 3g. Notification.requestPermission 延迟(d62):headless 无原生横幅,
374
+ // request 瞬回 denied —— 真机 request 会 pending 在横幅上数秒到分钟。
375
+ // 延迟 2-6s 再 resolve,模拟横幅期(用户"看了下然后拒绝")。
376
+ " try{",
377
+ " if(window.Notification&&Notification.requestPermission){",
378
+ " var _nrp=Notification.requestPermission.bind(Notification);",
379
+ " Notification.requestPermission=function(cb){",
380
+ " return new Promise(function(res){",
381
+ " setTimeout(function(){_nrp().then(function(r){if(cb)try{cb(r)}catch(e){}res(r);});},2000+Math.random()*4000);",
382
+ " });",
383
+ " };",
384
+ " }",
385
+ " }catch(e){}",
373
386
  // 3. toString disguise (name-list based)
374
387
  " var _ts=Function.prototype.toString;",
375
388
  " var _hf=document.hasFocus;",
@@ -515,6 +528,49 @@ var XBMouseImpl = class {
515
528
  this._x = x;
516
529
  this._y = y;
517
530
  }
531
+ /**
532
+ * Drag from the CURRENT cursor position to (x, y): press, traverse a
533
+ * bezier trajectory with the button held, release. Drives the REAL
534
+ * HTML5 DnD pipeline — field-verified (d59): this sequence fires
535
+ * dragstart → dragover… → drop → dragend, all isTrusted=true. No
536
+ * Input.dispatchDragEvent needed.
537
+ */
538
+ async drag(x, y, opts = {}) {
539
+ const stealth = process.env.XBROWSER_STEALTH !== "off";
540
+ await this.send("Input.dispatchMouseEvent", {
541
+ type: "mousePressed",
542
+ x: this._x,
543
+ y: this._y,
544
+ button: "left",
545
+ clickCount: 1
546
+ });
547
+ this._button = "left";
548
+ const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
549
+ const fx = this._x, fy = this._y;
550
+ for (let i = 1; i <= steps; i++) {
551
+ if (stealth) await sleep(rand(16, 28));
552
+ const t = i / steps;
553
+ this._x = fx + (x - fx) * t;
554
+ this._y = fy + (y - fy) * t;
555
+ await this.send("Input.dispatchMouseEvent", {
556
+ type: "mouseMoved",
557
+ x: this._x,
558
+ y: this._y,
559
+ button: this._button
560
+ });
561
+ }
562
+ this._x = x;
563
+ this._y = y;
564
+ await sleep(rand(60, 140));
565
+ await this.send("Input.dispatchMouseEvent", {
566
+ type: "mouseReleased",
567
+ x,
568
+ y,
569
+ button: "left",
570
+ clickCount: 1
571
+ });
572
+ this._button = "none";
573
+ }
518
574
  async wheel(deltaX, deltaY) {
519
575
  await this.send("Input.dispatchMouseEvent", {
520
576
  type: "mouseWheel",
@@ -1255,6 +1311,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
1255
1311
  `);
1256
1312
  return selected;
1257
1313
  }
1314
+ async dragAndDrop(source, target) {
1315
+ const boxes = await this.page.evaluate(`
1316
+ (function() {
1317
+ const s = ${this._q(source)}, t = ${this._q(target)};
1318
+ if (!s || !t) return null;
1319
+ const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
1320
+ return [c(s), c(t)];
1321
+ })()
1322
+ `);
1323
+ if (!boxes || !boxes[0] || !boxes[1]) {
1324
+ throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
1325
+ }
1326
+ await this.page.mouse.move(boxes[0].x, boxes[0].y);
1327
+ await this.page.mouse.drag(boxes[1].x, boxes[1].y);
1328
+ }
1258
1329
  async screenshot(opts = {}) {
1259
1330
  await waitForActionable(this.page, this.selector);
1260
1331
  const box = await this.page.evaluate(`
@@ -3359,7 +3430,7 @@ var XBBrowserImpl = class {
3359
3430
  this._exitHandler = null;
3360
3431
  }
3361
3432
  if (this.childProcess) {
3362
- const { killChrome: killChrome2 } = await import("./launcher-OZXJQPNG.js");
3433
+ const { killChrome: killChrome2 } = await import("./launcher-EXJHHAUL.js");
3363
3434
  await killChrome2(this.childProcess, this.tmpDir);
3364
3435
  }
3365
3436
  await this.conn.close();
@@ -3494,7 +3565,7 @@ var XBBrowserImpl = class {
3494
3565
  if (pageTargets.length === 0 && httpFallbackUrl) {
3495
3566
  console.log(`[discoverContexts] Target.getTargets returned ${targetInfos.length} targets (0 page type). Falling back to HTTP /json/list at ${httpFallbackUrl}`);
3496
3567
  try {
3497
- const { getCDPTargets: getCDPTargets2 } = await import("./launcher-OZXJQPNG.js");
3568
+ const { getCDPTargets: getCDPTargets2 } = await import("./launcher-EXJHHAUL.js");
3498
3569
  const httpPages = await getCDPTargets2(httpFallbackUrl);
3499
3570
  console.log(`[discoverContexts] HTTP /json/list returned ${httpPages.length} pages`);
3500
3571
  for (const p of httpPages) {
@@ -101,6 +101,7 @@ async function launchChrome(options = {}) {
101
101
  ];
102
102
  if (headless) {
103
103
  allArgs.push("--headless", "--hide-scrollbars", "--mute-audio");
104
+ allArgs.push("--autoplay-policy=no-user-gesture-required");
104
105
  }
105
106
  let tmpDir;
106
107
  if (userDataDir) {
@@ -160,6 +161,15 @@ async function connectToCDP(rawEndpoint) {
160
161
  }
161
162
  return resolveEndpointFromHTTP(rawEndpoint);
162
163
  }
164
+ function joinCdpHttpUrl(baseURL, path) {
165
+ try {
166
+ const u = new URL(baseURL);
167
+ u.pathname = (u.pathname.replace(/\/+$/, "") || "") + path;
168
+ return u.toString();
169
+ } catch {
170
+ return `${baseURL}${path}`;
171
+ }
172
+ }
163
173
  async function findFreePort() {
164
174
  const { createServer } = await import("net");
165
175
  return new Promise((resolve, reject) => {
@@ -193,7 +203,7 @@ async function waitForCDPReady(port, timeoutMs, child) {
193
203
  throw new Error(`Chrome CDP not ready after ${timeoutMs}ms (port ${port})`);
194
204
  }
195
205
  async function resolveEndpointFromHTTP(baseURL) {
196
- const url = `${baseURL}/json/version`;
206
+ const url = joinCdpHttpUrl(baseURL, "/json/version");
197
207
  const resp = await fetch(url, { signal: AbortSignal.timeout(3e3) });
198
208
  if (!resp.ok) {
199
209
  throw new Error(`CDP HTTP ${resp.status}: ${url}`);
@@ -205,7 +215,7 @@ async function resolveEndpointFromHTTP(baseURL) {
205
215
  return data.webSocketDebuggerUrl;
206
216
  }
207
217
  async function getCDPTargets(baseURL) {
208
- const url = `${baseURL}/json/list`;
218
+ const url = joinCdpHttpUrl(baseURL, "/json/list");
209
219
  const resp = await fetch(url, { signal: AbortSignal.timeout(5e3) });
210
220
  if (!resp.ok) {
211
221
  throw new Error(`CDP list HTTP ${resp.status}: ${url}`);
@@ -258,6 +268,7 @@ export {
258
268
  findChrome,
259
269
  launchChrome,
260
270
  connectToCDP,
271
+ joinCdpHttpUrl,
261
272
  getCDPTargets,
262
273
  killChrome
263
274
  };
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  connectToCDP,
7
7
  launchChrome
8
- } from "./chunk-TNEN6VQ2.js";
8
+ } from "./chunk-3KZ34AUC.js";
9
9
  import {
10
10
  errMsg
11
11
  } from "./chunk-GDKLH7ZY.js";
@@ -381,6 +381,19 @@ function buildStealthInitScript() {
381
381
  " document.fonts.add(ff);ff.load();}catch(e2){}",
382
382
  " });",
383
383
  " }catch(e){}",
384
+ // 3g. Notification.requestPermission 延迟(d62):headless 无原生横幅,
385
+ // request 瞬回 denied —— 真机 request 会 pending 在横幅上数秒到分钟。
386
+ // 延迟 2-6s 再 resolve,模拟横幅期(用户"看了下然后拒绝")。
387
+ " try{",
388
+ " if(window.Notification&&Notification.requestPermission){",
389
+ " var _nrp=Notification.requestPermission.bind(Notification);",
390
+ " Notification.requestPermission=function(cb){",
391
+ " return new Promise(function(res){",
392
+ " setTimeout(function(){_nrp().then(function(r){if(cb)try{cb(r)}catch(e){}res(r);});},2000+Math.random()*4000);",
393
+ " });",
394
+ " };",
395
+ " }",
396
+ " }catch(e){}",
384
397
  // 3. toString disguise (name-list based)
385
398
  " var _ts=Function.prototype.toString;",
386
399
  " var _hf=document.hasFocus;",
@@ -526,6 +539,49 @@ var XBMouseImpl = class {
526
539
  this._x = x;
527
540
  this._y = y;
528
541
  }
542
+ /**
543
+ * Drag from the CURRENT cursor position to (x, y): press, traverse a
544
+ * bezier trajectory with the button held, release. Drives the REAL
545
+ * HTML5 DnD pipeline — field-verified (d59): this sequence fires
546
+ * dragstart → dragover… → drop → dragend, all isTrusted=true. No
547
+ * Input.dispatchDragEvent needed.
548
+ */
549
+ async drag(x, y, opts = {}) {
550
+ const stealth = process.env.XBROWSER_STEALTH !== "off";
551
+ await this.send("Input.dispatchMouseEvent", {
552
+ type: "mousePressed",
553
+ x: this._x,
554
+ y: this._y,
555
+ button: "left",
556
+ clickCount: 1
557
+ });
558
+ this._button = "left";
559
+ const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
560
+ const fx = this._x, fy = this._y;
561
+ for (let i = 1; i <= steps; i++) {
562
+ if (stealth) await sleep2(rand(16, 28));
563
+ const t = i / steps;
564
+ this._x = fx + (x - fx) * t;
565
+ this._y = fy + (y - fy) * t;
566
+ await this.send("Input.dispatchMouseEvent", {
567
+ type: "mouseMoved",
568
+ x: this._x,
569
+ y: this._y,
570
+ button: this._button
571
+ });
572
+ }
573
+ this._x = x;
574
+ this._y = y;
575
+ await sleep2(rand(60, 140));
576
+ await this.send("Input.dispatchMouseEvent", {
577
+ type: "mouseReleased",
578
+ x,
579
+ y,
580
+ button: "left",
581
+ clickCount: 1
582
+ });
583
+ this._button = "none";
584
+ }
529
585
  async wheel(deltaX, deltaY) {
530
586
  await this.send("Input.dispatchMouseEvent", {
531
587
  type: "mouseWheel",
@@ -1164,6 +1220,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
1164
1220
  `);
1165
1221
  return selected;
1166
1222
  }
1223
+ async dragAndDrop(source, target) {
1224
+ const boxes = await this.page.evaluate(`
1225
+ (function() {
1226
+ const s = ${this._q(source)}, t = ${this._q(target)};
1227
+ if (!s || !t) return null;
1228
+ const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
1229
+ return [c(s), c(t)];
1230
+ })()
1231
+ `);
1232
+ if (!boxes || !boxes[0] || !boxes[1]) {
1233
+ throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
1234
+ }
1235
+ await this.page.mouse.move(boxes[0].x, boxes[0].y);
1236
+ await this.page.mouse.drag(boxes[1].x, boxes[1].y);
1237
+ }
1167
1238
  async screenshot(opts = {}) {
1168
1239
  await waitForActionable(this.page, this.selector);
1169
1240
  const box = await this.page.evaluate(`
@@ -3268,7 +3339,7 @@ var XBBrowserImpl = class {
3268
3339
  this._exitHandler = null;
3269
3340
  }
3270
3341
  if (this.childProcess) {
3271
- const { killChrome: killChrome2 } = await import("./launcher-L2JNDB2H.js");
3342
+ const { killChrome: killChrome2 } = await import("./launcher-44STYRJC.js");
3272
3343
  await killChrome2(this.childProcess, this.tmpDir);
3273
3344
  }
3274
3345
  await this.conn.close();
@@ -3403,7 +3474,7 @@ var XBBrowserImpl = class {
3403
3474
  if (pageTargets.length === 0 && httpFallbackUrl) {
3404
3475
  console.log(`[discoverContexts] Target.getTargets returned ${targetInfos.length} targets (0 page type). Falling back to HTTP /json/list at ${httpFallbackUrl}`);
3405
3476
  try {
3406
- const { getCDPTargets: getCDPTargets2 } = await import("./launcher-L2JNDB2H.js");
3477
+ const { getCDPTargets: getCDPTargets2 } = await import("./launcher-44STYRJC.js");
3407
3478
  const httpPages = await getCDPTargets2(httpFallbackUrl);
3408
3479
  console.log(`[discoverContexts] HTTP /json/list returned ${httpPages.length} pages`);
3409
3480
  for (const p of httpPages) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-A5HJ6IRE.js";
3
+ } from "./chunk-LL37GYPP.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -639,16 +639,40 @@ async function createSession(name, url, options) {
639
639
  (t) => t.url && t.url !== "about:blank" && !t.url.startsWith("chrome://") && !t.url.startsWith("chrome-untrusted://") && !t.url.startsWith("chrome-error://") && (url ? t.url.includes(new URL(url).hostname) : true)
640
640
  );
641
641
  if (matchTarget && matchTarget.url) {
642
- targetPage = await context.newPage();
643
- await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
642
+ const existing2 = context.pages().find((p) => {
643
+ try {
644
+ return p.url() === matchTarget.url;
645
+ } catch {
646
+ return false;
647
+ }
644
648
  });
649
+ if (existing2) {
650
+ targetPage = existing2;
651
+ } else {
652
+ targetPage = await context.newPage();
653
+ await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
654
+ });
655
+ }
645
656
  }
646
657
  }
647
658
  if (!targetPage) {
648
659
  const pages = context.pages();
649
- if (pages.length > 0) {
660
+ if (pages.length > 1) {
661
+ try {
662
+ for (const p of pages) {
663
+ const vis = await p.evaluate("document.visibilityState").catch(() => "hidden");
664
+ if (vis === "visible") {
665
+ targetPage = p;
666
+ break;
667
+ }
668
+ }
669
+ } catch {
670
+ }
671
+ }
672
+ if (!targetPage && pages.length > 0) {
650
673
  targetPage = pages[0];
651
- } else {
674
+ }
675
+ if (!targetPage) {
652
676
  targetPage = await context.newPage();
653
677
  }
654
678
  }
@@ -105,6 +105,7 @@ async function launchChrome(options = {}) {
105
105
  ];
106
106
  if (headless) {
107
107
  allArgs.push("--headless", "--hide-scrollbars", "--mute-audio");
108
+ allArgs.push("--autoplay-policy=no-user-gesture-required");
108
109
  }
109
110
  let tmpDir;
110
111
  if (userDataDir) {
@@ -164,6 +165,15 @@ async function connectToCDP(rawEndpoint) {
164
165
  }
165
166
  return resolveEndpointFromHTTP(rawEndpoint);
166
167
  }
168
+ function joinCdpHttpUrl(baseURL, path) {
169
+ try {
170
+ const u = new URL(baseURL);
171
+ u.pathname = (u.pathname.replace(/\/+$/, "") || "") + path;
172
+ return u.toString();
173
+ } catch {
174
+ return `${baseURL}${path}`;
175
+ }
176
+ }
167
177
  async function findFreePort() {
168
178
  const { createServer } = await import("net");
169
179
  return new Promise((resolve, reject) => {
@@ -197,7 +207,7 @@ async function waitForCDPReady(port, timeoutMs, child) {
197
207
  throw new Error(`Chrome CDP not ready after ${timeoutMs}ms (port ${port})`);
198
208
  }
199
209
  async function resolveEndpointFromHTTP(baseURL) {
200
- const url = `${baseURL}/json/version`;
210
+ const url = joinCdpHttpUrl(baseURL, "/json/version");
201
211
  const resp = await fetch(url, { signal: AbortSignal.timeout(3e3) });
202
212
  if (!resp.ok) {
203
213
  throw new Error(`CDP HTTP ${resp.status}: ${url}`);
@@ -209,7 +219,7 @@ async function resolveEndpointFromHTTP(baseURL) {
209
219
  return data.webSocketDebuggerUrl;
210
220
  }
211
221
  async function getCDPTargets(baseURL) {
212
- const url = `${baseURL}/json/list`;
222
+ const url = joinCdpHttpUrl(baseURL, "/json/list");
213
223
  const resp = await fetch(url, { signal: AbortSignal.timeout(5e3) });
214
224
  if (!resp.ok) {
215
225
  throw new Error(`CDP list HTTP ${resp.status}: ${url}`);
@@ -263,6 +273,7 @@ export {
263
273
  findChrome,
264
274
  launchChrome,
265
275
  connectToCDP,
276
+ joinCdpHttpUrl,
266
277
  getCDPTargets,
267
278
  killChrome
268
279
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  connectToCDP,
3
3
  launchChrome
4
- } from "./chunk-TNEN6VQ2.js";
4
+ } from "./chunk-3KZ34AUC.js";
5
5
  import {
6
6
  errMsg
7
7
  } from "./chunk-GDKLH7ZY.js";
@@ -380,6 +380,19 @@ function buildStealthInitScript() {
380
380
  " document.fonts.add(ff);ff.load();}catch(e2){}",
381
381
  " });",
382
382
  " }catch(e){}",
383
+ // 3g. Notification.requestPermission 延迟(d62):headless 无原生横幅,
384
+ // request 瞬回 denied —— 真机 request 会 pending 在横幅上数秒到分钟。
385
+ // 延迟 2-6s 再 resolve,模拟横幅期(用户"看了下然后拒绝")。
386
+ " try{",
387
+ " if(window.Notification&&Notification.requestPermission){",
388
+ " var _nrp=Notification.requestPermission.bind(Notification);",
389
+ " Notification.requestPermission=function(cb){",
390
+ " return new Promise(function(res){",
391
+ " setTimeout(function(){_nrp().then(function(r){if(cb)try{cb(r)}catch(e){}res(r);});},2000+Math.random()*4000);",
392
+ " });",
393
+ " };",
394
+ " }",
395
+ " }catch(e){}",
383
396
  // 3. toString disguise (name-list based)
384
397
  " var _ts=Function.prototype.toString;",
385
398
  " var _hf=document.hasFocus;",
@@ -525,6 +538,49 @@ var XBMouseImpl = class {
525
538
  this._x = x;
526
539
  this._y = y;
527
540
  }
541
+ /**
542
+ * Drag from the CURRENT cursor position to (x, y): press, traverse a
543
+ * bezier trajectory with the button held, release. Drives the REAL
544
+ * HTML5 DnD pipeline — field-verified (d59): this sequence fires
545
+ * dragstart → dragover… → drop → dragend, all isTrusted=true. No
546
+ * Input.dispatchDragEvent needed.
547
+ */
548
+ async drag(x, y, opts = {}) {
549
+ const stealth = process.env.XBROWSER_STEALTH !== "off";
550
+ await this.send("Input.dispatchMouseEvent", {
551
+ type: "mousePressed",
552
+ x: this._x,
553
+ y: this._y,
554
+ button: "left",
555
+ clickCount: 1
556
+ });
557
+ this._button = "left";
558
+ const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
559
+ const fx = this._x, fy = this._y;
560
+ for (let i = 1; i <= steps; i++) {
561
+ if (stealth) await sleep2(rand(16, 28));
562
+ const t = i / steps;
563
+ this._x = fx + (x - fx) * t;
564
+ this._y = fy + (y - fy) * t;
565
+ await this.send("Input.dispatchMouseEvent", {
566
+ type: "mouseMoved",
567
+ x: this._x,
568
+ y: this._y,
569
+ button: this._button
570
+ });
571
+ }
572
+ this._x = x;
573
+ this._y = y;
574
+ await sleep2(rand(60, 140));
575
+ await this.send("Input.dispatchMouseEvent", {
576
+ type: "mouseReleased",
577
+ x,
578
+ y,
579
+ button: "left",
580
+ clickCount: 1
581
+ });
582
+ this._button = "none";
583
+ }
528
584
  async wheel(deltaX, deltaY) {
529
585
  await this.send("Input.dispatchMouseEvent", {
530
586
  type: "mouseWheel",
@@ -1265,6 +1321,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
1265
1321
  `);
1266
1322
  return selected;
1267
1323
  }
1324
+ async dragAndDrop(source, target) {
1325
+ const boxes = await this.page.evaluate(`
1326
+ (function() {
1327
+ const s = ${this._q(source)}, t = ${this._q(target)};
1328
+ if (!s || !t) return null;
1329
+ const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
1330
+ return [c(s), c(t)];
1331
+ })()
1332
+ `);
1333
+ if (!boxes || !boxes[0] || !boxes[1]) {
1334
+ throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
1335
+ }
1336
+ await this.page.mouse.move(boxes[0].x, boxes[0].y);
1337
+ await this.page.mouse.drag(boxes[1].x, boxes[1].y);
1338
+ }
1268
1339
  async screenshot(opts = {}) {
1269
1340
  await waitForActionable(this.page, this.selector);
1270
1341
  const box = await this.page.evaluate(`
@@ -3369,7 +3440,7 @@ var XBBrowserImpl = class {
3369
3440
  this._exitHandler = null;
3370
3441
  }
3371
3442
  if (this.childProcess) {
3372
- const { killChrome: killChrome2 } = await import("./launcher-L2JNDB2H.js");
3443
+ const { killChrome: killChrome2 } = await import("./launcher-44STYRJC.js");
3373
3444
  await killChrome2(this.childProcess, this.tmpDir);
3374
3445
  }
3375
3446
  await this.conn.close();
@@ -3504,7 +3575,7 @@ var XBBrowserImpl = class {
3504
3575
  if (pageTargets.length === 0 && httpFallbackUrl) {
3505
3576
  console.log(`[discoverContexts] Target.getTargets returned ${targetInfos.length} targets (0 page type). Falling back to HTTP /json/list at ${httpFallbackUrl}`);
3506
3577
  try {
3507
- const { getCDPTargets: getCDPTargets2 } = await import("./launcher-L2JNDB2H.js");
3578
+ const { getCDPTargets: getCDPTargets2 } = await import("./launcher-44STYRJC.js");
3508
3579
  const httpPages = await getCDPTargets2(httpFallbackUrl);
3509
3580
  console.log(`[discoverContexts] HTTP /json/list returned ${httpPages.length} pages`);
3510
3581
  for (const p of httpPages) {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createRuleEngine,
3
3
  launch
4
- } from "./chunk-LTBNQERK.js";
4
+ } from "./chunk-DVKIL7H6.js";
5
5
  import {
6
6
  errMsg
7
7
  } from "./chunk-GDKLH7ZY.js";
@@ -1066,16 +1066,40 @@ async function createSession(name, url, options) {
1066
1066
  (t) => t.url && t.url !== "about:blank" && !t.url.startsWith("chrome://") && !t.url.startsWith("chrome-untrusted://") && !t.url.startsWith("chrome-error://") && (url ? t.url.includes(new URL(url).hostname) : true)
1067
1067
  );
1068
1068
  if (matchTarget && matchTarget.url) {
1069
- targetPage = await context.newPage();
1070
- await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
1069
+ const existing2 = context.pages().find((p) => {
1070
+ try {
1071
+ return p.url() === matchTarget.url;
1072
+ } catch {
1073
+ return false;
1074
+ }
1071
1075
  });
1076
+ if (existing2) {
1077
+ targetPage = existing2;
1078
+ } else {
1079
+ targetPage = await context.newPage();
1080
+ await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
1081
+ });
1082
+ }
1072
1083
  }
1073
1084
  }
1074
1085
  if (!targetPage) {
1075
1086
  const pages = context.pages();
1076
- if (pages.length > 0) {
1087
+ if (pages.length > 1) {
1088
+ try {
1089
+ for (const p of pages) {
1090
+ const vis = await p.evaluate("document.visibilityState").catch(() => "hidden");
1091
+ if (vis === "visible") {
1092
+ targetPage = p;
1093
+ break;
1094
+ }
1095
+ }
1096
+ } catch {
1097
+ }
1098
+ }
1099
+ if (!targetPage && pages.length > 0) {
1077
1100
  targetPage = pages[0];
1078
- } else {
1101
+ }
1102
+ if (!targetPage) {
1079
1103
  targetPage = await context.newPage();
1080
1104
  }
1081
1105
  }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  connectToCDP,
3
3
  launchChrome
4
- } from "./chunk-TNEN6VQ2.js";
4
+ } from "./chunk-3KZ34AUC.js";
5
5
  import {
6
6
  errMsg
7
7
  } from "./chunk-GDKLH7ZY.js";
@@ -383,6 +383,19 @@ function buildStealthInitScript() {
383
383
  " document.fonts.add(ff);ff.load();}catch(e2){}",
384
384
  " });",
385
385
  " }catch(e){}",
386
+ // 3g. Notification.requestPermission 延迟(d62):headless 无原生横幅,
387
+ // request 瞬回 denied —— 真机 request 会 pending 在横幅上数秒到分钟。
388
+ // 延迟 2-6s 再 resolve,模拟横幅期(用户"看了下然后拒绝")。
389
+ " try{",
390
+ " if(window.Notification&&Notification.requestPermission){",
391
+ " var _nrp=Notification.requestPermission.bind(Notification);",
392
+ " Notification.requestPermission=function(cb){",
393
+ " return new Promise(function(res){",
394
+ " setTimeout(function(){_nrp().then(function(r){if(cb)try{cb(r)}catch(e){}res(r);});},2000+Math.random()*4000);",
395
+ " });",
396
+ " };",
397
+ " }",
398
+ " }catch(e){}",
386
399
  // 3. toString disguise (name-list based)
387
400
  " var _ts=Function.prototype.toString;",
388
401
  " var _hf=document.hasFocus;",
@@ -528,6 +541,49 @@ var XBMouseImpl = class {
528
541
  this._x = x;
529
542
  this._y = y;
530
543
  }
544
+ /**
545
+ * Drag from the CURRENT cursor position to (x, y): press, traverse a
546
+ * bezier trajectory with the button held, release. Drives the REAL
547
+ * HTML5 DnD pipeline — field-verified (d59): this sequence fires
548
+ * dragstart → dragover… → drop → dragend, all isTrusted=true. No
549
+ * Input.dispatchDragEvent needed.
550
+ */
551
+ async drag(x, y, opts = {}) {
552
+ const stealth = process.env.XBROWSER_STEALTH !== "off";
553
+ await this.send("Input.dispatchMouseEvent", {
554
+ type: "mousePressed",
555
+ x: this._x,
556
+ y: this._y,
557
+ button: "left",
558
+ clickCount: 1
559
+ });
560
+ this._button = "left";
561
+ const steps = opts.steps ?? Math.max(10, Math.min(24, Math.round(Math.hypot(x - this._x, y - this._y) / 20)));
562
+ const fx = this._x, fy = this._y;
563
+ for (let i = 1; i <= steps; i++) {
564
+ if (stealth) await sleep2(rand(16, 28));
565
+ const t = i / steps;
566
+ this._x = fx + (x - fx) * t;
567
+ this._y = fy + (y - fy) * t;
568
+ await this.send("Input.dispatchMouseEvent", {
569
+ type: "mouseMoved",
570
+ x: this._x,
571
+ y: this._y,
572
+ button: this._button
573
+ });
574
+ }
575
+ this._x = x;
576
+ this._y = y;
577
+ await sleep2(rand(60, 140));
578
+ await this.send("Input.dispatchMouseEvent", {
579
+ type: "mouseReleased",
580
+ x,
581
+ y,
582
+ button: "left",
583
+ clickCount: 1
584
+ });
585
+ this._button = "none";
586
+ }
531
587
  async wheel(deltaX, deltaY) {
532
588
  await this.send("Input.dispatchMouseEvent", {
533
589
  type: "mouseWheel",
@@ -1268,6 +1324,21 @@ var XBLocatorImpl = class _XBLocatorImpl {
1268
1324
  `);
1269
1325
  return selected;
1270
1326
  }
1327
+ async dragAndDrop(source, target) {
1328
+ const boxes = await this.page.evaluate(`
1329
+ (function() {
1330
+ const s = ${this._q(source)}, t = ${this._q(target)};
1331
+ if (!s || !t) return null;
1332
+ const c = (el) => { const r = el.getBoundingClientRect(); return { x: r.x + r.width / 2, y: r.y + r.height / 2 }; };
1333
+ return [c(s), c(t)];
1334
+ })()
1335
+ `);
1336
+ if (!boxes || !boxes[0] || !boxes[1]) {
1337
+ throw new Error(`dragAndDrop: element not found (${source} / ${target})`);
1338
+ }
1339
+ await this.page.mouse.move(boxes[0].x, boxes[0].y);
1340
+ await this.page.mouse.drag(boxes[1].x, boxes[1].y);
1341
+ }
1271
1342
  async screenshot(opts = {}) {
1272
1343
  await waitForActionable(this.page, this.selector);
1273
1344
  const box = await this.page.evaluate(`
@@ -3372,7 +3443,7 @@ var XBBrowserImpl = class {
3372
3443
  this._exitHandler = null;
3373
3444
  }
3374
3445
  if (this.childProcess) {
3375
- const { killChrome: killChrome2 } = await import("./launcher-L2JNDB2H.js");
3446
+ const { killChrome: killChrome2 } = await import("./launcher-44STYRJC.js");
3376
3447
  await killChrome2(this.childProcess, this.tmpDir);
3377
3448
  }
3378
3449
  await this.conn.close();
@@ -3507,7 +3578,7 @@ var XBBrowserImpl = class {
3507
3578
  if (pageTargets.length === 0 && httpFallbackUrl) {
3508
3579
  console.log(`[discoverContexts] Target.getTargets returned ${targetInfos.length} targets (0 page type). Falling back to HTTP /json/list at ${httpFallbackUrl}`);
3509
3580
  try {
3510
- const { getCDPTargets: getCDPTargets3 } = await import("./launcher-L2JNDB2H.js");
3581
+ const { getCDPTargets: getCDPTargets3 } = await import("./launcher-44STYRJC.js");
3511
3582
  const httpPages = await getCDPTargets3(httpFallbackUrl);
3512
3583
  console.log(`[discoverContexts] HTTP /json/list returned ${httpPages.length} pages`);
3513
3584
  for (const p of httpPages) {
@@ -5873,16 +5944,40 @@ async function createSession(name, url, options) {
5873
5944
  (t) => t.url && t.url !== "about:blank" && !t.url.startsWith("chrome://") && !t.url.startsWith("chrome-untrusted://") && !t.url.startsWith("chrome-error://") && (url ? t.url.includes(new URL(url).hostname) : true)
5874
5945
  );
5875
5946
  if (matchTarget && matchTarget.url) {
5876
- targetPage = await context.newPage();
5877
- await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
5947
+ const existing2 = context.pages().find((p) => {
5948
+ try {
5949
+ return p.url() === matchTarget.url;
5950
+ } catch {
5951
+ return false;
5952
+ }
5878
5953
  });
5954
+ if (existing2) {
5955
+ targetPage = existing2;
5956
+ } else {
5957
+ targetPage = await context.newPage();
5958
+ await targetPage.goto(matchTarget.url, { waitUntil: "domcontentloaded", timeout: 15e3 }).catch(() => {
5959
+ });
5960
+ }
5879
5961
  }
5880
5962
  }
5881
5963
  if (!targetPage) {
5882
5964
  const pages = context.pages();
5883
- if (pages.length > 0) {
5965
+ if (pages.length > 1) {
5966
+ try {
5967
+ for (const p of pages) {
5968
+ const vis = await p.evaluate("document.visibilityState").catch(() => "hidden");
5969
+ if (vis === "visible") {
5970
+ targetPage = p;
5971
+ break;
5972
+ }
5973
+ }
5974
+ } catch {
5975
+ }
5976
+ }
5977
+ if (!targetPage && pages.length > 0) {
5884
5978
  targetPage = pages[0];
5885
- } else {
5979
+ }
5980
+ if (!targetPage) {
5886
5981
  targetPage = await context.newPage();
5887
5982
  }
5888
5983
  }
package/dist/cli.js CHANGED
@@ -72,8 +72,8 @@ import {
72
72
  setActivePage,
73
73
  sleep,
74
74
  wheelDelta
75
- } from "./chunk-5EYOEB4R.js";
76
- import "./chunk-TNEN6VQ2.js";
75
+ } from "./chunk-OU335JBI.js";
76
+ import "./chunk-3KZ34AUC.js";
77
77
  import {
78
78
  errMsg
79
79
  } from "./chunk-GDKLH7ZY.js";
@@ -947,14 +947,14 @@ var mouseCommand = registerCommand({
947
947
  description: "Control the mouse (move, click, etc.)",
948
948
  scope: "page",
949
949
  parameters: z6.object({
950
- action: z6.enum(["move", "down", "up", "click", "dblclick"]),
950
+ action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
951
951
  x: z6.coerce.number(),
952
952
  y: z6.coerce.number(),
953
953
  button: z6.enum(["left", "right", "middle"]).optional(),
954
954
  steps: z6.coerce.number().optional()
955
955
  }),
956
956
  result: z6.object({
957
- action: z6.enum(["move", "down", "up", "click", "dblclick"]),
957
+ action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
958
958
  x: z6.number(),
959
959
  y: z6.number()
960
960
  }),
@@ -978,6 +978,9 @@ var mouseCommand = registerCommand({
978
978
  case "dblclick":
979
979
  await ctx.page.mouse.dblclick(p.x, p.y, { button });
980
980
  break;
981
+ case "drag":
982
+ await ctx.page.mouse.drag(p.x, p.y, p.steps ? { steps: p.steps } : {});
983
+ break;
981
984
  }
982
985
  return ok6({ action: p.action, x: p.x, y: p.y });
983
986
  }
@@ -7542,7 +7545,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7542
7545
  }
7543
7546
  let targetPageOverride = null;
7544
7547
  if (_target && extraOpts?.cdpEndpoint) {
7545
- const { findTargetPage } = await import("./browser-KT4FOWBO.js");
7548
+ const { findTargetPage } = await import("./browser-W3Z4HPJN.js");
7546
7549
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7547
7550
  if (!targetPageOverride) {
7548
7551
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -13717,7 +13720,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
13717
13720
  const targetPage = pages[cmdTabIndex];
13718
13721
  await targetPage.bringToFront().catch(() => {
13719
13722
  });
13720
- const { setActivePage: setActivePage2 } = await import("./browser-KT4FOWBO.js");
13723
+ const { setActivePage: setActivePage2 } = await import("./browser-W3Z4HPJN.js");
13721
13724
  setActivePage2(session, targetPage);
13722
13725
  }
13723
13726
  }
@@ -13993,7 +13996,7 @@ async function main() {
13993
13996
  const command = process.argv[2];
13994
13997
  const isLongRunning = command === "preview" || command === "serve";
13995
13998
  if (!isLongRunning) {
13996
- const { ensureProcessCanExit } = await import("./browser-KT4FOWBO.js");
13999
+ const { ensureProcessCanExit } = await import("./browser-W3Z4HPJN.js");
13997
14000
  await ensureProcessCanExit().catch(() => {
13998
14001
  });
13999
14002
  process.exit(process.exitCode || exitCode);
@@ -34,17 +34,17 @@ import {
34
34
  resolveLaunchOpts,
35
35
  saveSessionDiskMeta,
36
36
  setActivePage
37
- } from "./chunk-GWQ5NTVE.js";
37
+ } from "./chunk-MMZCBUD3.js";
38
38
  import {
39
39
  createRuleEngine,
40
40
  rand,
41
41
  sleep,
42
42
  wheelDelta
43
- } from "./chunk-LTBNQERK.js";
43
+ } from "./chunk-DVKIL7H6.js";
44
44
  import {
45
45
  queryJS
46
46
  } from "./chunk-3FWLW7FS.js";
47
- import "./chunk-TNEN6VQ2.js";
47
+ import "./chunk-3KZ34AUC.js";
48
48
  import {
49
49
  errMsg
50
50
  } from "./chunk-GDKLH7ZY.js";
@@ -907,14 +907,14 @@ var mouseCommand = registerCommand({
907
907
  description: "Control the mouse (move, click, etc.)",
908
908
  scope: "page",
909
909
  parameters: z6.object({
910
- action: z6.enum(["move", "down", "up", "click", "dblclick"]),
910
+ action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
911
911
  x: z6.coerce.number(),
912
912
  y: z6.coerce.number(),
913
913
  button: z6.enum(["left", "right", "middle"]).optional(),
914
914
  steps: z6.coerce.number().optional()
915
915
  }),
916
916
  result: z6.object({
917
- action: z6.enum(["move", "down", "up", "click", "dblclick"]),
917
+ action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
918
918
  x: z6.number(),
919
919
  y: z6.number()
920
920
  }),
@@ -938,6 +938,9 @@ var mouseCommand = registerCommand({
938
938
  case "dblclick":
939
939
  await ctx.page.mouse.dblclick(p.x, p.y, { button });
940
940
  break;
941
+ case "drag":
942
+ await ctx.page.mouse.drag(p.x, p.y, p.steps ? { steps: p.steps } : {});
943
+ break;
941
944
  }
942
945
  return ok6({ action: p.action, x: p.x, y: p.y });
943
946
  }
@@ -7060,7 +7063,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7060
7063
  }
7061
7064
  let targetPageOverride = null;
7062
7065
  if (_target && extraOpts?.cdpEndpoint) {
7063
- const { findTargetPage } = await import("./browser-AOVQTGJ7.js");
7066
+ const { findTargetPage } = await import("./browser-UPKOT3V6.js");
7064
7067
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7065
7068
  if (!targetPageOverride) {
7066
7069
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -8879,7 +8882,7 @@ function createRPCHandler() {
8879
8882
  if (isNewFormat) {
8880
8883
  try {
8881
8884
  const replayErrors = [];
8882
- const { SessionReplayer } = await import("./session-replayer-MJH5W7BB.js");
8885
+ const { SessionReplayer } = await import("./session-replayer-J4GXUULG.js");
8883
8886
  const replayer = new SessionReplayer({
8884
8887
  page: session.page,
8885
8888
  stepDelay: slowMo * 500,
package/dist/index.d.ts CHANGED
@@ -311,6 +311,10 @@ interface XBMouse {
311
311
  steps?: number;
312
312
  }): Promise<void>;
313
313
  wheel(deltaX: number, deltaY: number): Promise<void>;
314
+ /** Drag from current position to (x,y) — drives the real HTML5 DnD pipeline */
315
+ drag(x: number, y: number, opts?: {
316
+ steps?: number;
317
+ }): Promise<void>;
314
318
  }
315
319
  interface XBKeyboard {
316
320
  press(key: string, opts?: {
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import {
18
18
  resolveLaunchOpts,
19
19
  saveSessionDiskMeta,
20
20
  setActivePage
21
- } from "./chunk-7V3B7VPX.js";
21
+ } from "./chunk-EI2XZIDF.js";
22
22
  import {
23
23
  detectAntiBot,
24
24
  formatDetectionMessage
@@ -86,8 +86,8 @@ import {
86
86
  rand,
87
87
  sleep,
88
88
  wheelDelta
89
- } from "./chunk-A5HJ6IRE.js";
90
- import "./chunk-TNEN6VQ2.js";
89
+ } from "./chunk-LL37GYPP.js";
90
+ import "./chunk-3KZ34AUC.js";
91
91
  import {
92
92
  errMsg
93
93
  } from "./chunk-GDKLH7ZY.js";
@@ -981,14 +981,14 @@ var mouseCommand = registerCommand({
981
981
  description: "Control the mouse (move, click, etc.)",
982
982
  scope: "page",
983
983
  parameters: z6.object({
984
- action: z6.enum(["move", "down", "up", "click", "dblclick"]),
984
+ action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
985
985
  x: z6.coerce.number(),
986
986
  y: z6.coerce.number(),
987
987
  button: z6.enum(["left", "right", "middle"]).optional(),
988
988
  steps: z6.coerce.number().optional()
989
989
  }),
990
990
  result: z6.object({
991
- action: z6.enum(["move", "down", "up", "click", "dblclick"]),
991
+ action: z6.enum(["move", "down", "up", "click", "dblclick", "drag"]),
992
992
  x: z6.number(),
993
993
  y: z6.number()
994
994
  }),
@@ -1012,6 +1012,9 @@ var mouseCommand = registerCommand({
1012
1012
  case "dblclick":
1013
1013
  await ctx.page.mouse.dblclick(p.x, p.y, { button });
1014
1014
  break;
1015
+ case "drag":
1016
+ await ctx.page.mouse.drag(p.x, p.y, p.steps ? { steps: p.steps } : {});
1017
+ break;
1015
1018
  }
1016
1019
  return ok6({ action: p.action, x: p.x, y: p.y });
1017
1020
  }
@@ -7893,7 +7896,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7893
7896
  }
7894
7897
  let targetPageOverride = null;
7895
7898
  if (_target && extraOpts?.cdpEndpoint) {
7896
- const { findTargetPage } = await import("./browser-3KTEVTMU.js");
7899
+ const { findTargetPage } = await import("./browser-SYE57VHU.js");
7897
7900
  targetPageOverride = await findTargetPage(extraOpts.cdpEndpoint, _target);
7898
7901
  if (!targetPageOverride) {
7899
7902
  return errorResult(`Target "${_target}" not found. Use 'xbrowser targets --cdp ${extraOpts.cdpEndpoint}' to list available pages.`);
@@ -14106,7 +14109,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
14106
14109
  const targetPage = pages[cmdTabIndex];
14107
14110
  await targetPage.bringToFront().catch(() => {
14108
14111
  });
14109
- const { setActivePage: setActivePage2 } = await import("./browser-3KTEVTMU.js");
14112
+ const { setActivePage: setActivePage2 } = await import("./browser-SYE57VHU.js");
14110
14113
  setActivePage2(session, targetPage);
14111
14114
  }
14112
14115
  }
@@ -17279,7 +17282,7 @@ var DataCollector = class {
17279
17282
  return results;
17280
17283
  }
17281
17284
  async createBrowserContext() {
17282
- const { launch } = await import("./cdp-driver-OC37OT4B.js");
17285
+ const { launch } = await import("./cdp-driver-KT6HL33W.js");
17283
17286
  const { browser } = await launch({
17284
17287
  headless: true,
17285
17288
  args: ["--no-sandbox", "--disable-setuid-sandbox"]
@@ -4,9 +4,10 @@ import {
4
4
  connectToCDP,
5
5
  findChrome,
6
6
  getCDPTargets,
7
+ joinCdpHttpUrl,
7
8
  killChrome,
8
9
  launchChrome
9
- } from "./chunk-TNEN6VQ2.js";
10
+ } from "./chunk-3KZ34AUC.js";
10
11
  import "./chunk-GDKLH7ZY.js";
11
12
  import "./chunk-KFQGP6VL.js";
12
13
  export {
@@ -15,6 +16,7 @@ export {
15
16
  connectToCDP,
16
17
  findChrome,
17
18
  getCDPTargets,
19
+ joinCdpHttpUrl,
18
20
  killChrome,
19
21
  launchChrome
20
22
  };
@@ -4,9 +4,10 @@ import {
4
4
  connectToCDP,
5
5
  findChrome,
6
6
  getCDPTargets,
7
+ joinCdpHttpUrl,
7
8
  killChrome,
8
9
  launchChrome
9
- } from "./chunk-AMI64BSD.js";
10
+ } from "./chunk-IWVG4XYZ.js";
10
11
  import "./chunk-3RG5ZIWI.js";
11
12
  export {
12
13
  ANTI_DETECT_ARGS,
@@ -14,6 +15,7 @@ export {
14
15
  connectToCDP,
15
16
  findChrome,
16
17
  getCDPTargets,
18
+ joinCdpHttpUrl,
17
19
  killChrome,
18
20
  launchChrome
19
21
  };
@@ -34,7 +34,7 @@ var SessionReplayer = class {
34
34
  if (this.opts.page) {
35
35
  this.page = this.opts.page;
36
36
  } else if (this.opts.cdpUrl) {
37
- const { launch } = await import("./cdp-driver-DKNLIA6B.js");
37
+ const { launch } = await import("./cdp-driver-4UAV56SQ.js");
38
38
  const { browser } = await launch({ cdpEndpoint: this.opts.cdpUrl });
39
39
  let contexts = browser.contexts();
40
40
  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.16.0",
3
+ "version": "1.18.0",
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": {