@xbrowser/cli 1.10.0 → 1.12.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.
Files changed (42) hide show
  1. package/dist/{anti-bot-DR56Y63V.js → anti-bot-GTTYNEFB.js} +1 -1
  2. package/dist/{browser-WQZ3D6AE.js → browser-3HQKDZQ6.js} +4 -2
  3. package/dist/{browser-T3V3JWVH.js → browser-ILXTEWH4.js} +1 -1
  4. package/dist/{browser-HBL72GPZ.js → browser-XPDMY2NX.js} +3 -3
  5. package/dist/{cdp-driver-J3YQ4LJV.js → cdp-driver-ESH3PDE6.js} +2 -1
  6. package/dist/cdp-driver-N2E2ZNSC.js +4644 -0
  7. package/dist/cdp-driver-YIKR4BUX.js +49 -0
  8. package/dist/chunk-3FWLW7FS.js +106 -0
  9. package/dist/chunk-A6LPGFAL.js +437 -0
  10. package/dist/{chunk-RRBXV7KE.js → chunk-DKM2JOZL.js} +633 -63
  11. package/dist/{chunk-ABXMBNQ6.js → chunk-H2A5JUK5.js} +37 -466
  12. package/dist/{chunk-5UGR6MUK.js → chunk-HBHOKZPN.js} +51 -16
  13. package/dist/{chunk-BNO7OKO4.js → chunk-HBMEFSTB.js} +39 -0
  14. package/dist/{chunk-INTQPBYF.js → chunk-JKVUFP3G.js} +6 -2
  15. package/dist/chunk-KJTABK3Z.js +1255 -0
  16. package/dist/{chunk-DWDXEGVK.js → chunk-NKW4A74J.js} +9 -3
  17. package/dist/{chunk-4452SPFI.js → chunk-NODRQGOK.js} +51 -16
  18. package/dist/{chunk-SQHSZENE.js → chunk-OMU63E6J.js} +3 -22
  19. package/dist/{chunk-NITFVWWS.js → chunk-OVW2UEWN.js} +981 -407
  20. package/dist/{chunk-WSCP7QCJ.js → chunk-R6IJ6PIV.js} +14 -11
  21. package/dist/{chunk-YMUSHPU4.js → chunk-SH6OTPXN.js} +46 -16
  22. package/dist/{chunk-MWFHZUIY.js → chunk-TEXCXIBW.js} +1 -1
  23. package/dist/{cdp-driver-2T4P4ZE2.js → chunk-Z6CUR3VG.js} +1542 -134
  24. package/dist/{chunk-IIM5GOD7.js → chunk-ZTHE5RBZ.js} +7 -1
  25. package/dist/cli.js +1136 -584
  26. package/dist/{daemon-client-GKEPT4NY.js → daemon-client-7D6EZNOE.js} +46 -16
  27. package/dist/{daemon-client-O6BYVRXV.js → daemon-client-HEGAXWGK.js} +1 -1
  28. package/dist/daemon-main.js +1031 -522
  29. package/dist/{human-interaction-5AO42MBA.js → human-interaction-4YR2N6R6.js} +2 -2
  30. package/dist/{human-interaction-C5OEGXGO.js → human-interaction-Y5IDH6LD.js} +1 -1
  31. package/dist/{human-interaction-ISXZTAYY.js → human-interaction-ZUTR5AC2.js} +2 -2
  32. package/dist/index.d.ts +10 -0
  33. package/dist/index.js +1147 -593
  34. package/dist/{proxy-C6CK3UH5.js → proxy-LUR4U5YF.js} +2 -1
  35. package/dist/{recovery-J2ISVGUL.js → recovery-FTZGV6VY.js} +2 -2
  36. package/dist/{recovery-ZJVVHP7N.js → recovery-L5GLDX4O.js} +1 -1
  37. package/dist/{recovery-EF33LKRJ.js → recovery-Z3RDZENA.js} +2 -2
  38. package/dist/{session-recorder-H3KEYU26.js → session-recorder-3BEVWHOK.js} +1 -1
  39. package/dist/{session-recorder-QRZMKFVL.js → session-recorder-SLDBENVF.js} +1 -1
  40. package/dist/{session-replayer-LJUC4TI7.js → session-replayer-K4A6OI4M.js} +90 -2
  41. package/package.json +1 -1
  42. package/dist/chunk-BAHSRZIX.js +0 -2191
