qwenproxy-cli 1.6.10 → 1.6.12

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.
@@ -997,7 +997,7 @@ var init_config = __esm({
997
997
  // Version header on Qwen API requests = the deployed web bundle version
998
998
  // (fallback when dynamic DOM detection is not yet completed).
999
999
  // Override via env when Qwen ships a new bundle.
1000
- QWEN_WEB_VERSION: z.string().default("0.3.26"),
1000
+ QWEN_WEB_VERSION: z.string().default("0.3.43"),
1001
1001
  // Controls bx-ua/bx-umidtoken injection on the GENERAL API paths
1002
1002
  // (chats/new, settings): those work without them (live-probed). The
1003
1003
  // completions path is the exception — the 0.2.86 HAR shows the real
@@ -1040,6 +1040,7 @@ var init_config = __esm({
1040
1040
  CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
1041
1041
  CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
1042
1042
  CAPTCHA_SOLVER_TIMEOUT_MS: z.string().default("15000"),
1043
+ CAPTCHA_SLIDER_TIMEOUT_MS: z.string().default("8000"),
1043
1044
  CAPTCHA_SOLVER_RETRY_DELAY_MS: z.string().default("1000"),
1044
1045
  CAPTCHA_SOLVER_SETTLE_MS: z.string().default("2000"),
1045
1046
  CAPTCHA_ACCOUNT_COOLDOWN_MS: z.string().default("120000"),
@@ -1191,6 +1192,8 @@ var init_config = __esm({
1191
1192
  enabled: env.CAPTCHA_SOLVER_ENABLED === "true",
1192
1193
  maxAttempts: Math.max(1, Math.min(5, parseInt(env.CAPTCHA_SOLVER_MAX_ATTEMPTS))),
1193
1194
  timeoutMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_TIMEOUT_MS)),
1195
+ /** Max wait for a challenge slider to become visible (slow WAF renders). */
1196
+ sliderTimeoutMs: Math.max(500, parseInt(env.CAPTCHA_SLIDER_TIMEOUT_MS)),
1194
1197
  retryDelayMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_RETRY_DELAY_MS)),
1195
1198
  settleMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_SETTLE_MS)),
1196
1199
  /** Rest an account whose challenge could not be cleared before reusing it. */
@@ -2035,6 +2038,26 @@ function clearAccountCooldown(accountId) {
2035
2038
  }
2036
2039
  }
2037
2040
  }
2041
+ function getAccountCooldownInfo(accountId) {
2042
+ const entry = cooldowns.get(accountId);
2043
+ if (!entry) return null;
2044
+ const remaining = entry.until - Date.now();
2045
+ if (remaining <= 0) {
2046
+ cooldowns.delete(accountId);
2047
+ if (accountId !== "global") {
2048
+ try {
2049
+ updateAccountCooldown(accountId, 0, null);
2050
+ } catch (err) {
2051
+ console.error(
2052
+ `\u274C [AccountManager] Failed to clear expired cooldown in DB:`,
2053
+ err.message
2054
+ );
2055
+ }
2056
+ }
2057
+ return null;
2058
+ }
2059
+ return { onCooldown: true, remainingMs: remaining, reason: entry.reason };
2060
+ }
2038
2061
  function markAccountHeadersReady(accountId) {
2039
2062
  if (!accountId || accountId === "global") return;
2040
2063
  headersReadyAccounts.add(accountId);
@@ -2348,6 +2371,294 @@ function logBaxiaCaptcha(event, fields = {}, important = false) {
2348
2371
  console.log(line);
2349
2372
  }
2350
2373
  }
