@xbrowser/cli 1.18.2 → 1.19.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,7 +20,7 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-7SDM4EA4.js";
23
+ } from "./chunk-KLXLNQI5.js";
24
24
  import "./chunk-3KZ34AUC.js";
25
25
  import "./chunk-GDKLH7ZY.js";
26
26
  import "./chunk-KFQGP6VL.js";
@@ -20,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-MTNVT2T7.js";
24
- import "./chunk-LL37GYPP.js";
23
+ } from "./chunk-2BPZ25RE.js";
24
+ import "./chunk-LKJZYVIX.js";
25
25
  import "./chunk-3KZ34AUC.js";
26
26
  import "./chunk-GDKLH7ZY.js";
27
27
  import "./chunk-A6LPGFAL.js";
@@ -20,8 +20,8 @@ import {
20
20
  saveSessionDiskMeta,
21
21
  setActivePage,
22
22
  touchSession
23
- } from "./chunk-NA7IP6PO.js";
24
- import "./chunk-DVKIL7H6.js";
23
+ } from "./chunk-C6PW3CPA.js";
24
+ import "./chunk-GKYSCHT4.js";
25
25
  import "./chunk-3FWLW7FS.js";
26
26
  import "./chunk-3KZ34AUC.js";
27
27
  import "./chunk-GDKLH7ZY.js";
@@ -14,7 +14,7 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-LL37GYPP.js";
17
+ } from "./chunk-LKJZYVIX.js";
18
18
  import {
19
19
  connectToCDP,
20
20
  findChrome,
@@ -14,7 +14,7 @@ import {
14
14
  scrollIntoView,
15
15
  waitForActionable,
16
16
  waitForNetworkIdle
17
- } from "./chunk-DVKIL7H6.js";
17
+ } from "./chunk-GKYSCHT4.js";
18
18
  import "./chunk-3FWLW7FS.js";
19
19
  import {
20
20
  connectToCDP,
@@ -133,8 +133,17 @@ function buildStealthInitScript() {
133
133
  " if(!e)return f.call(this,e);",
134
134
  " return f.call(this,new Proxy(e,{get:function(k,p){",
135
135
  ' if(p==="sourceCapabilities")return fc;',
136
- ' if(p==="isTrusted")return Reflect.get(k,"isTrusted");',
137
- ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])&&k.isTrusted===true){',
136
+ // S124 修正(d67 攻防):恒 true 是"过度伪装"——站点自己的合成事件
137
+ // 也变 true → 直接判定浏览器被篡改(比检测自动化更严重的指纹暴露)。
138
+ // 正确策略:透传原始值(CDP Input 事件本来就是 true,JS 合成本来是 false)
139
+ // + paste 定向伪装(合成的 paste 在真实场景都是 trusted 的键盘操作产物)
140
+ ' if(p==="isTrusted"){',
141
+ ' var orig=Reflect.get(k,"isTrusted");',
142
+ " if(orig===true)return true;",
143
+ ' if(k.type==="paste")return true;',
144
+ " return orig;",
145
+ " }",
146
+ ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])){',
138
147
  " var _f=((k.timeStamp||Date.now())%89)/89*0.7+0.15;",
139
148
  " return k[p]+_f;",
140
149
  " }",
@@ -144,6 +153,30 @@ function buildStealthInitScript() {
144
153
  " return o.call(this,t,w,op);",
145
154
  " };",
146
155
  " EventTarget.prototype.addEventListener=_ael;",
156
+ // window.event isTrusted 伪装(S123):AEL 参数包装收不到 window.event
157
+ // (它是原始 Event 对象的隐式引用)。定义 getter 拦截读取。
158
+ " try{",
159
+ ' var _weDesc=Object.getOwnPropertyDescriptor(Window.prototype,"event");',
160
+ " if(_weDesc&&_weDesc.get){",
161
+ " var _origWeGet=_weDesc.get;",
162
+ ' Object.defineProperty(Window.prototype,"event",{',
163
+ " configurable:true,",
164
+ " get:function(){",
165
+ " var ev=_origWeGet.call(this);",
166
+ " if(!ev)return ev;",
167
+ " return new Proxy(ev,{get:function(k,p){",
168
+ ' if(p==="isTrusted"){',
169
+ ' var orig=Reflect.get(k,"isTrusted");',
170
+ " if(orig===true)return true;",
171
+ ' if(k.type==="paste")return true;',
172
+ " return orig;",
173
+ " }",
174
+ ' var v=Reflect.get(k,p);return typeof v==="function"?v.bind(k):v;',
175
+ " }});",
176
+ " }",
177
+ " });",
178
+ " }",
179
+ " }catch(e){}",
147
180
  // 2. Screen override (prototype-level, not instance-level)
148
181
  " var _gw=function(){return 1728};",
149
182
  " var _gh=function(){return 1117};",
@@ -401,7 +434,12 @@ function buildStealthInitScript() {
401
434
  " };",
402
435
  // 4. onclick prototype hijack (dual-stream consistency)
403
436
  " var _ba=function(k,p){",
404
- ' if(p==="isTrusted")return Reflect.get(k,"isTrusted");',
437
+ ' if(p==="isTrusted"){',
438
+ ' var orig=Reflect.get(k,"isTrusted");',
439
+ " if(orig===true)return true;",
440
+ ' if(k.type==="paste")return true;',
441
+ " return orig;",
442
+ " }",
405
443
  ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])&&k.isTrusted===true){',
406
444
  " var _f=((k.timeStamp||Date.now())%89)/89*0.7+0.15;return k[p]+_f;",
407
445
  " }",
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  launch
3
- } from "./chunk-LL37GYPP.js";
3
+ } from "./chunk-LKJZYVIX.js";
4
4
  import {
5
5
  errMsg
6
6
  } from "./chunk-GDKLH7ZY.js";
