qwenproxy-cli 1.4.8 → 1.5.1

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.
@@ -1915,7 +1915,15 @@ function defaultCooldownDurationMs() {
1915
1915
  return computeQuotaCooldownMs(Date.now());
1916
1916
  }
1917
1917
  function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
1918
+ if (cooldownMs !== void 0 && cooldownMs <= 0) {
1919
+ clearAccountCooldown(accountId);
1920
+ return;
1921
+ }
1918
1922
  const duration = cooldownMs ?? defaultCooldownDurationMs();
1923
+ if (duration <= 0) {
1924
+ clearAccountCooldown(accountId);
1925
+ return;
1926
+ }
1919
1927
  const until = Date.now() + duration;
1920
1928
  const cooldownReason = reason ?? "RateLimited";
1921
1929
  cooldowns.set(accountId, {
@@ -1938,6 +1946,19 @@ function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
1938
1946
  );
1939
1947
  }
1940
1948
  }
1949
+ function clearAccountCooldown(accountId) {
1950
+ cooldowns.delete(accountId);
1951
+ if (accountId !== "global") {
1952
+ try {
1953
+ updateAccountCooldown(accountId, 0, null);
1954
+ } catch (err) {
1955
+ console.error(
1956
+ `\u274C [AccountManager] Failed to clear cooldown in DB for ${accountId}:`,
1957
+ err.message
1958
+ );
1959
+ }
1960
+ }
1961
+ }
1941
1962
  function markAccountHeadersReady(accountId) {
1942
1963
  if (!accountId || accountId === "global") return;
1943
1964
  headersReadyAccounts.add(accountId);
@@ -1946,6 +1967,9 @@ function unmarkAccountHeadersReady(accountId) {
1946
1967
  if (!accountId) return;
1947
1968
  headersReadyAccounts.delete(accountId);
1948
1969
  }
1970
+ function isAccountHeadersReady(accountId) {
1971
+ return headersReadyAccounts.has(accountId);
1972
+ }
1949
1973
  var cooldowns, headersReadyAccounts;
1950
1974
  var init_account_manager = __esm({
1951
1975
  "src/core/account-manager.ts"() {
@@ -2877,26 +2901,6 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
2877
2901
  }
2878
2902
  } catch {
2879
2903
  }
2880
- try {
2881
- const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
2882
- method: "GET",
2883
- credentials: "include",
2884
- signal: AbortSignal.timeout(3e3)
2885
- });
2886
- if (refreshRes.status === 200) {
2887
- const refreshJson = await refreshRes.json().catch(() => null);
2888
- if (refreshJson && refreshJson.success === false) {
2889
- const code = refreshJson.data?.code || refreshJson.code;
2890
- const details = String(refreshJson.data?.details || "");
2891
- if (code === "Unauthorized" || details.includes("revogado") || details.includes("revoked")) {
2892
- return false;
2893
- }
2894
- }
2895
- } else if (refreshRes.status === 401 || refreshRes.status === 403) {
2896
- return false;
2897
- }
2898
- } catch {
2899
- }
2900
2904
  return true;
