qwenproxy-cli 1.6.9 → 1.6.10

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.
@@ -3519,7 +3519,19 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
3519
3519
  if (localStorage.getItem("qwen_token_logged_out_marker")) {
3520
3520
  return false;
3521
3521
  }
3522
- const res = await fetch("/api/v1/auths/", { method: "GET" });
3522
+ const lsToken = (localStorage.getItem("token") || "").trim();
3523
+ if (lsToken && !/(?:^|;\s*)token=/.test(document.cookie || "")) {
3524
+ try {
3525
+ document.cookie = `token=${encodeURIComponent(lsToken)}; path=/; domain=.qwen.ai; max-age=31536000`;
3526
+ } catch {
3527
+ }
3528
+ }
3529
+ const authHeaders = lsToken ? { Authorization: `Bearer ${lsToken}` } : {};
3530
+ const res = await fetch("/api/v1/auths/", {
3531
+ method: "GET",
3532
+ headers: authHeaders,
3533
+ credentials: "include"
3534
+ });
3523
3535
  if (res.status !== 200) return false;
3524
3536
  const json = await res.json().catch(() => null);
3525
3537
  if (!json) return false;
@@ -3537,6 +3549,7 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
3537
3549
  try {
3538
3550
  const settingsRes = await fetch("/api/v2/users/user/settings", {
3539
3551
  method: "GET",
3552
+ headers: authHeaders,
3540
3553
  credentials: "include",
3541
3554
  signal: AbortSignal.timeout(3e3)
3542
3555
  });
@@ -4695,8 +4708,15 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
4695
4708
  const hasAuthCookie = cookies.some(
4696
4709
  (c) => c.name.toLowerCase().includes("token") || c.name.toLowerCase().includes("session")
4697
4710
  );
4711
+ let initialLoginAttempted = false;
4698
4712
  if (!hasAuthCookie && account.email && account.password) {
4699
- await loginToQwen(account.id, account.email, account.password);
4713
+ initialLoginAttempted = true;
4714
+ const loggedIn = await loginToQwen(account.id, account.email, account.password);
4715
+ if (!loggedIn) {
4716
+ throw new Error(
4717
+ `Authentication failed for account ${maskEmail(account.email)}`
4718
+ );
4719
+ }
4700
4720
  }
4701
4721
  try {
4702
4722
  await acctPage.goto(qwenUrl("/"), {
@@ -4706,13 +4726,21 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
4706
4726
  await sleep2(1500);
4707
4727
  const currentUrl = acctPage.url();
4708
4728
  const isAuthUrl = currentUrl.includes("/auth") || currentUrl.includes("/login");
4709
- if (isAuthUrl && account.email && account.password) {
4729
+ if (isAuthUrl && !initialLoginAttempted && account.email && account.password) {
4710
4730
  console.log(
4711
4731
  `[Playwright] Initial login needed for ${maskEmail(account.email)}, authenticating...`
4712
4732
  );
4713
- await loginToQwen(account.id, account.email, account.password);
4733
+ const loggedIn = await loginToQwen(account.id, account.email, account.password);
4734
+ if (!loggedIn) {
4735
+ throw new Error(
4736
+ `Authentication failed for account ${maskEmail(account.email)}`
4737
+ );
4738
+ }
4714
4739
  }
4715
4740
  } catch (err) {
4741
+ if (err?.message?.includes("Authentication failed for account")) {
4742
+ throw err;
4743
+ }
4716
4744
  console.warn(
4717
4745
  `\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
4718
4746
  );
@@ -5261,10 +5289,30 @@ async function loginToQwen(accountId, email, password) {
5261
5289
  const uiResult = await loginViaUi(page, email, password);
5262
5290
  if (uiResult.success) {
5263
5291
  cookieCaches.delete(accountId);
5264
- await saveStorageState(page.context(), accountId);
5265
5292
  try {
5266
- const liveCookies = await page.context().cookies();
5267
- const tokenCookie = liveCookies.find((c) => c.name === "token");
5293
+ let liveCookies = await page.context().cookies();
5294
+ let tokenCookie = liveCookies.find((c) => c.name === "token");
5295
+ if (!tokenCookie) {
5296
+ const lsTok = uiResult.token || await page.evaluate(() => (localStorage.getItem("token") || "").trim()).catch(() => "");
5297
+ if (lsTok) {
5298
+ await page.context().addCookies([
5299
+ {
5300
+ name: "token",
5301
+ value: lsTok,
5302
+ domain: ".qwen.ai",
5303
+ path: "/",
5304
+ expires: Math.floor(Date.now() / 1e3) + 31536e3,
5305
+ httpOnly: false,
5306
+ secure: true,
5307
+ sameSite: "Lax"
5308
+ }
5309
+ ]).catch(() => {
5310
+ });
5311
+ liveCookies = await page.context().cookies();
5312
+ tokenCookie = liveCookies.find((c) => c.name === "token");
5313
+ }
5314
+ }
5315
+ await saveStorageState(page.context(), accountId);
5268
5316
  if (tokenCookie) {
5269
5317
  const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
5270
5318
  const cache = getHeaderCache(accountId);
@@ -5273,7 +5321,7 @@ async function loginToQwen(accountId, email, password) {
5273
5321
  markAccountHeadersReady(accountId);
5274
5322
  const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
5275
5323
  const exp = parseJwtExpiry(tokenCookie.value);
5276
- let rTok = uiResult.refreshToken;
5324
+ let rTok = uiResult.refreshToken || liveCookies.find((c) => c.name === "refresh_token")?.value;
5277
5325
  if (!rTok) {
5278
5326
  try {
5279
5327
  rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
@@ -5354,8 +5402,9 @@ async function loginViaApi(page, email, password) {
5354
5402
  }
5355
5403
  const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
5356
5404
  const requestId = crypto3.randomUUID();
5405
+ const webVersion = getQwenWebVersion() || "0.3.26";
5357
5406
  const evalRes = await page.evaluate(
5358
- async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz }) => {
5407
+ async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
5359
5408
  try {
5360
5409
  const response = await fetch(signinUrl2, {
5361
5410
  method: "POST",
@@ -5365,7 +5414,7 @@ async function loginViaApi(page, email, password) {
5365
5414
  accept: "application/json, text/plain, */*",
5366
5415
  "content-type": "application/json",
5367
5416
  source: "web",
5368
- version: getQwenWebVersion() || "0.3.26",
5417
+ version,
5369
5418
  "x-request-origin": "https://chat.qwen.ai",
5370
5419
  timezone: tz,
5371
5420
  "x-request-id": requestId2
@@ -5378,7 +5427,14 @@ async function loginViaApi(page, email, password) {
5378
5427
  return { ok: false, error: e.message };
5379
5428
  }
5380
5429
  },
5381
- { email, password: hashedPassword, signinUrl, requestId, tz: formatAsciiTimezone() }
5430
+ {
5431
+ email,
5432
+ password: hashedPassword,
5433
+ signinUrl,
5434
+ requestId,
5435
+ tz: formatAsciiTimezone(),
5436
+ version: webVersion
5437
+ }
5382
5438
  ).catch(() => null);
5383
5439
  let data = evalRes?.data;
5384
5440
  let signinSuccess = Boolean(
@@ -5387,7 +5443,7 @@ async function loginViaApi(page, email, password) {
5387
5443
  if (!signinSuccess && !data?.data?.code) {
5388
5444
  const fallbackUrl = qwenUrl("/api/v2/auths/signin");
5389
5445
  const fallbackRes = await page.evaluate(
5390
- async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz }) => {
5446
+ async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz, version }) => {
5391
5447
  try {
5392
5448
  const response = await fetch(fallbackUrl2, {
5393
5449
  method: "POST",
@@ -5397,7 +5453,7 @@ async function loginViaApi(page, email, password) {
5397
5453
  accept: "application/json, text/plain, */*",
5398
5454
  "content-type": "application/json",
5399
5455
  source: "web",
5400
- version: getQwenWebVersion() || "0.3.26",
5456
+ version,
5401
5457
  timezone: tz,
5402
5458
  "x-request-id": requestId2
5403
5459
  },
@@ -5409,7 +5465,14 @@ async function loginViaApi(page, email, password) {
5409
5465
  return { ok: false, error: e.message };
5410
5466
  }
5411
5467
  },
5412
- { email, password: hashedPassword, fallbackUrl, requestId, tz: formatAsciiTimezone() }
5468
+ {
5469
+ email,
5470
+ password: hashedPassword,
5471
+ fallbackUrl,
5472
+ requestId,
5473
+ tz: formatAsciiTimezone(),
5474
+ version: webVersion
5475
+ }
5413
5476
  ).catch(() => null);
5414
5477
  if (fallbackRes?.data) {
5415
5478
  data = fallbackRes.data;
@@ -5634,28 +5697,34 @@ async function loginViaUi(page, email, password) {
5634
5697
  await sleep2(500);
5635
5698
  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")';
5636
5699
  const submitButton = page.locator(submitSelector).first();
5637
- await page.evaluate((sel) => {
5638
- try {
5639
- const btn = document.querySelector(sel);
5640
- if (btn) {
5641
- btn.removeAttribute("disabled");
5642
- btn.classList.remove("ant-btn-disabled");
5643
- btn.click();
5644
- }
5645
- } catch {
5646
- }
5647
- }, submitSelector).catch(() => {
5648
- });
5700
+ let submitted = false;
5649
5701
  try {
5650
5702
  if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
5651
- await submitButton.click({ force: true, timeout: 2e3 }).catch(() => {
5703
+ await submitButton.click({ timeout: 2e3 }).catch(() => {
5652
5704
  });
5705
+ submitted = true;
5653
5706
  }
5654
5707
  } catch {
5655
5708
  }
5656
- const passInput = page.locator(passwordSelector).first();
5657
- await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
5658
- });
5709
+ if (!submitted) {
5710
+ await page.evaluate(() => {
5711
+ try {
5712
+ const btn = document.querySelector(
5713
+ 'button.qwenchat-auth-pc-submit-button, button[type="submit"]'
5714
+ );
5715
+ if (btn) {
5716
+ btn.removeAttribute("disabled");
5717
+ btn.classList.remove("ant-btn-disabled");
5718
+ btn.click();
5719
+ }
5720
+ } catch {
5721
+ }
5722
+ }).catch(() => {
5723
+ });
5724
+ const passInput = page.locator(passwordSelector).first();
5725
+ await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
5726
+ });
5727
+ }
5659
5728
  const postSubmitDeadline = Date.now() + 15e3;
5660
5729
  while (Date.now() < postSubmitDeadline) {
5661
5730
  if (page.isClosed()) break;
@@ -5673,9 +5742,12 @@ async function loginViaUi(page, email, password) {
5673
5742
  ".ant-form-item-explain-error",
5674
5743
  ".ant-message-error",
5675
5744
  ".ant-message-notice",
5745
+ ".ant-message-custom-content",
5746
+ ".ant-notification-notice",
5676
5747
  '[role="alert"]',
5677
5748
  ".qwenchat-auth-error",
5678
- ".auth-error-message"
5749
+ ".auth-error-message",
5750
+ ".qwenchat-toast"
5679
5751
  ].join(", ");
5680
5752
  const errorEl = page.locator(errorSelector).first();
5681
5753
  if (await errorEl.isVisible().catch(() => false)) {
@@ -5689,7 +5761,15 @@ async function loginViaUi(page, email, password) {
5689
5761
  };
5690
5762
  }
5691
5763
  }
5692
- const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
5764
+ const codeSelector = [
5765
+ 'input[placeholder*="code" i]',
5766
+ 'input[placeholder*="c\xF3digo" i]',
5767
+ 'input[name*="code" i]',
5768
+ ".qwenchat-verification-code-input",
5769
+ ".qwenchat-verification-code-input-cell",
5770
+ '[aria-label*="Verification code" i]',
5771
+ '[aria-label*="c\xF3digo de verifica\xE7\xE3o" i]'
5772
+ ].join(", ");
5693
5773
  const codeInput = page.locator(codeSelector).first();
5694
5774
  if (await codeInput.isVisible().catch(() => false)) {
5695
5775
  return {
@@ -5699,17 +5779,45 @@ async function loginViaUi(page, email, password) {
5699
5779
  }
5700
5780
  try {
5701
5781
  const liveCookies = await page.context().cookies();
5702
- if (liveCookies.some((c) => c.name === "token")) {
5703
- return { success: true };
5782
+ const rTokCookie = liveCookies.find((c) => c.name === "refresh_token")?.value;
5783
+ const tokCookie = liveCookies.find((c) => c.name === "token")?.value;
5784
+ if (tokCookie) {
5785
+ return { success: true, token: tokCookie, refreshToken: rTokCookie };
5786
+ }
5787
+ const currentUrl = page.url();
5788
+ if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
5789
+ const lsTok = await page.evaluate(() => {
5790
+ const t = (localStorage.getItem("token") || "").trim();
5791
+ if (t) {
5792
+ try {
5793
+ document.cookie = `token=${encodeURIComponent(t)}; path=/; domain=.qwen.ai; max-age=31536000`;
5794
+ } catch {
5795
+ }
5796
+ }
5797
+ return t;
5798
+ }).catch(() => "");
5799
+ if (lsTok) {
5800
+ await page.context().addCookies([
5801
+ {
5802
+ name: "token",
5803
+ value: lsTok,
5804
+ domain: ".qwen.ai",
5805
+ path: "/",
5806
+ expires: Math.floor(Date.now() / 1e3) + 31536e3,
5807
+ httpOnly: false,
5808
+ secure: true,
5809
+ sameSite: "Lax"
5810
+ }
5811
+ ]).catch(() => {
5812
+ });
5813
+ return { success: true, token: lsTok, refreshToken: rTokCookie };
5814
+ }
5815
+ if (await isPageLoggedIn(page, 3e3)) {
5816
+ return { success: true, refreshToken: rTokCookie };
5817
+ }
5704
5818
  }
5705
5819
  } catch {
5706
5820
  }
5707
- const currentUrl = page.url();
5708
- if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
5709
- if (await isPageLoggedIn(page, 3e3)) {
5710
- return { success: true };
5711
- }
5712
- }
5713
5821
  await sleep2(1e3);
5714
5822
  }
5715
5823
  if (await isPageLoggedIn(page, 3e3)) {
@@ -5738,10 +5846,18 @@ async function refreshAccountToken(accountId) {
5738
5846
  } catch {
5739
5847
  }
5740
5848
  }
5849
+ if (!refreshToken) {
5850
+ try {
5851
+ const liveCookies = await page.context().cookies();
5852
+ refreshToken = liveCookies.find((c) => c.name === "refresh_token")?.value;
5853
+ } catch {
5854
+ }
5855
+ }
5741
5856
  if (refreshToken) {
5742
5857
  try {
5858
+ const webVersion = getQwenWebVersion() || "0.3.26";
5743
5859
  const refreshResult = await page.evaluate(
5744
- async ({ rTok, tz }) => {
5860
+ async ({ rTok, tz, version }) => {
5745
5861
  try {
5746
5862
  const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
5747
5863
  method: "GET",
@@ -5749,7 +5865,7 @@ async function refreshAccountToken(accountId) {
5749
5865
  headers: {
5750
5866
  accept: "application/json, text/plain, */*",
5751
5867
  source: "web",
5752
- version: getQwenWebVersion() || "0.3.26",
5868
+ version,
5753
5869
  "x-request-origin": "https://chat.qwen.ai",
5754
5870
  timezone: tz,
5755
5871
  authorization: `Bearer ${rTok}`
@@ -5761,7 +5877,7 @@ async function refreshAccountToken(accountId) {
5761
5877
  return { ok: false, error: e.message };
5762
5878
  }
5763
5879
  },
5764
- { rTok: refreshToken, tz: formatAsciiTimezone() }
5880
+ { rTok: refreshToken, tz: formatAsciiTimezone(), version: webVersion }
5765
5881
  );
5766
5882
  const json = refreshResult?.data;
5767
5883
  if (json && json.success === true && json.data) {