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.
- package/dist/clean-cache.js +390 -30
- package/dist/delete-chats.js +946 -445
- package/dist/index.js +612 -100
- package/dist/login.js +417 -51
- package/dist/reset-cooldowns.js +769 -407
- package/dist/sync-clients.js +4 -1
- package/package.json +2 -2
- package/src/api/server.ts +8 -4
- package/src/core/config.ts +4 -1
- package/src/core/model-alias.ts +1 -0
- package/src/core/version.ts +1 -1
- package/src/core/watchdog.ts +4 -3
- package/src/routes/chat/account.ts +12 -0
- package/src/routes/chat/streaming.ts +18 -2
- package/src/services/auth-playwright.ts +3 -2
- package/src/services/captcha-coordinator.ts +41 -11
- package/src/services/captcha-solver.ts +400 -2
- package/src/services/chat-cleanup.ts +11 -2
- package/src/services/playwright.ts +135 -50
- package/src/services/qwen-chat-pool.ts +52 -9
- package/src/services/qwen-headers.ts +18 -1
- package/src/services/qwen.ts +35 -7
- package/src/services/session-keeper.ts +70 -8
package/dist/reset-cooldowns.js
CHANGED
|
@@ -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.
|
|
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/
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
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
|
|
1705
|
-
|
|
1706
|
-
return {
|
|
1707
|
-
rss: mem.rss,
|
|
1708
|
-
totalSystemMemory,
|
|
1709
|
-
usagePercent
|
|
1710
|
-
};
|
|
1718
|
+
function qwenOrigin() {
|
|
1719
|
+
return QWEN_ORIGIN;
|
|
1711
1720
|
}
|
|
1712
|
-
var
|
|
1713
|
-
|
|
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/
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
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
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
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
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
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
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
{
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
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 =
|
|
2677
|
-
BAXIA_TRACK_SELECTOR =
|
|
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
|
|
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
|
-
|
|
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"] ||
|
|
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"] ||
|
|
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()
|
|
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
|
|
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()
|
|
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 ||
|
|
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 ||
|
|
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"] ||
|
|
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
|
-
|
|
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
|
|
5692
|
-
if (
|
|
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 (
|
|
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();
|