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/index.js CHANGED
@@ -1608,6 +1608,7 @@ function runMigrations(db2) {
1608
1608
  "sec_ch_ua_mobile TEXT",
1609
1609
  "sec_ch_ua_platform TEXT",
1610
1610
  "version TEXT",
1611
+ "refresh_token TEXT",
1611
1612
  "captured_at INTEGER DEFAULT 0"
1612
1613
  ];
1613
1614
  for (const col of authSessionCols) {
@@ -1686,11 +1687,11 @@ function saveAuthSession(accountId, session) {
1686
1687
  INSERT OR REPLACE INTO qwen_auth_sessions (
1687
1688
  account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
1688
1689
  sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
1689
- user_id, token_expires_at, captured_at, updated_at
1690
+ user_id, token_expires_at, refresh_token, captured_at, updated_at
1690
1691
  ) VALUES (
1691
1692
  ?, ?, ?, ?, ?, ?,
1692
1693
  ?, ?, ?, ?,
1693
- ?, ?, ?, datetime('now')
1694
+ ?, ?, ?, ?, datetime('now')
1694
1695
  )
1695
1696
  `);
1696
1697
  stmt.run(
@@ -1706,6 +1707,7 @@ function saveAuthSession(accountId, session) {
1706
1707
  session.version || null,
1707
1708
  session.userId || null,
1708
1709
  session.tokenExpiresAt || null,
1710
+ session.refreshToken || null,
1709
1711
  session.capturedAt ?? Date.now()
1710
1712
  );
1711
1713
  }
@@ -1714,7 +1716,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
1714
1716
  const row = database.prepare(
1715
1717
  `SELECT account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
1716
1718
  sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
1717
- user_id, token_expires_at, captured_at
1719
+ user_id, token_expires_at, refresh_token, captured_at
1718
1720
  FROM qwen_auth_sessions WHERE account_id = ?`
1719
1721
  ).get(accountId);
1720
1722
  if (!row) return null;
@@ -1722,7 +1724,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
1722
1724
  if (capturedAt <= 0 || Date.now() - capturedAt > maxAgeMs) {
1723
1725
  return null;
1724
1726
  }
1725
- if (row.token_expires_at) {
1727
+ if (!row.refresh_token && row.token_expires_at) {
1726
1728
  const tokenExpMs = Number(row.token_expires_at) * 1e3;
1727
1729
  if (tokenExpMs <= Date.now() + 5 * 60 * 1e3) {
1728
1730
  return null;
@@ -1744,6 +1746,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
1744
1746
  version: row.version || void 0,
1745
1747
  userId: row.user_id || void 0,
1746
1748
  tokenExpiresAt: row.token_expires_at ? Number(row.token_expires_at) : void 0,
1749
+ refreshToken: row.refresh_token || void 0,
1747
1750
  capturedAt
1748
1751
  };
1749
1752
  }
@@ -2983,7 +2986,15 @@ function defaultCooldownDurationMs() {
2983
2986
  return computeQuotaCooldownMs(Date.now());
2984
2987
  }
2985
2988
  function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
2989
+ if (cooldownMs !== void 0 && cooldownMs <= 0) {
2990
+ clearAccountCooldown(accountId);
2991
+ return;
2992
+ }
2986
2993
  const duration = cooldownMs ?? defaultCooldownDurationMs();
2994
+ if (duration <= 0) {
2995
+ clearAccountCooldown(accountId);
2996
+ return;
2997
+ }
2987
2998
  const until = Date.now() + duration;
2988
2999
  const cooldownReason = reason ?? "RateLimited";
2989
3000
  cooldowns.set(accountId, {
@@ -3983,7 +3994,8 @@ function buildQwenRequestHeaders(opts) {
3983
3994
  "bx-v": opts.bxV || "2.5.37",
3984
3995
  source: "web",
3985
3996
  version: opts.version || getQwenWebVersion(),
3986
- timezone: opts.extra?.timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
3997
+ timezone: opts.extra?.timezone || opts.extra?.Timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
3998
+ Timezone: opts.extra?.Timezone || opts.extra?.timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
3987
3999
  // Use the real browser client-hints when captured (anti-hardcoded); fall
3988
4000
  // back to the static fingerprint otherwise.
3989
4001
  "sec-ch-ua": opts.secChUa || `"Google Chrome";v="${getChromeMajor()}", "Chromium";v="${getChromeMajor()}", "Not.A/Brand";v="99"`,
@@ -4269,6 +4281,7 @@ __export(playwright_exports, {
4269
4281
  parseCookiesForBrowser: () => parseCookiesForBrowser,
4270
4282
  pruneAllPlaywrightProfiles: () => pruneAllPlaywrightProfiles,
4271
4283
  prunePlaywrightProfileCaches: () => prunePlaywrightProfileCaches,
4284
+ refreshAccountToken: () => refreshAccountToken,
4272
4285
  refreshHeaders: () => refreshHeaders,
4273
4286
  refreshHeadersWithProfileReset: () => refreshHeadersWithProfileReset,
4274
4287
  registerPlaywrightAccountForTests: () => registerPlaywrightAccountForTests,
@@ -5904,6 +5917,7 @@ async function loginToQwen(accountId, email, password) {
5904
5917
  secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || void 0,
5905
5918
  version: cache3.headers["version"] || void 0,
5906
5919
  tokenExpiresAt: exp || void 0,
5920
+ refreshToken: apiResult.refreshToken,
5907
5921
  capturedAt: Date.now()
5908
5922
  });
5909
5923
  }
@@ -5937,6 +5951,13 @@ async function loginToQwen(accountId, email, password) {
5937
5951
  markAccountHeadersReady(accountId);
5938
5952
  const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5939
5953
  const exp = parseJwtExpiry(tokenCookie.value);
5954
+ let rTok = uiResult.refreshToken;
5955
+ if (!rTok) {
5956
+ try {
5957
+ rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
5958
+ } catch {
5959
+ }
5960
+ }
5940
5961
  saveAuthSession2(accountId, {
5941
5962
  cookie: cookieStr,
5942
5963
  userAgent: cache3.headers["user-agent"] || "",
@@ -5948,6 +5969,7 @@ async function loginToQwen(accountId, email, password) {
5948
5969
  secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || void 0,
5949
5970
  version: cache3.headers["version"] || void 0,
5950
5971
  tokenExpiresAt: exp || void 0,
5972
+ refreshToken: rTok,
5951
5973
  capturedAt: Date.now()
5952
5974
  });
5953
5975
  }
@@ -6126,7 +6148,7 @@ async function loginViaApi(page, email, password) {
6126
6148
  });
6127
6149
  await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
6128
6150
  });
6129
- return { success: true };
6151
+ return { success: true, token, refreshToken };
6130
6152
  }
6131
6153
  }
6132
6154
  return {
@@ -6369,6 +6391,137 @@ async function loginViaUi(page, email, password) {
6369
6391
  return { success: false, reason: err?.message || String(err) };
6370
6392
  }
6371
6393
  }
6394
+ async function refreshAccountToken(accountId) {
6395
+ const page = accountPages.get(accountId);
6396
+ if (!page || page.isClosed()) {
6397
+ return { success: false, error: "Account page not active" };
6398
+ }
6399
+ const { getValidAuthSession: getValidAuthSession2, saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
6400
+ const session = getValidAuthSession2(accountId);
6401
+ let refreshToken = session?.refreshToken;
6402
+ if (!refreshToken) {
6403
+ try {
6404
+ refreshToken = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
6405
+ } catch {
6406
+ }
6407
+ }
6408
+ if (refreshToken) {
6409
+ try {
6410
+ const refreshResult = await page.evaluate(
6411
+ async ({ rTok }) => {
6412
+ try {
6413
+ const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
6414
+ method: "GET",
6415
+ credentials: "include",
6416
+ headers: {
6417
+ accept: "application/json, text/plain, */*",
6418
+ source: "web",
6419
+ version: "0.3.11",
6420
+ "x-request-origin": "https://chat.qwen.ai",
6421
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
6422
+ authorization: `Bearer ${rTok}`
6423
+ }
6424
+ });
6425
+ const json2 = await response.json().catch(() => null);
6426
+ return { ok: response.ok, status: response.status, data: json2 };
6427
+ } catch (e) {
6428
+ return { ok: false, error: e.message };
6429
+ }
6430
+ },
6431
+ { rTok: refreshToken }
6432
+ );
6433
+ const json = refreshResult?.data;
6434
+ if (json && json.success === true && json.data) {
6435
+ const newAccessToken = json.data.access_token || json.data.token;
6436
+ const newRefreshToken = json.data.refresh_token || refreshToken;
6437
+ if (newAccessToken) {
6438
+ await page.context().addCookies([
6439
+ {
6440
+ name: "token",
6441
+ value: newAccessToken,
6442
+ domain: ".qwen.ai",
6443
+ path: "/",
6444
+ expires: Math.floor(Date.now() / 1e3) + 31536e3,
6445
+ httpOnly: false,
6446
+ secure: true,
6447
+ sameSite: "Lax"
6448
+ }
6449
+ ]);
6450
+ await page.evaluate(
6451
+ ({ tok, rTok }) => {
6452
+ try {
6453
+ localStorage.removeItem("qwen_token_logged_out_marker");
6454
+ localStorage.setItem("token", tok);
6455
+ localStorage.setItem("access_token", tok);
6456
+ if (rTok) localStorage.setItem("refresh_token", rTok);
6457
+ document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
6458
+ } catch {
6459
+ }
6460
+ },
6461
+ { tok: newAccessToken, rTok: newRefreshToken }
6462
+ ).catch(() => {
6463
+ });
6464
+ const liveCookies = await page.context().cookies();
6465
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
6466
+ const cache3 = getHeaderCache(accountId);
6467
+ cache3.headers.cookie = cookieStr;
6468
+ cache3.lastRefresh = Date.now();
6469
+ markAccountHeadersReady(accountId);
6470
+ saveAuthSession2(accountId, {
6471
+ cookie: cookieStr,
6472
+ userAgent: cache3.headers["user-agent"] || session?.userAgent || "",
6473
+ bxV: cache3.headers["bx-v"] || session?.bxV || "2.5.37",
6474
+ bxUa: cache3.headers["bx-ua"] || session?.bxUa || "",
6475
+ bxUmidtoken: cache3.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
6476
+ secChUa: cache3.headers["sec-ch-ua"] || session?.secChUa,
6477
+ secChUaMobile: cache3.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
6478
+ secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
6479
+ version: cache3.headers["version"] || session?.version,
6480
+ userId: session?.userId,
6481
+ tokenExpiresAt: parseJwtExpiry(newAccessToken) || void 0,
6482
+ refreshToken: newRefreshToken,
6483
+ capturedAt: Date.now()
6484
+ });
6485
+ return { success: true, token: newAccessToken };
6486
+ }
6487
+ }
6488
+ } catch {
6489
+ }
6490
+ }
6491
+ const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
6492
+ const creds = getAccountCredentials2(accountId);
6493
+ if (creds && creds.email && creds.password) {
6494
+ const apiResult = await loginViaApi(page, creds.email, creds.password);
6495
+ if (apiResult.success) {
6496
+ const liveCookies = await page.context().cookies();
6497
+ const tokenCookie = liveCookies.find((c) => c.name === "token");
6498
+ if (tokenCookie) {
6499
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
6500
+ const cache3 = getHeaderCache(accountId);
6501
+ cache3.headers.cookie = cookieStr;
6502
+ cache3.lastRefresh = Date.now();
6503
+ markAccountHeadersReady(accountId);
6504
+ saveAuthSession2(accountId, {
6505
+ cookie: cookieStr,
6506
+ userAgent: cache3.headers["user-agent"] || session?.userAgent || "",
6507
+ bxV: cache3.headers["bx-v"] || session?.bxV || "2.5.37",
6508
+ bxUa: cache3.headers["bx-ua"] || session?.bxUa || "",
6509
+ bxUmidtoken: cache3.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
6510
+ secChUa: cache3.headers["sec-ch-ua"] || session?.secChUa,
6511
+ secChUaMobile: cache3.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
6512
+ secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
6513
+ version: cache3.headers["version"] || session?.version,
6514
+ userId: session?.userId,
6515
+ tokenExpiresAt: parseJwtExpiry(tokenCookie.value) || void 0,
6516
+ refreshToken: apiResult.refreshToken,
6517
+ capturedAt: Date.now()
6518
+ });
6519
+ return { success: true, token: tokenCookie.value };
6520
+ }
6521
+ }
6522
+ }
6523
+ return { success: false, error: "Could not refresh or re-authenticate token" };
6524
+ }
6372
6525
  async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
6373
6526
  const page = pageOverride ?? accountPages.get(accountId);
6374
6527
  if (!page || page.isClosed()) {
@@ -6885,16 +7038,9 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
6885
7038
  }
6886
7039
  };
6887
7040
  if (forceReauth) {
6888
- const alreadyIn = await isPageLoggedIn(page, 2e3).catch(() => false);
6889
- if (alreadyIn) {
6890
- const liveCookies = await page.context().cookies();
6891
- if (liveCookies.some((c) => c.name === "token")) {
6892
- const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
6893
- cache3.headers.cookie = cookieStr;
6894
- cache3.lastRefresh = Date.now();
6895
- markAccountHeadersReady(accountId);
6896
- return;
6897
- }
7041
+ const refreshed = await refreshAccountToken(accountId);
7042
+ if (refreshed.success) {
7043
+ return;
6898
7044
  }
6899
7045
  await executeReauth();
6900
7046
  } else {
@@ -7330,50 +7476,15 @@ async function keepAlivePlaywrightAccount(accountId) {
7330
7476
  const now = Date.now();
7331
7477
  const currentUrl = page.url();
7332
7478
  const cookie = await getCookies(accountId);
7333
- if (cookie && isTokenExpiringSoon(cookie, 2)) {
7334
- try {
7335
- await page.evaluate(async () => {
7336
- await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
7337
- method: "GET",
7338
- credentials: "include"
7339
- }).catch(() => {
7340
- });
7341
- await fetch("/api/v1/auths/", {
7342
- method: "GET",
7343
- credentials: "include"
7344
- }).catch(() => {
7345
- });
7346
- }).catch(() => {
7347
- });
7348
- const liveCookies = await page.context().cookies();
7349
- const tokenCookie = liveCookies.find((c) => c.name === "token");
7350
- if (tokenCookie) {
7351
- const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
7352
- const cache3 = getHeaderCache(accountId);
7353
- cache3.headers.cookie = cookieStr;
7354
- cache3.lastRefresh = Date.now();
7355
- markAccountHeadersReady(accountId);
7356
- lastKeepAliveNavigation.set(accountId, now);
7357
- touchAccountActivity(accountId);
7358
- return true;
7359
- }
7360
- } catch {
7361
- }
7362
- const loggedIn = await isPageLoggedIn(page, 2e3).catch(() => false);
7363
- if (!loggedIn) {
7364
- console.log(
7365
- `\u{1F493} [SessionKeeper] Account ${accountId} session expired; renewing session...`
7366
- );
7367
- try {
7368
- await refreshHeadersInternal(accountId, config.timeouts.headers, true);
7369
- lastKeepAliveNavigation.set(accountId, now);
7370
- touchAccountActivity(accountId);
7371
- return true;
7372
- } catch (err) {
7373
- console.warn(
7374
- `[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
7375
- );
7376
- }
7479
+ if (cookie && isTokenExpiringSoon(cookie, 5)) {
7480
+ console.log(
7481
+ `\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
7482
+ );
7483
+ const res = await refreshAccountToken(accountId);
7484
+ if (res.success) {
7485
+ lastKeepAliveNavigation.set(accountId, now);
7486
+ touchAccountActivity(accountId);
7487
+ return true;
7377
7488
  }
7378
7489
  }
7379
7490
  const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
@@ -8985,8 +9096,11 @@ ${thought}`);
8985
9096
  }
8986
9097
  return sections.join("\n\n");
8987
9098
  }
