qwenproxy-cli 1.4.7 → 1.5.0
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 +38 -5
- package/dist/delete-chats.js +262 -74
- package/dist/index.js +327 -111
- package/dist/login.js +169 -59
- package/dist/reset-cooldowns.js +25 -5
- package/package.json +1 -1
- package/src/core/account-manager.ts +9 -0
- package/src/core/database.ts +10 -5
- package/src/core/server-log-buffer.ts +10 -3
- package/src/core/version.ts +1 -1
- package/src/routes/chat/account.ts +22 -10
- package/src/routes/chat/helpers.ts +29 -1
- package/src/routes/chat/retry-policy.ts +9 -8
- package/src/routes/chat/streaming.ts +12 -5
- package/src/routes/upload.ts +19 -14
- package/src/services/playwright.ts +180 -58
- package/src/services/qwen-chat-pool.ts +18 -5
- package/src/services/qwen-headers.ts +2 -1
- package/src/services/qwen.ts +65 -15
package/dist/clean-cache.js
CHANGED
|
@@ -314,6 +314,7 @@ function runMigrations(db2) {
|
|
|
314
314
|
"sec_ch_ua_mobile TEXT",
|
|
315
315
|
"sec_ch_ua_platform TEXT",
|
|
316
316
|
"version TEXT",
|
|
317
|
+
"refresh_token TEXT",
|
|
317
318
|
"captured_at INTEGER DEFAULT 0"
|
|
318
319
|
];
|
|
319
320
|
for (const col of authSessionCols) {
|
|
@@ -392,11 +393,11 @@ function saveAuthSession(accountId, session) {
|
|
|
392
393
|
INSERT OR REPLACE INTO qwen_auth_sessions (
|
|
393
394
|
account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
|
|
394
395
|
sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
|
|
395
|
-
user_id, token_expires_at, captured_at, updated_at
|
|
396
|
+
user_id, token_expires_at, refresh_token, captured_at, updated_at
|
|
396
397
|
) VALUES (
|
|
397
398
|
?, ?, ?, ?, ?, ?,
|
|
398
399
|
?, ?, ?, ?,
|
|
399
|
-
?, ?, ?, datetime('now')
|
|
400
|
+
?, ?, ?, ?, datetime('now')
|
|
400
401
|
)
|
|
401
402
|
`);
|
|
402
403
|
stmt.run(
|
|
@@ -412,6 +413,7 @@ function saveAuthSession(accountId, session) {
|
|
|
412
413
|
session.version || null,
|
|
413
414
|
session.userId || null,
|
|
414
415
|
session.tokenExpiresAt || null,
|
|
416
|
+
session.refreshToken || null,
|
|
415
417
|
session.capturedAt ?? Date.now()
|
|
416
418
|
);
|
|
417
419
|
}
|
|
@@ -420,7 +422,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
420
422
|
const row = database.prepare(
|
|
421
423
|
`SELECT account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
|
|
422
424
|
sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
|
|
423
|
-
user_id, token_expires_at, captured_at
|
|
425
|
+
user_id, token_expires_at, refresh_token, captured_at
|
|
424
426
|
FROM qwen_auth_sessions WHERE account_id = ?`
|
|
425
427
|
).get(accountId);
|
|
426
428
|
if (!row) return null;
|
|
@@ -428,7 +430,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
428
430
|
if (capturedAt <= 0 || Date.now() - capturedAt > maxAgeMs) {
|
|
429
431
|
return null;
|
|
430
432
|
}
|
|
431
|
-
if (row.token_expires_at) {
|
|
433
|
+
if (!row.refresh_token && row.token_expires_at) {
|
|
432
434
|
const tokenExpMs = Number(row.token_expires_at) * 1e3;
|
|
433
435
|
if (tokenExpMs <= Date.now() + 5 * 60 * 1e3) {
|
|
434
436
|
return null;
|
|
@@ -450,6 +452,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
450
452
|
version: row.version || void 0,
|
|
451
453
|
userId: row.user_id || void 0,
|
|
452
454
|
tokenExpiresAt: row.token_expires_at ? Number(row.token_expires_at) : void 0,
|
|
455
|
+
refreshToken: row.refresh_token || void 0,
|
|
453
456
|
capturedAt
|
|
454
457
|
};
|
|
455
458
|
}
|
|
@@ -1912,7 +1915,15 @@ function defaultCooldownDurationMs() {
|
|
|
1912
1915
|
return computeQuotaCooldownMs(Date.now());
|
|
1913
1916
|
}
|
|
1914
1917
|
function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
|
|
1918
|
+
if (cooldownMs !== void 0 && cooldownMs <= 0) {
|
|
1919
|
+
clearAccountCooldown(accountId);
|
|
1920
|
+
return;
|
|
1921
|
+
}
|
|
1915
1922
|
const duration = cooldownMs ?? defaultCooldownDurationMs();
|
|
1923
|
+
if (duration <= 0) {
|
|
1924
|
+
clearAccountCooldown(accountId);
|
|
1925
|
+
return;
|
|
1926
|
+
}
|
|
1916
1927
|
const until = Date.now() + duration;
|
|
1917
1928
|
const cooldownReason = reason ?? "RateLimited";
|
|
1918
1929
|
cooldowns.set(accountId, {
|
|
@@ -1935,6 +1946,19 @@ function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
|
|
|
1935
1946
|
);
|
|
1936
1947
|
}
|
|
1937
1948
|
}
|
|
1949
|
+
function clearAccountCooldown(accountId) {
|
|
1950
|
+
cooldowns.delete(accountId);
|
|
1951
|
+
if (accountId !== "global") {
|
|
1952
|
+
try {
|
|
1953
|
+
updateAccountCooldown(accountId, 0, null);
|
|
1954
|
+
} catch (err) {
|
|
1955
|
+
console.error(
|
|
1956
|
+
`\u274C [AccountManager] Failed to clear cooldown in DB for ${accountId}:`,
|
|
1957
|
+
err.message
|
|
1958
|
+
);
|
|
1959
|
+
}
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1938
1962
|
function markAccountHeadersReady(accountId) {
|
|
1939
1963
|
if (!accountId || accountId === "global") return;
|
|
1940
1964
|
headersReadyAccounts.add(accountId);
|
|
@@ -3812,6 +3836,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
3812
3836
|
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
|
|
3813
3837
|
version: cache.headers["version"] || void 0,
|
|
3814
3838
|
tokenExpiresAt: exp || void 0,
|
|
3839
|
+
refreshToken: apiResult.refreshToken,
|
|
3815
3840
|
capturedAt: Date.now()
|
|
3816
3841
|
});
|
|
3817
3842
|
}
|
|
@@ -3845,6 +3870,13 @@ async function loginToQwen(accountId, email, password) {
|
|
|
3845
3870
|
markAccountHeadersReady(accountId);
|
|
3846
3871
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3847
3872
|
const exp = parseJwtExpiry(tokenCookie.value);
|
|
3873
|
+
let rTok = uiResult.refreshToken;
|
|
3874
|
+
if (!rTok) {
|
|
3875
|
+
try {
|
|
3876
|
+
rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
3877
|
+
} catch {
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3848
3880
|
saveAuthSession2(accountId, {
|
|
3849
3881
|
cookie: cookieStr,
|
|
3850
3882
|
userAgent: cache.headers["user-agent"] || "",
|
|
@@ -3856,6 +3888,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
3856
3888
|
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
|
|
3857
3889
|
version: cache.headers["version"] || void 0,
|
|
3858
3890
|
tokenExpiresAt: exp || void 0,
|
|
3891
|
+
refreshToken: rTok,
|
|
3859
3892
|
capturedAt: Date.now()
|
|
3860
3893
|
});
|
|
3861
3894
|
}
|
|
@@ -4034,7 +4067,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4034
4067
|
});
|
|
4035
4068
|
await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
|
|
4036
4069
|
});
|
|
4037
|
-
return { success: true };
|
|
4070
|
+
return { success: true, token, refreshToken };
|
|
4038
4071
|
}
|
|
4039
4072
|
}
|
|
4040
4073
|
return {
|
package/dist/delete-chats.js
CHANGED
|
@@ -314,6 +314,7 @@ function runMigrations(db2) {
|
|
|
314
314
|
"sec_ch_ua_mobile TEXT",
|
|
315
315
|
"sec_ch_ua_platform TEXT",
|
|
316
316
|
"version TEXT",
|
|
317
|
+
"refresh_token TEXT",
|
|
317
318
|
"captured_at INTEGER DEFAULT 0"
|
|
318
319
|
];
|
|
319
320
|
for (const col of authSessionCols) {
|
|
@@ -392,11 +393,11 @@ function saveAuthSession(accountId, session) {
|
|
|
392
393
|
INSERT OR REPLACE INTO qwen_auth_sessions (
|
|
393
394
|
account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
|
|
394
395
|
sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
|
|
395
|
-
user_id, token_expires_at, captured_at, updated_at
|
|
396
|
+
user_id, token_expires_at, refresh_token, captured_at, updated_at
|
|
396
397
|
) VALUES (
|
|
397
398
|
?, ?, ?, ?, ?, ?,
|
|
398
399
|
?, ?, ?, ?,
|
|
399
|
-
?, ?, ?, datetime('now')
|
|
400
|
+
?, ?, ?, ?, datetime('now')
|
|
400
401
|
)
|
|
401
402
|
`);
|
|
402
403
|
stmt.run(
|
|
@@ -412,6 +413,7 @@ function saveAuthSession(accountId, session) {
|
|
|
412
413
|
session.version || null,
|
|
413
414
|
session.userId || null,
|
|
414
415
|
session.tokenExpiresAt || null,
|
|
416
|
+
session.refreshToken || null,
|
|
415
417
|
session.capturedAt ?? Date.now()
|
|
416
418
|
);
|
|
417
419
|
}
|
|
@@ -420,7 +422,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
420
422
|
const row = database.prepare(
|
|
421
423
|
`SELECT account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
|
|
422
424
|
sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
|
|
423
|
-
user_id, token_expires_at, captured_at
|
|
425
|
+
user_id, token_expires_at, refresh_token, captured_at
|
|
424
426
|
FROM qwen_auth_sessions WHERE account_id = ?`
|
|
425
427
|
).get(accountId);
|
|
426
428
|
if (!row) return null;
|
|
@@ -428,7 +430,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
428
430
|
if (capturedAt <= 0 || Date.now() - capturedAt > maxAgeMs) {
|
|
429
431
|
return null;
|
|
430
432
|
}
|
|
431
|
-
if (row.token_expires_at) {
|
|
433
|
+
if (!row.refresh_token && row.token_expires_at) {
|
|
432
434
|
const tokenExpMs = Number(row.token_expires_at) * 1e3;
|
|
433
435
|
if (tokenExpMs <= Date.now() + 5 * 60 * 1e3) {
|
|
434
436
|
return null;
|
|
@@ -450,6 +452,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
|
|
|
450
452
|
version: row.version || void 0,
|
|
451
453
|
userId: row.user_id || void 0,
|
|
452
454
|
tokenExpiresAt: row.token_expires_at ? Number(row.token_expires_at) : void 0,
|
|
455
|
+
refreshToken: row.refresh_token || void 0,
|
|
453
456
|
capturedAt
|
|
454
457
|
};
|
|
455
458
|
}
|
|
@@ -1975,7 +1978,15 @@ function defaultCooldownDurationMs() {
|
|
|
1975
1978
|
return computeQuotaCooldownMs(Date.now());
|
|
1976
1979
|
}
|
|
1977
1980
|
function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
|
|
1981
|
+
if (cooldownMs !== void 0 && cooldownMs <= 0) {
|
|
1982
|
+
clearAccountCooldown(accountId);
|
|
1983
|
+
return;
|
|
1984
|
+
}
|
|
1978
1985
|
const duration = cooldownMs ?? defaultCooldownDurationMs();
|
|
1986
|
+
if (duration <= 0) {
|
|
1987
|
+
clearAccountCooldown(accountId);
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1979
1990
|
const until = Date.now() + duration;
|
|
1980
1991
|
const cooldownReason = reason ?? "RateLimited";
|
|
1981
1992
|
cooldowns.set(accountId, {
|
|
@@ -1998,6 +2009,19 @@ function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
|
|
|
1998
2009
|
);
|
|
1999
2010
|
}
|
|
2000
2011
|
}
|
|
2012
|
+
function clearAccountCooldown(accountId) {
|
|
2013
|
+
cooldowns.delete(accountId);
|
|
2014
|
+
if (accountId !== "global") {
|
|
2015
|
+
try {
|
|
2016
|
+
updateAccountCooldown(accountId, 0, null);
|
|
2017
|
+
} catch (err) {
|
|
2018
|
+
console.error(
|
|
2019
|
+
`\u274C [AccountManager] Failed to clear cooldown in DB for ${accountId}:`,
|
|
2020
|
+
err.message
|
|
2021
|
+
);
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2001
2025
|
function markAccountHeadersReady(accountId) {
|
|
2002
2026
|
if (!accountId || accountId === "global") return;
|
|
2003
2027
|
headersReadyAccounts.add(accountId);
|
|
@@ -2766,7 +2790,8 @@ function buildQwenRequestHeaders(opts) {
|
|
|
2766
2790
|
"bx-v": opts.bxV || "2.5.37",
|
|
2767
2791
|
source: "web",
|
|
2768
2792
|
version: opts.version || getQwenWebVersion(),
|
|
2769
|
-
timezone: opts.extra?.timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
2793
|
+
timezone: opts.extra?.timezone || opts.extra?.Timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
2794
|
+
Timezone: opts.extra?.Timezone || opts.extra?.timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
2770
2795
|
// Use the real browser client-hints when captured (anti-hardcoded); fall
|
|
2771
2796
|
// back to the static fingerprint otherwise.
|
|
2772
2797
|
"sec-ch-ua": opts.secChUa || `"Google Chrome";v="${getChromeMajor()}", "Chromium";v="${getChromeMajor()}", "Not.A/Brand";v="99"`,
|
|
@@ -3052,6 +3077,7 @@ __export(playwright_exports, {
|
|
|
3052
3077
|
parseCookiesForBrowser: () => parseCookiesForBrowser,
|
|
3053
3078
|
pruneAllPlaywrightProfiles: () => pruneAllPlaywrightProfiles,
|
|
3054
3079
|
prunePlaywrightProfileCaches: () => prunePlaywrightProfileCaches,
|
|
3080
|
+
refreshAccountToken: () => refreshAccountToken,
|
|
3055
3081
|
refreshHeaders: () => refreshHeaders,
|
|
3056
3082
|
refreshHeadersWithProfileReset: () => refreshHeadersWithProfileReset,
|
|
3057
3083
|
registerPlaywrightAccountForTests: () => registerPlaywrightAccountForTests,
|
|
@@ -4687,6 +4713,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4687
4713
|
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
|
|
4688
4714
|
version: cache.headers["version"] || void 0,
|
|
4689
4715
|
tokenExpiresAt: exp || void 0,
|
|
4716
|
+
refreshToken: apiResult.refreshToken,
|
|
4690
4717
|
capturedAt: Date.now()
|
|
4691
4718
|
});
|
|
4692
4719
|
}
|
|
@@ -4720,6 +4747,13 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4720
4747
|
markAccountHeadersReady(accountId);
|
|
4721
4748
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4722
4749
|
const exp = parseJwtExpiry(tokenCookie.value);
|
|
4750
|
+
let rTok = uiResult.refreshToken;
|
|
4751
|
+
if (!rTok) {
|
|
4752
|
+
try {
|
|
4753
|
+
rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
4754
|
+
} catch {
|
|
4755
|
+
}
|
|
4756
|
+
}
|
|
4723
4757
|
saveAuthSession2(accountId, {
|
|
4724
4758
|
cookie: cookieStr,
|
|
4725
4759
|
userAgent: cache.headers["user-agent"] || "",
|
|
@@ -4731,6 +4765,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4731
4765
|
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
|
|
4732
4766
|
version: cache.headers["version"] || void 0,
|
|
4733
4767
|
tokenExpiresAt: exp || void 0,
|
|
4768
|
+
refreshToken: rTok,
|
|
4734
4769
|
capturedAt: Date.now()
|
|
4735
4770
|
});
|
|
4736
4771
|
}
|
|
@@ -4909,7 +4944,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4909
4944
|
});
|
|
4910
4945
|
await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
|
|
4911
4946
|
});
|
|
4912
|
-
return { success: true };
|
|
4947
|
+
return { success: true, token, refreshToken };
|
|
4913
4948
|
}
|
|
4914
4949
|
}
|
|
4915
4950
|
return {
|
|
@@ -5152,6 +5187,137 @@ async function loginViaUi(page, email, password) {
|
|
|
5152
5187
|
return { success: false, reason: err?.message || String(err) };
|
|
5153
5188
|
}
|
|
5154
5189
|
}
|
|
5190
|
+
async function refreshAccountToken(accountId) {
|
|
5191
|
+
const page = accountPages.get(accountId);
|
|
5192
|
+
if (!page || page.isClosed()) {
|
|
5193
|
+
return { success: false, error: "Account page not active" };
|
|
5194
|
+
}
|
|
5195
|
+
const { getValidAuthSession: getValidAuthSession2, saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5196
|
+
const session = getValidAuthSession2(accountId);
|
|
5197
|
+
let refreshToken = session?.refreshToken;
|
|
5198
|
+
if (!refreshToken) {
|
|
5199
|
+
try {
|
|
5200
|
+
refreshToken = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
5201
|
+
} catch {
|
|
5202
|
+
}
|
|
5203
|
+
}
|
|
5204
|
+
if (refreshToken) {
|
|
5205
|
+
try {
|
|
5206
|
+
const refreshResult = await page.evaluate(
|
|
5207
|
+
async ({ rTok }) => {
|
|
5208
|
+
try {
|
|
5209
|
+
const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
5210
|
+
method: "GET",
|
|
5211
|
+
credentials: "include",
|
|
5212
|
+
headers: {
|
|
5213
|
+
accept: "application/json, text/plain, */*",
|
|
5214
|
+
source: "web",
|
|
5215
|
+
version: "0.3.11",
|
|
5216
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
5217
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
5218
|
+
authorization: `Bearer ${rTok}`
|
|
5219
|
+
}
|
|
5220
|
+
});
|
|
5221
|
+
const json2 = await response.json().catch(() => null);
|
|
5222
|
+
return { ok: response.ok, status: response.status, data: json2 };
|
|
5223
|
+
} catch (e) {
|
|
5224
|
+
return { ok: false, error: e.message };
|
|
5225
|
+
}
|
|
5226
|
+
},
|
|
5227
|
+
{ rTok: refreshToken }
|
|
5228
|
+
);
|
|
5229
|
+
const json = refreshResult?.data;
|
|
5230
|
+
if (json && json.success === true && json.data) {
|
|
5231
|
+
const newAccessToken = json.data.access_token || json.data.token;
|
|
5232
|
+
const newRefreshToken = json.data.refresh_token || refreshToken;
|
|
5233
|
+
if (newAccessToken) {
|
|
5234
|
+
await page.context().addCookies([
|
|
5235
|
+
{
|
|
5236
|
+
name: "token",
|
|
5237
|
+
value: newAccessToken,
|
|
5238
|
+
domain: ".qwen.ai",
|
|
5239
|
+
path: "/",
|
|
5240
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
5241
|
+
httpOnly: false,
|
|
5242
|
+
secure: true,
|
|
5243
|
+
sameSite: "Lax"
|
|
5244
|
+
}
|
|
5245
|
+
]);
|
|
5246
|
+
await page.evaluate(
|
|
5247
|
+
({ tok, rTok }) => {
|
|
5248
|
+
try {
|
|
5249
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
5250
|
+
localStorage.setItem("token", tok);
|
|
5251
|
+
localStorage.setItem("access_token", tok);
|
|
5252
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
5253
|
+
document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
5254
|
+
} catch {
|
|
5255
|
+
}
|
|
5256
|
+
},
|
|
5257
|
+
{ tok: newAccessToken, rTok: newRefreshToken }
|
|
5258
|
+
).catch(() => {
|
|
5259
|
+
});
|
|
5260
|
+
const liveCookies = await page.context().cookies();
|
|
5261
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
5262
|
+
const cache = getHeaderCache(accountId);
|
|
5263
|
+
cache.headers.cookie = cookieStr;
|
|
5264
|
+
cache.lastRefresh = Date.now();
|
|
5265
|
+
markAccountHeadersReady(accountId);
|
|
5266
|
+
saveAuthSession2(accountId, {
|
|
5267
|
+
cookie: cookieStr,
|
|
5268
|
+
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
5269
|
+
bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
|
|
5270
|
+
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
5271
|
+
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
5272
|
+
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
5273
|
+
secChUaMobile: cache.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
|
|
5274
|
+
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
|
|
5275
|
+
version: cache.headers["version"] || session?.version,
|
|
5276
|
+
userId: session?.userId,
|
|
5277
|
+
tokenExpiresAt: parseJwtExpiry(newAccessToken) || void 0,
|
|
5278
|
+
refreshToken: newRefreshToken,
|
|
5279
|
+
capturedAt: Date.now()
|
|
5280
|
+
});
|
|
5281
|
+
return { success: true, token: newAccessToken };
|
|
5282
|
+
}
|
|
5283
|
+
}
|
|
5284
|
+
} catch {
|
|
5285
|
+
}
|
|
5286
|
+
}
|
|
5287
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
5288
|
+
const creds = getAccountCredentials2(accountId);
|
|
5289
|
+
if (creds && creds.email && creds.password) {
|
|
5290
|
+
const apiResult = await loginViaApi(page, creds.email, creds.password);
|
|
5291
|
+
if (apiResult.success) {
|
|
5292
|
+
const liveCookies = await page.context().cookies();
|
|
5293
|
+
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
5294
|
+
if (tokenCookie) {
|
|
5295
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
5296
|
+
const cache = getHeaderCache(accountId);
|
|
5297
|
+
cache.headers.cookie = cookieStr;
|
|
5298
|
+
cache.lastRefresh = Date.now();
|
|
5299
|
+
markAccountHeadersReady(accountId);
|
|
5300
|
+
saveAuthSession2(accountId, {
|
|
5301
|
+
cookie: cookieStr,
|
|
5302
|
+
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
5303
|
+
bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
|
|
5304
|
+
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
5305
|
+
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
5306
|
+
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
5307
|
+
secChUaMobile: cache.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
|
|
5308
|
+
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
|
|
5309
|
+
version: cache.headers["version"] || session?.version,
|
|
5310
|
+
userId: session?.userId,
|
|
5311
|
+
tokenExpiresAt: parseJwtExpiry(tokenCookie.value) || void 0,
|
|
5312
|
+
refreshToken: apiResult.refreshToken,
|
|
5313
|
+
capturedAt: Date.now()
|
|
5314
|
+
});
|
|
5315
|
+
return { success: true, token: tokenCookie.value };
|
|
5316
|
+
}
|
|
5317
|
+
}
|
|
5318
|
+
}
|
|
5319
|
+
return { success: false, error: "Could not refresh or re-authenticate token" };
|
|
5320
|
+
}
|
|
5155
5321
|
async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
|
|
5156
5322
|
const page = pageOverride ?? accountPages.get(accountId);
|
|
5157
5323
|
if (!page || page.isClosed()) {
|
|
@@ -5668,16 +5834,9 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
5668
5834
|
}
|
|
5669
5835
|
};
|
|
5670
5836
|
if (forceReauth) {
|
|
5671
|
-
const
|
|
5672
|
-
if (
|
|
5673
|
-
|
|
5674
|
-
if (liveCookies.some((c) => c.name === "token")) {
|
|
5675
|
-
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
5676
|
-
cache.headers.cookie = cookieStr;
|
|
5677
|
-
cache.lastRefresh = Date.now();
|
|
5678
|
-
markAccountHeadersReady(accountId);
|
|
5679
|
-
return;
|
|
5680
|
-
}
|
|
5837
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
5838
|
+
if (refreshed.success) {
|
|
5839
|
+
return;
|
|
5681
5840
|
}
|
|
5682
5841
|
await executeReauth();
|
|
5683
5842
|
} else {
|
|
@@ -6113,50 +6272,15 @@ async function keepAlivePlaywrightAccount(accountId) {
|
|
|
6113
6272
|
const now = Date.now();
|
|
6114
6273
|
const currentUrl = page.url();
|
|
6115
6274
|
const cookie = await getCookies(accountId);
|
|
6116
|
-
if (cookie && isTokenExpiringSoon(cookie,
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
method: "GET",
|
|
6126
|
-
credentials: "include"
|
|
6127
|
-
}).catch(() => {
|
|
6128
|
-
});
|
|
6129
|
-
}).catch(() => {
|
|
6130
|
-
});
|
|
6131
|
-
const liveCookies = await page.context().cookies();
|
|
6132
|
-
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
6133
|
-
if (tokenCookie) {
|
|
6134
|
-
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
6135
|
-
const cache = getHeaderCache(accountId);
|
|
6136
|
-
cache.headers.cookie = cookieStr;
|
|
6137
|
-
cache.lastRefresh = Date.now();
|
|
6138
|
-
markAccountHeadersReady(accountId);
|
|
6139
|
-
lastKeepAliveNavigation.set(accountId, now);
|
|
6140
|
-
touchAccountActivity(accountId);
|
|
6141
|
-
return true;
|
|
6142
|
-
}
|
|
6143
|
-
} catch {
|
|
6144
|
-
}
|
|
6145
|
-
const loggedIn = await isPageLoggedIn(page, 2e3).catch(() => false);
|
|
6146
|
-
if (!loggedIn) {
|
|
6147
|
-
console.log(
|
|
6148
|
-
`\u{1F493} [SessionKeeper] Account ${accountId} session expired; renewing session...`
|
|
6149
|
-
);
|
|
6150
|
-
try {
|
|
6151
|
-
await refreshHeadersInternal(accountId, config.timeouts.headers, true);
|
|
6152
|
-
lastKeepAliveNavigation.set(accountId, now);
|
|
6153
|
-
touchAccountActivity(accountId);
|
|
6154
|
-
return true;
|
|
6155
|
-
} catch (err) {
|
|
6156
|
-
console.warn(
|
|
6157
|
-
`[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
|
|
6158
|
-
);
|
|
6159
|
-
}
|
|
6275
|
+
if (cookie && isTokenExpiringSoon(cookie, 5)) {
|
|
6276
|
+
console.log(
|
|
6277
|
+
`\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
|
|
6278
|
+
);
|
|
6279
|
+
const res = await refreshAccountToken(accountId);
|
|
6280
|
+
if (res.success) {
|
|
6281
|
+
lastKeepAliveNavigation.set(accountId, now);
|
|
6282
|
+
touchAccountActivity(accountId);
|
|
6283
|
+
return true;
|
|
6160
6284
|
}
|
|
6161
6285
|
}
|
|
6162
6286
|
const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
|
|
@@ -7521,7 +7645,19 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
|
|
|
7521
7645
|
} catch {
|
|
7522
7646
|
}
|
|
7523
7647
|
}
|
|
7524
|
-
|
|
7648
|
+
const isUnauthorized = json?.data?.code?.toLowerCase() === "unauthorized" || json?.code?.toLowerCase() === "unauthorized" || rawLower.includes("unauthorized") || rawLower.includes("permission to access") || rawLower.includes("token has expired") || rawLower.includes("401");
|
|
7649
|
+
if (isUnauthorized) {
|
|
7650
|
+
if (accountId) {
|
|
7651
|
+
try {
|
|
7652
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
7653
|
+
const refreshed = await refreshAccountToken2(accountId);
|
|
7654
|
+
if (refreshed.success) {
|
|
7655
|
+
const { headers: freshHeaders } = await getQwenHeaders(false, accountId);
|
|
7656
|
+
return createQwenChatSession(freshHeaders, model, accountId, chatMode);
|
|
7657
|
+
}
|
|
7658
|
+
} catch {
|
|
7659
|
+
}
|
|
7660
|
+
}
|
|
7525
7661
|
throw new QwenUpstreamError(
|
|
7526
7662
|
`Qwen create chat unauthorized: ${raw.substring(0, 300)}`,
|
|
7527
7663
|
"Unauthorized",
|
|
@@ -8217,16 +8353,28 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
8217
8353
|
});
|
|
8218
8354
|
if (response2.status === 401) {
|
|
8219
8355
|
try {
|
|
8220
|
-
const
|
|
8221
|
-
|
|
8222
|
-
|
|
8223
|
-
|
|
8224
|
-
|
|
8225
|
-
|
|
8356
|
+
const rTok = localStorage.getItem("refresh_token");
|
|
8357
|
+
if (rTok) {
|
|
8358
|
+
const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
8359
|
+
method: "GET",
|
|
8360
|
+
credentials: "include",
|
|
8361
|
+
headers: {
|
|
8362
|
+
accept: "application/json, text/plain, */*",
|
|
8363
|
+
source: "web",
|
|
8364
|
+
version: "0.3.11",
|
|
8365
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
8366
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
8367
|
+
authorization: `Bearer ${rTok}`
|
|
8368
|
+
},
|
|
8369
|
+
signal: AbortSignal.timeout(5e3)
|
|
8370
|
+
});
|
|
8226
8371
|
const refreshJson = await refreshRes.json().catch(() => null);
|
|
8227
|
-
|
|
8228
|
-
|
|
8372
|
+
const freshTok = refreshJson?.data?.access_token || refreshJson?.data?.token;
|
|
8373
|
+
const nextRTok = refreshJson?.data?.refresh_token;
|
|
8374
|
+
if (refreshJson?.success === true && freshTok) {
|
|
8229
8375
|
localStorage.setItem("token", freshTok);
|
|
8376
|
+
localStorage.setItem("access_token", freshTok);
|
|
8377
|
+
if (nextRTok) localStorage.setItem("refresh_token", nextRTok);
|
|
8230
8378
|
document.cookie = `token=${encodeURIComponent(freshTok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
8231
8379
|
if (headers2["authorization"] || headers2["Authorization"]) {
|
|
8232
8380
|
headers2["authorization"] = `Bearer ${freshTok}`;
|
|
@@ -8264,13 +8412,29 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
8264
8412
|
}
|
|
8265
8413
|
);
|
|
8266
8414
|
const recoverOnTimeout = !options.noMutexRecovery;
|
|
8267
|
-
|
|
8415
|
+
let response = await withQwenBrowserPage(
|
|
8268
8416
|
accountId,
|
|
8269
8417
|
evaluateRequest,
|
|
8270
8418
|
void 0,
|
|
8271
8419
|
options.timeoutMs,
|
|
8272
8420
|
recoverOnTimeout
|
|
8273
8421
|
);
|
|
8422
|
+
if (response.status === 401 && accountId) {
|
|
8423
|
+
try {
|
|
8424
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
8425
|
+
const refreshed = await refreshAccountToken2(accountId);
|
|
8426
|
+
if (refreshed.success) {
|
|
8427
|
+
response = await withQwenBrowserPage(
|
|
8428
|
+
accountId,
|
|
8429
|
+
evaluateRequest,
|
|
8430
|
+
void 0,
|
|
8431
|
+
options.timeoutMs,
|
|
8432
|
+
recoverOnTimeout
|
|
8433
|
+
);
|
|
8434
|
+
}
|
|
8435
|
+
} catch {
|
|
8436
|
+
}
|
|
8437
|
+
}
|
|
8274
8438
|
return new Response(response.raw, {
|
|
8275
8439
|
status: response.status,
|
|
8276
8440
|
headers: response.contentType ? { "content-type": response.contentType } : void 0
|
|
@@ -8793,7 +8957,11 @@ async function syncQwenRequestPersonalization(instruction, accountId, metadata =
|
|
|
8793
8957
|
);
|
|
8794
8958
|
try {
|
|
8795
8959
|
currentSettings = null;
|
|
8796
|
-
const {
|
|
8960
|
+
const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
8961
|
+
if (accountId) {
|
|
8962
|
+
await refreshAccountToken2(accountId);
|
|
8963
|
+
}
|
|
8964
|
+
const { headers: freshHeaders } = await getQwenHeaders(false, accountId);
|
|
8797
8965
|
requestHeaders = buildCapturedQwenHeaders(freshHeaders, {
|
|
8798
8966
|
referer: qwenUrl("/settings/personalization")
|
|
8799
8967
|
});
|
|
@@ -9479,8 +9647,18 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
9479
9647
|
);
|
|
9480
9648
|
}
|
|
9481
9649
|
};
|
|
9650
|
+
let forceRefresh = options?.forceNewChat === true;
|
|
9651
|
+
if (!forceRefresh && accountId) {
|
|
9652
|
+
try {
|
|
9653
|
+
const basic = await getBasicHeaders2(accountId);
|
|
9654
|
+
if (isTokenExpiringSoon(basic.cookie, 3)) {
|
|
9655
|
+
forceRefresh = true;
|
|
9656
|
+
}
|
|
9657
|
+
} catch {
|
|
9658
|
+
}
|
|
9659
|
+
}
|
|
9482
9660
|
const captured = await getQwenHeaders(
|
|
9483
|
-
|
|
9661
|
+
forceRefresh,
|
|
9484
9662
|
accountId
|
|
9485
9663
|
);
|
|
9486
9664
|
ensureNotAborted();
|
|
@@ -9494,7 +9672,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
9494
9672
|
if (options && "chatSessionId" in options) {
|
|
9495
9673
|
if (options.chatSessionId === null || options.chatSessionId === "") {
|
|
9496
9674
|
const acquired = await acquireNewQwenChatSession(
|
|
9497
|
-
|
|
9675
|
+
activeHeaders,
|
|
9498
9676
|
model,
|
|
9499
9677
|
accountId,
|
|
9500
9678
|
options?.chatMode ?? "thread"
|
|
@@ -9502,6 +9680,11 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
9502
9680
|
chatSessionId = acquired.chatId;
|
|
9503
9681
|
leasedWarmChat = acquired.leasedFromPool;
|
|
9504
9682
|
createdNewChat = true;
|
|
9683
|
+
try {
|
|
9684
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
9685
|
+
activeHeaders = fresh.headers;
|
|
9686
|
+
} catch {
|
|
9687
|
+
}
|
|
9505
9688
|
} else {
|
|
9506
9689
|
chatSessionId = options.chatSessionId;
|
|
9507
9690
|
}
|
|
@@ -9509,7 +9692,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
9509
9692
|
chatSessionId = captured.chatSessionId;
|
|
9510
9693
|
if (!chatSessionId) {
|
|
9511
9694
|
const acquired = await acquireNewQwenChatSession(
|
|
9512
|
-
|
|
9695
|
+
activeHeaders,
|
|
9513
9696
|
model,
|
|
9514
9697
|
accountId,
|
|
9515
9698
|
options?.chatMode ?? "thread"
|
|
@@ -9517,6 +9700,11 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
|
|
|
9517
9700
|
chatSessionId = acquired.chatId;
|
|
9518
9701
|
leasedWarmChat = acquired.leasedFromPool;
|
|
9519
9702
|
createdNewChat = true;
|
|
9703
|
+
try {
|
|
9704
|
+
const fresh = await getQwenHeaders(false, accountId);
|
|
9705
|
+
activeHeaders = fresh.headers;
|
|
9706
|
+
} catch {
|
|
9707
|
+
}
|
|
9520
9708
|
}
|
|
9521
9709
|
}
|
|
9522
9710
|
ensureNotAborted();
|