@@ -1490,6 +1490,33 @@ var ACTION_SIGNAL_SCRIPT = `
1490
1490
  }
1491
1491
  }, true);
1492
1492
 
1493
+ // \u2500\u2500 Pointer-based drag (modern sliders, sortable lists) \u2500\u2500
1494
+ // HTML5 dragstart/drop never fires for pointer-driven drags \u2014 capture via
1495
+ // pointerdown/pointerup with a movement threshold instead (rec-duel d08).
1496
+ var __xb_ptr_down = null;
1497
+ document.addEventListener('pointerdown', function(e) {
1498
+ var t = actualTarget(e);
1499
+ __xb_ptr_down = { x: e.clientX, y: e.clientY, element: describe(t), ts: Date.now() };
1500
+ }, true);
1501
+ document.addEventListener('pointerup', function(e) {
1502
+ if (!__xb_ptr_down) return;
1503
+ var start = __xb_ptr_down;
1504
+ __xb_ptr_down = null;
1505
+ var dx = e.clientX - start.x, dy = e.clientY - start.y;
1506
+ if (Math.abs(dx) < 15 && Math.abs(dy) < 15) return; // tap/click, not a drag
1507
+ pushAction('drag', {
1508
+ x: e.clientX,
1509
+ y: e.clientY,
1510
+ element: start.element,
1511
+ drag: {
1512
+ fromX: start.x,
1513
+ fromY: start.y,
1514
+ toX: e.clientX,
1515
+ toY: e.clientY,
1516
+ },
1517
+ });
1518
+ }, true);
1519
+
1493
1520
  // \u2500\u2500 Drag & drop \u2500\u2500
1494
1521
  var __xb_drag_source = null;
1495
1522
  var __xb_drag_start_pos = null;
@@ -2382,8 +2409,7 @@ var SessionRecorder = class _SessionRecorder {
2382
2409
  "resize",
2383
2410
  "clipboard",
2384
2411
  "touch",
2385
- "contextmenu",
2386
- "drag"
2412
+ "contextmenu"
2387
2413
  ]);
2388
2414
  constructor(context, page, sessionName) {
2389
2415
  this.context = context;
@@ -2400,8 +2426,8 @@ var SessionRecorder = class _SessionRecorder {
2400
2426
  async recordCommandAction(action) {
2401
2427
  const dedupFromAction = this.dedupKey(action.type, action.selector, action.element?.tag, action.value);
2402
2428
  if (dedupFromAction) {
2403
- const expires = this.dedupMap.get(dedupFromAction);
2404
- if (expires && Date.now() < expires) {
2429
+ const entry = this.dedupMap.get(dedupFromAction);
2430
+ if (entry && entry.origin === "signal" && Date.now() < entry.expires) {
2405
2431
  return;
2406
2432
  }
2407
2433
  }
@@ -2418,19 +2444,25 @@ var SessionRecorder = class _SessionRecorder {
2418
2444
  value: action.value
2419
2445
  };
2420
2446
  this.actions.push(actionToPush);
2421
- actionToPush.elementScreenshot = await this.captureElementScreenshot(this.page, {
2422
- type: action.type,
2423
- element: actionToPush.element
2424
- });
2425
- await this.captureAutoSnapshot(this.page, actionToPush, "after").catch(() => {
2426
- });
2447
+ actionToPush.elementScreenshot = await Promise.race([
2448
+ this.captureElementScreenshot(this.page, {
2449
+ type: action.type,
2450
+ element: actionToPush.element
2451
+ }).catch(() => void 0),
2452
+ new Promise((r) => setTimeout(r, 3e3))
2453
+ ]);
2454
+ await Promise.race([
2455
+ this.captureAutoSnapshot(this.page, actionToPush, "after").catch(() => {
2456
+ }),
2457
+ new Promise((r) => setTimeout(r, 6e3))
2458
+ ]);
2427
2459
  this.lastActionTs = ts;
2428
- this.dedupMap.set(dedupFromAction, Date.now() + 2e3);
2460
+ this.dedupMap.set(dedupFromAction, { expires: Date.now() + 4e3, origin: "command" });
2429
2461
  this.dedupActionCount++;
2430
2462
  if (this.dedupActionCount % 200 === 0) {
2431
2463
  const now = Date.now();
2432
2464
  for (const [k, v] of this.dedupMap) {
2433
- if (now >= v) this.dedupMap.delete(k);
2465
+ if (now >= v.expires) this.dedupMap.delete(k);
2434
2466
  }
2435
2467
  }
2436
2468
  if (action.url && action.url !== "about:blank") {
@@ -3143,8 +3175,8 @@ var SessionRecorder = class _SessionRecorder {
3143
3175
  }
3144
3176
  const dedupFromSignal = this.dedupKey(raw.type, raw.element?.selector, raw.element?.tag, raw.value);
3145
3177
  if (dedupFromSignal) {
3146
- const expires = this.dedupMap.get(dedupFromSignal);
3147
- if (expires && Date.now() < expires) {
3178
+ const entry = this.dedupMap.get(dedupFromSignal);
3179
+ if (entry && entry.origin === "command" && Date.now() < entry.expires) {
3148
3180
  continue;
3149
3181
  }
3150
3182
  }
@@ -3187,7 +3219,10 @@ var SessionRecorder = class _SessionRecorder {
3187
3219
  // run before the last sample lands — passthrough keeps whatever has
3188
3220
  // been collected so far.
3189
3221
  hoverContext: raw.hoverContext,
3190
- files: raw.files
3222
+ files: raw.files,
3223
+ // Pointer-drag payload (fromX/fromY/toX/toY) — replayer replays the
3224
+ // drag from these coordinates; dropping it made drags no-ops (d08)
3225
+ drag: raw.drag
3191
3226
  });
3192
3227
  const pushed = this.actions[this.actions.length - 1];
3193
3228
  pushed.elementScreenshot = await this.captureElementScreenshot(page, raw);
@@ -3196,7 +3231,7 @@ var SessionRecorder = class _SessionRecorder {
3196
3231
  this.lastActionTs = raw.ts;
3197
3232
  const dedupKey = this.dedupKey(raw.type, raw.element?.selector, raw.element?.tag, raw.value);
3198
3233
  if (dedupKey) {
3199
- this.dedupMap.set(dedupKey, Date.now() + 2e3);
3234
+ this.dedupMap.set(dedupKey, { expires: Date.now() + 4e3, origin: "signal" });
3200
3235
  this.dedupActionCount++;
3201
3236
  }
3202
3237
  const verifyTypes = /* @__PURE__ */ new Set(["click", "submit", "input", "change", "cdp-click", "cdp-fill"]);
@@ -1,3 +1,40 @@
1
+ // src/config.ts
2
+ import { homedir, tmpdir } from "os";
3
+ import { join } from "path";
4
+ import { loadConfig as coreLoadConfig, saveConfig as coreSaveConfig } from "@dyyz1993/xcli-core";
5
+ function getConfigSource() {
6
+ return { configDir: join(homedir() || tmpdir(), ".xbrowser") };
7
+ }
8
+ function loadConfig() {
9
+ return coreLoadConfig(getConfigSource());
10
+ }
11
+ function getConfigValue(key) {
12
+ const parts = key.split(".");
13
+ let obj = loadConfig();
14
+ for (const part of parts) {
15
+ if (obj && typeof obj === "object") {
16
+ obj = obj[part];
17
+ } else {
18
+ return void 0;
19
+ }
20
+ }
21
+ return obj;
22
+ }
23
+ function getCaptchaConfig() {
24
+ const config = loadConfig();
25
+ return {
26
+ notifyUrl: process.env.XBROWSER_NOTIFY_URL || config.captcha?.notifyUrl,
27
+ autoOpen: process.env.XBROWSER_AUTO_OPEN === "true" || config.captcha?.autoOpen === true,
28
+ timeout: parseInt(process.env.XBROWSER_CAPTCHA_TIMEOUT || "") || config.captcha?.timeout || 120,
29
+ previewPort: parseInt(process.env.XBROWSER_PREVIEW_PORT || "") || config.preview?.port || 9223
30
+ };
31
+ }
32
+ function resolveScreenshotsDir() {
33
+ const configured = getConfigValue("screenshots.dir");
34
+ if (typeof configured === "string" && configured.trim()) return configured.trim();
35
+ return join(tmpdir(), "xbrowser", "screenshots");
36
+ }
37
+
1
38
  // src/screencast.ts
2
39
  var ScreencastCapturer = class {
3
40
  interval;
@@ -140,5 +177,7 @@ var ScreencastCapturer = class {
140
177
  };
141
178
 
142
179
  export {
180
+ getCaptchaConfig,
181
+ resolveScreenshotsDir,
143
182
  ScreencastCapturer
144
183
  };
@@ -13,7 +13,11 @@ var WARNING_TEXTS = [
13
13
  { text: "unusual traffic", severity: "high" },
14
14
  { text: "please verify you are human", severity: "medium" },
15
15
  { text: "access denied", severity: "high" },
16
- { text: "blocked", severity: "high" },
16
+ // 裸词 "blocked" 会误伤大量正常页面("unblocked"、adblock 检测脚本文本、
17
+ // CSS-in-JS 字符串等,实测 doubao.com),只匹配完整阻断短语
18
+ { text: "you have been blocked", severity: "high" },
19
+ { text: "your access has been blocked", severity: "high" },
20
+ { text: "access blocked", severity: "high" },
17
21
  { text: "rate limit", severity: "medium" },
18
22
  { text: "too many requests", severity: "medium" },
19
23
  { text: "\u9A8C\u8BC1", severity: "low" },
@@ -122,7 +126,7 @@ async function detectCaptcha(page) {
122
126
  }
123
127
  async function detectWarningText(page) {
124
128
  try {
125
- const pageText = await page.textContent("body").catch(() => "") || "";
129
+ const pageText = await page.evaluate(() => document.body?.innerText || "").catch(() => "") || "";
126
130
  const lowerText = pageText.toLowerCase();
127
131
  for (const { text, severity } of WARNING_TEXTS) {
128
132
  if (lowerText.includes(text.toLowerCase())) {