2901
2905
  } catch {
2902
2906
  return false;
@@ -3702,7 +3706,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
3702
3706
  `\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
3703
3707
  );
3704
3708
  }
3705
- if (!options.skipHeaderCapture) {
3709
+ if (!options.skipHeaderCapture && !isAccountHeadersReady(account.id)) {
3706
3710
  acctPage.__qwenChatHomeLoaded = true;
3707
3711
  await captureQwenHeaders(account.id);
3708
3712
  }
@@ -3912,7 +3916,7 @@ async function loginToQwen(accountId, email, password) {
3912
3916
  );
3913
3917
  markAccountRateLimited(
3914
3918
  accountId,
3915
- 24 * 3600 * 1e3,
3919
+ 300 * 1e3,
3916
3920
  "AuthFailed: All login methods exhausted"
3917
3921
  );
3918
3922
  return false;
@@ -4189,38 +4193,49 @@ async function loginViaUi(page, email, password) {
4189
4193
  try {
4190
4194
  const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
4191
4195
  const passEl = document.querySelector('input[type="password"], input[name="password"]');
4192
- if (emailEl) {
4193
- emailEl.dispatchEvent(new Event("input", { bubbles: true }));
4194
- emailEl.dispatchEvent(new Event("change", { bubbles: true }));
4195
- emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
4196
- }
4197
- if (passEl) {
4198
- passEl.dispatchEvent(new Event("input", { bubbles: true }));
4199
- passEl.dispatchEvent(new Event("change", { bubbles: true }));
4200
- passEl.dispatchEvent(new Event("blur", { bubbles: true }));
4201
- }
4196
+ const setReactValue = (el, val) => {
4197
+ const proto = Object.getPrototypeOf(el);
4198
+ const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
4199
+ if (setter) {
4200
+ setter.call(el, val);
4201
+ } else {
4202
+ el.value = val;
4203
+ }
4204
+ el.dispatchEvent(new Event("input", { bubbles: true }));
4205
+ el.dispatchEvent(new Event("change", { bubbles: true }));
4206
+ el.dispatchEvent(new Event("blur", { bubbles: true }));
4207
+ };
4208
+ if (emailEl) setReactValue(emailEl, emailEl.value);
4209
+ if (passEl) setReactValue(passEl, passEl.value);
4202
4210
  } catch {
4203
4211
  }
4204
4212
  }).catch(() => {
4205
4213
  });
4214
+ await sleep2(500);
4206
4215
  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")';
4207
4216
  const submitButton = page.locator(submitSelector).first();
4217
+ await page.evaluate((sel) => {
4218
+ try {
4219
+ const btn = document.querySelector(sel);
4220
+ if (btn) {
4221
+ btn.removeAttribute("disabled");
4222
+ btn.classList.remove("ant-btn-disabled");
4223
+ btn.click();
4224
+ }
4225
+ } catch {
4226
+ }
4227
+ }, submitSelector).catch(() => {
4228
+ });
4208
4229
  try {
4209
- await page.waitForSelector('button[type="submit"]:not([disabled])', {
4210
- timeout: 4e3
4211
- });
4212
- await submitButton.click();
4213
- } catch {
4214
- const isDisabled = await submitButton.isDisabled().catch(() => true);
4215
- if (!isDisabled) {
4216
- await submitButton.click({ force: true }).catch(() => {
4230
+ if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
4231
+ await submitButton.click({ force: true, timeout: 2e3 }).catch(() => {
4217
4232
  });
4218
- } else {
4219
- if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
4220
- return { success: true };
4221
- }
4222
4233
  }
4234
+ } catch {
4223
4235
  }
4236
+ const passInput = page.locator(passwordSelector).first();
4237
+ await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
4238
+ });
4224
4239
  const postSubmitDeadline = Date.now() + 15e3;
4225
4240
  while (Date.now() < postSubmitDeadline) {
4226
4241
  if (page.isClosed()) break;
@@ -1978,7 +1978,15 @@ function defaultCooldownDurationMs() {
1978
1978
  return computeQuotaCooldownMs(Date.now());
1979
1979
  }
1980
1980
  function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
1981
+ if (cooldownMs !== void 0 && cooldownMs <= 0) {
1982
+ clearAccountCooldown(accountId);
1983
+ return;
1984
+ }
1981
1985
  const duration = cooldownMs ?? defaultCooldownDurationMs();
1986
+ if (duration <= 0) {
1987
+ clearAccountCooldown(accountId);
1988
+ return;
1989
+ }
1982
1990
  const until = Date.now() + duration;
1983
1991
  const cooldownReason = reason ?? "RateLimited";
1984
1992
  cooldowns.set(accountId, {
@@ -2001,6 +2009,19 @@ function markAccountRateLimited(accountId, cooldownMs, reason, options = {}) {
2001
2009
  );
2002
2010
  }
2003
2011
  }
2012
+ function clearAccountCooldown(accountId) {
2013
+ cooldowns.delete(accountId);
2014
+ if (accountId !== "global") {
2015
+ try {
2016
+ updateAccountCooldown(accountId, 0, null);
2017
+ } catch (err) {
2018
+ console.error(
2019
+ `\u274C [AccountManager] Failed to clear cooldown in DB for ${accountId}:`,
2020
+ err.message
2021
+ );
2022
+ }
2023
+ }
2024
+ }
2004
2025
  function markAccountHeadersReady(accountId) {
2005
2026
  if (!accountId || accountId === "global") return;
2006
2027
  headersReadyAccounts.add(accountId);
@@ -2009,6 +2030,9 @@ function unmarkAccountHeadersReady(accountId) {
2009
2030
  if (!accountId) return;
2010
2031
  headersReadyAccounts.delete(accountId);
2011
2032
  }
2033
+ function isAccountHeadersReady(accountId) {
2034
+ return headersReadyAccounts.has(accountId);
2035
+ }
2012
2036
  var cooldowns, headersReadyAccounts;
2013
2037
  var init_account_manager = __esm({
2014
2038
  "src/core/account-manager.ts"() {
@@ -2769,7 +2793,8 @@ function buildQwenRequestHeaders(opts) {
2769
2793
  "bx-v": opts.bxV || "2.5.37",
2770
2794
  source: "web",
2771
2795
  version: opts.version || getQwenWebVersion(),
2772
- timezone: opts.extra?.timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
2796
+ timezone: opts.extra?.timezone || opts.extra?.Timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
2797
+ Timezone: opts.extra?.Timezone || opts.extra?.timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
2773
2798
  // Use the real browser client-hints when captured (anti-hardcoded); fall
2774
2799
  // back to the static fingerprint otherwise.
2775
2800
  "sec-ch-ua": opts.secChUa || `"Google Chrome";v="${getChromeMajor()}", "Chromium";v="${getChromeMajor()}", "Not.A/Brand";v="99"`,
@@ -3311,26 +3336,6 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
3311
3336
  }
3312
3337
  } catch {
3313
3338
  }
3314
- try {
3315
- const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
3316
- method: "GET",
3317
- credentials: "include",
3318
- signal: AbortSignal.timeout(3e3)
3319
- });
3320
- if (refreshRes.status === 200) {
3321
- const refreshJson = await refreshRes.json().catch(() => null);
3322
- if (refreshJson && refreshJson.success === false) {
3323
- const code = refreshJson.data?.code || refreshJson.code;
3324
- const details = String(refreshJson.data?.details || "");
3325
- if (code === "Unauthorized" || details.includes("revogado") || details.includes("revoked")) {
3326
- return false;
3327
- }
3328
- }
3329
- } else if (refreshRes.status === 401 || refreshRes.status === 403) {
3330
- return false;
3331
- }
3332
- } catch {
3333
- }
3334
3339
  return true;
3335
3340
  } catch {
3336
3341
  return false;
@@ -4458,7 +4463,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
4458
4463
  `\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
4459
4464
  );
