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.
@@ -1236,6 +1236,26 @@ function clearAllAccountCooldowns() {
1236
1236
  cooldowns.clear();
1237
1237
  return count;
1238
1238
  }
1239
+ function getAccountCooldownInfo(accountId) {
1240
+ const entry = cooldowns.get(accountId);
1241
+ if (!entry) return null;
1242
+ const remaining = entry.until - Date.now();
1243
+ if (remaining <= 0) {
1244
+ cooldowns.delete(accountId);
1245
+ if (accountId !== "global") {
1246
+ try {
1247
+ updateAccountCooldown(accountId, 0, null);
1248
+ } catch (err) {
1249
+ console.error(
1250
+ `\u274C [AccountManager] Failed to clear expired cooldown in DB:`,
1251
+ err.message
1252
+ );
1253
+ }
1254
+ }
1255
+ return null;
1256
+ }
1257
+ return { onCooldown: true, remainingMs: remaining, reason: entry.reason };
1258
+ }
1239
1259
  function markAccountHeadersReady(accountId) {
1240
1260
  if (!accountId || accountId === "global") return;
1241
1261
  headersReadyAccounts.add(accountId);
@@ -1334,7 +1354,7 @@ var init_config = __esm({
1334
1354
  // Version header on Qwen API requests = the deployed web bundle version
1335
1355
  // (fallback when dynamic DOM detection is not yet completed).
1336
1356
  // Override via env when Qwen ships a new bundle.
1337
- QWEN_WEB_VERSION: z.string().default("0.3.26"),
1357
+ QWEN_WEB_VERSION: z.string().default("0.3.43"),
1338
1358
  // Controls bx-ua/bx-umidtoken injection on the GENERAL API paths
1339
1359
  // (chats/new, settings): those work without them (live-probed). The
1340
1360
  // completions path is the exception — the 0.2.86 HAR shows the real
@@ -1377,6 +1397,7 @@ var init_config = __esm({
1377
1397
  CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
1378
1398
  CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
1379
1399
  CAPTCHA_SOLVER_TIMEOUT_MS: z.string().default("15000"),
1400
+ CAPTCHA_SLIDER_TIMEOUT_MS: z.string().default("8000"),
1380
1401
  CAPTCHA_SOLVER_RETRY_DELAY_MS: z.string().default("1000"),
1381
1402
  CAPTCHA_SOLVER_SETTLE_MS: z.string().default("2000"),
1382
1403
  CAPTCHA_ACCOUNT_COOLDOWN_MS: z.string().default("120000"),
@@ -1528,6 +1549,8 @@ var init_config = __esm({
1528
1549
  enabled: env.CAPTCHA_SOLVER_ENABLED === "true",
1529
1550
  maxAttempts: Math.max(1, Math.min(5, parseInt(env.CAPTCHA_SOLVER_MAX_ATTEMPTS))),
1530
1551
  timeoutMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_TIMEOUT_MS)),
1552
+ /** Max wait for a challenge slider to become visible (slow WAF renders). */
1553
+ sliderTimeoutMs: Math.max(500, parseInt(env.CAPTCHA_SLIDER_TIMEOUT_MS)),
1531
1554
  retryDelayMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_RETRY_DELAY_MS)),
1532
1555
  settleMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_SETTLE_MS)),
1533
1556
  /** Rest an account whose challenge could not be cleared before reusing it. */
@@ -1687,67 +1710,367 @@ var init_config = __esm({
1687
1710
  }
1688
1711
  });
1689
1712
 