@@ -68,7 +68,9 @@ async function resolveCDPEndpoint(raw) {
68
68
  }
69
69
  if (raw.startsWith("http://") || raw.startsWith("https://")) {
70
70
  try {
71
- const httpResp = await fetchNoProxy(`${raw}/json/version`);
71
+ const u = new URL(raw);
72
+ u.pathname = (u.pathname.replace(/\/+$/, "") || "") + "/json/version";
73
+ const httpResp = await fetchNoProxy(u.toString());
72
74
  const data = await httpResp.json();
73
75
  if (!data.webSocketDebuggerUrl) {
74
76
  throw new Error(`Could not discover CDP endpoint from ${raw}`);
@@ -206,9 +208,17 @@ function discoverChromiumPath() {
206
208
  }
207
209
  return void 0;
208
210
  }
211
+ var _browserPool = /* @__PURE__ */ new Map();
209
212
  async function createBrowser(options) {
210
213
  if (options?.cdpEndpoint) {
211
214
  const realEndpoint = await resolveCDPEndpoint(options.cdpEndpoint);
215
+ if (!options.intercept) {
216
+ const pooled = _browserPool.get(realEndpoint);
217
+ if (pooled && !pooled.disconnected) {
218
+ return pooled;
219
+ }
220
+ if (pooled) _browserPool.delete(realEndpoint);
221
+ }
212
222
  if (options.intercept) {
213
223
  const config = typeof options.intercept === "object" ? { ...options.intercept, cdpEndpoint: realEndpoint } : { cdpEndpoint: realEndpoint };
214
224
  _sharedCdpProxy = new CDPInterceptorProxy(config);
@@ -221,6 +231,7 @@ async function createBrowser(options) {
221
231
  await browser2.discoverContexts().catch((err) => {
222
232
  console.error(`[browser] discoverContexts failed: ${errMsg(err)}`);
223
233
  });
234
+ if (!options.intercept) _browserPool.set(realEndpoint, browser2);
224
235
  return browser2;
225
236
  }
226
237
  const executablePath = options?.executablePath || process.env.XBROWSER_CHROMIUM_PATH || discoverChromiumPath();
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createRuleEngine,
3
3
  launch
4
- } from "./chunk-DVKIL7H6.js";
4
+ } from "./chunk-GKYSCHT4.js";
5
5
  import {
6
6
  errMsg
7
7
  } from "./chunk-GDKLH7ZY.js";
@@ -495,7 +495,9 @@ async function resolveCDPEndpoint(raw) {
495
495
  }
496
496
  if (raw.startsWith("http://") || raw.startsWith("https://")) {
497
497
  try {
498
- const httpResp = await fetchNoProxy(`${raw}/json/version`);
498
+ const u = new URL(raw);
499
+ u.pathname = (u.pathname.replace(/\/+$/, "") || "") + "/json/version";
500
+ const httpResp = await fetchNoProxy(u.toString());
499
501
  const data = await httpResp.json();
500
502
  if (!data.webSocketDebuggerUrl) {
501
503
  throw new Error(`Could not discover CDP endpoint from ${raw}`);
@@ -633,9 +635,17 @@ function discoverChromiumPath() {
633
635
  }
634
636
  return void 0;
635
637
  }
638
+ var _browserPool = /* @__PURE__ */ new Map();
636
639
  async function createBrowser(options) {
637
640
  if (options?.cdpEndpoint) {
638
641
  const realEndpoint = await resolveCDPEndpoint(options.cdpEndpoint);
642
+ if (!options.intercept) {
643
+ const pooled = _browserPool.get(realEndpoint);
644
+ if (pooled && !pooled.disconnected) {
645
+ return pooled;
646
+ }
647
+ if (pooled) _browserPool.delete(realEndpoint);
648
+ }
639
649
  if (options.intercept) {
640
650
  const config = typeof options.intercept === "object" ? { ...options.intercept, cdpEndpoint: realEndpoint } : { cdpEndpoint: realEndpoint };
641
651
  _sharedCdpProxy = new CDPInterceptorProxy(config);
@@ -648,6 +658,7 @@ async function createBrowser(options) {
648
658
  await browser2.discoverContexts().catch((err) => {
649
659
  console.error(`[browser] discoverContexts failed: ${errMsg(err)}`);
650
660
  });
661
+ if (!options.intercept) _browserPool.set(realEndpoint, browser2);
651
662
  return browser2;
652
663
  }
653
664
  const executablePath = options?.executablePath || process.env.XBROWSER_CHROMIUM_PATH || discoverChromiumPath();
@@ -144,8 +144,17 @@ function buildStealthInitScript() {
144
144
  " if(!e)return f.call(this,e);",
145
145
  " return f.call(this,new Proxy(e,{get:function(k,p){",
146
146
  ' if(p==="sourceCapabilities")return fc;',
147
- ' if(p==="isTrusted")return Reflect.get(k,"isTrusted");',
148
- ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])&&k.isTrusted===true){',
147
+ // S124 修正(d67 攻防):恒 true 是"过度伪装"——站点自己的合成事件
148
+ // 也变 true → 直接判定浏览器被篡改(比检测自动化更严重的指纹暴露)。
149
+ // 正确策略:透传原始值(CDP Input 事件本来就是 true,JS 合成本来是 false)
150
+ // + paste 定向伪装(合成的 paste 在真实场景都是 trusted 的键盘操作产物)
151
+ ' if(p==="isTrusted"){',
152
+ ' var orig=Reflect.get(k,"isTrusted");',
153
+ " if(orig===true)return true;",
154
+ ' if(k.type==="paste")return true;',
155
+ " return orig;",
156
+ " }",
157
+ ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])){',
149
158
  " var _f=((k.timeStamp||Date.now())%89)/89*0.7+0.15;",
150
159
  " return k[p]+_f;",
151
160
  " }",
@@ -155,6 +164,30 @@ function buildStealthInitScript() {
155
164
  " return o.call(this,t,w,op);",
156
165
  " };",
157
166
  " EventTarget.prototype.addEventListener=_ael;",
167
+ // window.event isTrusted 伪装(S123):AEL 参数包装收不到 window.event
168
+ // (它是原始 Event 对象的隐式引用)。定义 getter 拦截读取。
169
+ " try{",
170
+ ' var _weDesc=Object.getOwnPropertyDescriptor(Window.prototype,"event");',
171
+ " if(_weDesc&&_weDesc.get){",
172
+ " var _origWeGet=_weDesc.get;",
173
+ ' Object.defineProperty(Window.prototype,"event",{',
174
+ " configurable:true,",
175
+ " get:function(){",
176
+ " var ev=_origWeGet.call(this);",
177
+ " if(!ev)return ev;",
178
+ " return new Proxy(ev,{get:function(k,p){",
179
+ ' if(p==="isTrusted"){',
180
+ ' var orig=Reflect.get(k,"isTrusted");',
181
+ " if(orig===true)return true;",
182
+ ' if(k.type==="paste")return true;',
183
+ " return orig;",
184
+ " }",
185
+ ' var v=Reflect.get(k,p);return typeof v==="function"?v.bind(k):v;',
186
+ " }});",
187
+ " }",
188
+ " });",
189
+ " }",
190
+ " }catch(e){}",
158
191
  // 2. Screen override (prototype-level, not instance-level)
159
192
  " var _gw=function(){return 1728};",
160
193
  " var _gh=function(){return 1117};",
@@ -412,7 +445,12 @@ function buildStealthInitScript() {
412
445
  " };",
413
446
  // 4. onclick prototype hijack (dual-stream consistency)
414
447
  " var _ba=function(k,p){",
415
- ' if(p==="isTrusted")return Reflect.get(k,"isTrusted");',
448
+ ' if(p==="isTrusted"){',
449
+ ' var orig=Reflect.get(k,"isTrusted");',
450
+ " if(orig===true)return true;",
451
+ ' if(k.type==="paste")return true;',
452
+ " return orig;",
453
+ " }",
416
454
  ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])&&k.isTrusted===true){',
417
455
  " var _f=((k.timeStamp||Date.now())%89)/89*0.7+0.15;return k[p]+_f;",
418
456
  " }",
@@ -146,8 +146,17 @@ function buildStealthInitScript() {
146
146
  " if(!e)return f.call(this,e);",
147
147
  " return f.call(this,new Proxy(e,{get:function(k,p){",
148
148
  ' if(p==="sourceCapabilities")return fc;',
149
- ' if(p==="isTrusted")return Reflect.get(k,"isTrusted");',
150
- ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])&&k.isTrusted===true){',
149
+ // S124 修正(d67 攻防):恒 true 是"过度伪装"——站点自己的合成事件
150
+ // 也变 true → 直接判定浏览器被篡改(比检测自动化更严重的指纹暴露)。
151
+ // 正确策略:透传原始值(CDP Input 事件本来就是 true,JS 合成本来是 false)
152
+ // + paste 定向伪装(合成的 paste 在真实场景都是 trusted 的键盘操作产物)
153
+ ' if(p==="isTrusted"){',
154
+ ' var orig=Reflect.get(k,"isTrusted");',
155
+ " if(orig===true)return true;",
156
+ ' if(k.type==="paste")return true;',
157
+ " return orig;",
158
+ " }",
159
+ ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])){',
151
160
  " var _f=((k.timeStamp||Date.now())%89)/89*0.7+0.15;",
152
161
  " return k[p]+_f;",
153
162
  " }",
@@ -157,6 +166,30 @@ function buildStealthInitScript() {
157
166
  " return o.call(this,t,w,op);",
158
167
  " };",
159
168
  " EventTarget.prototype.addEventListener=_ael;",
169
+ // window.event isTrusted 伪装(S123):AEL 参数包装收不到 window.event
170
+ // (它是原始 Event 对象的隐式引用)。定义 getter 拦截读取。
171
+ " try{",
172
+ ' var _weDesc=Object.getOwnPropertyDescriptor(Window.prototype,"event");',
173
+ " if(_weDesc&&_weDesc.get){",
174
+ " var _origWeGet=_weDesc.get;",
175
+ ' Object.defineProperty(Window.prototype,"event",{',
176
+ " configurable:true,",
177
+ " get:function(){",
178
+ " var ev=_origWeGet.call(this);",
179
+ " if(!ev)return ev;",
180
+ " return new Proxy(ev,{get:function(k,p){",
181
+ ' if(p==="isTrusted"){',
182
+ ' var orig=Reflect.get(k,"isTrusted");',
183
+ " if(orig===true)return true;",
184
+ ' if(k.type==="paste")return true;',
185
+ " return orig;",
186
+ " }",
187
+ ' var v=Reflect.get(k,p);return typeof v==="function"?v.bind(k):v;',
188
+ " }});",
189
+ " }",
190
+ " });",
191
+ " }",
192
+ " }catch(e){}",
160
193
  // 2. Screen override (prototype-level, not instance-level)
161
194
  " var _gw=function(){return 1728};",
162
195
  " var _gh=function(){return 1117};",
@@ -414,7 +447,12 @@ function buildStealthInitScript() {
414
447
  " };",
415
448
  // 4. onclick prototype hijack (dual-stream consistency)
416
449
  " var _ba=function(k,p){",
417
- ' if(p==="isTrusted")return Reflect.get(k,"isTrusted");',
450
+ ' if(p==="isTrusted"){',
451
+ ' var orig=Reflect.get(k,"isTrusted");',
452
+ " if(orig===true)return true;",
453
+ ' if(k.type==="paste")return true;',
454
+ " return orig;",
455
+ " }",
418
456
  ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])&&k.isTrusted===true){',
419
457
  " var _f=((k.timeStamp||Date.now())%89)/89*0.7+0.15;return k[p]+_f;",
420
458
  " }",
@@ -5373,7 +5411,9 @@ async function resolveCDPEndpoint(raw) {
5373
5411
  }
5374
5412
  if (raw.startsWith("http://") || raw.startsWith("https://")) {
5375
5413
  try {
5376
- const httpResp = await fetchNoProxy(`${raw}/json/version`);
5414
+ const u = new URL(raw);
5415
+ u.pathname = (u.pathname.replace(/\/+$/, "") || "") + "/json/version";
5416
+ const httpResp = await fetchNoProxy(u.toString());
5377
5417
  const data = await httpResp.json();
5378
5418
  if (!data.webSocketDebuggerUrl) {
5379
5419
  throw new Error(`Could not discover CDP endpoint from ${raw}`);
@@ -5511,9 +5551,17 @@ function discoverChromiumPath() {
5511
5551
  }
5512
5552
  return void 0;
5513
5553
  }
5554
+ var _browserPool = /* @__PURE__ */ new Map();
5514
5555
  async function createBrowser(options) {
5515
5556
  if (options?.cdpEndpoint) {
5516
5557
  const realEndpoint = await resolveCDPEndpoint(options.cdpEndpoint);
5558
+ if (!options.intercept) {
5559
+ const pooled = _browserPool.get(realEndpoint);
5560
+ if (pooled && !pooled.disconnected) {
5561
+ return pooled;
5562
+ }
5563
+ if (pooled) _browserPool.delete(realEndpoint);
5564
+ }
5517
5565
  if (options.intercept) {
5518
5566
  const config = typeof options.intercept === "object" ? { ...options.intercept, cdpEndpoint: realEndpoint } : { cdpEndpoint: realEndpoint };
5519
5567
  _sharedCdpProxy = new CDPInterceptorProxy(config);
@@ -5526,6 +5574,7 @@ async function createBrowser(options) {
5526
5574
  await browser2.discoverContexts().catch((err) => {
5527
5575
  console.error(`[browser] discoverContexts failed: ${errMsg(err)}`);
5528
5576
  });
5577
+ if (!options.intercept) _browserPool.set(realEndpoint, browser2);
5529
5578
  return browser2;
5530
5579
  }
5531
5580
  const executablePath = options?.executablePath || process.env.XBROWSER_CHROMIUM_PATH || discoverChromiumPath();
@@ -143,8 +143,17 @@ function buildStealthInitScript() {
143
143
  " if(!e)return f.call(this,e);",
144
144
  " return f.call(this,new Proxy(e,{get:function(k,p){",
145
145
  ' if(p==="sourceCapabilities")return fc;',
146
- ' if(p==="isTrusted")return Reflect.get(k,"isTrusted");',
147
- ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])&&k.isTrusted===true){',
146
+ // S124 修正(d67 攻防):恒 true 是"过度伪装"——站点自己的合成事件
147
+ // 也变 true → 直接判定浏览器被篡改(比检测自动化更严重的指纹暴露)。
148
+ // 正确策略:透传原始值(CDP Input 事件本来就是 true,JS 合成本来是 false)
149
+ // + paste 定向伪装(合成的 paste 在真实场景都是 trusted 的键盘操作产物)
150
+ ' if(p==="isTrusted"){',
151
+ ' var orig=Reflect.get(k,"isTrusted");',
152
+ " if(orig===true)return true;",
153
+ ' if(k.type==="paste")return true;',
154
+ " return orig;",
155
+ " }",
156
+ ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])){',
148
157
  " var _f=((k.timeStamp||Date.now())%89)/89*0.7+0.15;",
149
158
  " return k[p]+_f;",
150
159
  " }",
@@ -154,6 +163,30 @@ function buildStealthInitScript() {
154
163
  " return o.call(this,t,w,op);",
155
164
  " };",
156
165
  " EventTarget.prototype.addEventListener=_ael;",
166
+ // window.event isTrusted 伪装(S123):AEL 参数包装收不到 window.event
167
+ // (它是原始 Event 对象的隐式引用)。定义 getter 拦截读取。
168
+ " try{",
169
+ ' var _weDesc=Object.getOwnPropertyDescriptor(Window.prototype,"event");',
170
+ " if(_weDesc&&_weDesc.get){",
171
+ " var _origWeGet=_weDesc.get;",
172
+ ' Object.defineProperty(Window.prototype,"event",{',
173
+ " configurable:true,",
174
+ " get:function(){",
175
+ " var ev=_origWeGet.call(this);",
176
+ " if(!ev)return ev;",
177
+ " return new Proxy(ev,{get:function(k,p){",
178
+ ' if(p==="isTrusted"){',
179
+ ' var orig=Reflect.get(k,"isTrusted");',
180
+ " if(orig===true)return true;",
181
+ ' if(k.type==="paste")return true;',
182
+ " return orig;",
183
+ " }",
184
+ ' var v=Reflect.get(k,p);return typeof v==="function"?v.bind(k):v;',
185
+ " }});",
186
+ " }",
187
+ " });",
188
+ " }",
189
+ " }catch(e){}",
157
190
  // 2. Screen override (prototype-level, not instance-level)
158
191
  " var _gw=function(){return 1728};",
159
192
  " var _gh=function(){return 1117};",
@@ -411,7 +444,12 @@ function buildStealthInitScript() {
411
444
  " };",
412
445
  // 4. onclick prototype hijack (dual-stream consistency)
413
446
  " var _ba=function(k,p){",
414
- ' if(p==="isTrusted")return Reflect.get(k,"isTrusted");',
447
+ ' if(p==="isTrusted"){',
448
+ ' var orig=Reflect.get(k,"isTrusted");',
449
+ " if(orig===true)return true;",
450
+ ' if(k.type==="paste")return true;',
451
+ " return orig;",
452
+ " }",
415
453
  ' if((p==="clientX"||p==="clientY")&&k.type==="click"&&Number.isInteger(k[p])&&k.isTrusted===true){',
416
454
  " var _f=((k.timeStamp||Date.now())%89)/89*0.7+0.15;return k[p]+_f;",
417
455
  " }",