4460
4465
  }
4461
- if (!options.skipHeaderCapture) {
4466
+ if (!options.skipHeaderCapture && !isAccountHeadersReady(account.id)) {
4462
4467
  acctPage.__qwenChatHomeLoaded = true;
4463
4468
  await captureQwenHeaders(account.id);
4464
4469
  }
@@ -4788,7 +4793,7 @@ async function loginToQwen(accountId, email, password) {
4788
4793
  );
4789
4794
  markAccountRateLimited(
4790
4795
  accountId,
4791
- 24 * 3600 * 1e3,
4796
+ 300 * 1e3,
4792
4797
  "AuthFailed: All login methods exhausted"
4793
4798
  );
4794
4799
  return false;
@@ -5065,38 +5070,49 @@ async function loginViaUi(page, email, password) {
5065
5070
  try {
5066
5071
  const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
5067
5072
  const passEl = document.querySelector('input[type="password"], input[name="password"]');
5068
- if (emailEl) {
5069
- emailEl.dispatchEvent(new Event("input", { bubbles: true }));
5070
- emailEl.dispatchEvent(new Event("change", { bubbles: true }));
5071
- emailEl.dispatchEvent(new Event("blur", { bubbles: true }));
5072
- }
5073
- if (passEl) {
5074
- passEl.dispatchEvent(new Event("input", { bubbles: true }));
5075
- passEl.dispatchEvent(new Event("change", { bubbles: true }));
5076
- passEl.dispatchEvent(new Event("blur", { bubbles: true }));
5077
- }
5073
+ const setReactValue = (el, val) => {
5074
+ const proto = Object.getPrototypeOf(el);
5075
+ const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
5076
+ if (setter) {
5077
+ setter.call(el, val);
5078
+ } else {
5079
+ el.value = val;
5080
+ }
5081
+ el.dispatchEvent(new Event("input", { bubbles: true }));
5082
+ el.dispatchEvent(new Event("change", { bubbles: true }));
5083
+ el.dispatchEvent(new Event("blur", { bubbles: true }));
5084
+ };
5085
+ if (emailEl) setReactValue(emailEl, emailEl.value);
5086
+ if (passEl) setReactValue(passEl, passEl.value);
5078
5087
  } catch {
5079
5088
  }
5080
5089
  }).catch(() => {
5081
5090
  });
5091
+ await sleep2(500);
5082
5092
  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")';
5083
5093
  const submitButton = page.locator(submitSelector).first();