9099
+ function isAnswerPhase(phase) {
9100
+ return typeof phase === "string" && ANSWER_PHASES.has(phase);
9101
+ }
8988
9102
  function isThinkingPhase(phase) {
8989
- return phase === "think" || phase === "thinking_summary";
9103
+ return typeof phase === "string" && THINKING_PHASES.has(phase);
8990
9104
  }
8991
9105
  function extractThinkingContent(delta) {
8992
9106
  if (Array.isArray(delta?.extra?.summary_title?.content) || Array.isArray(delta?.extra?.summary_thought?.content)) {
@@ -9077,9 +9191,25 @@ function buildUsage(accumulator) {
9077
9191
  }
9078
9192
  return usage;
9079
9193
  }
9194
+ var ANSWER_PHASES, THINKING_PHASES;
9080
9195
  var init_helpers = __esm({
9081
9196
  "src/routes/chat/helpers.ts"() {
9082
9197
  "use strict";
9198
+ ANSWER_PHASES = /* @__PURE__ */ new Set([
9199
+ "answer",
9200
+ "deep_research_answer",
9201
+ "ReportGeneration",
9202
+ "PdfMdGen",
9203
+ "image",
9204
+ "image_generation",
9205
+ "image_gen",
9206
+ "t2i"
9207
+ ]);
9208
+ THINKING_PHASES = /* @__PURE__ */ new Set([
9209
+ "think",
9210
+ "thinking_summary",
9211
+ "DeepThinking"
9212
+ ]);
9083
9213
  }
9084
9214
  });
9085
9215
 
@@ -9253,18 +9383,18 @@ function classifyRetryAction(err, options) {
9253
9383
  switchAccount: true,
9254
9384
  forceNewChat: true,
9255
9385
  retryAfterMs: baseDelayMs,
9256
- accountCooldownMs: config.concurrency.initFailureCooldownMs,
9386
+ accountCooldownMs: 0,
9257
9387
  accountCooldownReason: "PersonalizationFailed"
9258
9388
  });
