qwenproxy-cli 1.4.2 → 1.4.7

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.
@@ -3779,8 +3779,29 @@ function getStealthScript(profile) {
3779
3779
  const _toBlob = HTMLCanvasElement.prototype.toBlob;
3780
3780
  const _getImageData = CanvasRenderingContext2D.prototype.getImageData;
3781
3781
 
3782
+ function isCaptchaCanvas(canvas) {
3783
+ try {
3784
+ if (!canvas) return false;
3785
+ const id = (canvas.id || "").toLowerCase();
3786
+ const cls = (canvas.className || "").toLowerCase();
3787
+ return (
3788
+ id.includes("baxia") ||
3789
+ id.includes("nc_") ||
3790
+ id.includes("captcha") ||
3791
+ id.includes("punish") ||
3792
+ cls.includes("baxia") ||
3793
+ cls.includes("nc_") ||
3794
+ cls.includes("captcha") ||
3795
+ Boolean(canvas.closest?.("#baxia-dialog, #baxia-punish, [class*='baxia'], [class*='nc_'], .auth-layout"))
3796
+ );
3797
+ } catch(e) {
3798
+ return false;
3799
+ }
3800
+ }
3801
+
3782
3802
  function addNoise(canvas) {
3783
3803
  try {
3804
+ if (isCaptchaCanvas(canvas)) return;
3784
3805
  const ctx = canvas.getContext('2d');
3785
3806
  if (!ctx) return;
3786
3807
  const style = ctx.fillStyle;
@@ -3804,6 +3825,9 @@ function getStealthScript(profile) {
3804
3825
 
3805
3826
  CanvasRenderingContext2D.prototype.getImageData = function(x, y, w, h) {
3806
3827
  const imageData = _getImageData.apply(this, arguments);
3828
+ if (isCaptchaCanvas(this.canvas)) {
3829
+ return imageData;
3830
+ }
3807
3831
  const data = imageData.data;
3808
3832
  const maxPixels = Math.min(data.length / 4, 2500);
3809
3833
  for (let i = 0; i < maxPixels * 4; i += 4) {
@@ -4727,8 +4751,9 @@ async function loginToQwen(accountId, email, password) {
4727
4751
  }
4728
4752
  if (attempt < maxAttempts) {
4729
4753
  const backoffMs = attempt * 5e3;
4754
+ const failReason = uiResult.reason || apiResult.reason || "falha tempor\xE1ria";
4730
4755
  console.warn(
4731
- `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${apiResult.reason || uiResult.reason || "falha tempor\xE1ria"}), retrying in ${backoffMs / 1e3}s`
4756
+ `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1e3}s`
4732
4757
  );
4733
4758
  await sleep2(backoffMs);
4734
4759
  }
@@ -4758,37 +4783,52 @@ async function loginToQwen(accountId, email, password) {
4758
4783
  async function loginViaApi(page, email, password) {
4759
4784
  try {
4760
4785
  const hashedPassword = crypto3.createHash("sha256").update(password).digest("hex");
4761
- const signinUrl = qwenUrl("/api/v2/auths/signin");
4762
- let signinSuccess = false;
4763
- let data = null;
4764
- if (page.request && typeof page.request.post === "function") {
4765
- try {
4766
- const response = await page.request.post(signinUrl, {
4767
- data: {
4768
- email,
4769
- password: hashedPassword,
4770
- login_type: "email"
4771
- },
4772
- headers: {
4773
- "content-type": "application/json",
4774
- accept: "application/json, text/plain, */*",
4775
- referer: qwenUrl("/auth"),
4776
- origin: qwenOrigin(),
4777
- source: "web"
4778
- },
4779
- timeout: 1e4
4780
- });
4781
- data = await response.json().catch(() => null);
4782
- signinSuccess = Boolean(data && (data.success === true || data.token));
4783
- } catch {
4784
- }
4786
+ if (!page.url().includes("/auth")) {
4787
+ await page.goto(qwenUrl("/auth"), {
4788
+ waitUntil: "domcontentloaded",
4789
+ timeout: config.timeouts.navigation
4790
+ }).catch(() => {
4791
+ });
4792
+ await sleep2(1e3);
4785
4793
  }
4786
- if (!signinSuccess && !data) {
4787
- const requestId = crypto3.randomUUID();
4788
- const evalRes = await page.evaluate(
4789
- async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
4794
+ const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
4795
+ const requestId = crypto3.randomUUID();
4796
+ const evalRes = await page.evaluate(
4797
+ async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
4798
+ try {
4799
+ const response = await fetch(signinUrl2, {
4800
+ method: "POST",
4801
+ signal: AbortSignal.timeout(15e3),
4802
+ credentials: "include",
4803
+ headers: {
4804
+ accept: "application/json, text/plain, */*",
4805
+ "content-type": "application/json",
4806
+ source: "web",
4807
+ version: "0.3.11",
4808
+ "x-request-origin": "https://chat.qwen.ai",
4809
+ timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
4810
+ "x-request-id": requestId2
4811
+ },
4812
+ body: JSON.stringify({ email: email2, password: password2 })
4813
+ });
4814
+ const json = await response.json().catch(() => null);
4815
+ return { ok: response.ok, status: response.status, data: json };
4816
+ } catch (e) {
4817
+ return { ok: false, error: e.message };
4818
+ }
4819
+ },
4820
+ { email, password: hashedPassword, signinUrl, requestId }
4821
+ ).catch(() => null);
4822
+ let data = evalRes?.data;
4823
+ let signinSuccess = Boolean(
4824
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
4825
+ );
4826
+ if (!signinSuccess && !data?.data?.code) {
4827
+ const fallbackUrl = qwenUrl("/api/v2/auths/signin");
4828
+ const fallbackRes = await page.evaluate(
4829
+ async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
4790
4830
  try {
4791
- const response = await fetch(signinUrl2, {
4831
+ const response = await fetch(fallbackUrl2, {
4792
4832
  method: "POST",
4793
4833
  signal: AbortSignal.timeout(1e4),
4794
4834
  credentials: "include",
@@ -4796,10 +4836,11 @@ async function loginViaApi(page, email, password) {
4796
4836
  accept: "application/json, text/plain, */*",
4797
4837
  "content-type": "application/json",
4798
4838
  source: "web",
4839
+ version: "0.3.11",
4799
4840
  timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
4800
4841
  "x-request-id": requestId2
4801
4842
  },
4802
- body: JSON.stringify({ email: email2, password: password2, login_type: "email" })
4843
+ body: JSON.stringify({ email: email2, password: password2 })
4803
4844
  });
4804
4845
  const json = await response.json().catch(() => null);
4805
4846
  return { ok: response.ok, status: response.status, data: json };
@@ -4807,11 +4848,13 @@ async function loginViaApi(page, email, password) {
4807
4848
  return { ok: false, error: e.message };
4808
4849
  }
4809
4850
  },
4810
- { email, password: hashedPassword, signinUrl, requestId }
4851
+ { email, password: hashedPassword, fallbackUrl, requestId }
4811
4852
  ).catch(() => null);
4812
- if (evalRes?.data) {
4813
- data = evalRes.data;
4814
- signinSuccess = Boolean(data && (data.success === true || data.token));
4853
+ if (fallbackRes?.data) {
4854
+ data = fallbackRes.data;
4855
+ signinSuccess = Boolean(
4856
+ data && (data.success === true || data.token || data.data?.access_token || data.data?.token)
4857
+ );
4815
4858
  }
4816
4859
  }
4817
4860
  if (data?.success === false) {
@@ -4825,7 +4868,8 @@ async function loginViaApi(page, email, password) {
4825
4868
  };
4826
4869
  }
4827
4870
  if (signinSuccess) {
4828
- const token = data?.data?.token || data?.token;
4871
+ const token = data?.data?.access_token || data?.data?.token || data?.access_token || data?.token;
4872
+ const refreshToken = data?.data?.refresh_token || data?.refresh_token;
4829
4873
  if (token) {
4830
4874
  try {
4831
4875
  await page.context().addCookies([
@@ -4849,14 +4893,19 @@ async function loginViaApi(page, email, password) {
4849
4893
  }).catch(() => {
4850
4894
  });
4851
4895
  if (token) {
4852
- await page.evaluate((tok) => {
4853
- try {
4854
- localStorage.removeItem("qwen_token_logged_out_marker");
4855
- localStorage.setItem("token", tok);
4856
- document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
4857
- } catch {
4858
- }
4859
- }, token).catch(() => {
4896
+ await page.evaluate(
4897
+ ({ tok, rTok }) => {
4898
+ try {
4899
+ localStorage.removeItem("qwen_token_logged_out_marker");
4900
+ localStorage.setItem("token", tok);
4901
+ localStorage.setItem("access_token", tok);
4902
+ if (rTok) localStorage.setItem("refresh_token", rTok);
4903
+ document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
4904
+ } catch {
4905
+ }
4906
+ },
4907
+ { tok: token, rTok: refreshToken }
4908
+ ).catch(() => {
4860
4909
  });
4861
4910
  await page.reload({ waitUntil: "domcontentloaded" }).catch(() => {
4862
4911
  });
@@ -4884,11 +4933,23 @@ async function loginViaApi(page, email, password) {
4884
4933
  }
4885
4934
  async function loginViaUi(page, email, password) {
4886
4935
  try {
4887
- await page.goto(qwenUrl("/auth"), {
4888
- waitUntil: "domcontentloaded",
4889
- timeout: config.timeouts.navigation
4890
- });
4891
- await sleep2(1500);
4936
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3).catch(() => false)) {
4937
+ return { success: true };
4938
+ }
4939
+ try {
4940
+ await page.goto(qwenUrl("/auth"), {
4941
+ waitUntil: "domcontentloaded",
4942
+ timeout: Math.min(config.timeouts.navigation, 15e3)
4943
+ });
4944
+ await sleep2(1e3);
4945
+ } catch (gotoErr) {
4946
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
4947
+ return { success: true };
4948
+ }
4949
+ }
4950
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
4951
+ return { success: true };
4952
+ }
4892
4953
  const emailSelector = [
4893
4954
  'input[type="email"]',
4894
4955
  'input[name="email"]',
@@ -4898,7 +4959,7 @@ async function loginViaUi(page, email, password) {
4898
4959
  ].join(", ");
4899
4960
  try {
4900
4961
  await page.waitForSelector(emailSelector, {
4901
- timeout: Math.min(config.timeouts.page, 8e3)
4962
+ timeout: Math.min(config.timeouts.page, 5e3)
4902
4963
  });
4903
4964
  } catch {
4904
4965
  if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
@@ -4911,30 +4972,55 @@ async function loginViaUi(page, email, password) {
4911
4972
  return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
4912
4973
  }
4913
4974
  await clearVisibleChallenge(page);
4914
- const findPasswordModeButton = () => {
4915
- return page.locator('button, [role="button"], a, div').filter({
4916
- 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
4917
- }).first();
4975
+ const isPasswordInputPresent = async () => {
4976
+ return await page.locator('input[type="password"], input[name="password"]').count().catch(() => 0) > 0;
4918
4977
  };
4919
- try {
4920
- const pwdModeBtn = findPasswordModeButton();
4921
- if (await pwdModeBtn.isVisible({ timeout: 2e3 }).catch(() => false)) {
4922
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
4978
+ const revealPasswordMode = async () => {
4979
+ if (page.url().includes("/forget")) {
4980
+ await page.goto(qwenUrl("/auth"), { waitUntil: "domcontentloaded", timeout: 1e4 }).catch(() => {
4923
4981
  });
4924
- await sleep2(500);
4982
+ await sleep2(1e3);
4925
4983
  }
4926
- } catch {
4927
- }
4928
- await page.fill(emailSelector, email);
4929
- await sleep2(300);
4930
- try {
4931
- const pwdModeBtn = findPasswordModeButton();
4932
- if (await pwdModeBtn.isVisible({ timeout: 1500 }).catch(() => false)) {
4933
- await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
4984
+ if (await isPasswordInputPresent()) return;
4985
+ const btn = page.locator("button").filter({
4986
+ 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
4987
+ }).filter({
4988
+ hasNotText: /(?:esqueci|forgot|olvid|reset|recover)/i
4989
+ }).first();
4990
+ if (await btn.isVisible({ timeout: 1500 }).catch(() => false)) {
4991
+ await btn.click({ timeout: 2e3 }).catch(() => {
4934
4992
  });
4935
4993
  await sleep2(500);
4936
4994
  }
4995
+ if (await isPasswordInputPresent()) return;
4996
+ await page.evaluate(() => {
4997
+ try {
4998
+ const buttons = Array.from(document.querySelectorAll("button, [role='button'], a"));
4999
+ for (const b of buttons) {
5000
+ const txt = (b.innerText || "").trim().toLowerCase();
5001
+ 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")) {
5002
+ b.click();
5003
+ return true;
5004
+ }
5005
+ }
5006
+ } catch {
5007
+ }
5008
+ return false;
5009
+ }).catch(() => false);
5010
+ await sleep2(500);
5011
+ };
5012
+ await revealPasswordMode();
5013
+ try {
5014
+ await page.fill(emailSelector, email, { timeout: 8e3 });
5015
+ await sleep2(300);
4937
5016
  } catch {
5017
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
5018
+ return { success: true };
5019
+ }
5020
+ throw new Error(`Campo de e-mail n\xE3o encontrado na tela de autentica\xE7\xE3o`);
5021
+ }
5022
+ if (!await isPasswordInputPresent()) {
5023
+ await revealPasswordMode();
4938
5024
  }
4939
5025
  const passwordSelector = 'input[type="password"], input[name="password"]';
4940
5026
  try {
@@ -4953,61 +5039,108 @@ async function loginViaUi(page, email, password) {
4953
5039
  reason: "Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o"
4954
5040
  };
4955
5041
  }
4956
- await page.fill(passwordSelector, password);
4957
- await sleep2(500);
5042
+ try {
5043
+ await page.fill(passwordSelector, password, { timeout: 8e3 });
5044
+ await sleep2(500);
5045
+ } catch {
5046
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3)) {
5047
+ return { success: true };
5048
+ }
5049
+ throw new Error(`Campo de senha n\xE3o encontrado na tela de autentica\xE7\xE3o`);
5050
+ }
5051
+ await page.evaluate(() => {
5052
+ try {
5053
+ const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
5054
+ const passEl = document.querySelector('input[type="password"], input[name="password"]');
5055
+ if (emailEl) {
5056
+ emailEl.dispatchEvent(new Event("input", { bubbles: true }));
5057
+ emailEl.dispatchEvent(new Event("change", { bubbles: true }));
5058
+ emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
5059
+ }
5060
+ if (passEl) {
5061
+ passEl.dispatchEvent(new Event("input", { bubbles: true }));
5062
+ passEl.dispatchEvent(new Event("change", { bubbles: true }));
5063
+ passEl.dispatchEvent(new Event("blur", { bubbles: true }));
5064
+ }
5065
+ } catch {
5066
+ }
5067
+ }).catch(() => {
5068
+ });
4958
5069
  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")';
4959
5070
  const submitButton = page.locator(submitSelector).first();
4960
5071
  try {
4961
5072
  await page.waitForSelector('button[type="submit"]:not([disabled])', {
4962
- timeout: 5e3
5073
+ timeout: 4e3
4963
5074
  });
4964
5075
  await submitButton.click();
4965
5076
  } catch {
4966
- await page.keyboard.press("Enter");
4967
- }
4968
- await sleep2(3e3);
4969
- await solveBaxiaCaptcha(page, {
4970
- waitForMs: 2e3,
4971
- maxAttempts: config.captcha.maxAttempts,
4972
- retryDelayMs: config.captcha.retryDelayMs
4973
- }).catch(() => {
4974
- });
4975
- const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
4976
- const codeInput = page.locator(codeSelector).first();
4977
- if (await codeInput.isVisible().catch(() => false)) {
4978
- return {
4979
- success: false,
4980
- reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
4981
- };
5077
+ const isDisabled = await submitButton.isDisabled().catch(() => true);
5078
+ if (!isDisabled) {
5079
+ await submitButton.click({ force: true }).catch(() => {
5080
+ });
5081
+ } else {
5082
+ if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
5083
+ return { success: true };
5084
+ }
5085
+ }
4982
5086
  }
4983
- const errorSelector = [
4984
- ".qwen-chat-v2-toast-text",
4985
- ".qwen-chat-v2-toast-content",
4986
- ".ant-form-item-explain-error",
4987
- ".ant-message-error",
4988
- ".ant-message-notice",
4989
- '[role="alert"]',
4990
- ".qwenchat-auth-error",
4991
- ".auth-error-message"
4992
- ].join(", ");
4993
- const errorEl = page.locator(errorSelector).first();
4994
- if (await errorEl.isVisible().catch(() => false)) {
4995
- const errorText = (await errorEl.innerText().catch(() => "")).trim();
4996
- if (errorText) {
4997
- const classified = classifyQwenAuthError(void 0, errorText);
5087
+ const postSubmitDeadline = Date.now() + 15e3;
5088
+ while (Date.now() < postSubmitDeadline) {
5089
+ if (page.isClosed()) break;
5090
+ if (config.captcha.enabled) {
5091
+ await solveBaxiaCaptcha(page, {
5092
+ waitForMs: 1500,
5093
+ maxAttempts: config.captcha.maxAttempts,
5094
+ retryDelayMs: config.captcha.retryDelayMs
5095
+ }).catch(() => {
5096
+ });
5097
+ }
5098
+ const errorSelector = [
5099
+ ".qwen-chat-v2-toast-text",
5100
+ ".qwen-chat-v2-toast-content",
5101
+ ".ant-form-item-explain-error",
5102
+ ".ant-message-error",
5103
+ ".ant-message-notice",
5104
+ '[role="alert"]',
5105
+ ".qwenchat-auth-error",
5106
+ ".auth-error-message"
5107
+ ].join(", ");
5108
+ const errorEl = page.locator(errorSelector).first();
5109
+ if (await errorEl.isVisible().catch(() => false)) {
5110
+ const errorText = (await errorEl.innerText().catch(() => "")).trim();
5111
+ if (errorText) {
5112
+ const classified = classifyQwenAuthError(void 0, errorText);
5113
+ return {
5114
+ success: false,
5115
+ permanentFailure: classified.isPermanent,
5116
+ reason: `Formul\xE1rio: ${classified.reason}`
5117
+ };
5118
+ }
5119
+ }
5120
+ const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
5121
+ const codeInput = page.locator(codeSelector).first();
5122
+ if (await codeInput.isVisible().catch(() => false)) {
4998
5123
  return {
4999
5124
  success: false,
5000
- permanentFailure: classified.isPermanent,
5001
- reason: `Formul\xE1rio: ${classified.reason}`
5125
+ reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
5002
5126
  };
5003
5127
  }
5128
+ try {
5129
+ const liveCookies = await page.context().cookies();
5130
+ if (liveCookies.some((c) => c.name === "token")) {
5131
+ return { success: true };
5132
+ }
5133
+ } catch {
5134
+ }
5135
+ const currentUrl = page.url();
5136
+ if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
5137
+ if (await isPageLoggedIn(page, 3e3)) {
5138
+ return { success: true };
5139
+ }
5140
+ }
5141
+ await sleep2(1e3);
5004
5142
  }
5005
- const isLoggedIn = await isPageLoggedIn(page);
5006
- if (isLoggedIn) {
5007
- await page.goto(qwenUrl("/"), {
5008
- waitUntil: "domcontentloaded",
5009
- timeout: config.timeouts.navigation
5010
- });
5143
+ if (await isPageLoggedIn(page, 3e3)) {
5011
5144
  return { success: true };
5012
5145
  }
5013
5146
  return {
@@ -5535,6 +5668,17 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
5535
5668
  }
5536
5669
  };
5537
5670
  if (forceReauth) {
5671
+ const alreadyIn = await isPageLoggedIn(page, 2e3).catch(() => false);
5672
+ if (alreadyIn) {
5673
+ const liveCookies = await page.context().cookies();
5674
+ if (liveCookies.some((c) => c.name === "token")) {
5675
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
5676
+ cache.headers.cookie = cookieStr;
5677
+ cache.lastRefresh = Date.now();
5678
+ markAccountHeadersReady(accountId);
5679
+ return;
5680
+ }
5681
+ }
5538
5682
  await executeReauth();
5539
5683
  } else {
5540
5684
  try {
@@ -5969,19 +6113,50 @@ async function keepAlivePlaywrightAccount(accountId) {
5969
6113
  const now = Date.now();
5970
6114
  const currentUrl = page.url();
5971
6115
  const cookie = await getCookies(accountId);
5972
- if (cookie && isTokenExpiringSoon(cookie, 45)) {
5973
- console.log(
5974
- `\u{1F493} [SessionKeeper] Account ${accountId} token expires within 45m; proactively renewing session...`
5975
- );
6116
+ if (cookie && isTokenExpiringSoon(cookie, 2)) {
5976
6117
  try {
5977
- await refreshHeadersInternal(accountId, config.timeouts.headers, true);
5978
- lastKeepAliveNavigation.set(accountId, now);
5979
- touchAccountActivity(accountId);
5980
- return true;
5981
- } catch (err) {
5982
- console.warn(
5983
- `[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
6118
+ await page.evaluate(async () => {
6119
+ await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
6120
+ method: "GET",
6121
+ credentials: "include"
6122
+ }).catch(() => {
6123
+ });
6124
+ await fetch("/api/v1/auths/", {
6125
+ method: "GET",
6126
+ credentials: "include"
6127
+ }).catch(() => {
6128
+ });
6129
+ }).catch(() => {
6130
+ });
6131
+ const liveCookies = await page.context().cookies();
6132
+ const tokenCookie = liveCookies.find((c) => c.name === "token");
6133
+ if (tokenCookie) {
6134
+ const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
6135
+ const cache = getHeaderCache(accountId);
6136
+ cache.headers.cookie = cookieStr;
6137
+ cache.lastRefresh = Date.now();
6138
+ markAccountHeadersReady(accountId);
6139
+ lastKeepAliveNavigation.set(accountId, now);
6140
+ touchAccountActivity(accountId);
6141
+ return true;
6142
+ }
6143
+ } catch {
6144
+ }
6145
+ const loggedIn = await isPageLoggedIn(page, 2e3).catch(() => false);
6146
+ if (!loggedIn) {
6147
+ console.log(
6148
+ `\u{1F493} [SessionKeeper] Account ${accountId} session expired; renewing session...`
5984
6149
  );
6150
+ try {
6151
+ await refreshHeadersInternal(accountId, config.timeouts.headers, true);
6152
+ lastKeepAliveNavigation.set(accountId, now);
6153
+ touchAccountActivity(accountId);
6154
+ return true;
6155
+ } catch (err) {
6156
+ console.warn(
6157
+ `[SessionKeeper] Proactive session renewal failed for ${accountId}: ${getErrorMessage(err)}`
6158
+ );
6159
+ }
5985
6160
  }
5986
6161
  }
5987
6162
  const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;