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/login.js CHANGED
@@ -359,6 +359,7 @@ function runMigrations(db2) {
359
359
  "sec_ch_ua_mobile TEXT",
360
360
  "sec_ch_ua_platform TEXT",
361
361
  "version TEXT",
362
+ "refresh_token TEXT",
362
363
  "captured_at INTEGER DEFAULT 0"
363
364
  ];
364
365
  for (const col of authSessionCols) {
@@ -437,11 +438,11 @@ function saveAuthSession(accountId, session) {
437
438
  INSERT OR REPLACE INTO qwen_auth_sessions (
438
439
  account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
439
440
  sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
440
- user_id, token_expires_at, captured_at, updated_at
441
+ user_id, token_expires_at, refresh_token, captured_at, updated_at
441
442
  ) VALUES (
442
443
  ?, ?, ?, ?, ?, ?,
443
444
  ?, ?, ?, ?,
444
- ?, ?, ?, datetime('now')
445
+ ?, ?, ?, ?, datetime('now')
445
446
  )
446
447
  `);
447
448
  stmt.run(
@@ -457,6 +458,7 @@ function saveAuthSession(accountId, session) {
457
458
  session.version || null,
458
459
  session.userId || null,
459
460
  session.tokenExpiresAt || null,
461
+ session.refreshToken || null,
460
462
  session.capturedAt ?? Date.now()
461
463
  );
462
464
  }
@@ -465,7 +467,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
465
467
  const row = database.prepare(
466
468
  `SELECT account_id, cookie, user_agent, bx_v, bx_ua, bx_umidtoken,
467
469
  sec_ch_ua, sec_ch_ua_mobile, sec_ch_ua_platform, version,
468
- user_id, token_expires_at, captured_at
470
+ user_id, token_expires_at, refresh_token, captured_at
469
471
  FROM qwen_auth_sessions WHERE account_id = ?`
470
472
  ).get(accountId);
471
473
  if (!row) return null;
@@ -473,7 +475,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
473
475
  if (capturedAt <= 0 || Date.now() - capturedAt > maxAgeMs) {
474
476
  return null;
475
477
  }
476
- if (row.token_expires_at) {
478
+ if (!row.refresh_token && row.token_expires_at) {
477
479
  const tokenExpMs = Number(row.token_expires_at) * 1e3;
478
480
  if (tokenExpMs <= Date.now() + 5 * 60 * 1e3) {
479
481
  return null;
@@ -495,6 +497,7 @@ function getValidAuthSession(accountId, maxAgeMs = 30 * 24 * 60 * 60 * 1e3) {
495
497
  version: row.version || void 0,
496
498
  userId: row.user_id || void 0,
497
499
  tokenExpiresAt: row.token_expires_at ? Number(row.token_expires_at) : void 0,
500
+ refreshToken: row.refresh_token || void 0,
498
501
  capturedAt
499
502
  };
500
503
  }
@@ -3137,6 +3140,7 @@ __export(playwright_exports, {
3137
3140
  parseCookiesForBrowser: () => parseCookiesForBrowser,
3138
3141
  pruneAllPlaywrightProfiles: () => pruneAllPlaywrightProfiles,
3139
3142
  prunePlaywrightProfileCaches: () => prunePlaywrightProfileCaches,
3143
+ refreshAccountToken: () => refreshAccountToken,
3140
3144
  refreshHeaders: () => refreshHeaders,
3141
3145
  refreshHeadersWithProfileReset: () => refreshHeadersWithProfileReset,
3142
3146
  registerPlaywrightAccountForTests: () => registerPlaywrightAccountForTests,
@@ -3864,8 +3868,29 @@ function getStealthScript(profile) {
3864
3868
  const _toBlob = HTMLCanvasElement.prototype.toBlob;
3865
3869
  const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
3866
3870
 
3871
+ function isCaptchaCanvas(canvas) {
3872
+ try {
3873
+ if (!canvas) return false;
3874
+ const id = (canvas.id || "").toLowerCase();
3875
+ const cls = (canvas.className || "").toLowerCase();
3876
+ return (
3877
+ id.includes("baxia") ||
3878
+ id.includes("nc_") ||
3879
+ id.includes("captcha") ||
3880
+ id.includes("punish") ||
3881
+ cls.includes("baxia") ||
3882
+ cls.includes("nc_") ||
3883
+ cls.includes("captcha") ||
3884
+ Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
3885
+ );
3886
+ } catch(e) {
3887
+ return false;
3888
+ }
3889
+ }
3890
+
3867
3891
  function addNoise(canvas) {
3868
3892
  try {
3893
+ if (isCaptchaCanvas(canvas)) return;
3869
3894
  const ctx = canvas.getContext('2d');
3870
3895
  if (!ctx) return;
3871
3896
  const style = ctx.fillStyle;
@@ -3889,6 +3914,9 @@ function getStealthScript(profile) {
3889
3914
 
3890
3915
  CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
3891
3916
  const imageData = _getImageData.apply(this, arguments);
3917
+ if (isCaptchaCanvas(this.canvas)) {
3918
+ return imageData;
3919
+ }
3892
3920
  const data = imageData.data;
3893
3921
  const maxPixels = Math.min(data.length / 4, 2500);
3894
3922
  for (let i = 0; i < maxPixels * 4; i += 4) {
@@ -4748,6 +4776,7 @@ async function loginToQwen(accountId, email, password) {
4748
4776
  secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
4749
4777
  version: cache.headers["version"] || void 0,
4750
4778
  tokenExpiresAt: exp || void 0,
4779
+ refreshToken: apiResult.refreshToken,
4751
4780
  capturedAt: Date.now()
4752
4781
  });
4753
4782
  }
@@ -4781,6 +4810,13 @@ async function loginToQwen(accountId, email, password) {
4781
4810
  markAccountHeadersReady(accountId);
4782
4811
  const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
4783
4812
  const exp = parseJwtExpiry(tokenCookie.value);
4813
+ let rTok = uiResult.refreshToken;
4814
+ if (!rTok) {
4815
+ try {
4816
+ rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
4817
+ } catch {
4818
+ }
4819
+ }
4784
4820
  saveAuthSession2(accountId, {
4785
4821
  cookie: cookieStr,
4786
4822
  userAgent: cache.headers["user-agent"] || "",
@@ -4792,6 +4828,7 @@ async function loginToQwen(accountId, email, password) {
4792
4828
  secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
4793
4829
  version: cache.headers["version"] || void 0,
4794
4830
  tokenExpiresAt: exp || void 0,
4831
+ refreshToken: rTok,
4795
4832
  capturedAt: Date.now()
4796
4833
  });
4797
4834
  }
@@ -4844,37 +4881,52 @@ async function loginToQwen(accountId, email, password) {
4844
4881
  async function loginViaApi(page, email, password) {
4845
4882
  try {
4846
4883
  const hashedPassword = crypto3.createHash("sha256").update(password).digest("hex");
4847
- const signinUrl = qwenUrl("/api/v2/auths/signin");
4848
- let signinSuccess = false;
4849
- let data = null;
4850
- if (page.request && typeof page.request.post === "function") {
4851
- try {
4852
- const response = await page.request.post(signinUrl, {
4853
- data: {
4854
- email,
4855
- password: hashedPassword,
4856
- login_type: "email"
4857
- },
4858
- headers: {
4859
- "content-type": "application/json",
4860
- accept: "application/json, text/plain, */*",
4861
- referer: qwenUrl("/auth"),
4862
- origin: qwenOrigin(),
4863
- source: "web"
4864
- },
4865
- timeout: 1e4
4866
- });
4867
- data = await response.json().catch(() => null);
4868
- signinSuccess = Boolean(data && (data.success === true || data.token));
4869
- } catch {
4870
- }
4884
+ if (!page.url().includes("/auth")) {
4885
+ await page.goto(qwenUrl("/auth"), {
4886
+ waitUntil: "domcontentloaded",
4887
+ timeout: config.timeouts.navigation
4888
+ }).catch(() => {
4889
+ });
4890
+ await sleep2(1e3);
4871
4891
  }
4872
- if (!signinSuccess && !data) {
4873
- const requestId = crypto3.randomUUID();
4874
- const evalRes = await page.evaluate(
4875
- async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
4892
+ const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
4893
+ const requestId = crypto3.randomUUID();
4894
+ const evalRes = await page.evaluate(
4895
+ async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
4896
+ try {
4897
+ const response = await fetch(signinUrl2, {
4898
+ method: "POST",
4899
+ signal: AbortSignal.timeout(15e3),
4900
+ credentials: "include",
4901
+ headers: {
4902
+ accept: "application/json, text/plain, */*",
4903
+ "content-type": "application/json",
4904
+ source: "web",
4905
+ version: "0.3.11",
4906
+ "x-request-origin": "https://chat.qwen.ai",
4907
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
4908
+ "x-request-id": requestId2
4909
+ },
4910
+ body: JSON.stringify({ email: email2, password: password2 })
4911
+ });
4912
+ const json = await response.json().catch(() => null);
4913
+ return { ok: response.ok, status: response.status, data: json };
4914
+ } catch (e) {
4915
+ return { ok: false, error: e.message };
4916
+ }
4917
+ },
4918
+ { email, password: hashedPassword, signinUrl, requestId }
4919
+ ).catch(() => null);
4920
+ let data = evalRes?.data;
4921
+ let signinSuccess = Boolean(
4922
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
4923
+ );
4924
+ if (!signinSuccess && !data?.data?.code) {
4925
+ const fallbackUrl = qwenUrl("/api/v2/auths/signin");
4926
+ const fallbackRes = await page.evaluate(
4927
+ async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
4876
4928
  try {
4877
- const response = await fetch(signinUrl2, {
4929
+ const response = await fetch(fallbackUrl2, {
4878
4930
  method: "POST",
4879
4931
  signal: AbortSignal.timeout(1e4),
4880
4932
  credentials: "include",
@@ -4882,10 +4934,11 @@ async function loginViaApi(page, email, password) {
4882
4934
  accept: "application/json, text/plain, */*",
4883
4935
  "content-type": "application/json",
4884
4936
  source: "web",
4937
+ version: "0.3.11",
4885
4938
  timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
4886
4939
  "x-request-id": requestId2
4887
4940
  },
4888
- body: JSON.stringify({ email: email2, password: password2, login_type: "email" })
4941
+ body: JSON.stringify({ email: email2, password: password2 })
4889
4942
  });
4890
4943
  const json = await response.json().catch(() => null);
4891
4944
  return { ok: response.ok, status: response.status, data: json };
@@ -4893,11 +4946,13 @@ async function loginViaApi(page, email, password) {
4893
4946
  return { ok: false, error: e.message };
4894
4947
  }
4895
4948
  },
4896
- { email, password: hashedPassword, signinUrl, requestId }
4949
+ { email, password: hashedPassword, fallbackUrl, requestId }
4897
4950
  ).catch(() => null);
4898
- if (evalRes?.data) {
4899
- data = evalRes.data;
4900
- signinSuccess = Boolean(data && (data.success === true || data.token));
4951
+ if (fallbackRes?.data) {
4952
+ data = fallbackRes.data;
4953
+ signinSuccess = Boolean(
4954
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
4955
+ );
4901
4956
  }
4902
4957
  }
4903
4958
  if (data?.success === false) {
@@ -4911,7 +4966,8 @@ async function loginViaApi(page, email, password) {
4911
4966
  };
4912
4967
  }
4913
4968
  if (signinSuccess) {
4914
- const token = data?.data?.token || data?.token;
4969
+ const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
4970
+ const refreshToken = data?.data?.refresh_token || data?.refresh_token;
4915
4971
  if (token) {
4916
4972
  try {
4917
4973
  await page.context().addCookies([
@@ -4935,18 +4991,23 @@ async function loginViaApi(page, email, password) {
4935
4991
  }).catch(() => {
4936
4992
  });
4937
4993
  if (token) {
4938
- await page.evaluate((tok) => {
4939
- try {
4940
- localStorage.removeItem("qwen_token_logged_out_marker");
4941
- localStorage.setItem("token", tok);
4942
- document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
4943
- } catch {
4944
- }
4945
- }, token).catch(() => {
4994
+ await page.evaluate(
4995
+ ({ tok, rTok }) => {
4996
+ try {
4997
+ localStorage.removeItem("qwen_token_logged_out_marker");
4998
+ localStorage.setItem("token", tok);
4999
+ localStorage.setItem("access_token", tok);
5000
+ if (rTok) localStorage.setItem("refresh_token", rTok);
5001
+ document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
5002
+ } catch {
5003
+ }
5004
+ },
5005
+ { tok: token, rTok: refreshToken }
5006
+ ).catch(() => {
4946
5007
  });
4947
5008
  await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
4948
5009
  });
4949
- return { success: true };
5010
+ return { success: true, token, refreshToken };
4950
5011
  }
4951
5012
  }
4952
5013
  return {
@@ -4970,11 +5031,23 @@ async function loginViaApi(page, email, password) {
4970
5031
  }
4971
5032
  async function loginViaUi(page, email, password) {
4972
5033
  try {
4973
- await page.goto(qwenUrl("/auth"), {
4974
- waitUntil: "domcontentloaded",
4975
- timeout: config.timeouts.navigation
4976
- });
4977
- await sleep2(1500);
5034
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
5035
+ return { success: true };
5036
+ }
5037
+ try {
5038
+ await page.goto(qwenUrl("/auth"), {
5039
+ waitUntil: "domcontentloaded",
5040
+ timeout: Math.min(config.timeouts.navigation, 15e3)
5041
+ });
5042
+ await sleep2(1e3);
5043
+ } catch (gotoErr) {
5044
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
5045
+ return { success: true };
5046
+ }
5047
+ }
5048
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
5049
+ return { success: true };
5050
+ }
4978
5051
  const emailSelector = [
4979
5052
  'input[type="email"]',
4980
5053
  'input[name="email"]',
@@ -4984,7 +5057,7 @@ async function loginViaUi(page, email, password) {
4984
5057
  ].join(", ");
4985
5058
  try {
4986
5059
  await page.waitForSelector(emailSelector, {
4987
- timeout: Math.min(config.timeouts.page, 8e3)
5060
+ timeout: Math.min(config.timeouts.page, 5e3)
4988
5061
  });
4989
5062
  } catch {
4990
5063
  if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
@@ -4997,30 +5070,55 @@ async function loginViaUi(page, email, password) {
4997
5070
  return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
4998
5071
  }
4999
5072
  await clearVisibleChallenge(page);
5000
- const findPasswordModeButton = () => {
5001
- return page.locator('button, [role="button"], a, div').filter({
5002
- 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
5003
- }).first();
5073
+ const isPasswordInputPresent = async () => {
5074
+ return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
5004
5075
  };
5005
- try {
5006
- const pwdModeBtn = findPasswordModeButton();
5007
- if (await pwdModeBtn.isVisible({ timeout: 2e3 }).catch(() => false)) {
5008
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
5076
+ const revealPasswordMode = async () => {
5077
+ if (page.url().includes("/forget")) {
5078
+ await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
5009
5079
  });
5010
- await sleep2(500);
5080
+ await sleep2(1e3);
5011
5081
  }
5012
- } catch {
5013
- }
5014
- await page.fill(emailSelector, email);
5015
- await sleep2(300);
5016
- try {
5017
- const pwdModeBtn = findPasswordModeButton();
5018
- if (await pwdModeBtn.isVisible({ timeout: 1500 }).catch(() => false)) {
5019
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
5082
+ if (await isPasswordInputPresent()) return;
5083
+ const btn = page.locator("button").filter({
5084
+ 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
5085
+ }).filter({
5086
+ hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
5087
+ }).first();
5088
+ if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
5089
+ await btn.click({ timeout: 2e3 }).catch(() => {
5020
5090
  });
5021
5091
  await sleep2(500);
5022
5092
  }
5093
+ if (await isPasswordInputPresent()) return;
5094
+ await page.evaluate(() => {
5095
+ try {
5096
+ const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
5097
+ for (const b of buttons) {
5098
+ const txt = (b.innerText || "").trim().toLowerCase();
5099
+ 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")) {
5100
+ b.click();
5101
+ return true;
5102
+ }
5103
+ }
5104
+ } catch {
5105
+ }
5106
+ return false;
5107
+ }).catch(() => false);
5108
+ await sleep2(500);
5109
+ };
5110
+ await revealPasswordMode();
5111
+ try {
5112
+ await page.fill(emailSelector, email, { timeout: 8e3 });
5113
+ await sleep2(300);
5023
5114
  } catch {
5115
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
5116
+ return { success: true };
5117
+ }
5118
+ throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
5119
+ }
5120
+ if (!await isPasswordInputPresent()) {
5121
+ await revealPasswordMode();
5024
5122
  }
5025
5123
  const passwordSelector = 'input[type="password"], input[name="password"]';
5026
5124
  try {
@@ -5039,17 +5137,50 @@ async function loginViaUi(page, email, password) {
5039
5137
  reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
5040
5138
  };
5041
5139
  }
5042
- await page.fill(passwordSelector, password);
5043
- await sleep2(500);
5140
+ try {
5141
+ await page.fill(passwordSelector, password, { timeout: 8e3 });
5142
+ await sleep2(500);
5143
+ } catch {
5144
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
5145
+ return { success: true };
5146
+ }
5147
+ throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
5148
+ }
5149
+ await page.evaluate(() => {
5150
+ try {
5151
+ const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
5152
+ const passEl = document.querySelector('input[type="password"], input[name="password"]');
5153
+ if (emailEl) {
5154
+ emailEl.dispatchEvent(new Event("input", { bubbles: true }));
5155
+ emailEl.dispatchEvent(new Event("change", { bubbles: true }));
5156
+ emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
5157
+ }
5158
+ if (passEl) {
5159
+ passEl.dispatchEvent(new Event("input", { bubbles: true }));
5160
+ passEl.dispatchEvent(new Event("change", { bubbles: true }));
5161
+ passEl.dispatchEvent(new Event("blur", { bubbles: true }));
5162
+ }
5163
+ } catch {
5164
+ }
5165
+ }).catch(() => {
5166
+ });
5044
5167
  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")';
5045
5168
  const submitButton = page.locator(submitSelector).first();
5046
5169
  try {
5047
5170
  await page.waitForSelector('button[type="submit"]:not([disabled])', {
5048
- timeout: 5e3
5171
+ timeout: 4e3
5049
5172
  });
5050
5173
  await submitButton.click();
5051
5174
  } catch {
5052
- await page.keyboard.press("Enter");
5175
+ const isDisabled = await submitButton.isDisabled().catch(() => true);
5176
+ if (!isDisabled) {
5177
+ await submitButton.click({ force: true }).catch(() => {
5178
+ });
5179
+ } else {
5180
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
5181
+ return { success: true };
5182
+ }
5183
+ }
5053
5184
  }
5054
5185
  const postSubmitDeadline = Date.now() + 15e3;
5055
5186
  while (Date.now() < postSubmitDeadline) {
@@ -5119,6 +5250,137 @@ async function loginViaUi(page, email, password) {
5119
5250
  return { success: false, reason: err?.message || String(err) };
5120
5251
  }
5121
5252
  }
5253
+ async function refreshAccountToken(accountId) {
5254
+ const page = accountPages.get(accountId);
5255
+ if (!page || page.isClosed()) {
5256
+ return { success: false, error: "Account page not active" };
5257
+ }
5258
+ const { getValidAuthSession: getValidAuthSession2, saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5259
+ const session = getValidAuthSession2(accountId);
5260
+ let refreshToken = session?.refreshToken;
5261
+ if (!refreshToken) {
5262
+ try {
5263
+ refreshToken = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
5264
+ } catch {
5265
+ }
5266
+ }
5267
+ if (refreshToken) {
5268
+ try {
5269
+ const refreshResult = await page.evaluate(
5270
+ async ({ rTok }) => {
5271
+ try {
5272
+ const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
5273
+ method: "GET",
5274
+ credentials: "include",
5275
+ headers: {
5276
+ accept: "application/json, text/plain, */*",
5277
+ source: "web",
5278
+ version: "0.3.11",
5279
+ "x-request-origin": "https://chat.qwen.ai",
5280
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
5281
+ authorization: `Bearer ${rTok}`
5282
+ }
5283
+ });
5284
+ const json2 = await response.json().catch(() => null);
5285
+ return { ok: response.ok, status: response.status, data: json2 };
5286
+ } catch (e) {
5287
+ return { ok: false, error: e.message };
5288
+ }
5289
+ },
5290
+ { rTok: refreshToken }
5291
+ );
5292
+ const json = refreshResult?.data;
5293
+ if (json && json.success === true && json.data) {
5294
+ const newAccessToken = json.data.access_token || json.data.token;
5295
+ const newRefreshToken = json.data.refresh_token || refreshToken;
5296
+ if (newAccessToken) {
5297
+ await page.context().addCookies([
5298
+ {
5299
+ name: "token",
5300
+ value: newAccessToken,
5301
+ domain: ".qwen.ai",
5302
+ path: "/",
5303
+ expires: Math.floor(Date.now() / 1e3) + 31536e3,
5304
+ httpOnly: false,
5305
+ secure: true,
5306
+ sameSite: "Lax"
5307
+ }
5308
+ ]);
5309
+ await page.evaluate(
5310
+ ({ tok, rTok }) => {
5311
+ try {
5312
+ localStorage.removeItem("qwen_token_logged_out_marker");
5313
+ localStorage.setItem("token", tok);
5314
+ localStorage.setItem("access_token", tok);
5315
+ if (rTok) localStorage.setItem("refresh_token", rTok);
5316
+ document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
5317
+ } catch {
5318
+ }
5319
+ },
5320
+ { tok: newAccessToken, rTok: newRefreshToken }
5321
+ ).catch(() => {
5322
+ });
5323
+ const liveCookies = await page.context().cookies();
5324
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
5325
+ const cache = getHeaderCache(accountId);
5326
+ cache.headers.cookie = cookieStr;
5327
+ cache.lastRefresh = Date.now();
5328
+ markAccountHeadersReady(accountId);
5329
+ saveAuthSession2(accountId, {
5330
+ cookie: cookieStr,
5331
+ userAgent: cache.headers["user-agent"] || session?.userAgent || "",
5332
+ bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
5333
+ bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
5334
+ bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
5335
+ secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
5336
+ secChUaMobile: cache.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
5337
+ secChUaPlatform: cache.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
5338
+ version: cache.headers["version"] || session?.version,
5339
+ userId: session?.userId,
5340
+ tokenExpiresAt: parseJwtExpiry(newAccessToken) || void 0,
5341
+ refreshToken: newRefreshToken,
5342
+ capturedAt: Date.now()
5343
+ });
5344
+ return { success: true, token: newAccessToken };
5345
+ }
5346
+ }
5347
+ } catch {
5348
+ }
5349
+ }
5350
+ const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
5351
+ const creds = getAccountCredentials2(accountId);
5352
+ if (creds && creds.email && creds.password) {
5353
+ const apiResult = await loginViaApi(page, creds.email, creds.password);
5354
+ if (apiResult.success) {
5355
+ const liveCookies = await page.context().cookies();
5356
+ const tokenCookie = liveCookies.find((c) => c.name === "token");
5357
+ if (tokenCookie) {
5358
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
5359
+ const cache = getHeaderCache(accountId);
5360
+ cache.headers.cookie = cookieStr;
5361
+ cache.lastRefresh = Date.now();
5362
+ markAccountHeadersReady(accountId);
5363
+ saveAuthSession2(accountId, {
5364
+ cookie: cookieStr,
5365
+ userAgent: cache.headers["user-agent"] || session?.userAgent || "",
5366
+ bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
5367
+ bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
5368
+ bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
5369
+ secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
5370
+ secChUaMobile: cache.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
5371
+ secChUaPlatform: cache.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
5372
+ version: cache.headers["version"] || session?.version,
5373
+ userId: session?.userId,
5374
+ tokenExpiresAt: parseJwtExpiry(tokenCookie.value) || void 0,
5375
+ refreshToken: apiResult.refreshToken,
5376
+ capturedAt: Date.now()
5377
+ });
5378
+ return { success: true, token: tokenCookie.value };
5379
+ }
5380
+ }
5381
+ }
5382
+ return { success: false, error: "Could not refresh or re-authenticate token" };
5383
+ }
5122
5384
  async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
5123
5385
  const page = pageOverride ?? accountPages.get(accountId);
5124
5386
  if (!page || page.isClosed()) {
@@ -5635,6 +5897,10 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
5635
5897
  }
5636
5898
  };
5637
5899
  if (forceReauth) {
5900
+ const refreshed = await refreshAccountToken(accountId);
5901
+ if (refreshed.success) {
5902
+ return;
5903
+ }
5638
5904
  await executeReauth();
5639
5905
  } else {
5640
5906
  try {
@@ -6069,19 +6335,15 @@ async function keepAlivePlaywrightAccount(accountId) {
6069
6335
  const now = Date.now();
6070
6336
  const currentUrl = page.url();
6071
6337
  const cookie = await getCookies(accountId);
6072
- if (cookie && isTokenExpiringSoon(cookie, 45)) {
6338
+ if (cookie && isTokenExpiringSoon(cookie, 5)) {
6073
6339
  console.log(
6074
- `\u{1F493} [SessionKeeper] Account ${accountId} token expires within 45m; proactively renewing session...`
6340
+ `\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
6075
6341
  );
6076
- try {
6077
- await refreshHeadersInternal(accountId, config.timeouts.headers, true);
6342
+ const res = await refreshAccountToken(accountId);
6343
+ if (res.success) {
6078
6344
  lastKeepAliveNavigation.set(accountId, now);
6079
6345
  touchAccountActivity(accountId);
6080
6346
  return true;
6081
- } catch (err) {
6082
- console.warn(
6083
- `[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
6084
- );
6085
6347
  }
6086
6348
  }
6087
6349
  const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;