9259
9389
  }
9260
- if (code === "createchatinvalidresponse" || code === "createchatfailed" || code === "unauthorized" || message.includes("401 n\xE3o autorizado") || message.includes("n\xE3o tem permiss\xE3o para acessar") || message.includes("401 unauthorized") || message.includes('"code":"unauthorized"') || message.includes('"code": "unauthorized"')) {
9390
+ if (code === "createchatinvalidresponse" || code === "createchatfailed" || code === "unauthorized" || message.includes("401 n\xE3o autorizado") || message.includes("n\xE3o tem permiss\xE3o para acessar") || message.includes("401 unauthorized") || message.includes('"code":"unauthorized"') || message.includes('"code": "unauthorized"') || message.includes("token has expired")) {
9261
9391
  return makeRetryAction("account_initialization_failed", {
9262
9392
  switchAccount: true,
9263
9393
  forceNewChat: true,
9264
9394
  retryWithFullPrompt: true,
9265
9395
  retryAfterMs: Math.min(baseDelayMs, 1e3),
9266
- accountCooldownMs: config.concurrency.initFailureCooldownMs,
9267
- accountCooldownReason: "AuthInitFailed"
9396
+ accountCooldownMs: 0,
9397
+ accountCooldownReason: "AuthExpired"
9268
9398
  });
9269
9399
  }
9270
9400
  if (isCorruptedChatHistoryError(err)) {
@@ -9681,8 +9811,8 @@ async function requestCompletionsInBrowser(params) {
9681
9811
  const choice = chunk?.choices?.[0];
9682
9812
  const delta = choice?.delta;
9683
9813
  const phase = delta?.phase;
9684
- const isAnswerPhase = !phase || phase === "answer";
9685
- if (choice?.finish_reason || delta?.status === "finished" && isAnswerPhase) {
9814
+ const isAnswerPhase2 = !phase || phase === "answer";
9815
+ if (choice?.finish_reason || delta?.status === "finished" && isAnswerPhase2) {
9686
9816
  finished = true;
9687
9817
  break;
9688
9818
  }
@@ -10733,7 +10863,19 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
10733
10863
  } catch {
10734
10864
  }
10735
10865
  }
10736
- if (json?.data?.code === "Unauthorized" || json?.code === "Unauthorized" || rawLower.includes("unauthorized") || rawLower.includes("permission to access")) {
10866
+ 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");
10867
+ if (isUnauthorized) {
10868
+ if (accountId) {
10869
+ try {
10870
+ const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
10871
+ const refreshed = await refreshAccountToken2(accountId);
10872
+ if (refreshed.success) {
10873
+ const { headers: freshHeaders } = await getQwenHeaders(false, accountId);
10874
+ return createQwenChatSession(freshHeaders, model, accountId, chatMode);
10875
+ }
10876
+ } catch {
10877
+ }
10878
+ }
10737
10879
  throw new QwenUpstreamError(
10738
10880
  `Qwen create chat unauthorized: ${raw.substring(0, 300)}`,
10739
10881
  "Unauthorized",
@@ -11429,16 +11571,28 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
11429
11571
  });
11430
11572
  if (response2.status === 401) {
11431
11573
  try {
11432
- const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
11433
- method: "GET",
11434
- credentials: "include",
11435
- signal: AbortSignal.timeout(3e3)
11436
- });
11437
- if (refreshRes.status === 200) {
11574
+ const rTok = localStorage.getItem("refresh_token");
11575
+ if (rTok) {
11576
+ const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
11577
+ method: "GET",
11578
+ credentials: "include",
11579
+ headers: {
11580
+ accept: "application/json, text/plain, */*",
11581
+ source: "web",
11582
+ version: "0.3.11",
11583
+ "x-request-origin": "https://chat.qwen.ai",
11584
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
11585
+ authorization: `Bearer ${rTok}`
11586
+ },
11587
+ signal: AbortSignal.timeout(5e3)
11588
+ });
11438
11589
  const refreshJson = await refreshRes.json().catch(() => null);
11439
- if (refreshJson && refreshJson.success === true && refreshJson.data?.token) {
11440
- const freshTok = refreshJson.data.token;
11590
+ const freshTok = refreshJson?.data?.access_token || refreshJson?.data?.token;
11591
+ const nextRTok = refreshJson?.data?.refresh_token;
11592
+ if (refreshJson?.success === true && freshTok) {
11441
11593
  localStorage.setItem("token", freshTok);
11594
+ localStorage.setItem("access_token", freshTok);
11595
+ if (nextRTok) localStorage.setItem("refresh_token", nextRTok);
11442
11596
  document.cookie = `token=${encodeURIComponent(freshTok)}; path=/; domain=.qwen.ai; max-age=31536000`;
11443
11597
  if (headers2["authorization"] || headers2["Authorization"]) {
11444
11598
  headers2["authorization"] = `Bearer ${freshTok}`;
@@ -11476,13 +11630,29 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
11476
11630
  }
11477
11631
  );
11478
11632
  const recoverOnTimeout = !options.noMutexRecovery;
11479
- const response = await withQwenBrowserPage(
11633
+ let response = await withQwenBrowserPage(
11480
11634
  accountId,
11481
11635
  evaluateRequest,
11482
11636
  void 0,
11483
11637
  options.timeoutMs,
11484
11638
  recoverOnTimeout
11485
11639
  );
11640
+ if (response.status === 401 && accountId) {
11641
+ try {
11642
+ const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
11643
+ const refreshed = await refreshAccountToken2(accountId);
11644
+ if (refreshed.success) {
11645
+ response = await withQwenBrowserPage(
11646
+ accountId,
11647
+ evaluateRequest,
11648
+ void 0,
11649
+ options.timeoutMs,
11650
+ recoverOnTimeout
11651
+ );
11652
+ }
11653
+ } catch {
11654
+ }
11655
+ }
11486
11656
  return new Response(response.raw, {
11487
11657
  status: response.status,
11488
11658
  headers: response.contentType ? { "content-type": response.contentType } : void 0
@@ -12005,7 +12175,11 @@ async function syncQwenRequestPersonalization(instruction, accountId, metadata =
12005
12175
  );
12006
12176
  try {
12007
12177
  currentSettings = null;
12008
- const { headers: freshHeaders } = await getQwenHeaders(true, accountId, true);
12178
+ const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
12179
+ if (accountId) {
12180
+ await refreshAccountToken2(accountId);
12181
+ }
12182
+ const { headers: freshHeaders } = await getQwenHeaders(false, accountId);
12009
12183
  requestHeaders = buildCapturedQwenHeaders(freshHeaders, {
12010
12184
  referer: qwenUrl("/settings/personalization")
12011
12185
  });
@@ -12691,8 +12865,18 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
12691
12865
  );
12692
12866
  }
12693
12867
  };
12868
+ let forceRefresh = options?.forceNewChat === true;
12869
+ if (!forceRefresh && accountId) {
12870
+ try {
12871
+ const basic = await getBasicHeaders2(accountId);
12872
+ if (isTokenExpiringSoon(basic.cookie, 3)) {
12873
+ forceRefresh = true;
12874
+ }
12875
+ } catch {
12876
+ }
12877
+ }
12694
12878
  const captured = await getQwenHeaders(
12695
- options?.forceNewChat === true,
12879
+ forceRefresh,
12696
12880
  accountId
12697
12881
  );
12698
12882
  ensureNotAborted();
@@ -12706,7 +12890,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
12706
12890
  if (options && "chatSessionId" in options) {
12707
12891
  if (options.chatSessionId === null || options.chatSessionId === "") {
12708
12892
  const acquired = await acquireNewQwenChatSession(
12709
- headers,
12893
+ activeHeaders,
12710
12894
  model,
12711
12895
  accountId,
12712
12896
  options?.chatMode ?? "thread"
@@ -12714,6 +12898,11 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
12714
12898
  chatSessionId = acquired.chatId;
12715
12899
  leasedWarmChat = acquired.leasedFromPool;
12716
12900
  createdNewChat = true;
12901
+ try {
12902
+ const fresh = await getQwenHeaders(false, accountId);
12903
+ activeHeaders = fresh.headers;
12904
+ } catch {
12905
+ }
12717
12906
  } else {
12718
12907
  chatSessionId = options.chatSessionId;
12719
12908
  }
@@ -12721,7 +12910,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
12721
12910
  chatSessionId = captured.chatSessionId;
12722
12911
  if (!chatSessionId) {
12723
12912
  const acquired = await acquireNewQwenChatSession(
12724
- headers,
12913
+ activeHeaders,
12725
12914
  model,
12726
12915
  accountId,
12727
12916
  options?.chatMode ?? "thread"
@@ -12729,6 +12918,11 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
12729
12918
  chatSessionId = acquired.chatId;
12730
12919
  leasedWarmChat = acquired.leasedFromPool;
12731
12920
  createdNewChat = true;
12921
+ try {
12922
+ const fresh = await getQwenHeaders(false, accountId);
12923
+ activeHeaders = fresh.headers;
12924
+ } catch {
12925
+ }
12732
12926
  }
12733
12927
  }
12734
12928
  ensureNotAborted();
@@ -13887,10 +14081,12 @@ async function getSTSToken(filename, filesize, filetype, headers, accountId) {
13887
14081
  }
13888
14082
  data = await response.json().catch(() => null);
13889
14083
  }
13890
- const is401 = data?.success === false && (data?.data?.code === "Unauthorized" || typeof data?.data?.details === "string" && data.data.details.includes("401"));
14084
+ const codeLower = (data?.data?.code || data?.code || "").toLowerCase();
14085
+ const detailsLower = (typeof data?.data?.details === "string" ? data.data.details : typeof data?.message === "string" ? data.message : "").toLowerCase();
14086
+ const is401 = data?.success === false && (codeLower === "unauthorized" || detailsLower.includes("401") || detailsLower.includes("token has expired") || detailsLower.includes("unauthorized"));
13891
14087
  if (is401) {
13892
14088
  try {
13893
- const { refreshHeaders: refreshHeaders2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
14089
+ const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
13894
14090
  const { getBasicHeaders: getBasicHeaders3 } = await Promise.resolve().then(() => (init_auth_playwright(), auth_playwright_exports));
13895
14091
  const { loadAccounts: loadAccounts3 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
13896
14092
  const resolvedId2 = accountId ?? loadAccounts3()[0]?.id;
@@ -13898,16 +14094,18 @@ async function getSTSToken(filename, filesize, filetype, headers, accountId) {
13898
14094
  console.warn(
13899
14095
  `[Upload] STS token 401 \u2014 refreshing session with re-auth and retrying...`
13900
14096
  );
13901
- await refreshHeaders2(resolvedId2, void 0, true);
13902
- const fresh = await getBasicHeaders3(resolvedId2);
13903
- headers.cookie = fresh.cookie;
13904
- headers["user-agent"] = fresh.userAgent;
13905
- headers["bx-v"] = fresh.bxV;
13906
- if (fresh.bxUa) headers["bx-ua"] = fresh.bxUa;
13907
- if (fresh.bxUmidtoken) headers["bx-umidtoken"] = fresh.bxUmidtoken;
13908
- const retryRes = await doFetch(headers);
13909
- if (retryRes.ok) {
13910
- data = await retryRes.json().catch(() => null);
14097
+ const refreshResult = await refreshAccountToken2(resolvedId2);
14098
+ if (refreshResult.success) {
14099
+ const fresh = await getBasicHeaders3(resolvedId2);
14100
+ headers.cookie = fresh.cookie;
14101
+ headers["user-agent"] = fresh.userAgent;
14102
+ headers["bx-v"] = fresh.bxV;
14103
+ if (fresh.bxUa) headers["bx-ua"] = fresh.bxUa;
14104
+ if (fresh.bxUmidtoken) headers["bx-umidtoken"] = fresh.bxUmidtoken;
14105
+ const retryRes = await doFetch(headers);
14106
+ if (retryRes.ok) {
14107
+ data = await retryRes.json().catch(() => null);
14108
+ }
13911
14109
  }
13912
14110
  }
13913
14111
  } catch (refreshErr) {
@@ -17022,15 +17220,26 @@ ${loopReminder}` : truncation.prompt;
17022
17220
  }
17023
17221
  }
17024
17222
  if (policy.reason === "account_initialization_failed") {
17025
- console.warn(
17026
- `\u26A0\uFE0F [Chat] Account initialization failed | ${currentAccountEmail} | cooldown=${Math.round((policy.accountCooldownMs ?? 0) / 1e3)}s`
17027
- );
17028
- markAccountFailed(currentAccountId);
17029
- markAccountRateLimited(
17030
- currentAccountId,
17031
- policy.accountCooldownMs,
17032
- policy.accountCooldownReason
17033
- );
17223
+ const cooldownMs = policy.accountCooldownMs ?? 0;
17224
+ if (cooldownMs > 0) {
17225
+ console.warn(
17226
+ `\u26A0\uFE0F [Chat] Account initialization failed | ${currentAccountEmail} | cooldown=${Math.round(cooldownMs / 1e3)}s`
17227
+ );
17228
+ markAccountFailed(currentAccountId);
17229
+ markAccountRateLimited(
17230
+ currentAccountId,
17231
+ cooldownMs,
17232
+ policy.accountCooldownReason
17233
+ );
17234
+ } else {
17235
+ console.warn(
17236
+ `\u26A0\uFE0F [Chat] Account auth expired/retryable | ${currentAccountEmail} | rotating without cooldown`
17237
+ );
17238
+ if (policy.accountCooldownReason === "AuthExpired") {
17239
+ Promise.resolve().then(() => (init_playwright(), playwright_exports)).then(({ refreshAccountToken: refreshAccountToken2 }) => refreshAccountToken2(currentAccountId)).catch(() => {
17240
+ });
17241
+ }
17242
+ }
17034
17243
  return { success: false, error: err };
17035
17244
  }
17036
17245
  if (policy.retryable && shouldSwitchAccount && !isSingleAccount && accountSwitches < maxAccountSwitches) {
@@ -17039,7 +17248,7 @@ ${loopReminder}` : truncation.prompt;
17039
17248
  console.warn(
17040
17249
  `\u{1F504} [Chat] Switching account after ${policy.reason} | ${currentAccountEmail} -> ${maskEmail(nextAccount.email)}`
17041
17250
  );
17042
- if (policy.accountCooldownMs || policy.accountCooldownReason) {
17251
+ if ((policy.accountCooldownMs ?? 0) > 0) {
17043
17252
  markAccountRateLimited(
17044
17253
  currentAccountId,
17045
17254
  policy.accountCooldownMs,
@@ -19922,7 +20131,7 @@ async function processNonStreamingResponse(params) {
19922
20131
  foundStr = true;
19923
20132
  }
19924
20133
  }
19925
- } else if (delta.phase === "answer") {
20134
+ } else if (isAnswerPhase(delta.phase)) {
19926
20135
  isThinkingChunk = false;
19927
20136
  if (delta.content !== void 0) {
19928
20137
  const newContent = delta.content || "";
@@ -20661,13 +20870,17 @@ async function processStreamingResponse(params) {
20661
20870
  return false;
20662
20871
  }
20663
20872
  const switchAccount = policy.switchAccount && !retryInvalidInputOnSameAccount;
20664
- if (switchAccount && (policy.accountCooldownMs || policy.accountCooldownReason)) {
20873
+ if (switchAccount && (policy.accountCooldownMs ?? 0) > 0) {
20665
20874
  markAccountRateLimited(
20666
20875
  currentAccountId,
20667
20876
  policy.accountCooldownMs,
20668
20877
  policy.accountCooldownReason || "StreamRetry"
20669
20878
  );
20670
20879
  }
20880
+ if (policy.accountCooldownReason === "AuthExpired") {
20881
+ Promise.resolve().then(() => (init_playwright(), playwright_exports)).then(({ refreshAccountToken: refreshAccountToken2 }) => refreshAccountToken2(currentAccountId)).catch(() => {
20882
+ });
20883
+ }
20671
20884
  retryContext.releaseAccountLease?.();
20672
20885
  retryContext.releaseAccountLease = null;
20673
20886
  await reader.cancel().catch(() => void 0);
@@ -20911,7 +21124,7 @@ async function processStreamingResponse(params) {
20911
21124
  }
20912
21125
  );
20913
21126
  }
20914
- if (delta.phase === "answer" && delta.status === "finished") {
21127
+ if (isAnswerPhase(delta.phase) && delta.status === "finished") {
20915
21128
  upstreamDone = true;
20916
21129
  if (!clientDisconnected) flushWrites();
20917
21130
  break;
@@ -20934,7 +21147,7 @@ async function processStreamingResponse(params) {
20934
21147
  foundStr = true;
20935
21148
  }
20936
21149
  }
20937
- } else if (delta.phase === "answer") {
21150
+ } else if (isAnswerPhase(delta.phase)) {
20938
21151
  isThinkingChunk = false;
20939
21152
  if (delta.content !== void 0) {
20940
21153
  const newContent = delta.content || "";
@@ -21312,7 +21525,7 @@ Please retry your tool call(s) with correct JSON and valid tool names from the a
21312
21525
  if (!delta) {
21313
21526
  continue;
21314
21527
  }
21315
- if (delta.phase === "answer" && delta.status === "finished") {
21528
+ if (isAnswerPhase(delta.phase) && delta.status === "finished") {
21316
21529
  upstreamDone = true;
21317
21530
  break retryReadLoop;
21318
21531
  }
@@ -25506,11 +25719,14 @@ function recordServerLog(level, text) {
25506
25719
  }
25507
25720
  line = line.replace(/^(?:\[?(?:INFO|WARN|WARNING|ERROR|ERR|DEBUG)\]?\s+)+/i, "").replace(/([\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}\u{2300}-\u{23FF}]\uFE0F?)\s{2,}/gu, "$1 ");
25508
25721
  if (!line) continue;
25509
- const isDuplicate = logHistory.slice(-10).some((entry2) => entry2.time === time && entry2.level === level && entry2.message === line);
25722
+ const now = Date.now();
25723
+ const isDuplicate = logHistory.slice(-10).some(
25724
+ (entry2) => (entry2.time === time || entry2._ts && now - entry2._ts < 1500) && entry2.level === level && entry2.message === line
25725
+ );
25510
25726
  if (isDuplicate) {
25511
25727
  continue;
25512
25728
  }
25513
- const entry = { time, level, message: line };
25729
+ const entry = { time, level, message: line, _ts: now };
25514
25730
  logHistory.push(entry);
25515
25731
  if (logHistory.length > MAX_LOG_HISTORY) {
25516
25732
  logHistory.shift();
@@ -25673,7 +25889,7 @@ function getAppVersion() {
25673
25889
  }
25674
25890
  } catch {
25675
25891
  }
25676
- cachedVersion = "v1.4.7";
25892
+ cachedVersion = "v1.5.0";
25677
25893
  return cachedVersion;
25678
25894
  }
25679
25895
  var cachedVersion;