qwenproxy-cli 1.4.7 → 1.4.8

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
  }
@@ -4269,6 +4272,7 @@ __export(playwright_exports, {
4269
4272
  parseCookiesForBrowser: () => parseCookiesForBrowser,
4270
4273
  pruneAllPlaywrightProfiles: () => pruneAllPlaywrightProfiles,
4271
4274
  prunePlaywrightProfileCaches: () => prunePlaywrightProfileCaches,
4275
+ refreshAccountToken: () => refreshAccountToken,
4272
4276
  refreshHeaders: () => refreshHeaders,
4273
4277
  refreshHeadersWithProfileReset: () => refreshHeadersWithProfileReset,
4274
4278
  registerPlaywrightAccountForTests: () => registerPlaywrightAccountForTests,
@@ -5904,6 +5908,7 @@ async function loginToQwen(accountId, email, password) {
5904
5908
  secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || void 0,
5905
5909
  version: cache3.headers["version"] || void 0,
5906
5910
  tokenExpiresAt: exp || void 0,
5911
+ refreshToken: apiResult.refreshToken,
5907
5912
  capturedAt: Date.now()
5908
5913
  });
5909
5914
  }
@@ -5937,6 +5942,13 @@ async function loginToQwen(accountId, email, password) {
5937
5942
  markAccountHeadersReady(accountId);
5938
5943
  const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5939
5944
  const exp = parseJwtExpiry(tokenCookie.value);
5945
+ let rTok = uiResult.refreshToken;
5946
+ if (!rTok) {
5947
+ try {
5948
+ rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
5949
+ } catch {
5950
+ }
5951
+ }
5940
5952
  saveAuthSession2(accountId, {
5941
5953
  cookie: cookieStr,
5942
5954
  userAgent: cache3.headers["user-agent"] || "",
@@ -5948,6 +5960,7 @@ async function loginToQwen(accountId, email, password) {
5948
5960
  secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || void 0,
5949
5961
  version: cache3.headers["version"] || void 0,
5950
5962
  tokenExpiresAt: exp || void 0,
5963
+ refreshToken: rTok,
5951
5964
  capturedAt: Date.now()
5952
5965
  });
5953
5966
  }
@@ -6126,7 +6139,7 @@ async function loginViaApi(page, email, password) {
6126
6139
  });
6127
6140
  await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
6128
6141
  });
6129
- return { success: true };
6142
+ return { success: true, token, refreshToken };
6130
6143
  }
6131
6144
  }
6132
6145
  return {
@@ -6369,6 +6382,137 @@ async function loginViaUi(page, email, password) {
6369
6382
  return { success: false, reason: err?.message || String(err) };
6370
6383
  }
6371
6384
  }