1690
- // src/core/memory-usage.ts
1691
- import v8 from "v8";
1692
- import os2 from "os";
1693
- function getHeapUsageSnapshot(mem = process.memoryUsage(), heapSizeLimit = v8.getHeapStatistics().heap_size_limit) {
1694
- const limit = Number.isFinite(heapSizeLimit) && heapSizeLimit > 0 ? heapSizeLimit : Math.max(mem.heapTotal, 1);
1695
- const usagePercent = mem.heapUsed / limit * 100;
1696
- return {
1697
- heapUsed: mem.heapUsed,
1698
- heapTotal: mem.heapTotal,
1699
- heapSizeLimit: limit,
1700
- rss: mem.rss,
1701
- usagePercent
1702
- };
1713
+ // src/services/qwen-url.ts
1714
+ function qwenUrl(path6 = "") {
1715
+ const normalizedPath = path6.replace(/^\/+/, "");
1716
+ return normalizedPath ? `${QWEN_BASE_URL}/${normalizedPath}` : QWEN_BASE_URL;
1703
1717
  }
1704
- function getRssUsageSnapshot(mem = process.memoryUsage(), totalSystemMemory = os2.totalmem()) {
1705
- const usagePercent = Number.isFinite(totalSystemMemory) && totalSystemMemory > 0 ? mem.rss / totalSystemMemory * 100 : 0;
1706
- return {
1707
- rss: mem.rss,
1708
- totalSystemMemory,
1709
- usagePercent
1710
- };
1718
+ function qwenOrigin() {
1719
+ return QWEN_ORIGIN;
1711
1720
  }
1712
- var init_memory_usage = __esm({
1713
- "src/core/memory-usage.ts"() {
1721
+ var QWEN_BASE_URL, QWEN_ORIGIN;
1722
+ var init_qwen_url = __esm({
1723
+ "src/services/qwen-url.ts"() {
1714
1724
  "use strict";
1725
+ init_config();
1726
+ QWEN_BASE_URL = config.qwen.baseUrl.trim().replace(/\/+$/, "");
1727
+ QWEN_ORIGIN = new URL(QWEN_BASE_URL).origin;
1715
1728
  }
1716
1729
  });
1717
1730
 
1718
- // src/core/metrics.ts
1719
- import { EventEmitter } from "events";
1720
- var Metrics, metrics;
1721
- var init_metrics = __esm({
1722
- "src/core/metrics.ts"() {
1731
+ // src/services/fingerprint.ts
1732
+ function mulberry32(seed) {
1733
+ return () => {
1734
+ seed |= 0;
1735
+ seed = seed + 1831565813 | 0;
1736
+ let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
1737
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
1738
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
1739
+ };
1740
+ }
1741
+ function seedFromString(value) {
1742
+ let hash = 0;
1743
+ for (let i = 0; i < value.length; i++) {
1744
+ hash = (hash << 5) - hash + value.charCodeAt(i) | 0;
1745
+ }
1746
+ return hash >>> 0;
1747
+ }
1748
+ function pick(rng, values) {
1749
+ return values[Math.floor(rng() * values.length)];
1750
+ }
1751
+ function randInt(rng, min, max) {
1752
+ return Math.floor(rng() * (max - min + 1)) + min;
1753
+ }
1754
+ function updateChromeMajor(major) {
1755
+ if (typeof major === "number" && major >= 100) {
1756
+ dynamicChromeMajor = major;
1757
+ }
1758
+ }
1759
+ function getChromeMajor() {
1760
+ return dynamicChromeMajor;
1761
+ }
1762
+ function getSystemLocale() {
1763
+ return process.env.QWEN_LOCALE || (typeof Intl !== "undefined" && Intl.DateTimeFormat ? Intl.DateTimeFormat().resolvedOptions().locale : "") || "pt-BR";
1764
+ }
1765
+ function getLanguageProfiles(locale = getSystemLocale()) {
1766
+ const primary = locale.split("-")[0];
1767
+ if (primary === "en") {
1768
+ return [
1769
+ ["en-US", "en"],
1770
+ ["en-US", "en", "es"],
1771
+ ["en", "en-US"],
1772
+ ["en-US", "en;q=0.9"]
1773
+ ];
1774
+ }
1775
+ return [
1776
+ [locale, primary, "en-US", "en"],
1777
+ [locale, primary, "en-US", "en", "es"],
1778
+ [locale, "en-US", "en", primary],
1779
+ [locale, primary, "en"],
1780
+ [locale, `${primary};q=0.9`, "en-US;q=0.8", "en;q=0.7"]
1781
+ ];
1782
+ }
1783
+ function getFingerprintProfile(accountId) {
1784
+ const cached = profileCache.get(accountId);
1785
+ if (cached) return cached;
1786
+ const salt = rotationSalts.get(accountId) ?? 0;
1787
+ const seed = seedFromString(salt === 0 ? accountId : `${accountId}#r${salt}`);
1788
+ const rng = mulberry32(seed);
1789
+ const viewport = pick(rng, VIEWPORTS);
1790
+ const webgl = pick(rng, WEBGL_PROFILES);
1791
+ const languages = [...pick(rng, getLanguageProfiles())];
1792
+ const hardwareConcurrency = pick(rng, HARDWARE_CONCURRENCIES);
1793
+ const deviceMemory = pick(rng, DEVICE_MEMORIES);
1794
+ const platformInfo = pick(rng, PLATFORM_VERSIONS);
1795
+ const notABrand = pick(rng, NOT_A_BRAND_VARIANTS);
1796
+ const major = dynamicChromeMajor;
1797
+ const build = randInt(rng, 7300, 7600);
1798
+ const patch = randInt(rng, 0, 160);
1799
+ const chromeVersion = `${major}.0.${build}.${patch}`;
1800
+ const brands = [
1801
+ { brand: notABrand.brand, version: notABrand.version },
1802
+ { brand: "Google Chrome", version: String(major) },
1803
+ { brand: "Chromium", version: String(major) }
1804
+ ];
1805
+ const fullVersionList = [
1806
+ { brand: notABrand.brand, version: chromeVersion },
1807
+ { brand: "Google Chrome", version: chromeVersion },
1808
+ { brand: "Chromium", version: chromeVersion }
1809
+ ];
1810
+ const secChUa = brands.map((brand) => `"${brand.brand}";v="${brand.version}"`).join(", ");
1811
+ const userAgent = `Mozilla/5.0 (Windows NT ${platformInfo.major}.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
1812
+ const profile = {
1813
+ accountId,
1814
+ seed,
1815
+ userAgent,
1816
+ appVersion: userAgent.replace("Mozilla/", ""),
1817
+ chromeMajor: CHROME_MAJOR,
1818
+ chromeVersion,
1819
+ brands,
1820
+ fullVersionList,
1821
+ secChUa,
1822
+ platform: "Win32",
1823
+ platformVersion: platformInfo.platformVersion,
1824
+ architecture: "x86",
1825
+ bitness: "64",
1826
+ languages,
1827
+ locale: languages[0].split(";")[0],
1828
+ timezoneId: "America/Sao_Paulo",
1829
+ viewport,
1830
+ hardwareConcurrency,
1831
+ deviceMemory,
1832
+ webglVendor: webgl.vendor,
1833
+ webglRenderer: webgl.renderer,
1834
+ colorDepth: 24,
1835
+ pixelDepth: 24,
1836
+ canvasNoiseSeed: randInt(rng, 1, 2147483647),
1837
+ audioNoiseSeed: randInt(rng, 1, 2147483647),
1838
+ webglNoiseSeed: randInt(rng, 1, 2147483647),
1839
+ outerWidthOffset: randInt(rng, 0, 20),
1840
+ outerHeightOffset: randInt(rng, 75, 95)
1841
+ };
1842
+ profileCache.set(accountId, profile);
1843
+ return profile;
1844
+ }
1845
+ function clearFingerprintCache(accountId) {
1846
+ if (accountId) profileCache.delete(accountId);
1847
+ else profileCache.clear();
1848
+ }
1849
+ var dynamicChromeMajor, CHROME_MAJOR, VIEWPORTS, WEBGL_PROFILES, HARDWARE_CONCURRENCIES, DEVICE_MEMORIES, PLATFORM_VERSIONS, NOT_A_BRAND_VARIANTS, profileCache, rotationSalts;
1850
+ var init_fingerprint = __esm({
1851
+ "src/services/fingerprint.ts"() {
1723
1852
  "use strict";
1724
- init_config();
1725
- init_memory_usage();
1726
- Metrics = class extends EventEmitter {
1727
- metrics = /* @__PURE__ */ new Map();
1728
- collectionInterval = null;
1729
- constructor() {
1730
- super();
1731
- this.registerDefaults();
1853
+ dynamicChromeMajor = 151;
1854
+ CHROME_MAJOR = 151;
1855
+ VIEWPORTS = [
1856
+ { width: 1366, height: 768 },
1857
+ { width: 1440, height: 900 },
1858
+ { width: 1536, height: 864 },
1859
+ { width: 1600, height: 900 },
1860
+ { width: 1680, height: 1050 },
1861
+ { width: 1920, height: 1080 },
1862
+ { width: 1920, height: 1200 },
1863
+ { width: 1280, height: 720 },
1864
+ { width: 1280, height: 800 },
1865
+ { width: 1536, height: 864 }
1866
+ ];
1867
+ WEBGL_PROFILES = [
1868
+ {
1869
+ vendor: "Google Inc. (Intel)",
1870
+ renderer: "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1871
+ },
1872
+ {
1873
+ vendor: "Google Inc. (Intel)",
1874
+ renderer: "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)"
1875
+ },
1876
+ {
1877
+ vendor: "Google Inc. (Intel)",
1878
+ renderer: "ANGLE (Intel, Intel(R) UHD Graphics 770 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1879
+ },
1880
+ {
1881
+ vendor: "Google Inc. (NVIDIA)",
1882
+ renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1883
+ },
1884
+ {
1885
+ vendor: "Google Inc. (NVIDIA)",
1886
+ renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1887
+ },
1888
+ {
1889
+ vendor: "Google Inc. (NVIDIA)",
1890
+ renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3080 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1891
+ },
1892
+ {
1893
+ vendor: "Google Inc. (NVIDIA)",
1894
+ renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1895
+ },
1896
+ {
1897
+ vendor: "Google Inc. (NVIDIA)",
1898
+ renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1899
+ },
1900
+ {
1901
+ vendor: "Google Inc. (NVIDIA)",
1902
+ renderer: "ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)"
1903
+ },
1904
+ {
1905
+ vendor: "Google Inc. (AMD)",
1906
+ renderer: "ANGLE (AMD, AMD Radeon RX 6600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1907
+ },
1908
+ {
1909
+ vendor: "Google Inc. (AMD)",
1910
+ renderer: "ANGLE (AMD, AMD Radeon RX 7600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1911
+ },
1912
+ {
1913
+ vendor: "Google Inc. (AMD)",
1914
+ renderer: "ANGLE (AMD, AMD Radeon RX 580 Direct3D11 vs_5_0 ps_5_0, D3D11)"
1732
1915
  }
1733
- registerDefaults() {
1734
- const defaults = [
1735
- // Core request metrics
1736
- ["requests.total", "counter", "Total requests processed"],
1737
- ["requests.errors", "counter", "Total request errors"],
1738
- ["requests.delta", "counter", "Thread-native delta requests"],
1739
- ["requests.full", "counter", "Full context replay or initial requests"],
1740
- ["latency.request", "histogram", "Request latency (ms)"],
1741
- ["toolcalls.total", "counter", "Total tool calls processed"],
1742
- ["toolcalls.malformed", "counter", "Malformed tool calls detected"],
1743
- ["toolcalls.recovered", "counter", "Malformed tool calls recovered/healed"],
1744
- ["chats.cleaned", "counter", "Remote chats automatically cleaned"],
1745
- // Stream metrics
1746
- ["streams.active", "gauge", "Active SSE streams"],
1747
- ["streams.errors", "counter", "Stream errors"],
1748
- // CAPTCHA / anti-bot metrics
1749
- ["captcha.challenges.detected", "counter", "Detected CAPTCHA challenges"],
1750
- ["captcha.solves.succeeded", "counter", "Successful CAPTCHA solves"],
1916
+ ];
1917
+ HARDWARE_CONCURRENCIES = [4, 6, 8, 8, 8, 12, 16, 16, 24, 32];
1918
+ DEVICE_MEMORIES = [4, 8, 8, 8, 16, 16, 32];
1919
+ PLATFORM_VERSIONS = [
1920
+ { platform: "Windows", platformVersion: "14.0.0", major: "10" },
1921
+ { platform: "Windows", platformVersion: "15.0.0", major: "11" },
1922
+ { platform: "Windows", platformVersion: "14.0.0", major: "10" },
1923
+ { platform: "Windows", platformVersion: "15.0.0", major: "11" }
1924
+ ];
1925
+ NOT_A_BRAND_VARIANTS = [
1926
+ { brand: "Not/A)Brand", version: "99" },
1927
+ { brand: "Not)A_Brand", version: "99" },
1928
+ { brand: "Not/A)Brand", version: "8" },
1929
+ { brand: "Not?A_Brand", version: "24" },
1930
+ { brand: "Not/A)Brand", version: "99" }
1931
+ ];
1932
+ profileCache = /* @__PURE__ */ new Map();
1933
+ rotationSalts = /* @__PURE__ */ new Map();
1934
+ }
1935
+ });
1936
+
1937
+ // src/utils/timezone.ts
1938
+ function formatAsciiTimezone(date = /* @__PURE__ */ new Date()) {
1939
+ const dayName = DAYS[date.getDay()];
1940
+ const monthName = MONTHS[date.getMonth()];
1941
+ const day = String(date.getDate()).padStart(2, "0");
1942
+ const year = date.getFullYear();
1943
+ const hours = String(date.getHours()).padStart(2, "0");
1944
+ const minutes = String(date.getMinutes()).padStart(2, "0");
1945
+ const seconds = String(date.getSeconds()).padStart(2, "0");
1946
+ const offsetMinutes = -date.getTimezoneOffset();
1947
+ const sign = offsetMinutes >= 0 ? "+" : "-";
1948
+ const absOffset = Math.abs(offsetMinutes);
1949
+ const offsetHours = String(Math.floor(absOffset / 60)).padStart(2, "0");
1950
+ const offsetMins = String(absOffset % 60).padStart(2, "0");
1951
+ const tzOffset = `GMT${sign}${offsetHours}${offsetMins}`;
1952
+ return `${dayName} ${monthName} ${day} ${year} ${hours}:${minutes}:${seconds} ${tzOffset}`;
1953
+ }
1954
+ var DAYS, MONTHS;
1955
+ var init_timezone = __esm({
1956
+ "src/utils/timezone.ts"() {
1957
+ "use strict";
1958
+ DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
1959
+ MONTHS = [
1960
+ "Jan",
1961
+ "Feb",
1962
+ "Mar",
1963
+ "Apr",
1964
+ "May",
1965
+ "Jun",
1966
+ "Jul",
1967
+ "Aug",
1968
+ "Sep",
1969
+ "Oct",
1970
+ "Nov",
1971
+ "Dec"
1972
+ ];
1973
+ }
1974
+ });
1975
+
1976
+ // src/services/qwen-headers.ts
1977
+ import { v4 as uuidv4 } from "uuid";
1978
+ function getDefaultQwenUserAgent(major = getChromeMajor()) {
1979
+ return `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${major}.0.0.0 Safari/537.36`;
1980
+ }
1981
+ function updateQwenWebVersion(version) {
1982
+ if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
1983
+ dynamicWebVersion = version.trim();
1984
+ }
1985
+ }
1986
+ function getQwenWebVersion() {
1987
+ return dynamicWebVersion || config.qwen.webVersion;
1988
+ }
1989
+ function updateQwenBxVersion(version) {
1990
+ if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
1991
+ dynamicBxVersion = version.trim();
1992
+ }
1993
+ }
1994
+ function getQwenBxVersion() {
1995
+ return dynamicBxVersion || config.auth.bxV;
1996
+ }
1997
+ var dynamicWebVersion, dynamicBxVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
1998
+ var init_qwen_headers = __esm({
1999
+ "src/services/qwen-headers.ts"() {
2000
+ "use strict";
2001
+ init_qwen_url();
2002
+ init_config();
2003
+ init_fingerprint();
2004
+ init_timezone();
2005
+ dynamicWebVersion = null;
2006
+ dynamicBxVersion = null;
2007
+ QWEN_WEB_VERSION = config.qwen.webVersion;
2008
+ DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
2009
+ QWEN_TIMEZONE_HEADER = (/* @__PURE__ */ new Date()).toString().split(" (")[0];
2010
+ }
2011
+ });
2012
+
2013
+ // src/core/memory-usage.ts
2014
+ import v8 from "v8";
2015
+ import os2 from "os";
2016
+ function getHeapUsageSnapshot(mem = process.memoryUsage(), heapSizeLimit = v8.getHeapStatistics().heap_size_limit) {
2017
+ const limit = Number.isFinite(heapSizeLimit) && heapSizeLimit > 0 ? heapSizeLimit : Math.max(mem.heapTotal, 1);
2018
+ const usagePercent = mem.heapUsed / limit * 100;
2019
+ return {
2020
+ heapUsed: mem.heapUsed,
2021
+ heapTotal: mem.heapTotal,
2022
+ heapSizeLimit: limit,
2023
+ rss: mem.rss,
2024
+ usagePercent
2025
+ };
2026
+ }
2027
+ function getRssUsageSnapshot(mem = process.memoryUsage(), totalSystemMemory = os2.totalmem()) {
2028
+ const usagePercent = Number.isFinite(totalSystemMemory) && totalSystemMemory > 0 ? mem.rss / totalSystemMemory * 100 : 0;
2029
+ return {
2030
+ rss: mem.rss,
2031
+ totalSystemMemory,
2032
+ usagePercent
2033
+ };
2034
+ }
2035
+ var init_memory_usage = __esm({
2036
+ "src/core/memory-usage.ts"() {
2037
+ "use strict";
2038
+ }
2039
+ });
2040
+
2041
+ // src/core/metrics.ts
2042
+ import { EventEmitter } from "events";
2043
+ var Metrics, metrics;
2044
+ var init_metrics = __esm({
2045
+ "src/core/metrics.ts"() {
2046
+ "use strict";
2047
+ init_config();
2048
+ init_memory_usage();
2049
+ Metrics = class extends EventEmitter {
2050
+ metrics = /* @__PURE__ */ new Map();
2051
+ collectionInterval = null;
2052
+ constructor() {
2053
+ super();
2054
+ this.registerDefaults();
2055
+ }
2056
+ registerDefaults() {
2057
+ const defaults = [
2058
+ // Core request metrics
2059
+ ["requests.total", "counter", "Total requests processed"],
2060
+ ["requests.errors", "counter", "Total request errors"],
2061
+ ["requests.delta", "counter", "Thread-native delta requests"],
2062
+ ["requests.full", "counter", "Full context replay or initial requests"],
2063
+ ["latency.request", "histogram", "Request latency (ms)"],
2064
+ ["toolcalls.total", "counter", "Total tool calls processed"],
2065
+ ["toolcalls.malformed", "counter", "Malformed tool calls detected"],
2066
+ ["toolcalls.recovered", "counter", "Malformed tool calls recovered/healed"],
2067
+ ["chats.cleaned", "counter", "Remote chats automatically cleaned"],
2068
+ // Stream metrics
2069
+ ["streams.active", "gauge", "Active SSE streams"],
2070
+ ["streams.errors", "counter", "Stream errors"],
2071
+ // CAPTCHA / anti-bot metrics
2072
+ ["captcha.challenges.detected", "counter", "Detected CAPTCHA challenges"],
2073
+ ["captcha.solves.succeeded", "counter", "Successful CAPTCHA solves"],
1751
2074
  ["captcha.solves.failed", "counter", "Failed CAPTCHA solves"],
1752
2075
  ["captcha.solve.duration", "histogram", "CAPTCHA solve duration (ms)"],
1753
2076
  // Memory metrics
@@ -2062,247 +2385,41 @@ var init_mutex = __esm({
2062
2385
  }
2063
2386
  release() {
2064
2387
  const next = this.queue.shift();
2065
- if (next) {
2066
- const waitTime = Date.now() - next.enqueuedAt;
2067
- if (waitTime > 1e3 && logger.isLevelEnabled("debug")) {
2068
- logger.debug(`[Mutex:${this.name}] dequeued key=${next.key} waited=${waitTime}ms`);
2069
- }
2070
- next.waiter();
2071
- return;
2072
- }
2073
- this.locked = false;
2074
- this.lockedAt = 0;
2075
- this.lockedByKey = "";
2076
- }
2077
- /**
2078
- * Heartbeat the lock: extend lockedAt while the holder is actively making progress.
2079
- * Prevents premature force-release during long-running streaming generations.
2080
- */
2081
- touch(key) {
2082
- if (this.locked && (!key || this.lockedByKey === key)) {
2083
- this.lockedAt = Date.now();
2084
- }
2085
- }
2086
- /** Returns true if the mutex is not locked and has no waiting queue. */
2087
- isIdle() {
2088
- return !this.locked && this.queue.length === 0;
2089
- }
2090
- /** Returns diagnostic info about the current lock state. */
2091
- state() {
2092
- return {
2093
- locked: this.locked,
2094
- heldBy: this.lockedByKey,
2095
- heldForMs: this.locked ? Date.now() - this.lockedAt : 0,
2096
- queueLength: this.queue.length
2097
- };
2098
- }
2099
- };
2100
- }
2101
- });
2102
-
2103
- // src/services/fingerprint.ts
2104
- function mulberry32(seed) {
2105
- return () => {
2106
- seed |= 0;
2107
- seed = seed + 1831565813 | 0;
2108
- let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
2109
- t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
2110
- return ((t ^ t >>> 14) >>> 0) / 4294967296;
2111
- };
2112
- }
2113
- function seedFromString(value) {
2114
- let hash = 0;
2115
- for (let i = 0; i < value.length; i++) {
2116
- hash = (hash << 5) - hash + value.charCodeAt(i) | 0;
2117
- }
2118
- return hash >>> 0;
2119
- }
2120
- function pick(rng, values) {
2121
- return values[Math.floor(rng() * values.length)];
2122
- }
2123
- function randInt(rng, min, max) {
2124
- return Math.floor(rng() * (max - min + 1)) + min;
2125
- }
2126
- function updateChromeMajor(major) {
2127
- if (typeof major === "number" && major >= 100) {
2128
- dynamicChromeMajor = major;
2129
- }
2130
- }
2131
- function getChromeMajor() {
2132
- return dynamicChromeMajor;
2133
- }
2134
- function getSystemLocale() {
2135
- return process.env.QWEN_LOCALE || (typeof Intl !== "undefined" && Intl.DateTimeFormat ? Intl.DateTimeFormat().resolvedOptions().locale : "") || "pt-BR";
2136
- }
2137
- function getLanguageProfiles(locale = getSystemLocale()) {
2138
- const primary = locale.split("-")[0];
2139
- if (primary === "en") {
2140
- return [
2141
- ["en-US", "en"],
2142
- ["en-US", "en", "es"],
2143
- ["en", "en-US"],
2144
- ["en-US", "en;q=0.9"]
2145
- ];
2146
- }
2147
- return [
2148
- [locale, primary, "en-US", "en"],
2149
- [locale, primary, "en-US", "en", "es"],
2150
- [locale, "en-US", "en", primary],
2151
- [locale, primary, "en"],
2152
- [locale, `${primary};q=0.9`, "en-US;q=0.8", "en;q=0.7"]
2153
- ];
2154
- }
2155
- function getFingerprintProfile(accountId) {
2156
- const cached = profileCache.get(accountId);
2157
- if (cached) return cached;
2158
- const salt = rotationSalts.get(accountId) ?? 0;
2159
- const seed = seedFromString(salt === 0 ? accountId : `${accountId}#r${salt}`);
2160
- const rng = mulberry32(seed);
2161
- const viewport = pick(rng, VIEWPORTS);
2162
- const webgl = pick(rng, WEBGL_PROFILES);
2163
- const languages = [...pick(rng, getLanguageProfiles())];
2164
- const hardwareConcurrency = pick(rng, HARDWARE_CONCURRENCIES);
2165
- const deviceMemory = pick(rng, DEVICE_MEMORIES);
2166
- const platformInfo = pick(rng, PLATFORM_VERSIONS);
2167
- const notABrand = pick(rng, NOT_A_BRAND_VARIANTS);
2168
- const major = dynamicChromeMajor;
2169
- const build = randInt(rng, 7300, 7600);
2170
- const patch = randInt(rng, 0, 160);
2171
- const chromeVersion = `${major}.0.${build}.${patch}`;
2172
- const brands = [
2173
- { brand: notABrand.brand, version: notABrand.version },
2174
- { brand: "Google Chrome", version: String(major) },
2175
- { brand: "Chromium", version: String(major) }
2176
- ];
2177
- const fullVersionList = [
2178
- { brand: notABrand.brand, version: chromeVersion },
2179
- { brand: "Google Chrome", version: chromeVersion },
2180
- { brand: "Chromium", version: chromeVersion }
2181
- ];
2182
- const secChUa = brands.map((brand) => `"${brand.brand}";v="${brand.version}"`).join(", ");
2183
- const userAgent = `Mozilla/5.0 (Windows NT ${platformInfo.major}.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${chromeVersion} Safari/537.36`;
2184
- const profile = {
2185
- accountId,
2186
- seed,
2187
- userAgent,
2188
- appVersion: userAgent.replace("Mozilla/", ""),
2189
- chromeMajor: CHROME_MAJOR,
2190
- chromeVersion,
2191
- brands,
2192
- fullVersionList,
2193
- secChUa,
2194
- platform: "Win32",
2195
- platformVersion: platformInfo.platformVersion,
2196
- architecture: "x86",
2197
- bitness: "64",
2198
- languages,
2199
- locale: languages[0].split(";")[0],
2200
- timezoneId: "America/Sao_Paulo",
2201
- viewport,
2202
- hardwareConcurrency,
2203
- deviceMemory,
2204
- webglVendor: webgl.vendor,
2205
- webglRenderer: webgl.renderer,
2206
- colorDepth: 24,
2207
- pixelDepth: 24,
2208
- canvasNoiseSeed: randInt(rng, 1, 2147483647),
2209
- audioNoiseSeed: randInt(rng, 1, 2147483647),
2210
- webglNoiseSeed: randInt(rng, 1, 2147483647),
2211
- outerWidthOffset: randInt(rng, 0, 20),
2212
- outerHeightOffset: randInt(rng, 75, 95)
2213
- };
2214
- profileCache.set(accountId, profile);
2215
- return profile;
2216
- }
2217
- function clearFingerprintCache(accountId) {
2218
- if (accountId) profileCache.delete(accountId);
2219
- else profileCache.clear();
2220
- }
2221
- var dynamicChromeMajor, CHROME_MAJOR, VIEWPORTS, WEBGL_PROFILES, HARDWARE_CONCURRENCIES, DEVICE_MEMORIES, PLATFORM_VERSIONS, NOT_A_BRAND_VARIANTS, profileCache, rotationSalts;
2222
- var init_fingerprint = __esm({
2223
- "src/services/fingerprint.ts"() {
2224
- "use strict";
2225
- dynamicChromeMajor = 151;
2226
- CHROME_MAJOR = 151;
2227
- VIEWPORTS = [
2228
- { width: 1366, height: 768 },
2229
- { width: 1440, height: 900 },
2230
- { width: 1536, height: 864 },
2231
- { width: 1600, height: 900 },
2232
- { width: 1680, height: 1050 },
2233
- { width: 1920, height: 1080 },
2234
- { width: 1920, height: 1200 },
2235
- { width: 1280, height: 720 },
2236
- { width: 1280, height: 800 },
2237
- { width: 1536, height: 864 }
2238
- ];
2239
- WEBGL_PROFILES = [
2240
- {
2241
- vendor: "Google Inc. (Intel)",
2242
- renderer: "ANGLE (Intel, Intel(R) UHD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2243
- },
2244
- {
2245
- vendor: "Google Inc. (Intel)",
2246
- renderer: "ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)"
2247
- },
2248
- {
2249
- vendor: "Google Inc. (Intel)",
2250
- renderer: "ANGLE (Intel, Intel(R) UHD Graphics 770 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2251
- },
2252
- {
2253
- vendor: "Google Inc. (NVIDIA)",
2254
- renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2255
- },
2256
- {
2257
- vendor: "Google Inc. (NVIDIA)",
2258
- renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2259
- },
2260
- {
2261
- vendor: "Google Inc. (NVIDIA)",
2262
- renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 3080 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2263
- },
2264
- {
2265
- vendor: "Google Inc. (NVIDIA)",
2266
- renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4060 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2267
- },
2268
- {
2269
- vendor: "Google Inc. (NVIDIA)",
2270
- renderer: "ANGLE (NVIDIA, NVIDIA GeForce RTX 4070 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2271
- },
2272
- {
2273
- vendor: "Google Inc. (NVIDIA)",
2274
- renderer: "ANGLE (NVIDIA, NVIDIA GeForce GTX 1660 SUPER Direct3D11 vs_5_0 ps_5_0, D3D11)"
2275
- },
2276
- {
2277
- vendor: "Google Inc. (AMD)",
2278
- renderer: "ANGLE (AMD, AMD Radeon RX 6600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2279
- },
2280
- {
2281
- vendor: "Google Inc. (AMD)",
2282
- renderer: "ANGLE (AMD, AMD Radeon RX 7600 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2283
- },
2284
- {
2285
- vendor: "Google Inc. (AMD)",
2286
- renderer: "ANGLE (AMD, AMD Radeon RX 580 Direct3D11 vs_5_0 ps_5_0, D3D11)"
2388
+ if (next) {
2389
+ const waitTime = Date.now() - next.enqueuedAt;
2390
+ if (waitTime > 1e3 && logger.isLevelEnabled("debug")) {
2391
+ logger.debug(`[Mutex:${this.name}] dequeued key=${next.key} waited=${waitTime}ms`);
2392
+ }
2393
+ next.waiter();
2394
+ return;
2395
+ }
2396
+ this.locked = false;
2397
+ this.lockedAt = 0;
2398
+ this.lockedByKey = "";
2287
2399
  }
2288
- ];
2289
- HARDWARE_CONCURRENCIES = [4, 6, 8, 8, 8, 12, 16, 16, 24, 32];
2290
- DEVICE_MEMORIES = [4, 8, 8, 8, 16, 16, 32];
2291
- PLATFORM_VERSIONS = [
2292
- { platform: "Windows", platformVersion: "14.0.0", major: "10" },
2293
- { platform: "Windows", platformVersion: "15.0.0", major: "11" },
2294
- { platform: "Windows", platformVersion: "14.0.0", major: "10" },
2295
- { platform: "Windows", platformVersion: "15.0.0", major: "11" }
2296
- ];
2297
- NOT_A_BRAND_VARIANTS = [
2298
- { brand: "Not/A)Brand", version: "99" },
2299
- { brand: "Not)A_Brand", version: "99" },
2300
- { brand: "Not/A)Brand", version: "8" },
2301
- { brand: "Not?A_Brand", version: "24" },
2302
- { brand: "Not/A)Brand", version: "99" }
2303
- ];
2304
- profileCache = /* @__PURE__ */ new Map();
2305
- rotationSalts = /* @__PURE__ */ new Map();
2400
+ /**
2401
+ * Heartbeat the lock: extend lockedAt while the holder is actively making progress.
2402
+ * Prevents premature force-release during long-running streaming generations.
2403
+ */
2404
+ touch(key) {
2405
+ if (this.locked && (!key || this.lockedByKey === key)) {
2406
+ this.lockedAt = Date.now();
2407
+ }
2408
+ }
2409
+ /** Returns true if the mutex is not locked and has no waiting queue. */
2410
+ isIdle() {
2411
+ return !this.locked && this.queue.length === 0;
2412
+ }
2413
+ /** Returns diagnostic info about the current lock state. */
2414
+ state() {
2415
+ return {
2416
+ locked: this.locked,
2417
+ heldBy: this.lockedByKey,
2418
+ heldForMs: this.locked ? Date.now() - this.lockedAt : 0,
2419
+ queueLength: this.queue.length
2420
+ };
2421
+ }
2422
+ };
2306
2423
  }
2307
2424
  });
2308
2425
 
@@ -2390,6 +2507,294 @@ function logBaxiaCaptcha(event, fields = {}, important = false) {
2390
2507
  console.log(line);
2391
2508
  }
2392
2509
  }
2510
+ async function findVisibleLocatorWithin(page, selectors, timeoutMs) {
2511
+ const deadline = Date.now() + Math.max(0, timeoutMs);
2512
+ while (true) {
2513
+ const found = await findVisibleLocator(page, selectors);
2514
+ if (found) return found;
2515
+ if (Date.now() >= deadline) return null;
2516
+ await sleep(Math.min(150, Math.max(1, deadline - Date.now())));
2517
+ }
2518
+ }
2519
+ async function waitForHidden(locator, timeoutMs) {
2520
+ const deadline = Date.now() + Math.max(0, timeoutMs);
2521
+ while (true) {
2522
+ if (!await isVisible(locator)) return true;
2523
+ if (Date.now() >= deadline) return false;
2524
+ await sleep(Math.min(100, Math.max(1, deadline - Date.now())));
2525
+ }
2526
+ }
2527
+ async function computeAliyunPuzzleOffset(page) {
2528
+ return page.evaluate(() => {
2529
+ const background = document.querySelector(
2530
+ "#aliyunCaptcha-img"
2531
+ );
2532
+ const piece = document.querySelector(
2533
+ "#aliyunCaptcha-puzzle"
2534
+ );
2535
+ if (!background || !piece) {
2536
+ return Promise.resolve({ ok: false, reason: "missing puzzle images" });
2537
+ }
2538
+ const compute = () => {
2539
+ try {
2540
+ const width = background.naturalWidth;
2541
+ const height = background.naturalHeight;
2542
+ const pieceWidth = piece.naturalWidth;
2543
+ const pieceHeight = piece.naturalHeight;
2544
+ if (!width || !height || !pieceWidth || !pieceHeight) {
2545
+ return { ok: false, reason: "image dimensions unavailable" };
2546
+ }
2547
+ const backgroundCanvas = document.createElement("canvas");
2548
+ backgroundCanvas.id = "captcha-solver-canvas";
2549
+ backgroundCanvas.width = width;
2550
+ backgroundCanvas.height = height;
2551
+ const backgroundContext = backgroundCanvas.getContext("2d");
2552
+ if (!backgroundContext) {
2553
+ return { ok: false, reason: "no background context" };
2554
+ }
2555
+ const pieceCanvas = document.createElement("canvas");
2556
+ pieceCanvas.id = "captcha-solver-canvas";
2557
+ pieceCanvas.width = pieceWidth;
2558
+ pieceCanvas.height = pieceHeight;
2559
+ const pieceContext = pieceCanvas.getContext("2d");
2560
+ if (!pieceContext) {
2561
+ return { ok: false, reason: "no piece context" };
2562
+ }
2563
+ try {
2564
+ backgroundContext.drawImage(background, 0, 0);
2565
+ } catch {
2566
+ return { ok: false, reason: "background canvas tainted" };
2567
+ }
2568
+ try {
2569
+ pieceContext.drawImage(piece, 0, 0);
2570
+ } catch {
2571
+ return { ok: false, reason: "puzzle canvas tainted" };
2572
+ }
2573
+ const backgroundData = backgroundContext.getImageData(
2574
+ 0,
2575
+ 0,
2576
+ width,
2577
+ height
2578
+ ).data;
2579
+ const pieceData = pieceContext.getImageData(
2580
+ 0,
2581
+ 0,
2582
+ pieceWidth,
2583
+ pieceHeight
2584
+ ).data;
2585
+ let pieceMinX = pieceWidth;
2586
+ let pieceMaxX = -1;
2587
+ let pieceMinY = pieceHeight;
2588
+ let pieceMaxY = -1;
2589
+ for (let y = 0; y < pieceHeight; y++) {
2590
+ for (let x = 0; x < pieceWidth; x++) {
2591
+ if (pieceData[(y * pieceWidth + x) * 4 + 3] > 100) {
2592
+ if (x < pieceMinX) pieceMinX = x;
2593
+ if (x > pieceMaxX) pieceMaxX = x;
2594
+ if (y < pieceMinY) pieceMinY = y;
2595
+ if (y > pieceMaxY) pieceMaxY = y;
2596
+ }
2597
+ }
2598
+ }
2599
+ const puzzleWidth = pieceMaxX - pieceMinX + 1;
2600
+ if (puzzleWidth <= 0) {
2601
+ return { ok: false, reason: "empty puzzle piece" };
2602
+ }
2603
+ const yStart = Math.max(1, Math.min(height - 2, pieceMinY + 5));
2604
+ const yEnd = Math.max(
2605
+ yStart,
2606
+ Math.min(height - 2, pieceMaxY - 5)
2607
+ );
2608
+ const columnGradients = new Float32Array(width);
2609
+ for (let x = 1; x < width - 1; x++) {
2610
+ let gradient = 0;
2611
+ for (let y = yStart; y <= yEnd; y++) {
2612
+ const left = (y * width + x - 1) * 4;
2613
+ const right = (y * width + x + 1) * 4;
2614
+ gradient += Math.abs(backgroundData[right] - backgroundData[left]) + Math.abs(backgroundData[right + 1] - backgroundData[left + 1]) + Math.abs(backgroundData[right + 2] - backgroundData[left + 2]);
2615
+ }
2616
+ columnGradients[x] = gradient;
2617
+ }
2618
+ let bestX = 0;
2619
+ let bestScore = 0;
2620
+ const minCandidateX = 30;
2621
+ const maxCandidateX = width - puzzleWidth - 20;
2622
+ for (let candidateX = minCandidateX; candidateX <= maxCandidateX; candidateX++) {
2623
+ let leftMax = 0;
2624
+ for (let dx = -2; dx <= 2; dx++) {
2625
+ const value = columnGradients[candidateX + pieceMinX + dx] || 0;
2626
+ if (value > leftMax) leftMax = value;
2627
+ }
2628
+ let rightMax = 0;
2629
+ for (let dx = -3; dx <= 1; dx++) {
2630
+ const value = columnGradients[candidateX + pieceMaxX + dx] || 0;
2631
+ if (value > rightMax) rightMax = value;
2632
+ }
2633
+ const score = Math.sqrt(leftMax * rightMax);
2634
+ if (score > bestScore) {
2635
+ bestScore = score;
2636
+ bestX = candidateX;
2637
+ }
2638
+ }
2639
+ if (bestScore <= 0) {
2640
+ return { ok: false, reason: "no matching hole edge" };
2641
+ }
2642
+ return {
2643
+ ok: true,
2644
+ offsetX: bestX - pieceMinX,
2645
+ naturalWidth: width
2646
+ };
2647
+ } catch (error) {
2648
+ return {
2649
+ ok: false,
2650
+ reason: error instanceof Error ? error.message : String(error)
2651
+ };
2652
+ }
2653
+ };
2654
+ return new Promise((resolve) => {
2655
+ if (background.complete && piece.complete) {
2656
+ resolve(compute());
2657
+ return;
2658
+ }
2659
+ let settled = false;
2660
+ const finish = () => {
2661
+ if (settled) return;
2662
+ settled = true;
2663
+ resolve(compute());
2664
+ };
2665
+ const fail = () => {
2666
+ if (settled) return;
2667
+ settled = true;
2668
+ resolve({ ok: false, reason: "puzzle image load error" });
2669
+ };
2670
+ background.addEventListener("load", finish, { once: true });
2671
+ piece.addEventListener("load", finish, { once: true });
2672
+ background.addEventListener("error", fail, { once: true });
2673
+ piece.addEventListener("error", fail, { once: true });
2674
+ setTimeout(() => {
2675
+ if (settled) return;
2676
+ settled = true;
2677
+ resolve({ ok: false, reason: "puzzle image load timeout" });
2678
+ }, 2e3);
2679
+ });
2680
+ });
2681
+ }
2682
+ async function solveAliyunWafCaptcha(page, options = {}) {
2683
+ const waitForMs = Math.max(0, options.waitForMs ?? 0);
2684
+ const maxAttempts = Math.max(
2685
+ 1,
2686
+ Math.min(5, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS)
2687
+ );
2688
+ const retryDelayMs = Math.max(
2689
+ 0,
2690
+ options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS
2691
+ );
2692
+ const settleMs = Math.max(0, options.settleMs ?? DEFAULT_SETTLE_MS);
2693
+ const sliderTimeoutMs = Math.max(
2694
+ 500,
2695
+ options.sliderTimeoutMs ?? DEFAULT_SLIDER_TIMEOUT_MS
2696
+ );
2697
+ const detected = await findVisibleLocatorWithin(
2698
+ page,
2699
+ ALIYUN_WAF_BLOCK_SELECTORS,
2700
+ waitForMs
2701
+ );
2702
+ if (!detected) return false;
2703
+ return withCaptchaMouseLock(async () => {
2704
+ const block = detected.locator;
2705
+ if (!await isVisible(block)) return false;
2706
+ logBaxiaCaptcha("aliyun_detected", { selector: detected.selector });
2707
+ let lastReason = "unknown";
2708
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
2709
+ try {
2710
+ const offset = await computeAliyunPuzzleOffset(page);
2711
+ if (!offset.ok || typeof offset.offsetX !== "number" || typeof offset.naturalWidth !== "number" || offset.naturalWidth <= 0) {
2712
+ lastReason = offset.reason || "offset_unavailable";
2713
+ logBaxiaCaptcha("aliyun_offset_failed", {
2714
+ attempt,
2715
+ reason: lastReason
2716
+ });
2717
+ } else {
2718
+ const slider = page.locator(ALIYUN_PUZZLE_SLIDER_SELECTOR).first();
2719
+ const track = page.locator(ALIYUN_PUZZLE_TRACK_SELECTOR).first();
2720
+ await slider.waitFor({ state: "visible", timeout: sliderTimeoutMs });
2721
+ const [sliderBox, trackBox] = await Promise.all([
2722
+ slider.boundingBox(),
2723
+ track.boundingBox()
2724
+ ]);
2725
+ if (!sliderBox || !trackBox || trackBox.width <= 0) {
2726
+ lastReason = "bounds_unavailable";
2727
+ logBaxiaCaptcha("aliyun_offset_failed", {
2728
+ attempt,
2729
+ reason: lastReason
2730
+ });
2731
+ } else {
2732
+ const scale = trackBox.width / offset.naturalWidth;
2733
+ const dragDistance = Math.round(offset.offsetX * scale);
2734
+ logBaxiaCaptcha("aliyun_geometry", {
2735
+ attempt,
2736
+ offset: offset.offsetX,
2737
+ scale: Number(scale.toFixed(2)),
2738
+ distance: dragDistance
2739
+ });
2740
+ if (dragDistance <= 0) {
2741
+ lastReason = "non_positive_distance";
2742
+ } else {
2743
+ const startX = sliderBox.x + sliderBox.width / 2;
2744
+ const startY = sliderBox.y + sliderBox.height / 2;
2745
+ await humanDrag(
2746
+ page,
2747
+ startX,
2748
+ startY,
2749
+ startX + dragDistance,
2750
+ startY
2751
+ );
2752
+ if (await waitForHidden(block, settleMs)) {
2753
+ logBaxiaCaptcha(
2754
+ "aliyun_solve_succeeded",
2755
+ { attempt, distance: dragDistance },
2756
+ true
2757
+ );
2758
+ return true;
2759
+ }
2760
+ lastReason = "not_solved";
2761
+ }
2762
+ }
2763
+ }
2764
+ } catch (error) {
2765
+ lastReason = error instanceof Error ? error.name : "UnknownError";
2766
+ logBaxiaCaptcha("aliyun_offset_failed", {
2767
+ attempt,
2768
+ error: lastReason,
2769
+ detail: sanitizeCaptchaErrorDetail(error)
2770
+ });
2771
+ }
2772
+ if (attempt < maxAttempts && retryDelayMs > 0) {
2773
+ await sleep(retryDelayMs);
2774
+ }
2775
+ }
2776
+ logBaxiaCaptcha(
2777
+ "aliyun_solve_failed",
2778
+ { attempts: maxAttempts, reason: lastReason },
2779
+ true
2780
+ );
2781
+ return false;
2782
+ });
2783
+ }
2784
+ async function solveVisibleCaptcha(page, options = {}) {
2785
+ if (typeof page.isClosed === "function" && page.isClosed()) return false;
2786
+ const totalWaitMs = Math.max(0, options.waitForMs ?? 0);
2787
+ const aliyunWaitMs = Math.min(totalWaitMs, ALIYUN_PROBE_MAX_WAIT_MS);
2788
+ const startedAt = Date.now();
2789
+ if (await solveAliyunWafCaptcha(page, { ...options, waitForMs: aliyunWaitMs })) {
2790
+ return true;
2791
+ }
2792
+ const remainingWaitMs = Math.max(
2793
+ 0,
2794
+ totalWaitMs - (Date.now() - startedAt)
2795
+ );
2796
+ return solveBaxiaCaptcha(page, { ...options, waitForMs: remainingWaitMs });
2797
+ }
2393
2798
  async function isVisible(locator) {
2394
2799
  return locator.isVisible().catch(() => false);
2395
2800
  }
@@ -2632,7 +3037,7 @@ async function solveBaxiaCaptchaUnlocked(page, options = {}) {
2632
3037
  );
2633
3038
  return false;
2634
3039
  }
2635
- 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;
3040
+ 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;
2636
3041
  var init_captcha_solver = __esm({
2637
3042
  "src/services/captcha-solver.ts"() {
2638
3043
  "use strict";
@@ -2658,14 +3063,20 @@ var init_captcha_solver = __esm({
2658
3063
  solve_failed: "\u274C",
2659
3064
  recovery_succeeded: "\u2705",
2660
3065
  recovery_not_solved: "\u26A0\uFE0F",
2661
- recovery_failed: "\u274C"
3066
+ recovery_failed: "\u274C",
3067
+ aliyun_detected: "\u{1F9E9}",
3068
+ aliyun_offset_failed: "\u{1F4D0}",
3069
+ aliyun_geometry: "\u{1F4D0}",
3070
+ aliyun_solve_succeeded: "\u2705",
3071
+ aliyun_solve_failed: "\u274C"
2662
3072
  };
2663
3073
  captchaDebugEnabled = process.env.CAPTCHA_DEBUG === "true";
2664
3074
  BAXIA_IFRAME_SELECTORS = [
2665
3075
  `${BAXIA_DIALOG_SELECTOR} ${BAXIA_CONTENT_SELECTOR} iframe`,
2666
3076
  `${BAXIA_CONTENT_SELECTOR} iframe`,
2667
3077
  "iframe#baxia-dialog-content",
2668
- 'iframe[src*="_____tmd_____/punish"]'
3078
+ 'iframe[src*="_____tmd_____/punish"]',
3079
+ 'iframe[src*="nocaptcha"]'
2669
3080
  ];
2670
3081
  BAXIA_DOCUMENT_SELECTORS = [
2671
3082
  "#nocaptcha",
@@ -2673,36 +3084,27 @@ var init_captcha_solver = __esm({
2673
3084
  "#baxia-punish"
2674
3085
  ];
2675
3086
  BAXIA_IFRAME_SELECTOR = BAXIA_IFRAME_SELECTORS.join(", ");
2676
- BAXIA_SLIDER_SELECTOR = "#nc_1_n1z, .nc_1_n1z, .btn_slide, .nc_wrapper .btn_slide, ._nc .btn_slide, .nc-container .btn_slide";
2677
- BAXIA_TRACK_SELECTOR = "#nc_1_n1t, .nc_scale, .nc_wrapper .nc_scale, ._nc .nc_scale, .nc-container .nc_scale";
3087
+ 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';
3088
+ BAXIA_TRACK_SELECTOR = '#nc_1_n1t, .nc_scale, span[id*="_n1t"], .nc_wrapper .nc_scale, ._nc .nc_scale, .nc-container .nc_scale';
2678
3089
  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';
2679
3090
  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"]';
2680
3091
  DEFAULT_MAX_ATTEMPTS = 3;
2681
3092
  DEFAULT_RETRY_DELAY_MS = 1e3;
2682
3093
  DEFAULT_SETTLE_MS = 2e3;
2683
3094
  DEFAULT_SLIDER_TIMEOUT_MS = 8e3;
3095
+ ALIYUN_WAF_CAPTCHA_SELECTOR = "#waf_nc_block";
3096
+ ALIYUN_WAF_CAPTCHA_WIDGET = "#aliyunCaptcha-window-embed";
3097
+ ALIYUN_WAF_BLOCK_SELECTORS = [
3098
+ ALIYUN_WAF_CAPTCHA_SELECTOR,
3099
+ ALIYUN_WAF_CAPTCHA_WIDGET
3100
+ ];
3101
+ ALIYUN_PUZZLE_SLIDER_SELECTOR = "#aliyunCaptcha-sliding-slider";
3102
+ ALIYUN_PUZZLE_TRACK_SELECTOR = "#aliyunCaptcha-sliding-body";
3103
+ ALIYUN_PROBE_MAX_WAIT_MS = 2e3;
2684
3104
  captchaMouseLock = Promise.resolve();
2685
3105
  }
2686
3106
  });
2687
3107
 
2688
- // src/services/qwen-url.ts
2689
- function qwenUrl(path6 = "") {
2690
- const normalizedPath = path6.replace(/^\/+/, "");
2691
- return normalizedPath ? `${QWEN_BASE_URL}/${normalizedPath}` : QWEN_BASE_URL;
2692
- }
2693
- function qwenOrigin() {
2694
- return QWEN_ORIGIN;
2695
- }
2696
- var QWEN_BASE_URL, QWEN_ORIGIN;
2697
- var init_qwen_url = __esm({
2698
- "src/services/qwen-url.ts"() {
2699
- "use strict";
2700
- init_config();
2701
- QWEN_BASE_URL = config.qwen.baseUrl.trim().replace(/\/+$/, "");
2702
- QWEN_ORIGIN = new URL(QWEN_BASE_URL).origin;
2703
- }
2704
- });
2705
-
2706
3108
  // src/core/waf-isolation.ts
2707
3109
  function setWafContextResetListener(fn) {
2708
3110
  contextResetListener = fn;
@@ -2719,73 +3121,6 @@ var init_waf_isolation = __esm({
2719
3121
  }
2720
3122
  });
2721
3123
 
2722
- // src/utils/timezone.ts
2723
- function formatAsciiTimezone(date = /* @__PURE__ */ new Date()) {
2724
- const dayName = DAYS[date.getDay()];
2725
- const monthName = MONTHS[date.getMonth()];
2726
- const day = String(date.getDate()).padStart(2, "0");
2727
- const year = date.getFullYear();
2728
- const hours = String(date.getHours()).padStart(2, "0");
2729
- const minutes = String(date.getMinutes()).padStart(2, "0");
2730
- const seconds = String(date.getSeconds()).padStart(2, "0");
2731
- const offsetMinutes = -date.getTimezoneOffset();
2732
- const sign = offsetMinutes >= 0 ? "+" : "-";
2733
- const absOffset = Math.abs(offsetMinutes);
2734
- const offsetHours = String(Math.floor(absOffset / 60)).padStart(2, "0");
2735
- const offsetMins = String(absOffset % 60).padStart(2, "0");
2736
- const tzOffset = `GMT${sign}${offsetHours}${offsetMins}`;
2737
- return `${dayName} ${monthName} ${day} ${year} ${hours}:${minutes}:${seconds} ${tzOffset}`;
2738
- }
2739
- var DAYS, MONTHS;
2740
- var init_timezone = __esm({
2741
- "src/utils/timezone.ts"() {
2742
- "use strict";
2743
- DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2744
- MONTHS = [
2745
- "Jan",
2746
- "Feb",
2747
- "Mar",
2748
- "Apr",
2749
- "May",
2750
- "Jun",
2751
- "Jul",
2752
- "Aug",
2753
- "Sep",
2754
- "Oct",
2755
- "Nov",
2756
- "Dec"
2757
- ];
2758
- }
2759
- });
2760
-
2761
- // src/services/qwen-headers.ts
2762
- import { v4 as uuidv4 } from "uuid";
2763
- function getDefaultQwenUserAgent(major = getChromeMajor()) {
2764
- return `Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/${major}.0.0.0 Safari/537.36`;
2765
- }
2766
- function updateQwenWebVersion(version) {
2767
- if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
2768
- dynamicWebVersion = version.trim();
2769
- }
2770
- }
2771
- function getQwenWebVersion() {
2772
- return dynamicWebVersion || config.qwen.webVersion;
2773
- }
2774
- var dynamicWebVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
2775
- var init_qwen_headers = __esm({
2776
- "src/services/qwen-headers.ts"() {
2777
- "use strict";
2778
- init_qwen_url();
2779
- init_config();
2780
- init_fingerprint();
2781
- init_timezone();
2782
- dynamicWebVersion = null;
2783
- QWEN_WEB_VERSION = config.qwen.webVersion;
2784
- DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
2785
- QWEN_TIMEZONE_HEADER = (/* @__PURE__ */ new Date()).toString().split(" (")[0];
2786
- }
2787
- });
2788
-
2789
3124
  // src/utils/jwt.ts
2790
3125
  var jwt_exports = {};
2791
3126
  __export(jwt_exports, {
@@ -3320,11 +3655,12 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
3320
3655
  async function clearVisibleChallenge(page) {
3321
3656
  if (page.isClosed()) return;
3322
3657
  if (config.captcha.enabled) {
3323
- await solveBaxiaCaptcha(page, {
3658
+ await solveVisibleCaptcha(page, {
3324
3659
  waitForMs: 0,
3325
3660
  maxAttempts: config.captcha.maxAttempts,
3326
3661
  retryDelayMs: config.captcha.retryDelayMs,
3327
- settleMs: config.captcha.settleMs
3662
+ settleMs: config.captcha.settleMs,
3663
+ sliderTimeoutMs: config.captcha.sliderTimeoutMs
3328
3664
  }).catch(() => false);
3329
3665
  }
3330
3666
  try {
@@ -3889,8 +4225,12 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
3889
4225
  if (accountPages.has(account.id)) {
3890
4226
  return;
3891
4227
  }
3892
- await evictIdlePlaywrightContextsToLimit().catch(() => {
3893
- });
4228
+ if (config.playwright.maxActiveContexts > 0) {
4229
+ await evictIdlePlaywrightContextsToLimit(
4230
+ Math.max(1, config.playwright.maxActiveContexts - 1)
4231
+ ).catch(() => {
4232
+ });
4233
+ }
3894
4234
  const profilePath = getAccountProfilePath(account.id);
3895
4235
  const fingerprint = getFingerprintProfile(account.id);
3896
4236
  const { engine, channel } = resolveBrowserEngine(browserType);
@@ -4066,6 +4406,9 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
4066
4406
  if (persisted.version) {
4067
4407
  updateQwenWebVersion(persisted.version);
4068
4408
  }
4409
+ if (persisted.bxV) {
4410
+ updateQwenBxVersion(persisted.bxV);
4411
+ }
4069
4412
  cache.lastRefresh = persisted.capturedAt;
4070
4413
  markAccountHeadersReady(account.id);
4071
4414
  restoredFromDb = true;
@@ -4159,7 +4502,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
4159
4502
  if (!acctPage.isClosed()) {
4160
4503
  try {
4161
4504
  const currentUrl = new URL(acctPage.url());
4162
- if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname !== "/") {
4505
+ if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname.includes("/auth") || currentUrl.pathname.includes("/login") || currentUrl.pathname.includes("_____tmd_____")) {
4163
4506
  await acctPage.goto(qwenUrl("/"), {
4164
4507
  waitUntil: "domcontentloaded",
4165
4508
  timeout: config.timeouts.navigation
@@ -4177,6 +4520,8 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
4177
4520
  } finally {
4178
4521
  release();
4179
4522
  }
4523
+ await evictIdlePlaywrightContextsToLimit().catch(() => {
4524
+ });
4180
4525
  })();
4181
4526
  try {
4182
4527
  await initPromise;
@@ -4260,7 +4605,7 @@ async function loginToQwen(accountId, email, password) {
4260
4605
  saveAuthSession2(accountId, {
4261
4606
  cookie: cookieStr,
4262
4607
  userAgent: cache.headers["user-agent"] || "",
4263
- bxV: cache.headers["bx-v"] || "2.5.37",
4608
+ bxV: cache.headers["bx-v"] || getQwenBxVersion(),
4264
4609
  bxUa: cache.headers["bx-ua"] || "",
4265
4610
  bxUmidtoken: cache.headers["bx-umidtoken"] || "",
4266
4611
  secChUa: cache.headers["sec-ch-ua"] || void 0,
@@ -4332,7 +4677,7 @@ async function loginToQwen(accountId, email, password) {
4332
4677
  saveAuthSession2(accountId, {
4333
4678
  cookie: cookieStr,
4334
4679
  userAgent: cache.headers["user-agent"] || "",
4335
- bxV: cache.headers["bx-v"] || "2.5.37",
4680
+ bxV: cache.headers["bx-v"] || getQwenBxVersion(),
4336
4681
  bxUa: cache.headers["bx-ua"] || "",
4337
4682
  bxUmidtoken: cache.headers["bx-umidtoken"] || "",
4338
4683
  secChUa: cache.headers["sec-ch-ua"] || void 0,
@@ -4403,7 +4748,7 @@ async function loginViaApi(page, email, password) {
4403
4748
  }
4404
4749
  const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
4405
4750
  const requestId = crypto3.randomUUID();
4406
- const webVersion = getQwenWebVersion() || "0.3.26";
4751
+ const webVersion = getQwenWebVersion();
4407
4752
  const evalRes = await page.evaluate(
4408
4753
  async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
4409
4754
  try {
@@ -4575,6 +4920,15 @@ async function loginViaUi(page, email, password) {
4575
4920
  if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
4576
4921
  return { success: true };
4577
4922
  }
4923
+ if (config.captcha.enabled) {
4924
+ await solveVisibleCaptcha(page, {
4925
+ waitForMs: 1500,
4926
+ maxAttempts: config.captcha.maxAttempts,
4927
+ retryDelayMs: config.captcha.retryDelayMs,
4928
+ settleMs: config.captcha.settleMs,
4929
+ sliderTimeoutMs: config.captcha.sliderTimeoutMs
4930
+ }).catch(() => false);
4931
+ }
4578
4932
  const emailSelector = [
4579
4933
  'input[type="email"]',
4580
4934
  'input[name="email"]',
@@ -4730,10 +5084,11 @@ async function loginViaUi(page, email, password) {
4730
5084
  while (Date.now() < postSubmitDeadline) {
4731
5085
  if (page.isClosed()) break;
4732
5086
  if (config.captcha.enabled) {
4733
- await solveBaxiaCaptcha(page, {
5087
+ await solveVisibleCaptcha(page, {
4734
5088
  waitForMs: 1500,
4735
5089
  maxAttempts: config.captcha.maxAttempts,
4736
- retryDelayMs: config.captcha.retryDelayMs
5090
+ retryDelayMs: config.captcha.retryDelayMs,
5091
+ sliderTimeoutMs: config.captcha.sliderTimeoutMs
4737
5092
  }).catch(() => {
4738
5093
  });
4739
5094
  }
@@ -4856,7 +5211,7 @@ async function refreshAccountToken(accountId) {
4856
5211
  }
4857
5212
  if (refreshToken) {
4858
5213
  try {
4859
- const webVersion = getQwenWebVersion() || "0.3.26";
5214
+ const webVersion = getQwenWebVersion();
4860
5215
  const refreshResult = await page.evaluate(
4861
5216
  async ({ rTok, tz, version }) => {
4862
5217
  try {
@@ -4921,7 +5276,7 @@ async function refreshAccountToken(accountId) {
4921
5276
  saveAuthSession2(accountId, {
4922
5277
  cookie: cookieStr,
4923
5278
  userAgent: cache.headers["user-agent"] || session?.userAgent || "",
4924
- bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
5279
+ bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
4925
5280
  bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
4926
5281
  bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
4927
5282
  secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
@@ -4956,7 +5311,7 @@ async function refreshAccountToken(accountId) {
4956
5311
  saveAuthSession2(accountId, {
4957
5312
  cookie: cookieStr,
4958
5313
  userAgent: cache.headers["user-agent"] || session?.userAgent || "",
4959
- bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
5314
+ bxV: cache.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
4960
5315
  bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
4961
5316
  bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
4962
5317
  secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
@@ -5104,7 +5459,7 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
5104
5459
  cookie: reqHeaders["cookie"] || "",
5105
5460
  "bx-ua": reqHeaders["bx-ua"] || "",
5106
5461
  "bx-umidtoken": reqHeaders["bx-umidtoken"] || "",
5107
- "bx-v": reqHeaders["bx-v"] || "2.5.37",
5462
+ "bx-v": reqHeaders["bx-v"] || getQwenBxVersion(),
5108
5463
  "user-agent": reqHeaders["user-agent"] || "",
5109
5464
  "x-request-id": reqHeaders["x-request-id"] || "",
5110
5465
  "version": reqHeaders["version"] || "",
@@ -5136,6 +5491,9 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
5136
5491
  if (capturedHeaders["version"]) {
5137
5492
  updateQwenWebVersion(capturedHeaders["version"]);
5138
5493
  }
5494
+ if (capturedHeaders["bx-v"]) {
5495
+ updateQwenBxVersion(capturedHeaders["bx-v"]);
5496
+ }
5139
5497
  markAccountHeadersReady(accountId);
5140
5498
  cache.lastRefresh = Date.now();
5141
5499
  cookieCaches.delete(accountId);
@@ -5679,7 +6037,11 @@ function priorityOrderForEviction(accountIds) {
5679
6037
  const ranked = getAccountsByPriority(accountIds.map((id) => ({ id })));
5680
6038
  const rank = /* @__PURE__ */ new Map();
5681
6039
  for (const [index, account] of ranked.entries()) {
5682
- rank.set(account.id, index);
6040
+ if (getAccountCooldownInfo(account.id)) {
6041
+ rank.set(account.id, Number.MAX_SAFE_INTEGER);
6042
+ } else {
6043
+ rank.set(account.id, index);
6044
+ }
5683
6045
  }
5684
6046
  return orderContextsForEviction(
5685
6047
  accountIds,
@@ -5687,14 +6049,15 @@ function priorityOrderForEviction(accountIds) {
5687
6049
  (id) => lastAccountActivity.get(id) ?? 0
5688
6050
  );
5689
6051
  }
5690
- async function evictIdlePlaywrightContextsToLimit() {
5691
- const max = config.playwright.maxActiveContexts;
5692
- if (max <= 0) return 0;
6052
+ async function evictIdlePlaywrightContextsToLimit(targetLimit) {
6053
+ const configuredMax = config.playwright.maxActiveContexts;
6054
+ if (configuredMax <= 0) return 0;
6055
+ const max = targetLimit !== void 0 ? Math.max(0, targetLimit) : configuredMax;
5693
6056
  if (accountPages.size <= max) return 0;
5694
6057
  const candidates = priorityOrderForEviction(
5695
6058
  Array.from(accountPages.keys()).filter((accountId) => {
5696
6059
  if (isAccountServingStream(accountId)) return false;
5697
- if (isAccountRecentlyActive(accountId, 3e4)) return false;
6060
+ if (hasActiveAccountLease(accountId)) return false;
5698
6061
  const mutex = accountMutexes.get(accountId);
5699
6062
  return mutex?.isIdle();
5700
6063
  })
@@ -5707,6 +6070,7 @@ async function evictIdlePlaywrightContextsToLimit() {
5707
6070
  for (const candidate of candidates) {
5708
6071
  if (accountPages.size <= max) break;
5709
6072
  if (isAccountServingStream(candidate.accountId)) continue;
6073
+ if (hasActiveAccountLease(candidate.accountId)) continue;
5710
6074
  const mutex = accountMutexes.get(candidate.accountId);
5711
6075
  if (!mutex?.isIdle()) continue;
5712
6076
  await closePlaywrightForAccount(candidate.accountId).catch((error) => {
@@ -5809,10 +6173,6 @@ async function closePlaywrightForAccount(accountId) {
5809
6173
  release();
5810
6174
  }
5811
6175
  }
5812
- function isAccountRecentlyActive(accountId, maxIdleMs = 3e5) {
5813
- const last = lastAccountActivity.get(accountId) ?? 0;
5814
- return last > 0 && Date.now() - last < maxIdleMs;
5815
- }
5816
6176
  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;
5817
6177
  var init_playwright = __esm({
5818
6178
  "src/services/playwright.ts"() {
@@ -5879,6 +6239,7 @@ var init_auth_playwright = __esm({
5879
6239
  init_errors();
5880
6240
  init_accounts();
5881
6241
  init_config();
6242
+ init_qwen_headers();
5882
6243
  init_playwright();
5883
6244
  init_jwt();
5884
6245
  }
@@ -6044,6 +6405,7 @@ var init_qwen_chat_pool = __esm({
6044
6405
  init_config();
6045
6406
  init_logger();
6046
6407
  init_account_manager();
6408
+ init_waf_isolation();
6047
6409
  init_model_alias();
6048
6410
  init_qwen_url();
6049
6411
  init_qwen_errors();