2374
+ async function findVisibleLocatorWithin(page, selectors, timeoutMs) {
2375
+ const deadline = Date.now() + Math.max(0, timeoutMs);
2376
+ while (true) {
2377
+ const found = await findVisibleLocator(page, selectors);
2378
+ if (found) return found;
2379
+ if (Date.now() >= deadline) return null;
2380
+ await sleep(Math.min(150, Math.max(1, deadline - Date.now())));
2381
+ }
2382
+ }
2383
+ async function waitForHidden(locator, timeoutMs) {
2384
+ const deadline = Date.now() + Math.max(0, timeoutMs);
2385
+ while (true) {
2386
+ if (!await isVisible(locator)) return true;
2387
+ if (Date.now() >= deadline) return false;
2388
+ await sleep(Math.min(100, Math.max(1, deadline - Date.now())));
2389
+ }
2390
+ }
2391
+ async function computeAliyunPuzzleOffset(page) {
2392
+ return page.evaluate(() => {
2393
+ const background = document.querySelector(
2394
+ "#aliyunCaptcha-img"
2395
+ );
2396
+ const piece = document.querySelector(
2397
+ "#aliyunCaptcha-puzzle"
2398
+ );
2399
+ if (!background || !piece) {
2400
+ return Promise.resolve({ ok: false, reason: "missing puzzle images" });
2401
+ }
2402
+ const compute = () => {
2403
+ try {
2404
+ const width = background.naturalWidth;
2405
+ const height = background.naturalHeight;
2406
+ const pieceWidth = piece.naturalWidth;
2407
+ const pieceHeight = piece.naturalHeight;
2408
+ if (!width || !height || !pieceWidth || !pieceHeight) {
2409
+ return { ok: false, reason: "image dimensions unavailable" };
2410
+ }
2411
+ const backgroundCanvas = document.createElement("canvas");
2412
+ backgroundCanvas.id = "captcha-solver-canvas";
2413
+ backgroundCanvas.width = width;
2414
+ backgroundCanvas.height = height;
2415
+ const backgroundContext = backgroundCanvas.getContext("2d");
2416
+ if (!backgroundContext) {
2417
+ return { ok: false, reason: "no background context" };
2418
+ }
2419
+ const pieceCanvas = document.createElement("canvas");
2420
+ pieceCanvas.id = "captcha-solver-canvas";
2421
+ pieceCanvas.width = pieceWidth;
2422
+ pieceCanvas.height = pieceHeight;
2423
+ const pieceContext = pieceCanvas.getContext("2d");
2424
+ if (!pieceContext) {
2425
+ return { ok: false, reason: "no piece context" };
2426
+ }
2427
+ try {
2428
+ backgroundContext.drawImage(background, 0, 0);
2429
+ } catch {
2430
+ return { ok: false, reason: "background canvas tainted" };
2431
+ }
2432
+ try {
2433
+ pieceContext.drawImage(piece, 0, 0);
2434
+ } catch {
2435
+ return { ok: false, reason: "puzzle canvas tainted" };
2436
+ }
2437
+ const backgroundData = backgroundContext.getImageData(
2438
+ 0,
2439
+ 0,
2440
+ width,
2441
+ height
2442
+ ).data;
2443
+ const pieceData = pieceContext.getImageData(
2444
+ 0,
2445
+ 0,
2446
+ pieceWidth,
2447
+ pieceHeight
2448
+ ).data;
2449
+ let pieceMinX = pieceWidth;
2450
+ let pieceMaxX = -1;
2451
+ let pieceMinY = pieceHeight;
2452
+ let pieceMaxY = -1;
2453
+ for (let y = 0; y < pieceHeight; y++) {
2454
+ for (let x = 0; x < pieceWidth; x++) {
2455
+ if (pieceData[(y * pieceWidth + x) * 4 + 3] > 100) {
2456
+ if (x < pieceMinX) pieceMinX = x;
2457
+ if (x > pieceMaxX) pieceMaxX = x;
2458
+ if (y < pieceMinY) pieceMinY = y;
2459
+ if (y > pieceMaxY) pieceMaxY = y;
2460
+ }
2461
+ }
2462
+ }
2463
+ const puzzleWidth = pieceMaxX - pieceMinX + 1;
2464
+ if (puzzleWidth <= 0) {
2465
+ return { ok: false, reason: "empty puzzle piece" };
2466
+ }
2467
+ const yStart = Math.max(1, Math.min(height - 2, pieceMinY + 5));
2468
+ const yEnd = Math.max(
2469
+ yStart,
2470
+ Math.min(height - 2, pieceMaxY - 5)
2471
+ );
2472
+ const columnGradients = new Float32Array(width);
2473
+ for (let x = 1; x < width - 1; x++) {
2474
+ let gradient = 0;
2475
+ for (let y = yStart; y <= yEnd; y++) {
2476
+ const left = (y * width + x - 1) * 4;
2477
+ const right = (y * width + x + 1) * 4;
2478
+ gradient += Math.abs(backgroundData[right] - backgroundData[left]) + Math.abs(backgroundData[right + 1] - backgroundData[left + 1]) + Math.abs(backgroundData[right + 2] - backgroundData[left + 2]);
2479
+ }
2480
+ columnGradients[x] = gradient;
2481
+ }
2482
+ let bestX = 0;
2483
+ let bestScore = 0;
2484
+ const minCandidateX = 30;
2485
+ const maxCandidateX = width - puzzleWidth - 20;
2486
+ for (let candidateX = minCandidateX; candidateX <= maxCandidateX; candidateX++) {
2487
+ let leftMax = 0;
2488
+ for (let dx = -2; dx <= 2; dx++) {
2489
+ const value = columnGradients[candidateX + pieceMinX + dx] || 0;
2490
+ if (value > leftMax) leftMax = value;
2491
+ }
2492
+ let rightMax = 0;
2493
+ for (let dx = -3; dx <= 1; dx++) {
2494
+ const value = columnGradients[candidateX + pieceMaxX + dx] || 0;
2495
+ if (value > rightMax) rightMax = value;
2496
+ }
2497
+ const score = Math.sqrt(leftMax * rightMax);
2498
+ if (score > bestScore) {
2499
+ bestScore = score;
2500
+ bestX = candidateX;
2501
+ }
2502
+ }
2503
+ if (bestScore <= 0) {
2504
+ return { ok: false, reason: "no matching hole edge" };
2505
+ }
2506
+ return {
2507
+ ok: true,
2508
+ offsetX: bestX - pieceMinX,
2509
+ naturalWidth: width
2510
+ };
2511
+ } catch (error) {
2512
+ return {
2513
+ ok: false,
2514
+ reason: error instanceof Error ? error.message : String(error)
2515
+ };
2516
+ }
2517
+ };
2518
+ return new Promise((resolve) => {
2519
+ if (background.complete && piece.complete) {
2520
+ resolve(compute());
2521
+ return;
2522
+ }
2523
+ let settled = false;
2524
+ const finish = () => {
2525
+ if (settled) return;
2526
+ settled = true;
2527
+ resolve(compute());
2528
+ };
2529
+ const fail = () => {
2530
+ if (settled) return;
2531
+ settled = true;
2532
+ resolve({ ok: false, reason: "puzzle image load error" });
2533
+ };
2534
+ background.addEventListener("load", finish, { once: true });
2535
+ piece.addEventListener("load", finish, { once: true });
2536
+ background.addEventListener("error", fail, { once: true });
2537
+ piece.addEventListener("error", fail, { once: true });
2538
+ setTimeout(() => {
2539
+ if (settled) return;
2540
+ settled = true;
2541
+ resolve({ ok: false, reason: "puzzle image load timeout" });
2542
+ }, 2e3);
2543
+ });
2544
+ });
2545
+ }
2546
+ async function solveAliyunWafCaptcha(page, options = {}) {
2547
+ const waitForMs = Math.max(0, options.waitForMs ?? 0);
2548
+ const maxAttempts = Math.max(
2549
+ 1,
2550
+ Math.min(5, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS)
2551
+ );
2552
+ const retryDelayMs = Math.max(
2553
+ 0,
2554
+ options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS
2555
+ );
2556
+ const settleMs = Math.max(0, options.settleMs ?? DEFAULT_SETTLE_MS);
2557
+ const sliderTimeoutMs = Math.max(
2558
+ 500,
2559
+ options.sliderTimeoutMs ?? DEFAULT_SLIDER_TIMEOUT_MS
2560
+ );
2561
+ const detected = await findVisibleLocatorWithin(
2562
+ page,
2563
+ ALIYUN_WAF_BLOCK_SELECTORS,
2564
+ waitForMs
2565
+ );
2566
+ if (!detected) return false;
2567
+ return withCaptchaMouseLock(async () => {
2568
+ const block = detected.locator;
2569
+ if (!await isVisible(block)) return false;
2570
+ logBaxiaCaptcha("aliyun_detected", { selector: detected.selector });
2571
+ let lastReason = "unknown";
2572
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
2573
+ try {
2574
+ const offset = await computeAliyunPuzzleOffset(page);
2575
+ if (!offset.ok || typeof offset.offsetX !== "number" || typeof offset.naturalWidth !== "number" || offset.naturalWidth <= 0) {
2576
+ lastReason = offset.reason || "offset_unavailable";
2577
+ logBaxiaCaptcha("aliyun_offset_failed", {
2578
+ attempt,
2579
+ reason: lastReason
2580
+ });
2581
+ } else {
2582
+ const slider = page.locator(ALIYUN_PUZZLE_SLIDER_SELECTOR).first();
2583
+ const track = page.locator(ALIYUN_PUZZLE_TRACK_SELECTOR).first();
2584
+ await slider.waitFor({ state: "visible", timeout: sliderTimeoutMs });
2585
+ const [sliderBox, trackBox] = await Promise.all([
2586
+ slider.boundingBox(),
2587
+ track.boundingBox()
2588
+ ]);
2589
+ if (!sliderBox || !trackBox || trackBox.width <= 0) {
2590
+ lastReason = "bounds_unavailable";
2591
+ logBaxiaCaptcha("aliyun_offset_failed", {
2592
+ attempt,
2593
+ reason: lastReason
2594
+ });
2595
+ } else {
2596
+ const scale = trackBox.width / offset.naturalWidth;
2597
+ const dragDistance = Math.round(offset.offsetX * scale);
2598
+ logBaxiaCaptcha("aliyun_geometry", {
2599
+ attempt,
2600
+ offset: offset.offsetX,
2601
+ scale: Number(scale.toFixed(2)),
2602
+ distance: dragDistance
2603
+ });
2604
+ if (dragDistance <= 0) {
2605
+ lastReason = "non_positive_distance";
2606
+ } else {
2607
+ const startX = sliderBox.x + sliderBox.width / 2;
2608
+ const startY = sliderBox.y + sliderBox.height / 2;
2609
+ await humanDrag(
2610
+ page,
2611
+ startX,
2612
+ startY,
2613
+ startX + dragDistance,
2614
+ startY
2615
+ );
2616
+ if (await waitForHidden(block, settleMs)) {
2617
+ logBaxiaCaptcha(
2618
+ "aliyun_solve_succeeded",
2619
+ { attempt, distance: dragDistance },
2620
+ true
2621
+ );
2622
+ return true;
2623
+ }
2624
+ lastReason = "not_solved";
2625
+ }
2626
+ }
2627
+ }
2628
+ } catch (error) {
2629
+ lastReason = error instanceof Error ? error.name : "UnknownError";
2630
+ logBaxiaCaptcha("aliyun_offset_failed", {
2631
+ attempt,
2632
+ error: lastReason,
2633
+ detail: sanitizeCaptchaErrorDetail(error)
2634
+ });
2635
+ }
2636
+ if (attempt < maxAttempts && retryDelayMs > 0) {
2637
+ await sleep(retryDelayMs);
2638
+ }
2639
+ }
2640
+ logBaxiaCaptcha(
2641
+ "aliyun_solve_failed",
2642
+ { attempts: maxAttempts, reason: lastReason },
2643
+ true
2644
+ );
2645
+ return false;
2646
+ });
2647
+ }
2648
+ async function solveVisibleCaptcha(page, options = {}) {
2649
+ if (typeof page.isClosed === "function" && page.isClosed()) return false;
2650
+ const totalWaitMs = Math.max(0, options.waitForMs ?? 0);
2651
+ const aliyunWaitMs = Math.min(totalWaitMs, ALIYUN_PROBE_MAX_WAIT_MS);
2652
+ const startedAt = Date.now();
2653
+ if (await solveAliyunWafCaptcha(page, { ...options, waitForMs: aliyunWaitMs })) {
2654
+ return true;
2655
+ }
2656
+ const remainingWaitMs = Math.max(
2657
+ 0,
2658
+ totalWaitMs - (Date.now() - startedAt)
2659
+ );
2660
+ return solveBaxiaCaptcha(page, { ...options, waitForMs: remainingWaitMs });
2661
+ }
2351
2662
  async function isVisible(locator) {
2352
2663
  return locator.isVisible().catch(() => false);
2353
2664
  }
