@xbrowser/cli 1.9.1 → 1.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,3 +1,21 @@
1
+ import {
2
+ detectAntiBot,
3
+ formatDetectionMessage
4
+ } from "./chunk-DPJNCMLC.js";
5
+ import {
6
+ CaptchaDetector,
7
+ HumanInteractionManager,
8
+ NPM_REGISTRY_URL,
9
+ NPM_SCOPE,
10
+ ScreencastCapturer,
11
+ WebhookNotifier,
12
+ getCaptchaConfig,
13
+ getConfigValue,
14
+ getMarketplaceUrl,
15
+ loadConfig,
16
+ resolveNpmPackageWithFallback,
17
+ setConfigValue
18
+ } from "./chunk-ZJHQPMCY.js";
1
19
  import {
2
20
  forwardCommandLog,
3
21
  forwardNetworkAnalyze,
@@ -27,20 +45,6 @@ import {
27
45
  stopDaemonProcess,
28
46
  version
29
47
  } from "./chunk-53LRNYPG.js";
30
- import {
31
- CaptchaDetector,
32
- HumanInteractionManager,
33
- NPM_REGISTRY_URL,
34
- NPM_SCOPE,
35
- ScreencastCapturer,
36
- WebhookNotifier,
37
- getCaptchaConfig,
38
- getConfigValue,
39
- getMarketplaceUrl,
40
- loadConfig,
41
- resolveNpmPackageWithFallback,
42
- setConfigValue
43
- } from "./chunk-ZJHQPMCY.js";
44
48
  import {
45
49
  generateBashScript,
46
50
  generateJSScript,
@@ -6167,246 +6171,49 @@ function describeSelector(strategy, value, name) {
6167
6171
  }
6168
6172
  }
6169
6173
 
6170
- // src/anti-bot-detection.ts
6171
- var CAPTCHA_PATTERNS = [
6172
- { name: "reCAPTCHA", pattern: /recaptcha/i },
6173
- { name: "hCaptcha", pattern: /hcaptcha/i },
6174
- { name: "Turnstile", pattern: /turnstile/i },
6175
- { name: "Cloudflare", pattern: /cloudflare/i },
6176
- { name: "FunCaptcha", pattern: /funcaptcha/i },
6177
- { name: "AWS WAF", pattern: /aws.*challenge/i }
6178
- ];
6179
- var WARNING_TEXTS = [
6180
- { text: "detected as bot", severity: "high" },
6181
- { text: "suspicious activity", severity: "high" },
6182
- { text: "unusual traffic", severity: "high" },
6183
- { text: "please verify you are human", severity: "medium" },
6184
- { text: "access denied", severity: "high" },
6185
- { text: "blocked", severity: "high" },
6186
- { text: "rate limit", severity: "medium" },
6187
- { text: "too many requests", severity: "medium" },
6188
- { text: "\u9A8C\u8BC1", severity: "low" },
6189
- { text: "\u9A8C\u8BC1\u7801", severity: "low" }
6190
- ];
6191
- var BLOCKED_URL_PATTERNS = [
6192
- { name: "Cloudflare Challenge", pattern: /challenge-platform/i },
6193
- { name: "Cloudflare Captcha", pattern: /cf-challenge/i },
6194
- { name: "AWS WAF", pattern: /aws-waf/i },
6195
- { name: "Generic Captcha", pattern: /captcha/i }
6196
- ];
6197
- async function detectAntiBot(page, config = {}) {
6198
- const {
6199
- checkCaptcha = true,
6200
- checkWarning = true,
6201
- checkBlocked = true,
6202
- checkLogin = false,
6203
- checkWebdriver = true
6204
- } = config;
6205
- const result = {
6206
- detected: false
6207
- };
6208
- if (checkCaptcha) {
6209
- const captchaResult = await detectCaptcha2(page);
6210
- if (captchaResult.detected) {
6211
- return captchaResult;
6212
- }
6213
- }
6214
- if (checkWarning) {
6215
- const warningResult = await detectWarningText(page);
6216
- if (warningResult.detected) {
6217
- return warningResult;
6218
- }
6219
- }
6220
- if (checkBlocked) {
6221
- const blockedResult = await detectBlockedPage(page);
6222
- if (blockedResult.detected) {
6223
- return blockedResult;
6224
- }
6225
- }
6226
- if (checkWebdriver) {
6227
- const webdriverResult = await detectWebdriverExposure(page);
6228
- if (webdriverResult.detected) {
6229
- return webdriverResult;
6230
- }
6231
- }
6232
- if (checkLogin) {
6233
- const loginResult = await detectLoginRequired(page);
6234
- if (loginResult.detected) {
6235
- return loginResult;
6236
- }
6237
- }
6238
- return result;
6239
- }
6240
- async function detectCaptcha2(page) {
6241
- try {
6242
- const iframes = await page.frames();
6243
- for (const iframe of iframes) {
6244
- const src = iframe.url();
6245
- for (const pattern of CAPTCHA_PATTERNS) {
6246
- if (pattern.pattern.test(src)) {
6247
- return {
6248
- detected: true,
6249
- type: "captcha",
6250
- severity: "high",
6251
- message: `Detected ${pattern.name} CAPTCHA (iframe: ${src})`,
6252
- selector: `iframe[src*="${pattern.name.toLowerCase()}"]`,
6253
- actionRequired: "manual"
6254
- };
6255
- }
6256
- }
6257
- }
6258
- const captchaSelectors = [
6259
- ".g-recaptcha",
6260
- "#captcha",
6261
- '[class*="captcha"]',
6262
- '[id*="captcha"]',
6263
- 'iframe[src*="recaptcha"]',
6264
- 'iframe[src*="hcaptcha"]',
6265
- 'iframe[src*="turnstile"]'
6266
- ];
6267
- for (const selector of captchaSelectors) {
6268
- const element = await page.$(selector).catch(() => null);
6269
- if (element) {
6270
- return {
6271
- detected: true,
6272
- type: "captcha",
6273
- severity: "high",
6274
- message: `CAPTCHA element found: ${selector}`,
6275
- selector,
6276
- actionRequired: "manual"
6277
- };
6278
- }
6279
- }
6280
- return { detected: false };
6281
- } catch {
6282
- return { detected: false };
6174
+ // src/context.ts
6175
+ function checkBrowserScope(scope, ctx) {
6176
+ switch (scope) {
6177
+ case "project":
6178
+ return null;
6179
+ case "browser":
6180
+ return ctx.browser ? null : "\u9700\u8981\u6D4F\u89C8\u5668\u5B9E\u4F8B\uFF0C\u8BF7\u4F7F\u7528 --session \u9009\u9879";
6181
+ case "page":
6182
+ return ctx.page ? null : "\u9700\u8981\u6D3B\u8DC3\u7684\u9875\u9762\uFF0C\u8BF7\u4F7F\u7528 --session \u9009\u9879";
6183
+ case "element":
6184
+ return ctx.page ? null : "\u9700\u8981\u6D3B\u8DC3\u7684\u9875\u9762\uFF0C\u8BF7\u4F7F\u7528 --session \u9009\u9879";
6185
+ default:
6186
+ return null;
6283
6187
  }
6284
6188
  }
6285
- async function detectWarningText(page) {
6286
- try {
6287
- const pageText = await page.textContent("body").catch(() => "") || "";
6288
- const lowerText = pageText.toLowerCase();
6289
- for (const { text, severity } of WARNING_TEXTS) {
6290
- if (lowerText.includes(text.toLowerCase())) {
6291
- return {
6292
- detected: true,
6293
- type: "warning",
6294
- severity,
6295
- message: `Anti-bot warning text found: "${text}"`,
6296
- actionRequired: severity === "high" ? "manual" : "retry"
6297
- };
6298
- }
6299
- }
6300
- return { detected: false };
6301
- } catch {
6302
- return { detected: false };
6189
+ function assertPageScope(ctx) {
6190
+ if (!ctx.page) {
6191
+ throw new Error("\u9700\u8981\u6D3B\u8DC3\u7684\u9875\u9762\uFF0C\u8BF7\u4F7F\u7528 --session \u9009\u9879");
6303
6192
  }
6304
6193
  }
6305
- async function detectBlockedPage(page) {
6306
- try {
6307
- const url = page.url();
6308
- for (const { name, pattern } of BLOCKED_URL_PATTERNS) {
6309
- if (pattern.test(url)) {
6310
- return {
6311
- detected: true,
6312
- type: "blocked",
6313
- severity: "high",
6314
- message: `Blocked page detected: ${name} (${url})`,
6315
- actionRequired: "manual"
6316
- };
6317
- }
6194
+ var wsServerCache = /* @__PURE__ */ new WeakMap();
6195
+ function attachWaitForHuman(ctx, getOrCreateWSServer) {
6196
+ ctx.waitForHuman = async (options) => {
6197
+ if (!ctx.page) {
6198
+ throw new Error("waitForHuman requires an active page");
6318
6199
  }
6319
- return { detected: false };
6320
- } catch {
6321
- return { detected: false };
6322
- }
6200
+ const { HumanInteractionManager: HumanInteractionManager2 } = await import("./human-interaction-2DZK4MW7.js");
6201
+ const wsServer2 = await getOrCreateWSServer(ctx.browserContext);
6202
+ const manager = new HumanInteractionManager2(wsServer2, ctx.page);
6203
+ return manager.waitForHuman(options);
6204
+ };
6323
6205
  }
6324
- async function detectWebdriverExposure(page) {
6325
- try {
6326
- const webdriver = await page.evaluate(() => {
6327
- return {
6328
- webdriver: navigator.webdriver,
6329
- webdriverScriptFn: !!window.__webdriver_script_fn,
6330
- webdriverEvaluate: !!window.__webdriver_evaluate,
6331
- chrome: !!window.chrome,
6332
- permissions: navigator.permissions
6333
- };
6334
- }).catch(() => null);
6335
- if (!webdriver) {
6336
- return { detected: false };
6337
- }
6338
- const issues = [];
6339
- if (webdriver.webdriver === true) {
6340
- issues.push("navigator.webdriver === true");
6341
- }
6342
- if (webdriver.webdriverScriptFn) {
6343
- issues.push("__webdriver_script_fn present");
6344
- }
6345
- if (webdriver.webdriverEvaluate) {
6346
- issues.push("__webdriver_evaluate present");
6347
- }
6348
- if (!webdriver.chrome) {
6349
- issues.push("window.chrome missing");
6350
- }
6351
- if (!webdriver.permissions) {
6352
- issues.push("navigator.permissions missing");
6353
- }
6354
- if (issues.length > 0) {
6355
- return {
6356
- detected: true,
6357
- type: "warning",
6358
- severity: "high",
6359
- message: `Automation markers exposed: ${issues.join(", ")}`,
6360
- actionRequired: "manual"
6361
- };
6362
- }
6363
- return { detected: false };
6364
- } catch {
6365
- return { detected: false };
6366
- }
6206
+ function attachDetectAntiBot(ctx) {
6207
+ ctx.detectAntiBot = async (page, config) => {
6208
+ const { detectAntiBot: detectAntiBot2 } = await import("./anti-bot-MCVM6IFB.js");
6209
+ return detectAntiBot2(page, config);
6210
+ };
6367
6211
  }
6368
- async function detectLoginRequired(page) {
6369
- try {
6370
- const loginSelectors = [
6371
- 'a[href*="login"]',
6372
- 'a[href*="signin"]',
6373
- 'a[href*="sign-in"]',
6374
- 'button:has-text("Log in")',
6375
- 'button:has-text("Sign in")',
6376
- 'button:has-text("Login")',
6377
- 'button:has-text("\u767B\u5F55")'
6378
- ];
6379
- for (const selector of loginSelectors) {
6380
- const element = await page.$(selector).catch(() => null);
6381
- if (element) {
6382
- const rect = await element.boundingBox().catch(() => null);
6383
- if (rect && rect.y < 200) {
6384
- return {
6385
- detected: true,
6386
- type: "login",
6387
- severity: "medium",
6388
- message: "Login button detected in page header",
6389
- selector,
6390
- actionRequired: "manual"
6391
- };
6392
- }
6393
- }
6394
- }
6395
- return { detected: false };
6396
- } catch {
6397
- return { detected: false };
6398
- }
6212
+ function getWSServerFromCache(browserContext) {
6213
+ return wsServerCache.get(browserContext);
6399
6214
  }
6400
- function formatDetectionMessage(result) {
6401
- if (!result.detected) {
6402
- return "\u2705 No anti-bot detection detected.";
6403
- }
6404
- const emoji = result.severity === "high" ? "\u{1F6A8}" : result.severity === "medium" ? "\u26A0\uFE0F" : "\u2139\uFE0F";
6405
- const action = result.actionRequired === "manual" ? "Please handle manually" : result.actionRequired === "retry" ? "Consider retrying with delay" : "Consider switching to a different session";
6406
- return `${emoji} Detection: ${result.message}
6407
- Type: ${result.type}
6408
- Severity: ${result.severity}
6409
- Action: ${action}`;
6215
+ function setWSServerCache(browserContext, server) {
6216
+ wsServerCache.set(browserContext, server);
6410
6217
  }
6411
6218
 
6412
6219
  // src/plugin/loader.ts
@@ -7655,6 +7462,7 @@ async function executeCommand(commandName, params, sessionName = "default", extr
7655
7462
  cliName: "xbrowser",
7656
7463
  tips: new TipCollector2()
7657
7464
  };
7465
+ attachDetectAntiBot(ctx);
7658
7466
  if (_tabIndex !== void 0 && session?.context) {
7659
7467
  const pages = session.context.pages();
7660
7468
  if (_tabIndex >= 0 && _tabIndex < pages.length) {
@@ -8074,45 +7882,6 @@ function isChainInput(input) {
8074
7882
  return /\s&&\s|\|\|\s|\s;\s|;\s|\s,\s|\s\+\s|\s->\s/.test(input);
8075
7883
  }
8076
7884
 
8077
- // src/context.ts
8078
- function checkBrowserScope(scope, ctx) {
8079
- switch (scope) {
8080
- case "project":
8081
- return null;
8082
- case "browser":
8083
- return ctx.browser ? null : "\u9700\u8981\u6D4F\u89C8\u5668\u5B9E\u4F8B\uFF0C\u8BF7\u4F7F\u7528 --session \u9009\u9879";
8084
- case "page":
8085
- return ctx.page ? null : "\u9700\u8981\u6D3B\u8DC3\u7684\u9875\u9762\uFF0C\u8BF7\u4F7F\u7528 --session \u9009\u9879";
8086
- case "element":
8087
- return ctx.page ? null : "\u9700\u8981\u6D3B\u8DC3\u7684\u9875\u9762\uFF0C\u8BF7\u4F7F\u7528 --session \u9009\u9879";
8088
- default:
8089
- return null;
8090
- }
8091
- }
8092
- function assertPageScope(ctx) {
8093
- if (!ctx.page) {
8094
- throw new Error("\u9700\u8981\u6D3B\u8DC3\u7684\u9875\u9762\uFF0C\u8BF7\u4F7F\u7528 --session \u9009\u9879");
8095
- }
8096
- }
8097
- var wsServerCache = /* @__PURE__ */ new WeakMap();
8098
- function attachWaitForHuman(ctx, getOrCreateWSServer) {
8099
- ctx.waitForHuman = async (options) => {
8100
- if (!ctx.page) {
8101
- throw new Error("waitForHuman requires an active page");
8102
- }
8103
- const { HumanInteractionManager: HumanInteractionManager2 } = await import("./human-interaction-2DZK4MW7.js");
8104
- const wsServer2 = await getOrCreateWSServer(ctx.browserContext);
8105
- const manager = new HumanInteractionManager2(wsServer2, ctx.page);
8106
- return manager.waitForHuman(options);
8107
- };
8108
- }
8109
- function getWSServerFromCache(browserContext) {
8110
- return wsServerCache.get(browserContext);
8111
- }
8112
- function setWSServerCache(browserContext, server) {
8113
- wsServerCache.set(browserContext, server);
8114
- }
8115
-
8116
7885
  // src/scope.ts
8117
7886
  var BROWSER_SCOPE = {
8118
7887
  name: "browser",
@@ -13657,6 +13426,7 @@ Run "xbrowser ${command} ${subCommand} --help" to see available parameters.`
13657
13426
  },
13658
13427
  tips: new TipCollector3()
13659
13428
  };
13429
+ attachDetectAntiBot(ctx);
13660
13430
  try {
13661
13431
  const cmdStart = Date.now();
13662
13432
  const loginGuard = await checkPluginLoginRequired({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xbrowser/cli",
3
- "version": "1.9.1",
3
+ "version": "1.9.3",
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": {