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.
@@ -2990,7 +2990,19 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
2990
2990
  if (localStorage.getItem("qwen_token_logged_out_marker")) {
2991
2991
  return false;
2992
2992
  }
2993
- const res = await fetch("/api/v1/auths/", { method: "GET" });
2993
+ const lsToken = (localStorage.getItem("token") || "").trim();
2994
+ if (lsToken && !/(?:^|;\s*)token=/.test(document.cookie || "")) {
2995
+ try {
2996
+ document.cookie = `token=${encodeURIComponent(lsToken)}; path=/; domain=.qwen.ai; max-age=31536000`;
2997
+ } catch {
2998
+ }
2999
+ }
3000
+ const authHeaders = lsToken ? { Authorization: `Bearer ${lsToken}` } : {};
3001
+ const res = await fetch("/api/v1/auths/", {
3002
+ method: "GET",
3003
+ headers: authHeaders,
3004
+ credentials: "include"
3005
+ });
2994
3006
  if (res.status !== 200) return false;
2995
3007
  const json = await res.json().catch(() => null);
2996
3008
  if (!json) return false;
@@ -3008,6 +3020,7 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
3008
3020
  try {
3009
3021
  const settingsRes = await fetch("/api/v2/users/user/settings", {
3010
3022
  method: "GET",
3023
+ headers: authHeaders,
3011
3024
  credentials: "include",
3012
3025
  signal: AbortSignal.timeout(3e3)
3013
3026
  });
@@ -3836,8 +3849,15 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
3836
3849
  const hasAuthCookie = cookies.some(
3837
3850
  (c) => c.name.toLowerCase().includes("token") || c.name.toLowerCase().includes("session")
3838
3851
  );
3852
+ let initialLoginAttempted = false;
3839
3853
  if (!hasAuthCookie && account.email && account.password) {
3840
- await loginToQwen(account.id, account.email, account.password);
3854
+ initialLoginAttempted = true;
3855
+ const loggedIn = await loginToQwen(account.id, account.email, account.password);
3856
+ if (!loggedIn) {
3857
+ throw new Error(
3858
+ `Authentication failed for account ${maskEmail(account.email)}`
3859
+ );
3860
+ }
3841
3861
  }
3842
3862
  try {
3843
3863
  await acctPage.goto(qwenUrl("/"), {
@@ -3847,13 +3867,21 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
3847
3867
  await sleep2(1500);
3848
3868
  const currentUrl = acctPage.url();
3849
3869
  const isAuthUrl = currentUrl.includes("/auth") || currentUrl.includes("/login");
3850
- if (isAuthUrl && account.email && account.password) {
3870
+ if (isAuthUrl && !initialLoginAttempted && account.email && account.password) {
3851
3871
  console.log(
3852
3872
  `[Playwright] Initial login needed for ${maskEmail(account.email)}, authenticating...`
3853
3873
  );
3854
- await loginToQwen(account.id, account.email, account.password);
3874
+ const loggedIn = await loginToQwen(account.id, account.email, account.password);
3875
+ if (!loggedIn) {
3876
+ throw new Error(
3877
+ `Authentication failed for account ${maskEmail(account.email)}`
3878
+ );
3879
+ }
3855
3880
  }
3856
3881
  } catch (err) {
3882
+ if (err?.message?.includes("Authentication failed for account")) {
3883
+ throw err;
3884
+ }
3857
3885
  console.warn(
3858
3886
  `\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
3859
3887
  );
@@ -3996,10 +4024,30 @@ async function loginToQwen(accountId, email, password) {
3996
4024
  const uiResult = await loginViaUi(page, email, password);
3997
4025
  if (uiResult.success) {
3998
4026
  cookieCaches.delete(accountId);
3999
- await saveStorageState(page.context(), accountId);
4000
4027
  try {
4001
- const liveCookies = await page.context().cookies();
4002
- const tokenCookie = liveCookies.find((c) => c.name === "token");
4028
+ let liveCookies = await page.context().cookies();
4029
+ let tokenCookie = liveCookies.find((c) => c.name === "token");
4030
+ if (!tokenCookie) {
4031
+ const lsTok = uiResult.token || await page.evaluate(() => (localStorage.getItem("token") || "").trim()).catch(() => "");
4032
+ if (lsTok) {
4033
+ await page.context().addCookies([
4034
+ {
4035
+ name: "token",
4036
+ value: lsTok,
4037
+ domain: ".qwen.ai",
4038
+ path: "/",
4039
+ expires: Math.floor(Date.now() / 1e3) + 31536e3,
4040
+ httpOnly: false,
4041
+ secure: true,
4042
+ sameSite: "Lax"
4043
+ }
4044
+ ]).catch(() => {
4045
+ });
4046
+ liveCookies = await page.context().cookies();
4047
+ tokenCookie = liveCookies.find((c) => c.name === "token");
4048
+ }
4049
+ }
4050
+ await saveStorageState(page.context(), accountId);
4003
4051
  if (tokenCookie) {
4004
4052
  const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
4005
4053
  const cache = getHeaderCache(accountId);
@@ -4008,7 +4056,7 @@ async function loginToQwen(accountId, email, password) {
4008
4056
  markAccountHeadersReady(accountId);
4009
4057
  const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
4010
4058
  const exp = parseJwtExpiry(tokenCookie.value);
4011
- let rTok = uiResult.refreshToken;
4059
+ let rTok = uiResult.refreshToken || liveCookies.find((c) => c.name === "refresh_token")?.value;
4012
4060
  if (!rTok) {
4013
4061
  try {
4014
4062
  rTok = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
@@ -4089,8 +4137,9 @@ async function loginViaApi(page, email, password) {
4089
4137
  }
4090
4138
  const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
4091
4139
  const requestId = crypto3.randomUUID();
4140
+ const webVersion = getQwenWebVersion() || "0.3.26";
4092
4141
  const evalRes = await page.evaluate(
4093
- async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz }) => {
4142
+ async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
4094
4143
  try {
4095
4144
  const response = await fetch(signinUrl2, {
4096
4145
  method: "POST",
@@ -4100,7 +4149,7 @@ async function loginViaApi(page, email, password) {
4100
4149
  accept: "application/json, text/plain, */*",
4101
4150
  "content-type": "application/json",
4102
4151
  source: "web",
4103
- version: getQwenWebVersion() || "0.3.26",
4152
+ version,
4104
4153
  "x-request-origin": "https://chat.qwen.ai",
4105
4154
  timezone: tz,
4106
4155
  "x-request-id": requestId2
@@ -4113,7 +4162,14 @@ async function loginViaApi(page, email, password) {
4113
4162
  return { ok: false, error: e.message };
4114
4163
  }
4115
4164
  },
4116
- { email, password: hashedPassword, signinUrl, requestId, tz: formatAsciiTimezone() }
4165
+ {
4166
+ email,
4167
+ password: hashedPassword,
4168
+ signinUrl,
4169
+ requestId,
4170
+ tz: formatAsciiTimezone(),
4171
+ version: webVersion
4172
+ }
4117
4173
  ).catch(() => null);
4118
4174
  let data = evalRes?.data;
4119
4175
  let signinSuccess = Boolean(
@@ -4122,7 +4178,7 @@ async function loginViaApi(page, email, password) {
4122
4178
  if (!signinSuccess && !data?.data?.code) {
4123
4179
  const fallbackUrl = qwenUrl("/api/v2/auths/signin");
4124
4180
  const fallbackRes = await page.evaluate(
4125
- async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz }) => {
4181
+ async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz, version }) => {
4126
4182
  try {
4127
4183
  const response = await fetch(fallbackUrl2, {
4128
4184
  method: "POST",
@@ -4132,7 +4188,7 @@ async function loginViaApi(page, email, password) {
4132
4188
  accept: "application/json, text/plain, */*",
4133
4189
  "content-type": "application/json",
4134
4190
  source: "web",
4135
- version: getQwenWebVersion() || "0.3.26",
4191
+ version,
4136
4192
  timezone: tz,
4137
4193
  "x-request-id": requestId2
4138
4194
  },
@@ -4144,7 +4200,14 @@ async function loginViaApi(page, email, password) {
4144
4200
  return { ok: false, error: e.message };
4145
4201
  }
4146
4202
  },
4147
- { email, password: hashedPassword, fallbackUrl, requestId, tz: formatAsciiTimezone() }
4203
+ {
4204
+ email,
4205
+ password: hashedPassword,
4206
+ fallbackUrl,
4207
+ requestId,
4208
+ tz: formatAsciiTimezone(),
4209
+ version: webVersion
4210
+ }
4148
4211
  ).catch(() => null);
4149
4212
  if (fallbackRes?.data) {
4150
4213
  data = fallbackRes.data;
@@ -4369,28 +4432,34 @@ async function loginViaUi(page, email, password) {
4369
4432
  await sleep2(500);
4370
4433
  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")';
4371
4434
  const submitButton = page.locator(submitSelector).first();
4372
- await page.evaluate((sel) => {
4373
- try {
4374
- const btn = document.querySelector(sel);
4375
- if (btn) {
4376
- btn.removeAttribute("disabled");
4377
- btn.classList.remove("ant-btn-disabled");
4378
- btn.click();
4379
- }
4380
- } catch {
4381
- }
4382
- }, submitSelector).catch(() => {
4383
- });
4435
+ let submitted = false;
4384
4436
  try {
4385
4437
  if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
4386
- await submitButton.click({ force: true, timeout: 2e3 }).catch(() => {
4438
+ await submitButton.click({ timeout: 2e3 }).catch(() => {
4387
4439
  });
4440
+ submitted = true;
4388
4441
  }
4389
4442
  } catch {
4390
4443
  }
4391
- const passInput = page.locator(passwordSelector).first();
4392
- await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
4393
- });
4444
+ if (!submitted) {
4445
+ await page.evaluate(() => {
4446
+ try {
4447
+ const btn = document.querySelector(
4448
+ 'button.qwenchat-auth-pc-submit-button, button[type="submit"]'
4449
+ );
4450
+ if (btn) {
4451
+ btn.removeAttribute("disabled");
4452
+ btn.classList.remove("ant-btn-disabled");
4453
+ btn.click();
4454
+ }
4455
+ } catch {
4456
+ }
4457
+ }).catch(() => {
4458
+ });
4459
+ const passInput = page.locator(passwordSelector).first();
4460
+ await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
4461
+ });
4462
+ }
4394
4463
  const postSubmitDeadline = Date.now() + 15e3;
4395
4464
  while (Date.now() < postSubmitDeadline) {
4396
4465
  if (page.isClosed()) break;
@@ -4408,9 +4477,12 @@ async function loginViaUi(page, email, password) {
4408
4477
  ".ant-form-item-explain-error",
4409
4478
  ".ant-message-error",
4410
4479
  ".ant-message-notice",
4480
+ ".ant-message-custom-content",
4481
+ ".ant-notification-notice",
4411
4482
  '[role="alert"]',
4412
4483
  ".qwenchat-auth-error",
4413
- ".auth-error-message"
4484
+ ".auth-error-message",
4485
+ ".qwenchat-toast"
4414
4486
  ].join(", ");
4415
4487
  const errorEl = page.locator(errorSelector).first();
4416
4488
  if (await errorEl.isVisible().catch(() => false)) {
@@ -4424,7 +4496,15 @@ async function loginViaUi(page, email, password) {
4424
4496
  };
4425
4497
  }
4426
4498
  }
4427
- const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
4499
+ const codeSelector = [
4500
+ 'input[placeholder*="code" i]',
4501
+ 'input[placeholder*="c\xF3digo" i]',
4502
+ 'input[name*="code" i]',
4503
+ ".qwenchat-verification-code-input",
4504
+ ".qwenchat-verification-code-input-cell",
4505
+ '[aria-label*="Verification code" i]',
4506
+ '[aria-label*="c\xF3digo de verifica\xE7\xE3o" i]'
4507
+ ].join(", ");
4428
4508
  const codeInput = page.locator(codeSelector).first();
4429
4509
  if (await codeInput.isVisible().catch(() => false)) {
4430
4510
  return {
@@ -4434,16 +4514,44 @@ async function loginViaUi(page, email, password) {
4434
4514
  }
4435
4515
  try {
4436
4516
  const liveCookies = await page.context().cookies();
4437
- if (liveCookies.some((c) => c.name === "token")) {
4438
- return { success: true };
4517
+ const rTokCookie = liveCookies.find((c) => c.name === "refresh_token")?.value;
4518
+ const tokCookie = liveCookies.find((c) => c.name === "token")?.value;
4519
+ if (tokCookie) {
4520
+ return { success: true, token: tokCookie, refreshToken: rTokCookie };
4439
4521
  }
4440
- } catch {
4441
- }
4442
- const currentUrl = page.url();
4443
- if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
4444
- if (await isPageLoggedIn(page, 3e3)) {
4445
- return { success: true };
4522
+ const currentUrl = page.url();
4523
+ if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
4524
+ const lsTok = await page.evaluate(() => {
4525
+ const t = (localStorage.getItem("token") || "").trim();
4526
+ if (t) {
4527
+ try {
4528
+ document.cookie = `token=${encodeURIComponent(t)}; path=/; domain=.qwen.ai; max-age=31536000`;
4529
+ } catch {
4530
+ }
4531
+ }
4532
+ return t;
4533
+ }).catch(() => "");
4534
+ if (lsTok) {
4535
+ await page.context().addCookies([
4536
+ {
4537
+ name: "token",
4538
+ value: lsTok,
4539
+ domain: ".qwen.ai",
4540
+ path: "/",
4541
+ expires: Math.floor(Date.now() / 1e3) + 31536e3,
4542
+ httpOnly: false,
4543
+ secure: true,
4544
+ sameSite: "Lax"
4545
+ }
4546
+ ]).catch(() => {
4547
+ });
4548
+ return { success: true, token: lsTok, refreshToken: rTokCookie };
4549
+ }
4550
+ if (await isPageLoggedIn(page, 3e3)) {
4551
+ return { success: true, refreshToken: rTokCookie };
4552
+ }
4446
4553
  }
4554
+ } catch {
4447
4555
  }
4448
4556
  await sleep2(1e3);
4449
4557
  }
@@ -4473,10 +4581,18 @@ async function refreshAccountToken(accountId) {
4473
4581
  } catch {
4474
4582
  }
4475
4583
  }
4584
+ if (!refreshToken) {
4585
+ try {
4586
+ const liveCookies = await page.context().cookies();
4587
+ refreshToken = liveCookies.find((c) => c.name === "refresh_token")?.value;
4588
+ } catch {
4589
+ }
4590
+ }
4476
4591
  if (refreshToken) {
4477
4592
  try {
4593
+ const webVersion = getQwenWebVersion() || "0.3.26";
4478
4594
  const refreshResult = await page.evaluate(
4479
- async ({ rTok, tz }) => {
4595
+ async ({ rTok, tz, version }) => {
4480
4596
  try {
4481
4597
  const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
4482
4598
  method: "GET",
@@ -4484,7 +4600,7 @@ async function refreshAccountToken(accountId) {
4484
4600
  headers: {
4485
4601
  accept: "application/json, text/plain, */*",
4486
4602
  source: "web",
4487
- version: getQwenWebVersion() || "0.3.26",
4603
+ version,
4488
4604
  "x-request-origin": "https://chat.qwen.ai",
4489
4605
  timezone: tz,
4490
4606
  authorization: `Bearer ${rTok}`
@@ -4496,7 +4612,7 @@ async function refreshAccountToken(accountId) {
4496
4612
  return { ok: false, error: e.message };
4497
4613
  }
4498
4614
  },
4499
- { rTok: refreshToken, tz: formatAsciiTimezone() }
4615
+ { rTok: refreshToken, tz: formatAsciiTimezone(), version: webVersion }
4500
4616
  );
4501
4617
  const json = refreshResult?.data;
4502
4618
  if (json && json.success === true && json.data) {