qwenproxy-cli 1.6.9 → 1.6.11
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 +199 -55
- package/dist/delete-chats.js +269 -78
- package/dist/index.js +290 -88
- package/dist/login.js +203 -67
- package/dist/reset-cooldowns.js +199 -55
- package/package.json +2 -2
- package/src/api/server.ts +8 -4
- 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/captcha-coordinator.ts +36 -8
- package/src/services/chat-cleanup.ts +11 -2
- package/src/services/playwright.ts +244 -74
- package/src/services/qwen.ts +29 -3
package/dist/login.js
CHANGED
|
@@ -3492,7 +3492,19 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
3492
3492
|
if (localStorage.getItem("qwen_token_logged_out_marker")) {
|
|
3493
3493
|
return false;
|
|
3494
3494
|
}
|
|
3495
|
-
const
|
|
3495
|
+
const lsToken = (localStorage.getItem("token") || "").trim();
|
|
3496
|
+
if (lsToken && !/(?:^|;\s*)token=/.test(document.cookie || "")) {
|
|
3497
|
+
try {
|
|
3498
|
+
document.cookie = `token=${encodeURIComponent(lsToken)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
3499
|
+
} catch {
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
const authHeaders = lsToken ? { Authorization: `Bearer ${lsToken}` } : {};
|
|
3503
|
+
const res = await fetch("/api/v1/auths/", {
|
|
3504
|
+
method: "GET",
|
|
3505
|
+
headers: authHeaders,
|
|
3506
|
+
credentials: "include"
|
|
3507
|
+
});
|
|
3496
3508
|
if (res.status !== 200) return false;
|
|
3497
3509
|
const json = await res.json().catch(() => null);
|
|
3498
3510
|
if (!json) return false;
|
|
@@ -3510,6 +3522,7 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
3510
3522
|
try {
|
|
3511
3523
|
const settingsRes = await fetch("/api/v2/users/user/settings", {
|
|
3512
3524
|
method: "GET",
|
|
3525
|
+
headers: authHeaders,
|
|
3513
3526
|
credentials: "include",
|
|
3514
3527
|
signal: AbortSignal.timeout(3e3)
|
|
3515
3528
|
});
|
|
@@ -4297,14 +4310,15 @@ async function getBasicHeaders(accountId) {
|
|
|
4297
4310
|
`\u26A0\uFE0F [Playwright] Header refresh failed for ${accountId}; retaining the previous valid cache: ${getErrorMessage(error)}`
|
|
4298
4311
|
);
|
|
4299
4312
|
}
|
|
4300
|
-
} else if (hadUsableHeaders && headersAge > HEADER_CACHE_TTL * HEADER_REFRESH_THRESHOLD && !cache.refreshInProgress
|
|
4301
|
-
|
|
4313
|
+
} else if (hadUsableHeaders && headersAge > HEADER_CACHE_TTL * HEADER_REFRESH_THRESHOLD && !cache.refreshInProgress && // Header capture types into the chat input and sends a probe message on
|
|
4314
|
+
// the account's page. Doing that while the account is serving a stream
|
|
4315
|
+
// would mutate the live conversation (and can navigate the SPA), so the
|
|
4316
|
+
// proactive refresh waits until the account has no active lease.
|
|
4317
|
+
!hasActiveAccountLease(accountId)) {
|
|
4302
4318
|
refreshHeadersInternal(accountId).catch((error) => {
|
|
4303
4319
|
console.warn(
|
|
4304
4320
|
`\u26A0\uFE0F [Playwright] Background header refresh failed for ${accountId}: ${getErrorMessage(error)}`
|
|
4305
4321
|
);
|
|
4306
|
-
}).finally(() => {
|
|
4307
|
-
cache.refreshInProgress = false;
|
|
4308
4322
|
});
|
|
4309
4323
|
}
|
|
4310
4324
|
if (!hasRequiredQwenHeaders(cache.headers)) {
|
|
@@ -4442,8 +4456,12 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4442
4456
|
if (accountPages.has(account.id)) {
|
|
4443
4457
|
return;
|
|
4444
4458
|
}
|
|
4445
|
-
|
|
4446
|
-
|
|
4459
|
+
if (config.playwright.maxActiveContexts > 0) {
|
|
4460
|
+
await evictIdlePlaywrightContextsToLimit(
|
|
4461
|
+
Math.max(1, config.playwright.maxActiveContexts - 1)
|
|
4462
|
+
).catch(() => {
|
|
4463
|
+
});
|
|
4464
|
+
}
|
|
4447
4465
|
const profilePath = getAccountProfilePath(account.id);
|
|
4448
4466
|
const fingerprint = getFingerprintProfile(account.id);
|
|
4449
4467
|
const { engine, channel } = resolveBrowserEngine(browserType);
|
|
@@ -4668,8 +4686,15 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4668
4686
|
const hasAuthCookie = cookies.some(
|
|
4669
4687
|
(c) => c.name.toLowerCase().includes("token") || c.name.toLowerCase().includes("session")
|
|
4670
4688
|
);
|
|
4689
|
+
let initialLoginAttempted = false;
|
|
4671
4690
|
if (!hasAuthCookie && account.email && account.password) {
|
|
4672
|
-
|
|
4691
|
+
initialLoginAttempted = true;
|
|
4692
|
+
const loggedIn = await loginToQwen(account.id, account.email, account.password);
|
|
4693
|
+
if (!loggedIn) {
|
|
4694
|
+
throw new Error(
|
|
4695
|
+
`Authentication failed for account ${maskEmail(account.email)}`
|
|
4696
|
+
);
|
|
4697
|
+
}
|
|
4673
4698
|
}
|
|
4674
4699
|
try {
|
|
4675
4700
|
await acctPage.goto(qwenUrl("/"), {
|
|
@@ -4679,13 +4704,21 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4679
4704
|
await sleep2(1500);
|
|
4680
4705
|
const currentUrl = acctPage.url();
|
|
4681
4706
|
const isAuthUrl = currentUrl.includes("/auth") || currentUrl.includes("/login");
|
|
4682
|
-
if (isAuthUrl && account.email && account.password) {
|
|
4707
|
+
if (isAuthUrl && !initialLoginAttempted && account.email && account.password) {
|
|
4683
4708
|
console.log(
|
|
4684
4709
|
`[Playwright] Initial login needed for ${maskEmail(account.email)}, authenticating...`
|
|
4685
4710
|
);
|
|
4686
|
-
await loginToQwen(account.id, account.email, account.password);
|
|
4711
|
+
const loggedIn = await loginToQwen(account.id, account.email, account.password);
|
|
4712
|
+
if (!loggedIn) {
|
|
4713
|
+
throw new Error(
|
|
4714
|
+
`Authentication failed for account ${maskEmail(account.email)}`
|
|
4715
|
+
);
|
|
4716
|
+
}
|
|
4687
4717
|
}
|
|
4688
4718
|
} catch (err) {
|
|
4719
|
+
if (err?.message?.includes("Authentication failed for account")) {
|
|
4720
|
+
throw err;
|
|
4721
|
+
}
|
|
4689
4722
|
console.warn(
|
|
4690
4723
|
`\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
|
|
4691
4724
|
);
|
|
@@ -4697,7 +4730,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4697
4730
|
if (!acctPage.isClosed()) {
|
|
4698
4731
|
try {
|
|
4699
4732
|
const currentUrl = new URL(acctPage.url());
|
|
4700
|
-
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname
|
|
4733
|
+
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname.includes("/auth") || currentUrl.pathname.includes("/login") || currentUrl.pathname.includes("_____tmd_____")) {
|
|
4701
4734
|
await acctPage.goto(qwenUrl("/"), {
|
|
4702
4735
|
waitUntil: "domcontentloaded",
|
|
4703
4736
|
timeout: config.timeouts.navigation
|
|
@@ -4715,6 +4748,8 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4715
4748
|
} finally {
|
|
4716
4749
|
release();
|
|
4717
4750
|
}
|
|
4751
|
+
await evictIdlePlaywrightContextsToLimit().catch(() => {
|
|
4752
|
+
});
|
|
4718
4753
|
})();
|
|
4719
4754
|
try {
|
|
4720
4755
|
await initPromise;
|
|
@@ -5234,10 +5269,30 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5234
5269
|
const uiResult = await loginViaUi(page, email, password);
|
|
5235
5270
|
if (uiResult.success) {
|
|
5236
5271
|
cookieCaches.delete(accountId);
|
|
5237
|
-
await saveStorageState(page.context(), accountId);
|
|
5238
5272
|
try {
|
|
5239
|
-
|
|
5240
|
-
|
|
5273
|
+
let liveCookies = await page.context().cookies();
|
|
5274
|
+
let tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
5275
|
+
if (!tokenCookie) {
|
|
5276
|
+
const lsTok = uiResult.token || await page.evaluate(() => (localStorage.getItem("token") || "").trim()).catch(() => "");
|
|
5277
|
+
if (lsTok) {
|
|
5278
|
+
await page.context().addCookies([
|
|
5279
|
+
{
|
|
5280
|
+
name: "token",
|
|
5281
|
+
value: lsTok,
|
|
5282
|
+
domain: ".qwen.ai",
|
|
5283
|
+
path: "/",
|
|
5284
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
5285
|
+
httpOnly: false,
|
|
5286
|
+
secure: true,
|
|
5287
|
+
sameSite: "Lax"
|
|
5288
|
+
}
|
|
5289
|
+
]).catch(() => {
|
|
5290
|
+
});
|
|
5291
|
+
liveCookies = await page.context().cookies();
|
|
5292
|
+
tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5295
|
+
await saveStorageState(page.context(), accountId);
|
|
5241
5296
|
if (tokenCookie) {
|
|
5242
5297
|
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
5243
5298
|
const cache = getHeaderCache(accountId);
|
|
@@ -5246,7 +5301,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
5246
5301
|
markAccountHeadersReady(accountId);
|
|
5247
5302
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5248
5303
|
const exp = parseJwtExpiry(tokenCookie.value);
|
|
5249
|
-
let rTok = uiResult.refreshToken;
|
|
5304
|
+
let rTok = uiResult.refreshToken || liveCookies.find((c) => c.name === "refresh_token")?.value;
|
|
5250
5305
|
if (!rTok) {
|
|
5251
5306
|
try {
|
|
5252
5307
|
rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
@@ -5327,8 +5382,9 @@ async function loginViaApi(page, email, password) {
|
|
|
5327
5382
|
}
|
|
5328
5383
|
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
5329
5384
|
const requestId = crypto3.randomUUID();
|
|
5385
|
+
const webVersion = getQwenWebVersion() || "0.3.26";
|
|
5330
5386
|
const evalRes = await page.evaluate(
|
|
5331
|
-
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz }) => {
|
|
5387
|
+
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
|
|
5332
5388
|
try {
|
|
5333
5389
|
const response = await fetch(signinUrl2, {
|
|
5334
5390
|
method: "POST",
|
|
@@ -5338,7 +5394,7 @@ async function loginViaApi(page, email, password) {
|
|
|
5338
5394
|
accept: "application/json, text/plain, */*",
|
|
5339
5395
|
"content-type": "application/json",
|
|
5340
5396
|
source: "web",
|
|
5341
|
-
version
|
|
5397
|
+
version,
|
|
5342
5398
|
"x-request-origin": "https://chat.qwen.ai",
|
|
5343
5399
|
timezone: tz,
|
|
5344
5400
|
"x-request-id": requestId2
|
|
@@ -5351,7 +5407,14 @@ async function loginViaApi(page, email, password) {
|
|
|
5351
5407
|
return { ok: false, error: e.message };
|
|
5352
5408
|
}
|
|
5353
5409
|
},
|
|
5354
|
-
{
|
|
5410
|
+
{
|
|
5411
|
+
email,
|
|
5412
|
+
password: hashedPassword,
|
|
5413
|
+
signinUrl,
|
|
5414
|
+
requestId,
|
|
5415
|
+
tz: formatAsciiTimezone(),
|
|
5416
|
+
version: webVersion
|
|
5417
|
+
}
|
|
5355
5418
|
).catch(() => null);
|
|
5356
5419
|
let data = evalRes?.data;
|
|
5357
5420
|
let signinSuccess = Boolean(
|
|
@@ -5360,7 +5423,7 @@ async function loginViaApi(page, email, password) {
|
|
|
5360
5423
|
if (!signinSuccess && !data?.data?.code) {
|
|
5361
5424
|
const fallbackUrl = qwenUrl("/api/v2/auths/signin");
|
|
5362
5425
|
const fallbackRes = await page.evaluate(
|
|
5363
|
-
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz }) => {
|
|
5426
|
+
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz, version }) => {
|
|
5364
5427
|
try {
|
|
5365
5428
|
const response = await fetch(fallbackUrl2, {
|
|
5366
5429
|
method: "POST",
|
|
@@ -5370,7 +5433,7 @@ async function loginViaApi(page, email, password) {
|
|
|
5370
5433
|
accept: "application/json, text/plain, */*",
|
|
5371
5434
|
"content-type": "application/json",
|
|
5372
5435
|
source: "web",
|
|
5373
|
-
version
|
|
5436
|
+
version,
|
|
5374
5437
|
timezone: tz,
|
|
5375
5438
|
"x-request-id": requestId2
|
|
5376
5439
|
},
|
|
@@ -5382,7 +5445,14 @@ async function loginViaApi(page, email, password) {
|
|
|
5382
5445
|
return { ok: false, error: e.message };
|
|
5383
5446
|
}
|
|
5384
5447
|
},
|
|
5385
|
-
{
|
|
5448
|
+
{
|
|
5449
|
+
email,
|
|
5450
|
+
password: hashedPassword,
|
|
5451
|
+
fallbackUrl,
|
|
5452
|
+
requestId,
|
|
5453
|
+
tz: formatAsciiTimezone(),
|
|
5454
|
+
version: webVersion
|
|
5455
|
+
}
|
|
5386
5456
|
).catch(() => null);
|
|
5387
5457
|
if (fallbackRes?.data) {
|
|
5388
5458
|
data = fallbackRes.data;
|
|
@@ -5607,28 +5677,34 @@ async function loginViaUi(page, email, password) {
|
|
|
5607
5677
|
await sleep2(500);
|
|
5608
5678
|
const submitSelector = 'button.qwenchat-auth-pc-submit-button, button[type="submit"], button:has-text("Log in"), button:has-text("Sign in"), button:has-text("Fazer login"), button:has-text("Entrar"), button:has-text("Iniciar sesi\xF3n"), button:has-text("\u767B\u5F55")';
|
|
5609
5679
|
const submitButton = page.locator(submitSelector).first();
|
|
5610
|
-
|
|
5611
|
-
try {
|
|
5612
|
-
const btn = document.querySelector(sel);
|
|
5613
|
-
if (btn) {
|
|
5614
|
-
btn.removeAttribute("disabled");
|
|
5615
|
-
btn.classList.remove("ant-btn-disabled");
|
|
5616
|
-
btn.click();
|
|
5617
|
-
}
|
|
5618
|
-
} catch {
|
|
5619
|
-
}
|
|
5620
|
-
}, submitSelector).catch(() => {
|
|
5621
|
-
});
|
|
5680
|
+
let submitted = false;
|
|
5622
5681
|
try {
|
|
5623
5682
|
if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
|
|
5624
|
-
await submitButton.click({
|
|
5683
|
+
await submitButton.click({ timeout: 2e3 }).catch(() => {
|
|
5625
5684
|
});
|
|
5685
|
+
submitted = true;
|
|
5626
5686
|
}
|
|
5627
5687
|
} catch {
|
|
5628
5688
|
}
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5689
|
+
if (!submitted) {
|
|
5690
|
+
await page.evaluate(() => {
|
|
5691
|
+
try {
|
|
5692
|
+
const btn = document.querySelector(
|
|
5693
|
+
'button.qwenchat-auth-pc-submit-button, button[type="submit"]'
|
|
5694
|
+
);
|
|
5695
|
+
if (btn) {
|
|
5696
|
+
btn.removeAttribute("disabled");
|
|
5697
|
+
btn.classList.remove("ant-btn-disabled");
|
|
5698
|
+
btn.click();
|
|
5699
|
+
}
|
|
5700
|
+
} catch {
|
|
5701
|
+
}
|
|
5702
|
+
}).catch(() => {
|
|
5703
|
+
});
|
|
5704
|
+
const passInput = page.locator(passwordSelector).first();
|
|
5705
|
+
await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
|
|
5706
|
+
});
|
|
5707
|
+
}
|
|
5632
5708
|
const postSubmitDeadline = Date.now() + 15e3;
|
|
5633
5709
|
while (Date.now() < postSubmitDeadline) {
|
|
5634
5710
|
if (page.isClosed()) break;
|
|
@@ -5646,9 +5722,12 @@ async function loginViaUi(page, email, password) {
|
|
|
5646
5722
|
".ant-form-item-explain-error",
|
|
5647
5723
|
".ant-message-error",
|
|
5648
5724
|
".ant-message-notice",
|
|
5725
|
+
".ant-message-custom-content",
|
|
5726
|
+
".ant-notification-notice",
|
|
5649
5727
|
'[role="alert"]',
|
|
5650
5728
|
".qwenchat-auth-error",
|
|
5651
|
-
".auth-error-message"
|
|
5729
|
+
".auth-error-message",
|
|
5730
|
+
".qwenchat-toast"
|
|
5652
5731
|
].join(", ");
|
|
5653
5732
|
const errorEl = page.locator(errorSelector).first();
|
|
5654
5733
|
if (await errorEl.isVisible().catch(() => false)) {
|
|
@@ -5662,7 +5741,15 @@ async function loginViaUi(page, email, password) {
|
|
|
5662
5741
|
};
|
|
5663
5742
|
}
|
|
5664
5743
|
}
|
|
5665
|
-
const codeSelector =
|
|
5744
|
+
const codeSelector = [
|
|
5745
|
+
'input[placeholder*="code" i]',
|
|
5746
|
+
'input[placeholder*="c\xF3digo" i]',
|
|
5747
|
+
'input[name*="code" i]',
|
|
5748
|
+
".qwenchat-verification-code-input",
|
|
5749
|
+
".qwenchat-verification-code-input-cell",
|
|
5750
|
+
'[aria-label*="Verification code" i]',
|
|
5751
|
+
'[aria-label*="c\xF3digo de verifica\xE7\xE3o" i]'
|
|
5752
|
+
].join(", ");
|
|
5666
5753
|
const codeInput = page.locator(codeSelector).first();
|
|
5667
5754
|
if (await codeInput.isVisible().catch(() => false)) {
|
|
5668
5755
|
return {
|
|
@@ -5672,16 +5759,44 @@ async function loginViaUi(page, email, password) {
|
|
|
5672
5759
|
}
|
|
5673
5760
|
try {
|
|
5674
5761
|
const liveCookies = await page.context().cookies();
|
|
5675
|
-
|
|
5676
|
-
|
|
5762
|
+
const rTokCookie = liveCookies.find((c) => c.name === "refresh_token")?.value;
|
|
5763
|
+
const tokCookie = liveCookies.find((c) => c.name === "token")?.value;
|
|
5764
|
+
if (tokCookie) {
|
|
5765
|
+
return { success: true, token: tokCookie, refreshToken: rTokCookie };
|
|
5677
5766
|
}
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5767
|
+
const currentUrl = page.url();
|
|
5768
|
+
if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
|
|
5769
|
+
const lsTok = await page.evaluate(() => {
|
|
5770
|
+
const t = (localStorage.getItem("token") || "").trim();
|
|
5771
|
+
if (t) {
|
|
5772
|
+
try {
|
|
5773
|
+
document.cookie = `token=${encodeURIComponent(t)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
5774
|
+
} catch {
|
|
5775
|
+
}
|
|
5776
|
+
}
|
|
5777
|
+
return t;
|
|
5778
|
+
}).catch(() => "");
|
|
5779
|
+
if (lsTok) {
|
|
5780
|
+
await page.context().addCookies([
|
|
5781
|
+
{
|
|
5782
|
+
name: "token",
|
|
5783
|
+
value: lsTok,
|
|
5784
|
+
domain: ".qwen.ai",
|
|
5785
|
+
path: "/",
|
|
5786
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
5787
|
+
httpOnly: false,
|
|
5788
|
+
secure: true,
|
|
5789
|
+
sameSite: "Lax"
|
|
5790
|
+
}
|
|
5791
|
+
]).catch(() => {
|
|
5792
|
+
});
|
|
5793
|
+
return { success: true, token: lsTok, refreshToken: rTokCookie };
|
|
5794
|
+
}
|
|
5795
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
5796
|
+
return { success: true, refreshToken: rTokCookie };
|
|
5797
|
+
}
|
|
5684
5798
|
}
|
|
5799
|
+
} catch {
|
|
5685
5800
|
}
|
|
5686
5801
|
await sleep2(1e3);
|
|
5687
5802
|
}
|
|
@@ -5711,10 +5826,18 @@ async function refreshAccountToken(accountId) {
|
|
|
5711
5826
|
} catch {
|
|
5712
5827
|
}
|
|
5713
5828
|
}
|
|
5829
|
+
if (!refreshToken) {
|
|
5830
|
+
try {
|
|
5831
|
+
const liveCookies = await page.context().cookies();
|
|
5832
|
+
refreshToken = liveCookies.find((c) => c.name === "refresh_token")?.value;
|
|
5833
|
+
} catch {
|
|
5834
|
+
}
|
|
5835
|
+
}
|
|
5714
5836
|
if (refreshToken) {
|
|
5715
5837
|
try {
|
|
5838
|
+
const webVersion = getQwenWebVersion() || "0.3.26";
|
|
5716
5839
|
const refreshResult = await page.evaluate(
|
|
5717
|
-
async ({ rTok, tz }) => {
|
|
5840
|
+
async ({ rTok, tz, version }) => {
|
|
5718
5841
|
try {
|
|
5719
5842
|
const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
5720
5843
|
method: "GET",
|
|
@@ -5722,7 +5845,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5722
5845
|
headers: {
|
|
5723
5846
|
accept: "application/json, text/plain, */*",
|
|
5724
5847
|
source: "web",
|
|
5725
|
-
version
|
|
5848
|
+
version,
|
|
5726
5849
|
"x-request-origin": "https://chat.qwen.ai",
|
|
5727
5850
|
timezone: tz,
|
|
5728
5851
|
authorization: `Bearer ${rTok}`
|
|
@@ -5734,7 +5857,7 @@ async function refreshAccountToken(accountId) {
|
|
|
5734
5857
|
return { ok: false, error: e.message };
|
|
5735
5858
|
}
|
|
5736
5859
|
},
|
|
5737
|
-
{ rTok: refreshToken, tz: formatAsciiTimezone() }
|
|
5860
|
+
{ rTok: refreshToken, tz: formatAsciiTimezone(), version: webVersion }
|
|
5738
5861
|
);
|
|
5739
5862
|
const json = refreshResult?.data;
|
|
5740
5863
|
if (json && json.success === true && json.data) {
|
|
@@ -6395,19 +6518,26 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
6395
6518
|
await executeReauth();
|
|
6396
6519
|
} else {
|
|
6397
6520
|
try {
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6521
|
+
const currentUrl = typeof page.url === "function" ? page.url() : "";
|
|
6522
|
+
const needsNavigation = !currentUrl.startsWith(qwenOrigin()) || currentUrl.includes("/auth") || currentUrl.includes("/login") || currentUrl.includes("_____tmd_____");
|
|
6523
|
+
if (needsNavigation) {
|
|
6524
|
+
await page.goto(qwenUrl("/"), {
|
|
6525
|
+
waitUntil: "domcontentloaded",
|
|
6526
|
+
timeout: Math.min(
|
|
6527
|
+
config.timeouts.navigation,
|
|
6528
|
+
boundedTimeoutMs,
|
|
6529
|
+
SESSION_PROBE_NAVIGATION_TIMEOUT_MS
|
|
6530
|
+
)
|
|
6531
|
+
});
|
|
6532
|
+
await sleep2(2e3);
|
|
6533
|
+
}
|
|
6534
|
+
const url = typeof page.url === "function" ? page.url() : "";
|
|
6408
6535
|
const isAuthUrl = url.includes("auth") || url.includes("login");
|
|
6409
6536
|
if (isAuthUrl) {
|
|
6410
|
-
await
|
|
6537
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
6538
|
+
if (!refreshed.success) {
|
|
6539
|
+
await executeReauth();
|
|
6540
|
+
}
|
|
6411
6541
|
}
|
|
6412
6542
|
} catch (navErr) {
|
|
6413
6543
|
console.warn(
|
|
@@ -6464,7 +6594,7 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
6464
6594
|
if (capturedPage && !capturedPage.isClosed()) {
|
|
6465
6595
|
try {
|
|
6466
6596
|
const currentUrl = new URL(capturedPage.url());
|
|
6467
|
-
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname
|
|
6597
|
+
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname.includes("/auth") || currentUrl.pathname.includes("/login") || currentUrl.pathname.includes("_____tmd_____")) {
|
|
6468
6598
|
await capturedPage.goto(qwenUrl("/"), {
|
|
6469
6599
|
waitUntil: "domcontentloaded",
|
|
6470
6600
|
timeout: Math.min(config.timeouts.navigation, boundedTimeoutMs)
|
|
@@ -6780,7 +6910,11 @@ function priorityOrderForEviction(accountIds) {
|
|
|
6780
6910
|
const ranked = getAccountsByPriority(accountIds.map((id) => ({ id })));
|
|
6781
6911
|
const rank = /* @__PURE__ */ new Map();
|
|
6782
6912
|
for (const [index, account] of ranked.entries()) {
|
|
6783
|
-
|
|
6913
|
+
if (getAccountCooldownInfo(account.id)) {
|
|
6914
|
+
rank.set(account.id, Number.MAX_SAFE_INTEGER);
|
|
6915
|
+
} else {
|
|
6916
|
+
rank.set(account.id, index);
|
|
6917
|
+
}
|
|
6784
6918
|
}
|
|
6785
6919
|
return orderContextsForEviction(
|
|
6786
6920
|
accountIds,
|
|
@@ -6817,14 +6951,15 @@ async function closeIdlePlaywrightAccounts(idleMs) {
|
|
|
6817
6951
|
}
|
|
6818
6952
|
return closed;
|
|
6819
6953
|
}
|
|
6820
|
-
async function evictIdlePlaywrightContextsToLimit() {
|
|
6821
|
-
const
|
|
6822
|
-
if (
|
|
6954
|
+
async function evictIdlePlaywrightContextsToLimit(targetLimit) {
|
|
6955
|
+
const configuredMax = config.playwright.maxActiveContexts;
|
|
6956
|
+
if (configuredMax <= 0) return 0;
|
|
6957
|
+
const max = targetLimit !== void 0 ? Math.max(0, targetLimit) : configuredMax;
|
|
6823
6958
|
if (accountPages.size <= max) return 0;
|
|
6824
6959
|
const candidates = priorityOrderForEviction(
|
|
6825
6960
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
6826
6961
|
if (isAccountServingStream(accountId)) return false;
|
|
6827
|
-
if (
|
|
6962
|
+
if (hasActiveAccountLease(accountId)) return false;
|
|
6828
6963
|
const mutex = accountMutexes.get(accountId);
|
|
6829
6964
|
return mutex?.isIdle();
|
|
6830
6965
|
})
|
|
@@ -6837,6 +6972,7 @@ async function evictIdlePlaywrightContextsToLimit() {
|
|
|
6837
6972
|
for (const candidate of candidates) {
|
|
6838
6973
|
if (accountPages.size <= max) break;
|
|
6839
6974
|
if (isAccountServingStream(candidate.accountId)) continue;
|
|
6975
|
+
if (hasActiveAccountLease(candidate.accountId)) continue;
|
|
6840
6976
|
const mutex = accountMutexes.get(candidate.accountId);
|
|
6841
6977
|
if (!mutex?.isIdle()) continue;
|
|
6842
6978
|
await closePlaywrightForAccount(candidate.accountId).catch((error) => {
|