6385
+ async function refreshAccountToken(accountId) {
6386
+ const page = accountPages.get(accountId);
6387
+ if (!page || page.isClosed()) {
6388
+ return { success: false, error: "Account page not active" };
6389
+ }
6390
+ const { getValidAuthSession: getValidAuthSession2, saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
6391
+ const session = getValidAuthSession2(accountId);
6392
+ let refreshToken = session?.refreshToken;
6393
+ if (!refreshToken) {
6394
+ try {
6395
+ refreshToken = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
6396
+ } catch {
6397
+ }
6398
+ }
6399
+ if (refreshToken) {
6400
+ try {
6401
+ const refreshResult = await page.evaluate(
6402
+ async ({ rTok }) => {
6403
+ try {
6404
+ const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
6405
+ method: "GET",
6406
+ credentials: "include",
6407
+ headers: {
6408
+ accept: "application/json, text/plain, */*",
6409
+ source: "web",
6410
+ version: "0.3.11",
6411
+ "x-request-origin": "https://chat.qwen.ai",
6412
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
6413
+ authorization: `Bearer ${rTok}`
6414
+ }
6415
+ });
6416
+ const json2 = await response.json().catch(() => null);
6417
+ return { ok: response.ok, status: response.status, data: json2 };
6418
+ } catch (e) {
6419
+ return { ok: false, error: e.message };
6420
+ }
6421
+ },
6422
+ { rTok: refreshToken }
6423
+ );
6424
+ const json = refreshResult?.data;
6425
+ if (json && json.success === true && json.data) {
6426
+ const newAccessToken = json.data.access_token || json.data.token;
6427
+ const newRefreshToken = json.data.refresh_token || refreshToken;
6428
+ if (newAccessToken) {
6429
+ await page.context().addCookies([
6430
+ {
6431
+ name: "token",
6432
+ value: newAccessToken,
6433
+ domain: ".qwen.ai",
6434
+ path: "/",
6435
+ expires: Math.floor(Date.now() / 1e3) + 31536e3,
6436
+ httpOnly: false,
6437
+ secure: true,
6438
+ sameSite: "Lax"
6439
+ }
6440
+ ]);
6441
+ await page.evaluate(
6442
+ ({ tok, rTok }) => {
6443
+ try {
6444
+ localStorage.removeItem("qwen_token_logged_out_marker");
6445
+ localStorage.setItem("token", tok);
6446
+ localStorage.setItem("access_token", tok);
6447
+ if (rTok) localStorage.setItem("refresh_token", rTok);
6448
+ document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
6449
+ } catch {
6450
+ }
6451
+ },
6452
+ { tok: newAccessToken, rTok: newRefreshToken }
6453
+ ).catch(() => {
6454
+ });
6455
+ const liveCookies = await page.context().cookies();
6456
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
6457
+ const cache3 = getHeaderCache(accountId);
6458
+ cache3.headers.cookie = cookieStr;
6459
+ cache3.lastRefresh = Date.now();
6460
+ markAccountHeadersReady(accountId);
6461
+ saveAuthSession2(accountId, {
6462
+ cookie: cookieStr,
6463
+ userAgent: cache3.headers["user-agent"] || session?.userAgent || "",
6464
+ bxV: cache3.headers["bx-v"] || session?.bxV || "2.5.37",
6465
+ bxUa: cache3.headers["bx-ua"] || session?.bxUa || "",
6466
+ bxUmidtoken: cache3.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
6467
+ secChUa: cache3.headers["sec-ch-ua"] || session?.secChUa,
6468
+ secChUaMobile: cache3.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
6469
+ secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
6470
+ version: cache3.headers["version"] || session?.version,
6471
+ userId: session?.userId,
6472
+ tokenExpiresAt: parseJwtExpiry(newAccessToken) || void 0,
6473
+ refreshToken: newRefreshToken,
6474
+ capturedAt: Date.now()
6475
+ });
6476
+ return { success: true, token: newAccessToken };
6477
+ }
6478
+ }
6479
+ } catch {
6480
+ }
6481
+ }
6482
+ const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
6483
+ const creds = getAccountCredentials2(accountId);
6484
+ if (creds && creds.email && creds.password) {
6485
+ const apiResult = await loginViaApi(page, creds.email, creds.password);
6486
+ if (apiResult.success) {
6487
+ const liveCookies = await page.context().cookies();
6488
+ const tokenCookie = liveCookies.find((c) => c.name === "token");
6489
+ if (tokenCookie) {
6490
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
6491
+ const cache3 = getHeaderCache(accountId);
6492
+ cache3.headers.cookie = cookieStr;
6493
+ cache3.lastRefresh = Date.now();
6494
+ markAccountHeadersReady(accountId);
6495
+ saveAuthSession2(accountId, {
6496
+ cookie: cookieStr,
6497
+ userAgent: cache3.headers["user-agent"] || session?.userAgent || "",
6498
+ bxV: cache3.headers["bx-v"] || session?.bxV || "2.5.37",
6499
+ bxUa: cache3.headers["bx-ua"] || session?.bxUa || "",
6500
+ bxUmidtoken: cache3.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
6501
+ secChUa: cache3.headers["sec-ch-ua"] || session?.secChUa,
6502
+ secChUaMobile: cache3.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
6503
+ secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
6504
+ version: cache3.headers["version"] || session?.version,
6505
+ userId: session?.userId,
6506
+ tokenExpiresAt: parseJwtExpiry(tokenCookie.value) || void 0,
6507
+ refreshToken: apiResult.refreshToken,
6508
+ capturedAt: Date.now()
6509
+ });
6510
+ return { success: true, token: tokenCookie.value };
6511
+ }
6512
+ }
6513
+ }
6514
+ return { success: false, error: "Could not refresh or re-authenticate token" };
6515
+ }
6372
6516
  async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
6373
6517
  const page = pageOverride ?? accountPages.get(accountId);
6374
6518
  if (!page || page.isClosed()) {
@@ -6885,16 +7029,9 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
6885
7029
  }
6886
7030
  };
6887
7031
  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
- }
7032
+ const refreshed = await refreshAccountToken(accountId);
7033
+ if (refreshed.success) {
7034
+ return;
6898
7035
  }
6899
7036
  await executeReauth();
