qwenproxy-cli 1.4.3 → 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,
@@ -4996,8 +5000,29 @@ function getStealthScript(profile) {
4996
5000
  const _toBlob = HTMLCanvasElement.prototype.toBlob;
4997
5001
  const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
4998
5002
 
5003
+ function isCaptchaCanvas(canvas) {
5004
+ try {
5005
+ if (!canvas) return false;
5006
+ const id = (canvas.id || "").toLowerCase();
5007
+ const cls = (canvas.className || "").toLowerCase();
5008
+ return (
5009
+ id.includes("baxia") ||
5010
+ id.includes("nc_") ||
5011
+ id.includes("captcha") ||
5012
+ id.includes("punish") ||
5013
+ cls.includes("baxia") ||
5014
+ cls.includes("nc_") ||
5015
+ cls.includes("captcha") ||
5016
+ Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
5017
+ );
5018
+ } catch(e) {
5019
+ return false;
5020
+ }
5021
+ }
5022
+
4999
5023
  function addNoise(canvas) {
5000
5024
  try {
5025
+ if (isCaptchaCanvas(canvas)) return;
5001
5026
  const ctx = canvas.getContext('2d');
5002
5027
  if (!ctx) return;
5003
5028
  const style = ctx.fillStyle;
@@ -5021,6 +5046,9 @@ function getStealthScript(profile) {
5021
5046
 
5022
5047
  CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
5023
5048
  const imageData = _getImageData.apply(this, arguments);
5049
+ if (isCaptchaCanvas(this.canvas)) {
5050
+ return imageData;
5051
+ }
5024
5052
  const data = imageData.data;
5025
5053
  const maxPixels = Math.min(data.length / 4, 2500);
5026
5054
  for (let i = 0; i < maxPixels * 4; i += 4) {
@@ -5880,6 +5908,7 @@ async function loginToQwen(accountId, email, password) {
5880
5908
  secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || void 0,
5881
5909
  version: cache3.headers["version"] || void 0,
5882
5910
  tokenExpiresAt: exp || void 0,
5911
+ refreshToken: apiResult.refreshToken,
5883
5912
  capturedAt: Date.now()
5884
5913
  });
5885
5914
  }
@@ -5913,6 +5942,13 @@ async function loginToQwen(accountId, email, password) {
5913
5942
  markAccountHeadersReady(accountId);
5914
5943
  const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5915
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
+ }
5916
5952
  saveAuthSession2(accountId, {
5917
5953
  cookie: cookieStr,
5918
5954
  userAgent: cache3.headers["user-agent"] || "",
@@ -5924,6 +5960,7 @@ async function loginToQwen(accountId, email, password) {
5924
5960
  secChUaPlatform: cache3.headers["sec-ch-ua-platform"] || void 0,
5925
5961
  version: cache3.headers["version"] || void 0,
5926
5962
  tokenExpiresAt: exp || void 0,
5963
+ refreshToken: rTok,
5927
5964
  capturedAt: Date.now()
5928
5965
  });
5929
5966
  }
@@ -5976,37 +6013,52 @@ async function loginToQwen(accountId, email, password) {
5976
6013
  async function loginViaApi(page, email, password) {
5977
6014
  try {
5978
6015
  const hashedPassword = crypto5.createHash("sha256").update(password).digest("hex");
5979
- const signinUrl = qwenUrl("/api/v2/auths/signin");
5980
- let signinSuccess = false;
5981
- let data = null;
5982
- if (page.request && typeof page.request.post === "function") {
5983
- try {
5984
- const response = await page.request.post(signinUrl, {
5985
- data: {
5986
- email,
5987
- password: hashedPassword,
5988
- login_type: "email"
5989
- },
5990
- headers: {
5991
- "content-type": "application/json",
5992
- accept: "application/json, text/plain, */*",
5993
- referer: qwenUrl("/auth"),
5994
- origin: qwenOrigin(),
5995
- source: "web"
5996
- },
5997
- timeout: 1e4
5998
- });
5999
- data = await response.json().catch(() => null);
6000
- signinSuccess = Boolean(data && (data.success === true || data.token));
6001
- } catch {
6002
- }
6016
+ if (!page.url().includes("/auth")) {
6017
+ await page.goto(qwenUrl("/auth"), {
6018
+ waitUntil: "domcontentloaded",
6019
+ timeout: config.timeouts.navigation
6020
+ }).catch(() => {
6021
+ });
6022
+ await sleep2(1e3);
6003
6023
  }
6004
- if (!signinSuccess && !data) {
6005
- const requestId = crypto5.randomUUID();
6006
- const evalRes = await page.evaluate(
6007
- async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
6024
+ const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
6025
+ const requestId = crypto5.randomUUID();
6026
+ const evalRes = await page.evaluate(
6027
+ async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
6028
+ try {
6029
+ const response = await fetch(signinUrl2, {
6030
+ method: "POST",
6031
+ signal: AbortSignal.timeout(15e3),
6032
+ credentials: "include",
6033
+ headers: {
6034
+ accept: "application/json, text/plain, */*",
6035
+ "content-type": "application/json",
6036
+ source: "web",
6037
+ version: "0.3.11",
6038
+ "x-request-origin": "https://chat.qwen.ai",
6039
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
6040
+ "x-request-id": requestId2
6041
+ },
6042
+ body: JSON.stringify({ email: email2, password: password2 })
6043
+ });
6044
+ const json = await response.json().catch(() => null);
6045
+ return { ok: response.ok, status: response.status, data: json };
6046
+ } catch (e) {
6047
+ return { ok: false, error: e.message };
6048
+ }
6049
+ },
6050
+ { email, password: hashedPassword, signinUrl, requestId }
6051
+ ).catch(() => null);
6052
+ let data = evalRes?.data;
6053
+ let signinSuccess = Boolean(
6054
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
6055
+ );
6056
+ if (!signinSuccess && !data?.data?.code) {
6057
+ const fallbackUrl = qwenUrl("/api/v2/auths/signin");
6058
+ const fallbackRes = await page.evaluate(
6059
+ async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
6008
6060
  try {
6009
- const response = await fetch(signinUrl2, {
6061
+ const response = await fetch(fallbackUrl2, {
6010
6062
  method: "POST",
6011
6063
  signal: AbortSignal.timeout(1e4),
6012
6064
  credentials: "include",
@@ -6014,10 +6066,11 @@ async function loginViaApi(page, email, password) {
6014
6066
  accept: "application/json, text/plain, */*",
6015
6067
  "content-type": "application/json",
6016
6068
  source: "web",
6069
+ version: "0.3.11",
6017
6070
  timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
6018
6071
  "x-request-id": requestId2
6019
6072
  },
6020
- body: JSON.stringify({ email: email2, password: password2, login_type: "email" })
6073
+ body: JSON.stringify({ email: email2, password: password2 })
6021
6074
  });
6022
6075
  const json = await response.json().catch(() => null);
6023
6076
  return { ok: response.ok, status: response.status, data: json };
@@ -6025,11 +6078,13 @@ async function loginViaApi(page, email, password) {
6025
6078
  return { ok: false, error: e.message };
6026
6079
  }
6027
6080
  },
6028
- { email, password: hashedPassword, signinUrl, requestId }
6081
+ { email, password: hashedPassword, fallbackUrl, requestId }
6029
6082
  ).catch(() => null);
6030
- if (evalRes?.data) {
6031
- data = evalRes.data;
6032
- signinSuccess = Boolean(data && (data.success === true || data.token));
6083
+ if (fallbackRes?.data) {
6084
+ data = fallbackRes.data;
6085
+ signinSuccess = Boolean(
6086
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
6087
+ );
6033
6088
  }
6034
6089
  }
6035
6090
  if (data?.success === false) {
@@ -6043,7 +6098,8 @@ async function loginViaApi(page, email, password) {
6043
6098
  };
6044
6099
  }
6045
6100
  if (signinSuccess) {
6046
- const token = data?.data?.token || data?.token;
6101
+ const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
6102
+ const refreshToken = data?.data?.refresh_token || data?.refresh_token;
6047
6103
  if (token) {
6048
6104
  try {
6049
6105
  await page.context().addCookies([
@@ -6067,18 +6123,23 @@ async function loginViaApi(page, email, password) {
6067
6123
  }).catch(() => {
6068
6124
  });
6069
6125
  if (token) {
6070
- await page.evaluate((tok) => {
6071
- try {
6072
- localStorage.removeItem("qwen_token_logged_out_marker");
6073
- localStorage.setItem("token", tok);
6074
- document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
6075
- } catch {
6076
- }
6077
- }, token).catch(() => {
6126
+ await page.evaluate(
6127
+ ({ tok, rTok }) => {
6128
+ try {
6129
+ localStorage.removeItem("qwen_token_logged_out_marker");
6130
+ localStorage.setItem("token", tok);
6131
+ localStorage.setItem("access_token", tok);
6132
+ if (rTok) localStorage.setItem("refresh_token", rTok);
6133
+ document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
6134
+ } catch {
6135
+ }
6136
+ },
6137
+ { tok: token, rTok: refreshToken }
6138
+ ).catch(() => {
6078
6139
  });
6079
6140
  await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
6080
6141
  });
6081
- return { success: true };
6142
+ return { success: true, token, refreshToken };
6082
6143
  }
6083
6144
  }
6084
6145
  return {
@@ -6102,11 +6163,23 @@ async function loginViaApi(page, email, password) {
6102
6163
  }
6103
6164
  async function loginViaUi(page, email, password) {
6104
6165
  try {
6105
- await page.goto(qwenUrl("/auth"), {
6106
- waitUntil: "domcontentloaded",
6107
- timeout: config.timeouts.navigation
6108
- });
6109
- await sleep2(1500);
6166
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
6167
+ return { success: true };
6168
+ }
6169
+ try {
6170
+ await page.goto(qwenUrl("/auth"), {
6171
+ waitUntil: "domcontentloaded",
6172
+ timeout: Math.min(config.timeouts.navigation, 15e3)
6173
+ });
6174
+ await sleep2(1e3);
6175
+ } catch (gotoErr) {
6176
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
6177
+ return { success: true };
6178
+ }
6179
+ }
6180
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
6181
+ return { success: true };
6182
+ }
6110
6183
  const emailSelector = [
6111
6184
  'input[type="email"]',
6112
6185
  'input[name="email"]',
@@ -6116,7 +6189,7 @@ async function loginViaUi(page, email, password) {
6116
6189
  ].join(", ");
6117
6190
  try {
6118
6191
  await page.waitForSelector(emailSelector, {
6119
- timeout: Math.min(config.timeouts.page, 8e3)
6192
+ timeout: Math.min(config.timeouts.page, 5e3)
6120
6193
  });
6121
6194
  } catch {
6122
6195
  if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
@@ -6129,30 +6202,55 @@ async function loginViaUi(page, email, password) {
6129
6202
  return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
6130
6203
  }
6131
6204
  await clearVisibleChallenge(page);
6132
- const findPasswordModeButton = () => {
6133
- return page.locator('button, [role="button"], a, div').filter({
6134
- hasText: /(?:log\s*in\s*with\s*(?:a\s*)?password|fazer\s*login\s*com\s*senha|entrar\s*com\s*(?:uma\s*)?senha|iniciar\s*sesi[oó]n\s*con\s*contrase[nñ]a|密码登录)/i
6135
- }).first();
6205
+ const isPasswordInputPresent = async () => {
6206
+ return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
6136
6207
  };
6137
- try {
6138
- const pwdModeBtn = findPasswordModeButton();
6139
- if (await pwdModeBtn.isVisible({ timeout: 2e3 }).catch(() => false)) {
6140
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
6208
+ const revealPasswordMode = async () => {
6209
+ if (page.url().includes("/forget")) {
6210
+ await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
6141
6211
  });
6142
- await sleep2(500);
6212
+ await sleep2(1e3);
6143
6213
  }
6144
- } catch {
6145
- }
6146
- await page.fill(emailSelector, email);
6147
- await sleep2(300);
6148
- try {
6149
- const pwdModeBtn = findPasswordModeButton();
6150
- if (await pwdModeBtn.isVisible({ timeout: 1500 }).catch(() => false)) {
6151
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
6214
+ if (await isPasswordInputPresent()) return;
6215
+ const btn = page.locator("button").filter({
6216
+ hasText: /(?:log\s*in\s*with\s*(?:a\s*)?password|fazer\s*login\s*com\s*senha|entrar\s*com\s*(?:uma\s*)?senha|iniciar\s*sesi[oó]n\s*con\s*contrase[nñ]a|密码登录)/i
6217
+ }).filter({
6218
+ hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
6219
+ }).first();
6220
+ if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
6221
+ await btn.click({ timeout: 2e3 }).catch(() => {
6152
6222
  });
6153
6223
  await sleep2(500);
6154
6224
  }
6225
+ if (await isPasswordInputPresent()) return;
6226
+ await page.evaluate(() => {
6227
+ try {
6228
+ const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
6229
+ for (const b of buttons) {
6230
+ const txt = (b.innerText || "").trim().toLowerCase();
6231
+ if (/(?:log\s*in\s*with\s*(?:a\s*)?password|fazer\s*login\s*com\s*senha|entrar\s*com\s*(?:uma\s*)?senha|iniciar\s*sesi[oó]n\s*con\s*contrase[nñ]a|密码登录)/i.test(txt) && !txt.includes("esqueci") && !txt.includes("forgot") && !txt.includes("olvid") && !txt.includes("reset")) {
6232
+ b.click();
6233
+ return true;
6234
+ }
6235
+ }
6236
+ } catch {
6237
+ }
6238
+ return false;
6239
+ }).catch(() => false);
6240
+ await sleep2(500);
6241
+ };
6242
+ await revealPasswordMode();
6243
+ try {
6244
+ await page.fill(emailSelector, email, { timeout: 8e3 });
6245
+ await sleep2(300);
6155
6246
  } catch {
6247
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
6248
+ return { success: true };
6249
+ }
6250
+ throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
6251
+ }
6252
+ if (!await isPasswordInputPresent()) {
6253
+ await revealPasswordMode();
6156
6254
  }
6157
6255
  const passwordSelector = 'input[type="password"], input[name="password"]';
6158
6256
  try {
@@ -6171,17 +6269,50 @@ async function loginViaUi(page, email, password) {
6171
6269
  reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
6172
6270
  };
6173
6271
  }
6174
- await page.fill(passwordSelector, password);
6175
- await sleep2(500);
6272
+ try {
6273
+ await page.fill(passwordSelector, password, { timeout: 8e3 });
6274
+ await sleep2(500);
6275
+ } catch {
6276
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
6277
+ return { success: true };
6278
+ }
6279
+ throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
6280
+ }
6281
+ await page.evaluate(() => {
6282
+ try {
6283
+ const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
6284
+ const passEl = document.querySelector('input[type="password"], input[name="password"]');
6285
+ if (emailEl) {
6286
+ emailEl.dispatchEvent(new Event("input", { bubbles: true }));
6287
+ emailEl.dispatchEvent(new Event("change", { bubbles: true }));
6288
+ emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
6289
+ }
6290
+ if (passEl) {
6291
+ passEl.dispatchEvent(new Event("input", { bubbles: true }));
6292
+ passEl.dispatchEvent(new Event("change", { bubbles: true }));
6293
+ passEl.dispatchEvent(new Event("blur", { bubbles: true }));
6294
+ }
6295
+ } catch {
6296
+ }
6297
+ }).catch(() => {
6298
+ });
6176
6299
  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")';
6177
6300
  const submitButton = page.locator(submitSelector).first();
6178
6301
  try {
6179
6302
  await page.waitForSelector('button[type="submit"]:not([disabled])', {
6180
- timeout: 5e3
6303
+ timeout: 4e3
6181
6304
  });
6182
6305
  await submitButton.click();
6183
6306
  } catch {
6184
- await page.keyboard.press("Enter");
6307
+ const isDisabled = await submitButton.isDisabled().catch(() => true);
6308
+ if (!isDisabled) {
6309
+ await submitButton.click({ force: true }).catch(() => {
6310
+ });
6311
+ } else {
6312
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
6313
+ return { success: true };
6314
+ }
6315
+ }
6185
6316
  }
6186
6317
  const postSubmitDeadline = Date.now() + 15e3;
6187
6318
  while (Date.now() < postSubmitDeadline) {
@@ -6251,6 +6382,137 @@ async function loginViaUi(page, email, password) {
6251
6382
  return { success: false, reason: err?.message || String(err) };
6252
6383
  }
6253
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
+ }
6254
6516
  async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
6255
6517
  const page = pageOverride ?? accountPages.get(accountId);
6256
6518
  if (!page || page.isClosed()) {
@@ -6767,6 +7029,10 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
6767
7029
  }
6768
7030
  };
6769
7031
  if (forceReauth) {
7032
+ const refreshed = await refreshAccountToken(accountId);
7033
+ if (refreshed.success) {
7034
+ return;
7035
+ }
6770
7036
  await executeReauth();
6771
7037
  } else {
6772
7038
  try {
@@ -7201,19 +7467,15 @@ async function keepAlivePlaywrightAccount(accountId) {
7201
7467
  const now = Date.now();
7202
7468
  const currentUrl = page.url();
7203
7469
  const cookie = await getCookies(accountId);
7204
- if (cookie && isTokenExpiringSoon(cookie, 45)) {
7470
+ if (cookie && isTokenExpiringSoon(cookie, 5)) {
7205
7471
  console.log(
7206
- `\u{1F493} [SessionKeeper] Account ${accountId} token expires within 45m; proactively renewing session...`
7472
+ `\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
7207
7473
  );
7208
- try {
7209
- await refreshHeadersInternal(accountId, config.timeouts.headers, true);
7474
+ const res = await refreshAccountToken(accountId);
7475
+ if (res.success) {
7210
7476
  lastKeepAliveNavigation.set(accountId, now);
7211
7477
  touchAccountActivity(accountId);
7212
7478
  return true;
7213
- } catch (err) {
7214
- console.warn(
7215
- `[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
7216
- );
7217
7479
  }
7218
7480
  }
7219
7481
  const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
@@ -9097,7 +9359,7 @@ function classifyRetryAction(err, options) {
9097
9359
  accountCooldownReason: "PersonalizationFailed"
9098
9360
  });
9099
9361
  }
9100
- 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")) {
9101
9363
  return makeRetryAction("account_initialization_failed", {
9102
9364
  switchAccount: true,
9103
9365
  forceNewChat: true,
@@ -10574,6 +10836,16 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
10574
10836
  }
10575
10837
  }
10576
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
+ }
10577
10849
  throw new QwenUpstreamError(
10578
10850
  `Qwen create chat unauthorized: ${raw.substring(0, 300)}`,
10579
10851
  "Unauthorized",
@@ -11269,16 +11541,28 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
11269
11541
  });
11270
11542
  if (response2.status === 401) {
11271
11543
  try {
11272
- const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
11273
- method: "GET",
11274
- credentials: "include",
11275
- signal: AbortSignal.timeout(3e3)
11276
- });
11277
- 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
+ });
11278
11559
  const refreshJson = await refreshRes.json().catch(() => null);
11279
- if (refreshJson && refreshJson.success === true && refreshJson.data?.token) {
11280
- 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) {
11281
11563
  localStorage.setItem("token", freshTok);
11564
+ localStorage.setItem("access_token", freshTok);
11565
+ if (nextRTok) localStorage.setItem("refresh_token", nextRTok);
11282
11566
  document.cookie = `token=${encodeURIComponent(freshTok)}; path=/; domain=.qwen.ai; max-age=31536000`;
11283
11567
  if (headers2["authorization"] || headers2["Authorization"]) {
11284
11568
  headers2["authorization"] = `Bearer ${freshTok}`;
@@ -11316,13 +11600,29 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
11316
11600
  }
11317
11601
  );
11318
11602
  const recoverOnTimeout = !options.noMutexRecovery;
11319
- const response = await withQwenBrowserPage(
11603
+ let response = await withQwenBrowserPage(
11320
11604
  accountId,
11321
11605
  evaluateRequest,
11322
11606
  void 0,
11323
11607
  options.timeoutMs,
11324
11608
  recoverOnTimeout
11325
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
+ }
11326
11626
  return new Response(response.raw, {
11327
11627
  status: response.status,
11328
11628
  headers: response.contentType ? { "content-type": response.contentType } : void 0
@@ -11845,7 +12145,11 @@ async function syncQwenRequestPersonalization(instruction, accountId, metadata =
11845
12145
  );
11846
12146
  try {
11847
12147
  currentSettings = null;
11848
- 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);
11849
12153
  requestHeaders = buildCapturedQwenHeaders(freshHeaders, {
11850
12154
  referer: qwenUrl("/settings/personalization")
11851
12155
  });
@@ -25513,7 +25817,7 @@ function getAppVersion() {
25513
25817
  }
25514
25818
  } catch {
25515
25819
  }
25516
- cachedVersion = "v1.4.3";
25820
+ cachedVersion = "v1.4.8";
25517
25821
  return cachedVersion;
25518
25822
  }
25519
25823
  var cachedVersion;