@@ -2590,7 +2901,7 @@ async function solveBaxiaCaptchaUnlocked(page, options = {}) {
2590
2901
  );
2591
2902
  return false;
2592
2903
  }
2593
- var BAXIA_DIALOG_SELECTOR, BAXIA_CONTENT_SELECTOR, CAPTCHA_EVENT_EMOJI, captchaDebugEnabled, BAXIA_IFRAME_SELECTORS, BAXIA_DOCUMENT_SELECTORS, BAXIA_IFRAME_SELECTOR, BAXIA_SLIDER_SELECTOR, BAXIA_TRACK_SELECTOR, BAXIA_SUCCESS_SELECTOR, BAXIA_RELOAD_SELECTOR, DEFAULT_MAX_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_SETTLE_MS, DEFAULT_SLIDER_TIMEOUT_MS, captchaMouseLock;
2904
+ var BAXIA_DIALOG_SELECTOR, BAXIA_CONTENT_SELECTOR, CAPTCHA_EVENT_EMOJI, captchaDebugEnabled, BAXIA_IFRAME_SELECTORS, BAXIA_DOCUMENT_SELECTORS, BAXIA_IFRAME_SELECTOR, BAXIA_SLIDER_SELECTOR, BAXIA_TRACK_SELECTOR, BAXIA_SUCCESS_SELECTOR, BAXIA_RELOAD_SELECTOR, DEFAULT_MAX_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_SETTLE_MS, DEFAULT_SLIDER_TIMEOUT_MS, ALIYUN_WAF_CAPTCHA_SELECTOR, ALIYUN_WAF_CAPTCHA_WIDGET, ALIYUN_WAF_BLOCK_SELECTORS, ALIYUN_PUZZLE_SLIDER_SELECTOR, ALIYUN_PUZZLE_TRACK_SELECTOR, ALIYUN_PROBE_MAX_WAIT_MS, captchaMouseLock;
2594
2905
  var init_captcha_solver = __esm({
2595
2906
  "src/services/captcha-solver.ts"() {
2596
2907
  "use strict";
@@ -2616,14 +2927,20 @@ var init_captcha_solver = __esm({
2616
2927
  solve_failed: "\u274C",
2617
2928
  recovery_succeeded: "\u2705",
2618
2929
  recovery_not_solved: "\u26A0\uFE0F",
2619
- recovery_failed: "\u274C"
2930
+ recovery_failed: "\u274C",
2931
+ aliyun_detected: "\u{1F9E9}",
2932
+ aliyun_offset_failed: "\u{1F4D0}",
2933
+ aliyun_geometry: "\u{1F4D0}",
2934
+ aliyun_solve_succeeded: "\u2705",
2935
+ aliyun_solve_failed: "\u274C"
2620
2936
  };
2621
2937
  captchaDebugEnabled = process.env.CAPTCHA_DEBUG === "true";
2622
2938
  BAXIA_IFRAME_SELECTORS = [
2623
2939
  `${BAXIA_DIALOG_SELECTOR} ${BAXIA_CONTENT_SELECTOR} iframe`,
2624
2940
  `${BAXIA_CONTENT_SELECTOR} iframe`,
2625
2941
  "iframe#baxia-dialog-content",
2626
- 'iframe[src*="_____tmd_____/punish"]'
2942
+ 'iframe[src*="_____tmd_____/punish"]',
2943
+ 'iframe[src*="nocaptcha"]'
2627
2944
  ];
2628
2945
  BAXIA_DOCUMENT_SELECTORS = [
2629
2946
  "#nocaptcha",
@@ -2631,14 +2948,23 @@ var init_captcha_solver = __esm({
2631
2948
  "#baxia-punish"
2632
2949
  ];
2633
2950
  BAXIA_IFRAME_SELECTOR = BAXIA_IFRAME_SELECTORS.join(", ");
2634
- BAXIA_SLIDER_SELECTOR = "#nc_1_n1z, .nc_1_n1z, .btn_slide, .nc_wrapper .btn_slide, ._nc .btn_slide, .nc-container .btn_slide";
2635
- BAXIA_TRACK_SELECTOR = "#nc_1_n1t, .nc_scale, .nc_wrapper .nc_scale, ._nc .nc_scale, .nc-container .nc_scale";
2951
+ BAXIA_SLIDER_SELECTOR = '#nc_1_n1z, .nc_1_n1z, .btn_slide, .nc_iconfont.btn_slide, span[id*="_n1z"], .nc_wrapper .btn_slide, ._nc .btn_slide, .nc-container .btn_slide';
2952
+ BAXIA_TRACK_SELECTOR = '#nc_1_n1t, .nc_scale, span[id*="_n1t"], .nc_wrapper .nc_scale, ._nc .nc_scale, .nc-container .nc_scale';
2636
2953
  BAXIA_SUCCESS_SELECTOR = '.btn_ok, .nc_ok, .nc_success, .nc_result, .nc_wrapper.nc-success, .nc_wrapper.success, [data-nc-lang="SUCCESS"], [data-nc-lang="success"], #nc-loading-circle';
2637
2954
  BAXIA_RELOAD_SELECTOR = '#nc_1_refresh1, .errloading a, .nc-container .errloading a, .btn_refresh, .clickCaptcha_text .btn_refresh, [data-nc-lang="REFRESH"], a[id*="refresh"]';
2638
2955
  DEFAULT_MAX_ATTEMPTS = 3;
2639
2956
  DEFAULT_RETRY_DELAY_MS = 1e3;
2640
2957
  DEFAULT_SETTLE_MS = 2e3;
2641
2958
  DEFAULT_SLIDER_TIMEOUT_MS = 8e3;
2959
+ ALIYUN_WAF_CAPTCHA_SELECTOR = "#waf_nc_block";
2960
+ ALIYUN_WAF_CAPTCHA_WIDGET = "#aliyunCaptcha-window-embed";
2961
+ ALIYUN_WAF_BLOCK_SELECTORS = [
2962
+ ALIYUN_WAF_CAPTCHA_SELECTOR,
2963
+ ALIYUN_WAF_CAPTCHA_WIDGET
2964
+ ];
2965
+ ALIYUN_PUZZLE_SLIDER_SELECTOR = "#aliyunCaptcha-sliding-slider";
2966
+ ALIYUN_PUZZLE_TRACK_SELECTOR = "#aliyunCaptcha-sliding-body";
2967
+ ALIYUN_PROBE_MAX_WAIT_MS = 2e3;
2642
2968
  captchaMouseLock = Promise.resolve();
2643
2969
  }
2644
2970
  });
@@ -2729,7 +3055,15 @@ function updateQwenWebVersion(version) {
2729
3055
  function getQwenWebVersion() {
2730
3056
  return dynamicWebVersion || config.qwen.webVersion;
2731
3057
  }
2732
- var dynamicWebVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
3058
+ function updateQwenBxVersion(version) {
3059
+ if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
3060
+ dynamicBxVersion = version.trim();
3061
+ }
3062
+ }
3063
+ function getQwenBxVersion() {
3064
+ return dynamicBxVersion || config.auth.bxV;
3065
+ }
3066
+ var dynamicWebVersion, dynamicBxVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
2733
3067
  var init_qwen_headers = __esm({
2734
3068
  "src/services/qwen-headers.ts"() {
2735
3069
  "use strict";
@@ -2738,6 +3072,7 @@ var init_qwen_headers = __esm({
2738
3072
  init_fingerprint();
2739
3073
  init_timezone();
2740
3074
  dynamicWebVersion = null;
3075
+ dynamicBxVersion = null;
2741
3076
  QWEN_WEB_VERSION = config.qwen.webVersion;
2742
3077
  DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
2743
3078
  QWEN_TIMEZONE_HEADER = (/* @__PURE__ */ new Date()).toString().split(" (")[0];
@@ -3054,11 +3389,12 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
3054
3389
  async function clearVisibleChallenge(page) {
3055
3390
  if (page.isClosed()) return;
3056
3391
  if (config.captcha.enabled) {
3057
- await solveBaxiaCaptcha(page, {
3392
+ await solveVisibleCaptcha(page, {
3058
3393
  waitForMs: 0,
3059
3394
  maxAttempts: config.captcha.maxAttempts,
3060
3395
  retryDelayMs: config.captcha.retryDelayMs,
3061
- settleMs: config.captcha.settleMs
3396
+ settleMs: config.captcha.settleMs,
3397
+ sliderTimeoutMs: config.captcha.sliderTimeoutMs
3062
3398
  }).catch(() => false);
3063
3399
  }
3064
3400
  try {
@@ -3623,8 +3959,12 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
3623
3959
  if (accountPages.has(account.id)) {
3624
3960
  return;
3625
3961
  }
3626
- await evictIdlePlaywrightContextsToLimit().catch(() => {
3627
- });
3962
+ if (config.playwright.maxActiveContexts > 0) {
3963
+ await evictIdlePlaywrightContextsToLimit(
3964
+ Math.max(1, config.playwright.maxActiveContexts - 1)
3965
+ ).catch(() => {
3966
+ });
3967
+ }
3628
3968
  const profilePath = getAccountProfilePath(account.id);
3629
3969
  const fingerprint = getFingerprintProfile(account.id);
3630
3970
  const { engine, channel } = resolveBrowserEngine(browserType);
@@ -3800,6 +4140,9 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
3800
4140
  if (persisted.version) {
3801
4141
  updateQwenWebVersion(persisted.version);
3802
4142
  }
4143
+ if (persisted.bxV) {
4144
+ updateQwenBxVersion(persisted.bxV);
4145
+ }
3803
4146
  cache.lastRefresh = persisted.capturedAt;
3804
4147
  markAccountHeadersReady(account.id);
3805
4148
  restoredFromDb = true;
@@ -3893,7 +4236,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
3893
4236
  if (!acctPage.isClosed()) {
3894
4237
  try {
3895
4238
  const currentUrl = new URL(acctPage.url());
3896
- if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname !== "/") {
4239
+ if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname.includes("/auth") || currentUrl.pathname.includes("/login") || currentUrl.pathname.includes("_____tmd_____")) {
3897
4240
  await acctPage.goto(qwenUrl("/"), {
3898
4241
  waitUntil: "domcontentloaded",
3899
4242
  timeout: config.timeouts.navigation
@@ -3911,6 +4254,8 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
3911
4254
  } finally {
3912
4255
  release();
3913
4256
  }
4257
+ await evictIdlePlaywrightContextsToLimit().catch(() => {
4258
+ });
3914
4259
  })();
3915
4260
  try {
3916
4261
  await initPromise;
@@ -3994,7 +4339,7 @@ async function loginToQwen(accountId, email, password) {
3994
4339
  saveAuthSession2(accountId, {
3995
4340
  cookie: cookieStr,
3996
4341
  userAgent: cache.headers["user-agent"] || "",
3997
- bxV: cache.headers["bx-v"] || "2.5.37",
4342
+ bxV: cache.headers["bx-v"] || getQwenBxVersion(),
3998
4343
  bxUa: cache.headers["bx-ua"] || "",
3999
4344
  bxUmidtoken: cache.headers["bx-umidtoken"] || "",
4000
4345
  secChUa: cache.headers["sec-ch-ua"] || void 0,
@@ -4066,7 +4411,7 @@ async function loginToQwen(accountId, email, password) {
4066
4411
  saveAuthSession2(accountId, {
4067
4412
  cookie: cookieStr,
4068
4413
  userAgent: cache.headers["user-agent"] || "",
4069
- bxV: cache.headers["bx-v"] || "2.5.37",
4414
+ bxV: cache.headers["bx-v"] || getQwenBxVersion(),
4070
4415
  bxUa: cache.headers["bx-ua"] || "",
4071
4416
  bxUmidtoken: cache.headers["bx-umidtoken"] || "",
4072
4417
  secChUa: cache.headers["sec-ch-ua"] || void 0,
@@ -4137,7 +4482,7 @@ async function loginViaApi(page, email, password) {
4137
4482
  }
4138
4483
  const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
4139
4484
  const requestId = crypto3.randomUUID();
4140
- const webVersion = getQwenWebVersion() || "0.3.26";
4485
+ const webVersion = getQwenWebVersion();
4141
4486
  const evalRes = await page.evaluate(
4142
4487
  async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
4143
4488
  try {
@@ -4309,6 +4654,15 @@ async function loginViaUi(page, email, password) {
4309
4654
  if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
4310
4655
  return { success: true };
4311
4656
  }
4657
+ if (config.captcha.enabled) {
4658
+ await solveVisibleCaptcha(page, {
4659
+ waitForMs: 1500,
4660
+ maxAttempts: config.captcha.maxAttempts,
4661
+ retryDelayMs: config.captcha.retryDelayMs,
4662
+ settleMs: config.captcha.settleMs,
4663
+ sliderTimeoutMs: config.captcha.sliderTimeoutMs
4664
+ }).catch(() => false);
4665
+ }
4312
4666
  const emailSelector = [
4313
4667
  'input[type="email"]',
4314
4668
  'input[name="email"]',
@@ -4464,10 +4818,11 @@ async function loginViaUi(page, email, password) {
4464
4818
  while (Date.now() < postSubmitDeadline) {
4465
4819
  if (page.isClosed()) break;
4466
4820
  if (config.captcha.enabled) {
4467
- await solveBaxiaCaptcha(page, {
4821
+ await solveVisibleCaptcha(page, {
4468
4822
  waitForMs: 1500,
4469
4823
  maxAttempts: config.captcha.maxAttempts,
4470
- retryDelayMs: config.captcha.retryDelayMs
4824
+ retryDelayMs: config.captcha.retryDelayMs,
4825
+ sliderTimeoutMs: config.captcha.sliderTimeoutMs
4471
4826
  }).catch(() => {
4472
4827
  });
4473
4828
  }
@@ -4590,7 +4945,7 @@ async function refreshAccountToken(accountId) {
4590
4945
  }
4591
4946
  if (refreshToken) {
4592
4947
  try {
4593
- const webVersion = getQwenWebVersion() || "0.3.26";
4948
+ const webVersion = getQwenWebVersion();
4594
4949
  const refreshResult = await page.evaluate(
4595
4950
  async ({ rTok, tz, version }) => {
4596
4951
  try {
@@ -4655,7 +5010,7 @@ async function refreshAccountToken(accountId) {
4655
5010
  saveAuthSession2(accountId, {
4656
5011
  cookie: cookieStr,
4657
5012
  userAgent: cache.headers["user-agent"] || session?.userAgent || "",
4658
- bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
5013
+ bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
4659
5014
  bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
4660
5015
  bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
4661
5016
  secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
@@ -4690,7 +5045,7 @@ async function refreshAccountToken(accountId) {
4690
5045
  saveAuthSession2(accountId, {
4691
5046
  cookie: cookieStr,
4692
5047
  userAgent: cache.headers["user-agent"] || session?.userAgent || "",
4693
- bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
5048
+ bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
4694
5049
  bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
4695
5050
  bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
4696
5051
  secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
@@ -4838,7 +5193,7 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
4838
5193
  cookie: reqHeaders["cookie"] || "",
4839
5194
  "bx-ua": reqHeaders["bx-ua"] || "",
4840
5195
  "bx-umidtoken": reqHeaders["bx-umidtoken"] || "",
4841
- "bx-v": reqHeaders["bx-v"] || "2.5.37",
5196
+ "bx-v": reqHeaders["bx-v"] || getQwenBxVersion(),
4842
5197
  "user-agent": reqHeaders["user-agent"] || "",
4843
5198
  "x-request-id": reqHeaders["x-request-id"] || "",
4844
5199
  "version": reqHeaders["version"] || "",
@@ -4870,6 +5225,9 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
4870
5225
  if (capturedHeaders["version"]) {
4871
5226
  updateQwenWebVersion(capturedHeaders["version"]);
4872
5227
  }
5228
+ if (capturedHeaders["bx-v"]) {
5229
+ updateQwenBxVersion(capturedHeaders["bx-v"]);
5230
+ }
4873
5231
  markAccountHeadersReady(accountId);
4874
5232
  cache.lastRefresh = Date.now();
4875
5233
  cookieCaches.delete(accountId);
@@ -5413,7 +5771,11 @@ function priorityOrderForEviction(accountIds) {
5413
5771
  const ranked = getAccountsByPriority(accountIds.map((id) => ({ id })));
5414
5772
  const rank = /* @__PURE__ */ new Map();
5415
5773
  for (const [index, account] of ranked.entries()) {
5416
- rank.set(account.id, index);
5774
+ if (getAccountCooldownInfo(account.id)) {
5775
+ rank.set(account.id, Number.MAX_SAFE_INTEGER);
5776
+ } else {
5777
+ rank.set(account.id, index);
5778
+ }
5417
5779
  }
5418
5780
  return orderContextsForEviction(
5419
5781
  accountIds,
@@ -5421,14 +5783,15 @@ function priorityOrderForEviction(accountIds) {
5421
5783
  (id) => lastAccountActivity.get(id) ?? 0
5422
5784
  );
5423
5785
  }
5424
- async function evictIdlePlaywrightContextsToLimit() {
5425
- const max = config.playwright.maxActiveContexts;
5426
- if (max <= 0) return 0;
5786
+ async function evictIdlePlaywrightContextsToLimit(targetLimit) {
5787
+ const configuredMax = config.playwright.maxActiveContexts;
5788
+ if (configuredMax <= 0) return 0;
5789
+ const max = targetLimit !== void 0 ? Math.max(0, targetLimit) : configuredMax;
5427
5790
  if (accountPages.size <= max) return 0;
5428
5791
  const candidates = priorityOrderForEviction(
5429
5792
  Array.from(accountPages.keys()).filter((accountId) => {
5430
5793
  if (isAccountServingStream(accountId)) return false;
5431
- if (isAccountRecentlyActive(accountId, 3e4)) return false;
5794
+ if (hasActiveAccountLease(accountId)) return false;
5432
5795
  const mutex = accountMutexes.get(accountId);
5433
5796
  return mutex?.isIdle();
5434
5797
  })
@@ -5441,6 +5804,7 @@ async function evictIdlePlaywrightContextsToLimit() {
5441
5804
  for (const candidate of candidates) {
5442
5805
  if (accountPages.size <= max) break;
5443
5806
  if (isAccountServingStream(candidate.accountId)) continue;
5807
+ if (hasActiveAccountLease(candidate.accountId)) continue;
5444
5808
  const mutex = accountMutexes.get(candidate.accountId);
5445
5809
  if (!mutex?.isIdle()) continue;
5446
5810
  await closePlaywrightForAccount(candidate.accountId).catch((error) => {
@@ -5543,10 +5907,6 @@ async function closePlaywrightForAccount(accountId) {
5543
5907
  release();
5544
5908
  }
5545
5909
  }
5546
- function isAccountRecentlyActive(accountId, maxIdleMs = 3e5) {
5547
- const last = lastAccountActivity.get(accountId) ?? 0;
5548
- return last > 0 && Date.now() - last < maxIdleMs;
5549
- }
5550
5910
  var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, inFlightAccountInits, headerCaches, HEADER_CACHE_TTL, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, lastProactiveTokenRefresh, profileResetQueue, profileResetChain, closingAllPlaywright, sleep2, HEADER_CAPTURE_SETTLE_MS, PLAYWRIGHT_MUTEX_WAIT_MS, ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, SESSION_PROBE_NAVIGATION_TIMEOUT_MS, HEADER_CAPTURE_TRIGGER_GRACE_MS, FIRST_TRIGGER_GRACE_MS, HEADER_CAPTURE_TRIGGER_ATTEMPTS, CHAT_INPUT_APPEAR_TIMEOUT_MS, CHAT_INPUT_ACTION_TIMEOUT_MS, PROFILE_RESET_TIMEOUT_MS;
5551
5911
  var init_playwright = __esm({
5552
5912
  "src/services/playwright.ts"() {