5094
+ await page.evaluate((sel) => {
5095
+ try {
5096
+ const btn = document.querySelector(sel);
5097
+ if (btn) {
5098
+ btn.removeAttribute("disabled");
5099
+ btn.classList.remove("ant-btn-disabled");
5100
+ btn.click();
5101
+ }
5102
+ } catch {
5103
+ }
5104
+ }, submitSelector).catch(() => {
5105
+ });
5084
5106
  try {
5085
- await page.waitForSelector('button[type="submit"]:not([disabled])', {
5086
- timeout: 4e3
5087
- });
5088
- await submitButton.click();
5089
- } catch {
5090
- const isDisabled = await submitButton.isDisabled().catch(() => true);
5091
- if (!isDisabled) {
5092
- await submitButton.click({ force: true }).catch(() => {
5107
+ if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
5108
+ await submitButton.click({ force: true, timeout: 2e3 }).catch(() => {
5093
5109
  });
5094
- } else {
5095
- if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
5096
- return { success: true };
5097
- }
5098
5110
  }
5111
+ } catch {
5099
5112
  }
5113
+ const passInput = page.locator(passwordSelector).first();
5114
+ await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
5115
+ });
5100
5116
  const postSubmitDeadline = Date.now() + 15e3;
5101
5117
  while (Date.now() < postSubmitDeadline) {
5102
5118
  if (page.isClosed()) break;
@@ -7623,13 +7639,15 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
7623
7639
  } catch {
7624
7640
  }
7625
7641
  }
7626
- if (json?.data?.code === "Unauthorized" || json?.code === "Unauthorized" || rawLower.includes("unauthorized") || rawLower.includes("permission to access")) {
7642
+ const isUnauthorized = json?.data?.code?.toLowerCase() === "unauthorized" || json?.code?.toLowerCase() === "unauthorized" || rawLower.includes("unauthorized") || rawLower.includes("permission to access") || rawLower.includes("token has expired") || rawLower.includes("401");
7643
+ if (isUnauthorized) {
7627
7644
  if (accountId) {
7628
7645
  try {
7629
7646
  const { refreshAccountToken: refreshAccountToken2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
7630
7647
  const refreshed = await refreshAccountToken2(accountId);
7631
7648
  if (refreshed.success) {
7632
- return createQwenChatSession(headers, model, accountId, chatMode);
7649
+ const { headers: freshHeaders } = await getQwenHeaders(false, accountId);
7650
+ return createQwenChatSession(freshHeaders, model, accountId, chatMode);
7633
7651
  }
7634
7652
  } catch {
7635
7653
  }
@@ -9623,8 +9641,18 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
9623
9641
  );
9624
9642
  }
9625
9643
  };
9644
+ let forceRefresh = options?.forceNewChat === true;
9645
+ if (!forceRefresh && accountId) {
9646
+ try {
9647
+ const basic = await getBasicHeaders2(accountId);
9648
+ if (isTokenExpiringSoon(basic.cookie, 3)) {
9649
+ forceRefresh = true;
9650
+ }
9651
+ } catch {
9652
+ }
9653
+ }
9626
9654
  const captured = await getQwenHeaders(
9627
- options?.forceNewChat === true,
9655
+ forceRefresh,
9628
9656
  accountId
9629
9657
  );
9630
9658
  ensureNotAborted();
@@ -9638,7 +9666,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
9638
9666
  if (options && "chatSessionId" in options) {
9639
9667
  if (options.chatSessionId === null || options.chatSessionId === "") {
9640
9668
  const acquired = await acquireNewQwenChatSession(
9641
- headers,
9669
+ activeHeaders,
9642
9670
  model,
9643
9671
  accountId,
9644
9672
  options?.chatMode ?? "thread"
@@ -9646,6 +9674,11 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
9646
9674
  chatSessionId = acquired.chatId;
9647
9675
  leasedWarmChat = acquired.leasedFromPool;
9648
9676
  createdNewChat = true;
9677
+ try {
9678
+ const fresh = await getQwenHeaders(false, accountId);
9679
+ activeHeaders = fresh.headers;
9680
+ } catch {
9681
+ }
9649
9682
  } else {
9650
9683
  chatSessionId = options.chatSessionId;
9651
9684
  }
@@ -9653,7 +9686,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
9653
9686
  chatSessionId = captured.chatSessionId;
9654
9687
  if (!chatSessionId) {
9655
9688
  const acquired = await acquireNewQwenChatSession(
9656
- headers,
9689
+ activeHeaders,
9657
9690
  model,
9658
9691
  accountId,
9659
9692
  options?.chatMode ?? "thread"
@@ -9661,6 +9694,11 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
9661
9694
  chatSessionId = acquired.chatId;
9662
9695
  leasedWarmChat = acquired.leasedFromPool;
9663
9696
  createdNewChat = true;
9697
+ try {
9698
+ const fresh = await getQwenHeaders(false, accountId);
9699
+ activeHeaders = fresh.headers;
9700
+ } catch {
9701
+ }
9664
9702
  }
9665
9703
  }
9666
9704
  ensureNotAborted();