6900
7037
  } else {
@@ -7330,50 +7467,15 @@ async function keepAlivePlaywrightAccount(accountId) {
7330
7467
  const now = Date.now();
7331
7468
  const currentUrl = page.url();
7332
7469
  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
- }
7470
+ if (cookie && isTokenExpiringSoon(cookie, 5)) {
7471
+ console.log(
7472
+ `\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
7473
+ );
7474
+ const res = await refreshAccountToken(accountId);
7475
+ if (res.success) {
7476
+ lastKeepAliveNavigation.set(accountId, now);
7477
+ touchAccountActivity(accountId);
7478
+ return true;
7377
7479
  }
7378
7480
  }
7379
7481
  const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
@@ -9257,7 +9359,7 @@ function classifyRetryAction(err, options) {
9257
9359
  accountCooldownReason: "PersonalizationFailed"
9258
9360
  });
9259
9361
  }
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"')) {
9362
+ 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
9363
  return makeRetryAction("account_initialization_failed", {
9262
9364
  switchAccount: true,
9263
9365
  forceNewChat: true,
@@ -10734,6 +10836,16 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
10734
10836
  }
10735
10837
  }
10736
10838
  if (json?.data?.code === "Unauthorized" || json?.code === "Unauthorized" || rawLower.includes("unauthorized") || rawLower.includes("permission to access")) {
10839
+ if (accountId) {
10840
+ try {
10841
+ const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
10842
+ const refreshed = await refreshAccountToken2(accountId);
10843
+ if (refreshed.success) {
10844
+ return createQwenChatSession(headers, model, accountId, chatMode);
10845
+ }
10846
+ } catch {
10847
+ }
10848
+ }
10737
10849
  throw new QwenUpstreamError(
10738
10850
  `Qwen create chat unauthorized: ${raw.substring(0, 300)}`,
10739
10851
  "Unauthorized",
@@ -11429,16 +11541,28 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
11429
11541
  });
11430
11542
  if (response2.status === 401) {
11431
11543
  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) {
11544
+ const rTok = localStorage.getItem("refresh_token");
11545
+ if (rTok) {
11546
+ const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
11547
+ method: "GET",
11548
+ credentials: "include",
11549
+ headers: {
11550
+ accept: "application/json, text/plain, */*",
11551
+ source: "web",
11552
+ version: "0.3.11",
11553
+ "x-request-origin": "https://chat.qwen.ai",
11554
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
11555
+ authorization: `Bearer ${rTok}`
11556
+ },
11557
+ signal: AbortSignal.timeout(5e3)
11558
+ });
11438
11559
  const refreshJson = await refreshRes.json().catch(() => null);
11439
- if (refreshJson && refreshJson.success === true && refreshJson.data?.token) {
11440
- const freshTok = refreshJson.data.token;
11560
+ const freshTok = refreshJson?.data?.access_token || refreshJson?.data?.token;
11561
+ const nextRTok = refreshJson?.data?.refresh_token;
11562
+ if (refreshJson?.success === true && freshTok) {
11441
11563
  localStorage.setItem("token", freshTok);
11564
+ localStorage.setItem("access_token", freshTok);
11565
+ if (nextRTok) localStorage.setItem("refresh_token", nextRTok);
11442
11566
  document.cookie = `token=${encodeURIComponent(freshTok)}; path=/; domain=.qwen.ai; max-age=31536000`;
11443
11567
  if (headers2["authorization"] || headers2["Authorization"]) {
11444
11568
  headers2["authorization"] = `Bearer ${freshTok}`;
@@ -11476,13 +11600,29 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
11476
11600
  }
11477
11601
  );
11478
11602
  const recoverOnTimeout = !options.noMutexRecovery;
11479
- const response = await withQwenBrowserPage(
11603
+ let response = await withQwenBrowserPage(
11480
11604
  accountId,
11481
11605
  evaluateRequest,
11482
11606
  void 0,
11483
11607
  options.timeoutMs,
11484
11608
  recoverOnTimeout
11485
11609
  );
11610
+ if (response.status === 401 && accountId) {
11611
+ try {
11612
+ const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
11613
+ const refreshed = await refreshAccountToken2(accountId);
11614
+ if (refreshed.success) {
11615
+ response = await withQwenBrowserPage(
11616
+ accountId,
11617
+ evaluateRequest,
11618
+ void 0,
11619
+ options.timeoutMs,
11620
+ recoverOnTimeout
11621
+ );
11622
+ }
11623
+ } catch {
11624
+ }
11625
+ }
11486
11626
  return new Response(response.raw, {
11487
11627
  status: response.status,
11488
11628
  headers: response.contentType ? { "content-type": response.contentType } : void 0
@@ -12005,7 +12145,11 @@ async function syncQwenRequestPersonalization(instruction, accountId, metadata =
12005
12145
  );
12006
12146
  try {
12007
12147
  currentSettings = null;
12008
- const { headers: freshHeaders } = await getQwenHeaders(true, accountId, true);
12148
+ const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
12149
+ if (accountId) {
12150
+ await refreshAccountToken2(accountId);
12151
+ }
12152
+ const { headers: freshHeaders } = await getQwenHeaders(false, accountId);
12009
12153
  requestHeaders = buildCapturedQwenHeaders(freshHeaders, {
12010
12154
  referer: qwenUrl("/settings/personalization")
12011
12155
  });
@@ -25673,7 +25817,7 @@ function getAppVersion() {
25673
25817
  }
25674
25818
  } catch {
25675
25819
  }
25676
- cachedVersion = "v1.4.7";
25820
+ cachedVersion = "v1.4.8";
25677
25821
  return cachedVersion;
25678
25822
  }
25679
25823
  var cachedVersion;