qwenproxy-cli 1.4.2 → 1.4.3

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.
@@ -3852,8 +3852,9 @@ async function loginToQwen(accountId, email, password) {
3852
3852
  }
3853
3853
  if (attempt < maxAttempts) {
3854
3854
  const backoffMs = attempt * 5e3;
3855
+ const failReason = uiResult.reason || apiResult.reason || "falha tempor\xE1ria";
3855
3856
  console.warn(
3856
- `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${apiResult.reason || uiResult.reason || "falha tempor\xE1ria"}), retrying in ${backoffMs / 1e3}s`
3857
+ `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1e3}s`
3857
3858
  );
3858
3859
  await sleep2(backoffMs);
3859
3860
  }
@@ -4090,49 +4091,63 @@ async function loginViaUi(page, email, password) {
4090
4091
  } catch {
4091
4092
  await page.keyboard.press("Enter");
4092
4093
  }
4093
- await sleep2(3e3);
4094
- await solveBaxiaCaptcha(page, {
4095
- waitForMs: 2e3,
4096
- maxAttempts: config.captcha.maxAttempts,
4097
- retryDelayMs: config.captcha.retryDelayMs
4098
- }).catch(() => {
4099
- });
4100
- const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
4101
- const codeInput = page.locator(codeSelector).first();
4102
- if (await codeInput.isVisible().catch(() => false)) {
4103
- return {
4104
- success: false,
4105
- reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
4106
- };
4107
- }
4108
- const errorSelector = [
4109
- ".qwen-chat-v2-toast-text",
4110
- ".qwen-chat-v2-toast-content",
4111
- ".ant-form-item-explain-error",
4112
- ".ant-message-error",
4113
- ".ant-message-notice",
4114
- '[role="alert"]',
4115
- ".qwenchat-auth-error",
4116
- ".auth-error-message"
4117
- ].join(", ");
4118
- const errorEl = page.locator(errorSelector).first();
4119
- if (await errorEl.isVisible().catch(() => false)) {
4120
- const errorText = (await errorEl.innerText().catch(() => "")).trim();
4121
- if (errorText) {
4122
- const classified = classifyQwenAuthError(void 0, errorText);
4094
+ const postSubmitDeadline = Date.now() + 15e3;
4095
+ while (Date.now() < postSubmitDeadline) {
4096
+ if (page.isClosed()) break;
4097
+ if (config.captcha.enabled) {
4098
+ await solveBaxiaCaptcha(page, {
4099
+ waitForMs: 1500,
4100
+ maxAttempts: config.captcha.maxAttempts,
4101
+ retryDelayMs: config.captcha.retryDelayMs
4102
+ }).catch(() => {
4103
+ });
4104
+ }
4105
+ const errorSelector = [
4106
+ ".qwen-chat-v2-toast-text",
4107
+ ".qwen-chat-v2-toast-content",
4108
+ ".ant-form-item-explain-error",
4109
+ ".ant-message-error",
4110
+ ".ant-message-notice",
4111
+ '[role="alert"]',
4112
+ ".qwenchat-auth-error",
4113
+ ".auth-error-message"
4114
+ ].join(", ");
4115
+ const errorEl = page.locator(errorSelector).first();
4116
+ if (await errorEl.isVisible().catch(() => false)) {
4117
+ const errorText = (await errorEl.innerText().catch(() => "")).trim();
4118
+ if (errorText) {
4119
+ const classified = classifyQwenAuthError(void 0, errorText);
4120
+ return {
4121
+ success: false,
4122
+ permanentFailure: classified.isPermanent,
4123
+ reason: `Formul\xE1rio: ${classified.reason}`
4124
+ };
4125
+ }
4126
+ }
4127
+ const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
4128
+ const codeInput = page.locator(codeSelector).first();
4129
+ if (await codeInput.isVisible().catch(() => false)) {
4123
4130
  return {
4124
4131
  success: false,
4125
- permanentFailure: classified.isPermanent,
4126
- reason: `Formul\xE1rio: ${classified.reason}`
4132
+ reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
4127
4133
  };
4128
4134
  }
4135
+ try {
4136
+ const liveCookies = await page.context().cookies();
4137
+ if (liveCookies.some((c) => c.name === "token")) {
4138
+ return { success: true };
4139
+ }
4140
+ } catch {
4141
+ }
4142
+ const currentUrl = page.url();
4143
+ if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
4144
+ if (await isPageLoggedIn(page, 3e3)) {
4145
+ return { success: true };
4146
+ }
4147
+ }
4148
+ await sleep2(1e3);
4129
4149
  }
4130
- const isLoggedIn = await isPageLoggedIn(page);
4131
- if (isLoggedIn) {
4132
- await page.goto(qwenUrl("/"), {
4133
- waitUntil: "domcontentloaded",
4134
- timeout: config.timeouts.navigation
4135
- });
4150
+ if (await isPageLoggedIn(page, 3e3)) {
4136
4151
  return { success: true };
4137
4152
  }
4138
4153
  return {
@@ -4727,8 +4727,9 @@ async function loginToQwen(accountId, email, password) {
4727
4727
  }
4728
4728
  if (attempt < maxAttempts) {
4729
4729
  const backoffMs = attempt * 5e3;
4730
+ const failReason = uiResult.reason || apiResult.reason || "falha tempor\xE1ria";
4730
4731
  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`
4732
+ `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1e3}s`
4732
4733
  );
4733
4734
  await sleep2(backoffMs);
4734
4735
  }
@@ -4965,49 +4966,63 @@ async function loginViaUi(page, email, password) {
4965
4966
  } catch {
4966
4967
  await page.keyboard.press("Enter");
4967
4968
  }
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
- };
4982
- }
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);
4969
+ const postSubmitDeadline = Date.now() + 15e3;
4970
+ while (Date.now() < postSubmitDeadline) {
4971
+ if (page.isClosed()) break;
4972
+ if (config.captcha.enabled) {
4973
+ await solveBaxiaCaptcha(page, {
4974
+ waitForMs: 1500,
4975
+ maxAttempts: config.captcha.maxAttempts,
4976
+ retryDelayMs: config.captcha.retryDelayMs
4977
+ }).catch(() => {
4978
+ });
4979
+ }
4980
+ const errorSelector = [
4981
+ ".qwen-chat-v2-toast-text",
4982
+ ".qwen-chat-v2-toast-content",
4983
+ ".ant-form-item-explain-error",
4984
+ ".ant-message-error",
4985
+ ".ant-message-notice",
4986
+ '[role="alert"]',
4987
+ ".qwenchat-auth-error",
4988
+ ".auth-error-message"
4989
+ ].join(", ");
4990
+ const errorEl = page.locator(errorSelector).first();
4991
+ if (await errorEl.isVisible().catch(() => false)) {
4992
+ const errorText = (await errorEl.innerText().catch(() => "")).trim();
4993
+ if (errorText) {
4994
+ const classified = classifyQwenAuthError(void 0, errorText);
4995
+ return {
4996
+ success: false,
4997
+ permanentFailure: classified.isPermanent,
4998
+ reason: `Formul\xE1rio: ${classified.reason}`
4999
+ };
5000
+ }
5001
+ }
5002
+ const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
5003
+ const codeInput = page.locator(codeSelector).first();
5004
+ if (await codeInput.isVisible().catch(() => false)) {
4998
5005
  return {
4999
5006
  success: false,
5000
- permanentFailure: classified.isPermanent,
5001
- reason: `Formul\xE1rio: ${classified.reason}`
5007
+ reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
5002
5008
  };
5003
5009
  }
5010
+ try {
5011
+ const liveCookies = await page.context().cookies();
5012
+ if (liveCookies.some((c) => c.name === "token")) {
5013
+ return { success: true };
5014
+ }
5015
+ } catch {
5016
+ }
5017
+ const currentUrl = page.url();
5018
+ if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
5019
+ if (await isPageLoggedIn(page, 3e3)) {
5020
+ return { success: true };
5021
+ }
5022
+ }
5023
+ await sleep2(1e3);
5004
5024
  }
5005
- const isLoggedIn = await isPageLoggedIn(page);
5006
- if (isLoggedIn) {
5007
- await page.goto(qwenUrl("/"), {
5008
- waitUntil: "domcontentloaded",
5009
- timeout: config.timeouts.navigation
5010
- });
5025
+ if (await isPageLoggedIn(page, 3e3)) {
5011
5026
  return { success: true };
5012
5027
  }
5013
5028
  return {
package/dist/index.js CHANGED
@@ -5944,8 +5944,9 @@ async function loginToQwen(accountId, email, password) {
5944
5944
  }
5945
5945
  if (attempt < maxAttempts) {
5946
5946
  const backoffMs = attempt * 5e3;
5947
+ const failReason = uiResult.reason || apiResult.reason || "falha tempor\xE1ria";
5947
5948
  console.warn(
5948
- `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${apiResult.reason || uiResult.reason || "falha tempor\xE1ria"}), retrying in ${backoffMs / 1e3}s`
5949
+ `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1e3}s`
5949
5950
  );
5950
5951
  await sleep2(backoffMs);
5951
5952
  }
@@ -6182,49 +6183,63 @@ async function loginViaUi(page, email, password) {
6182
6183
  } catch {
6183
6184
  await page.keyboard.press("Enter");
6184
6185
  }
6185
- await sleep2(3e3);
6186
- await solveBaxiaCaptcha(page, {
6187
- waitForMs: 2e3,
6188
- maxAttempts: config.captcha.maxAttempts,
6189
- retryDelayMs: config.captcha.retryDelayMs
6190
- }).catch(() => {
6191
- });
6192
- const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
6193
- const codeInput = page.locator(codeSelector).first();
6194
- if (await codeInput.isVisible().catch(() => false)) {
6195
- return {
6196
- success: false,
6197
- reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
6198
- };
6199
- }
6200
- const errorSelector = [
6201
- ".qwen-chat-v2-toast-text",
6202
- ".qwen-chat-v2-toast-content",
6203
- ".ant-form-item-explain-error",
6204
- ".ant-message-error",
6205
- ".ant-message-notice",
6206
- '[role="alert"]',
6207
- ".qwenchat-auth-error",
6208
- ".auth-error-message"
6209
- ].join(", ");
6210
- const errorEl = page.locator(errorSelector).first();
6211
- if (await errorEl.isVisible().catch(() => false)) {
6212
- const errorText = (await errorEl.innerText().catch(() => "")).trim();
6213
- if (errorText) {
6214
- const classified = classifyQwenAuthError(void 0, errorText);
6186
+ const postSubmitDeadline = Date.now() + 15e3;
6187
+ while (Date.now() < postSubmitDeadline) {
6188
+ if (page.isClosed()) break;
6189
+ if (config.captcha.enabled) {
6190
+ await solveBaxiaCaptcha(page, {
6191
+ waitForMs: 1500,
6192
+ maxAttempts: config.captcha.maxAttempts,
6193
+ retryDelayMs: config.captcha.retryDelayMs
6194
+ }).catch(() => {
6195
+ });
6196
+ }
6197
+ const errorSelector = [
6198
+ ".qwen-chat-v2-toast-text",
6199
+ ".qwen-chat-v2-toast-content",
6200
+ ".ant-form-item-explain-error",
6201
+ ".ant-message-error",
6202
+ ".ant-message-notice",
6203
+ '[role="alert"]',
6204
+ ".qwenchat-auth-error",
6205
+ ".auth-error-message"
6206
+ ].join(", ");
6207
+ const errorEl = page.locator(errorSelector).first();
6208
+ if (await errorEl.isVisible().catch(() => false)) {
6209
+ const errorText = (await errorEl.innerText().catch(() => "")).trim();
6210
+ if (errorText) {
6211
+ const classified = classifyQwenAuthError(void 0, errorText);
6212
+ return {
6213
+ success: false,
6214
+ permanentFailure: classified.isPermanent,
6215
+ reason: `Formul\xE1rio: ${classified.reason}`
6216
+ };
6217
+ }
6218
+ }
6219
+ const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
6220
+ const codeInput = page.locator(codeSelector).first();
6221
+ if (await codeInput.isVisible().catch(() => false)) {
6215
6222
  return {
6216
6223
  success: false,
6217
- permanentFailure: classified.isPermanent,
6218
- reason: `Formul\xE1rio: ${classified.reason}`
6224
+ reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
6219
6225
  };
6220
6226
  }
6227
+ try {
6228
+ const liveCookies = await page.context().cookies();
6229
+ if (liveCookies.some((c) => c.name === "token")) {
6230
+ return { success: true };
6231
+ }
6232
+ } catch {
6233
+ }
6234
+ const currentUrl = page.url();
6235
+ if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
6236
+ if (await isPageLoggedIn(page, 3e3)) {
6237
+ return { success: true };
6238
+ }
6239
+ }
6240
+ await sleep2(1e3);
6221
6241
  }
6222
- const isLoggedIn = await isPageLoggedIn(page);
6223
- if (isLoggedIn) {
6224
- await page.goto(qwenUrl("/"), {
6225
- waitUntil: "domcontentloaded",
6226
- timeout: config.timeouts.navigation
6227
- });
6242
+ if (await isPageLoggedIn(page, 3e3)) {
6228
6243
  return { success: true };
6229
6244
  }
6230
6245
  return {
@@ -25498,7 +25513,7 @@ function getAppVersion() {
25498
25513
  }
25499
25514
  } catch {
25500
25515
  }
25501
- cachedVersion = "v1.4.2";
25516
+ cachedVersion = "v1.4.3";
25502
25517
  return cachedVersion;
25503
25518
  }
25504
25519
  var cachedVersion;
package/dist/login.js CHANGED
@@ -4812,8 +4812,9 @@ async function loginToQwen(accountId, email, password) {
4812
4812
  }
4813
4813
  if (attempt < maxAttempts) {
4814
4814
  const backoffMs = attempt * 5e3;
4815
+ const failReason = uiResult.reason || apiResult.reason || "falha tempor\xE1ria";
4815
4816
  console.warn(
4816
- `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${apiResult.reason || uiResult.reason || "falha tempor\xE1ria"}), retrying in ${backoffMs / 1e3}s`
4817
+ `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1e3}s`
4817
4818
  );
4818
4819
  await sleep2(backoffMs);
4819
4820
  }
@@ -5050,49 +5051,63 @@ async function loginViaUi(page, email, password) {
5050
5051
  } catch {
5051
5052
  await page.keyboard.press("Enter");
5052
5053
  }
5053
- await sleep2(3e3);
5054
- await solveBaxiaCaptcha(page, {
5055
- waitForMs: 2e3,
5056
- maxAttempts: config.captcha.maxAttempts,
5057
- retryDelayMs: config.captcha.retryDelayMs
5058
- }).catch(() => {
5059
- });
5060
- const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
5061
- const codeInput = page.locator(codeSelector).first();
5062
- if (await codeInput.isVisible().catch(() => false)) {
5063
- return {
5064
- success: false,
5065
- reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
5066
- };
5067
- }
5068
- const errorSelector = [
5069
- ".qwen-chat-v2-toast-text",
5070
- ".qwen-chat-v2-toast-content",
5071
- ".ant-form-item-explain-error",
5072
- ".ant-message-error",
5073
- ".ant-message-notice",
5074
- '[role="alert"]',
5075
- ".qwenchat-auth-error",
5076
- ".auth-error-message"
5077
- ].join(", ");
5078
- const errorEl = page.locator(errorSelector).first();
5079
- if (await errorEl.isVisible().catch(() => false)) {
5080
- const errorText = (await errorEl.innerText().catch(() => "")).trim();
5081
- if (errorText) {
5082
- const classified = classifyQwenAuthError(void 0, errorText);
5054
+ const postSubmitDeadline = Date.now() + 15e3;
5055
+ while (Date.now() < postSubmitDeadline) {
5056
+ if (page.isClosed()) break;
5057
+ if (config.captcha.enabled) {
5058
+ await solveBaxiaCaptcha(page, {
5059
+ waitForMs: 1500,
5060
+ maxAttempts: config.captcha.maxAttempts,
5061
+ retryDelayMs: config.captcha.retryDelayMs
5062
+ }).catch(() => {
5063
+ });
5064
+ }
5065
+ const errorSelector = [
5066
+ ".qwen-chat-v2-toast-text",
5067
+ ".qwen-chat-v2-toast-content",
5068
+ ".ant-form-item-explain-error",
5069
+ ".ant-message-error",
5070
+ ".ant-message-notice",
5071
+ '[role="alert"]',
5072
+ ".qwenchat-auth-error",
5073
+ ".auth-error-message"
5074
+ ].join(", ");
5075
+ const errorEl = page.locator(errorSelector).first();
5076
+ if (await errorEl.isVisible().catch(() => false)) {
5077
+ const errorText = (await errorEl.innerText().catch(() => "")).trim();
5078
+ if (errorText) {
5079
+ const classified = classifyQwenAuthError(void 0, errorText);
5080
+ return {
5081
+ success: false,
5082
+ permanentFailure: classified.isPermanent,
5083
+ reason: `Formul\xE1rio: ${classified.reason}`
5084
+ };
5085
+ }
5086
+ }
5087
+ const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
5088
+ const codeInput = page.locator(codeSelector).first();
5089
+ if (await codeInput.isVisible().catch(() => false)) {
5083
5090
  return {
5084
5091
  success: false,
5085
- permanentFailure: classified.isPermanent,
5086
- reason: `Formul\xE1rio: ${classified.reason}`
5092
+ reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
5087
5093
  };
5088
5094
  }
5095
+ try {
5096
+ const liveCookies = await page.context().cookies();
5097
+ if (liveCookies.some((c) => c.name === "token")) {
5098
+ return { success: true };
5099
+ }
5100
+ } catch {
5101
+ }
5102
+ const currentUrl = page.url();
5103
+ if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
5104
+ if (await isPageLoggedIn(page, 3e3)) {
5105
+ return { success: true };
5106
+ }
5107
+ }
5108
+ await sleep2(1e3);
5089
5109
  }
5090
- const isLoggedIn = await isPageLoggedIn(page);
5091
- if (isLoggedIn) {
5092
- await page.goto(qwenUrl("/"), {
5093
- waitUntil: "domcontentloaded",
5094
- timeout: config.timeouts.navigation
5095
- });
5110
+ if (await isPageLoggedIn(page, 3e3)) {
5096
5111
  return { success: true };
5097
5112
  }
5098
5113
  return {
@@ -6446,7 +6461,8 @@ async function addAccountFlow() {
6446
6461
  const { config: config3 } = await Promise.resolve().then(() => (init_config(), config_exports));
6447
6462
  const ok = await validateAccountLogin2(
6448
6463
  { id: tempId, email: trimmedEmail, password: trimmedPassword },
6449
- config3.playwright.headless,
6464
+ false,
6465
+ // Visible browser so user can see and complete challenges if needed
6450
6466
  config3.playwright.browser
6451
6467
  );
6452
6468
  if (ok) {
@@ -4088,8 +4088,9 @@ async function loginToQwen(accountId, email, password) {
4088
4088
  }
4089
4089
  if (attempt < maxAttempts) {
4090
4090
  const backoffMs = attempt * 5e3;
4091
+ const failReason = uiResult.reason || apiResult.reason || "falha tempor\xE1ria";
4091
4092
  console.warn(
4092
- `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${apiResult.reason || uiResult.reason || "falha tempor\xE1ria"}), retrying in ${backoffMs / 1e3}s`
4093
+ `\u26A0\uFE0F [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1e3}s`
4093
4094
  );
4094
4095
  await sleep2(backoffMs);
4095
4096
  }
@@ -4326,49 +4327,63 @@ async function loginViaUi(page, email, password) {
4326
4327
  } catch {
4327
4328
  await page.keyboard.press("Enter");
4328
4329
  }
4329
- await sleep2(3e3);
4330
- await solveBaxiaCaptcha(page, {
4331
- waitForMs: 2e3,
4332
- maxAttempts: config.captcha.maxAttempts,
4333
- retryDelayMs: config.captcha.retryDelayMs
4334
- }).catch(() => {
4335
- });
4336
- const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
4337
- const codeInput = page.locator(codeSelector).first();
4338
- if (await codeInput.isVisible().catch(() => false)) {
4339
- return {
4340
- success: false,
4341
- reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
4342
- };
4343
- }
4344
- const errorSelector = [
4345
- ".qwen-chat-v2-toast-text",
4346
- ".qwen-chat-v2-toast-content",
4347
- ".ant-form-item-explain-error",
4348
- ".ant-message-error",
4349
- ".ant-message-notice",
4350
- '[role="alert"]',
4351
- ".qwenchat-auth-error",
4352
- ".auth-error-message"
4353
- ].join(", ");
4354
- const errorEl = page.locator(errorSelector).first();
4355
- if (await errorEl.isVisible().catch(() => false)) {
4356
- const errorText = (await errorEl.innerText().catch(() => "")).trim();
4357
- if (errorText) {
4358
- const classified = classifyQwenAuthError(void 0, errorText);
4330
+ const postSubmitDeadline = Date.now() + 15e3;
4331
+ while (Date.now() < postSubmitDeadline) {
4332
+ if (page.isClosed()) break;
4333
+ if (config.captcha.enabled) {
4334
+ await solveBaxiaCaptcha(page, {
4335
+ waitForMs: 1500,
4336
+ maxAttempts: config.captcha.maxAttempts,
4337
+ retryDelayMs: config.captcha.retryDelayMs
4338
+ }).catch(() => {
4339
+ });
4340
+ }
4341
+ const errorSelector = [
4342
+ ".qwen-chat-v2-toast-text",
4343
+ ".qwen-chat-v2-toast-content",
4344
+ ".ant-form-item-explain-error",
4345
+ ".ant-message-error",
4346
+ ".ant-message-notice",
4347
+ '[role="alert"]',
4348
+ ".qwenchat-auth-error",
4349
+ ".auth-error-message"
4350
+ ].join(", ");
4351
+ const errorEl = page.locator(errorSelector).first();
4352
+ if (await errorEl.isVisible().catch(() => false)) {
4353
+ const errorText = (await errorEl.innerText().catch(() => "")).trim();
4354
+ if (errorText) {
4355
+ const classified = classifyQwenAuthError(void 0, errorText);
4356
+ return {
4357
+ success: false,
4358
+ permanentFailure: classified.isPermanent,
4359
+ reason: `Formul\xE1rio: ${classified.reason}`
4360
+ };
4361
+ }
4362
+ }
4363
+ const codeSelector = 'input[placeholder*="code" i], input[placeholder*="c\xF3digo" i], input[name*="code" i]';
4364
+ const codeInput = page.locator(codeSelector).first();
4365
+ if (await codeInput.isVisible().catch(() => false)) {
4359
4366
  return {
4360
4367
  success: false,
4361
- permanentFailure: classified.isPermanent,
4362
- reason: `Formul\xE1rio: ${classified.reason}`
4368
+ reason: "Conta requer c\xF3digo de verifica\xE7\xE3o enviado por e-mail (2FA/OTP)"
4363
4369
  };
4364
4370
  }
4371
+ try {
4372
+ const liveCookies = await page.context().cookies();
4373
+ if (liveCookies.some((c) => c.name === "token")) {
4374
+ return { success: true };
4375
+ }
4376
+ } catch {
4377
+ }
4378
+ const currentUrl = page.url();
4379
+ if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
4380
+ if (await isPageLoggedIn(page, 3e3)) {
4381
+ return { success: true };
4382
+ }
4383
+ }
4384
+ await sleep2(1e3);
4365
4385
  }
4366
- const isLoggedIn = await isPageLoggedIn(page);
4367
- if (isLoggedIn) {
4368
- await page.goto(qwenUrl("/"), {
4369
- waitUntil: "domcontentloaded",
4370
- timeout: config.timeouts.navigation
4371
- });
4386
+ if (await isPageLoggedIn(page, 3e3)) {
4372
4387
  return { success: true };
4373
4388
  }
4374
4389
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwenproxy-cli",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "High-performance OpenAI & Anthropic compatible API gateway for Qwen with multi-account rotation, interactive TUI, and resilient tool calling.",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
@@ -17,6 +17,6 @@ export function getAppVersion(): string {
17
17
  }
18
18
  }
19
19
  } catch {}
20
- cachedVersion = "v1.4.2";
20
+ cachedVersion = "v1.4.3";
21
21
  return cachedVersion;
22
22
  }
package/src/login.ts CHANGED
@@ -120,7 +120,7 @@ async function addAccountFlow() {
120
120
 
121
121
  const ok = await validateAccountLogin(
122
122
  { id: tempId, email: trimmedEmail, password: trimmedPassword },
123
- config.playwright.headless,
123
+ false, // Visible browser so user can see and complete challenges if needed
124
124
  config.playwright.browser,
125
125
  );
126
126
 
@@ -2163,8 +2163,9 @@ async function loginToQwen(
2163
2163
 
2164
2164
  if (attempt < maxAttempts) {
2165
2165
  const backoffMs = attempt * 5_000;
2166
+ const failReason = uiResult.reason || apiResult.reason || "falha temporária";
2166
2167
  console.warn(
2167
- `⚠️ [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${apiResult.reason || uiResult.reason || "falha temporária"}), retrying in ${backoffMs / 1000}s`,
2168
+ `⚠️ [Playwright] Login attempt ${attempt}/${maxAttempts} failed for ${maskEmail(email)} (${failReason}), retrying in ${backoffMs / 1000}s`,
2168
2169
  );
2169
2170
  await sleep(backoffMs);
2170
2171
  }
@@ -2447,58 +2448,76 @@ async function loginViaUi(
2447
2448
  } catch {
2448
2449
  await page.keyboard.press("Enter");
2449
2450
  }
2450
- await sleep(3000);
2451
-
2452
- // If a slider puzzle captcha appeared after submit, solve it automatically
2453
- await solveBaxiaCaptcha(page, {
2454
- waitForMs: 2000,
2455
- maxAttempts: config.captcha.maxAttempts,
2456
- retryDelayMs: config.captcha.retryDelayMs,
2457
- }).catch(() => {});
2451
+ // Post-submit verification loop: wait up to 15s for captcha, redirect, cookies, or errors
2452
+ const postSubmitDeadline = Date.now() + 15_000;
2453
+ while (Date.now() < postSubmitDeadline) {
2454
+ if (page.isClosed()) break;
2455
+
2456
+ // If a slider puzzle captcha appeared after submit, solve it automatically
2457
+ if (config.captcha.enabled) {
2458
+ await solveBaxiaCaptcha(page, {
2459
+ waitForMs: 1500,
2460
+ maxAttempts: config.captcha.maxAttempts,
2461
+ retryDelayMs: config.captcha.retryDelayMs,
2462
+ }).catch(() => {});
2463
+ }
2458
2464
 
2459
- // Check if an OTP code verification screen appeared (e.g. 2FA / email verification code)
2460
- const codeSelector =
2461
- 'input[placeholder*="code" i], input[placeholder*="código" i], input[name*="code" i]';
2462
- const codeInput = page.locator(codeSelector).first();
2463
- if (await codeInput.isVisible().catch(() => false)) {
2464
- return {
2465
- success: false,
2466
- reason: "Conta requer código de verificação enviado por e-mail (2FA/OTP)",
2467
- };
2468
- }
2465
+ // Check for UI error elements in DOM (Ant Design errors, alerts, toasts)
2466
+ const errorSelector = [
2467
+ ".qwen-chat-v2-toast-text",
2468
+ ".qwen-chat-v2-toast-content",
2469
+ ".ant-form-item-explain-error",
2470
+ ".ant-message-error",
2471
+ ".ant-message-notice",
2472
+ '[role="alert"]',
2473
+ ".qwenchat-auth-error",
2474
+ ".auth-error-message",
2475
+ ].join(", ");
2476
+ const errorEl = page.locator(errorSelector).first();
2477
+ if (await errorEl.isVisible().catch(() => false)) {
2478
+ const errorText = (await errorEl.innerText().catch(() => "")).trim();
2479
+ if (errorText) {
2480
+ const classified = classifyQwenAuthError(undefined, errorText);
2481
+ return {
2482
+ success: false,
2483
+ permanentFailure: classified.isPermanent,
2484
+ reason: `Formulário: ${classified.reason}`,
2485
+ };
2486
+ }
2487
+ }
2469
2488
 
2470
- // Check for UI error elements in DOM (Ant Design errors, alerts, toasts)
2471
- const errorSelector = [
2472
- ".qwen-chat-v2-toast-text",
2473
- ".qwen-chat-v2-toast-content",
2474
- ".ant-form-item-explain-error",
2475
- ".ant-message-error",
2476
- ".ant-message-notice",
2477
- '[role="alert"]',
2478
- ".qwenchat-auth-error",
2479
- ".auth-error-message",
2480
- ].join(", ");
2481
- const errorEl = page.locator(errorSelector).first();
2482
- if (await errorEl.isVisible().catch(() => false)) {
2483
- const errorText = (await errorEl.innerText().catch(() => "")).trim();
2484
- if (errorText) {
2485
- const classified = classifyQwenAuthError(undefined, errorText);
2489
+ // Check if an OTP code verification screen appeared (e.g. 2FA / email verification code)
2490
+ const codeSelector =
2491
+ 'input[placeholder*="code" i], input[placeholder*="código" i], input[name*="code" i]';
2492
+ const codeInput = page.locator(codeSelector).first();
2493
+ if (await codeInput.isVisible().catch(() => false)) {
2486
2494
  return {
2487
2495
  success: false,
2488
- permanentFailure: classified.isPermanent,
2489
- reason: `Formulário: ${classified.reason}`,
2496
+ reason: "Conta requer código de verificação enviado por e-mail (2FA/OTP)",
2490
2497
  };
2491
2498
  }
2492
- }
2493
2499
 
2494
- // Check if login was successful
2495
- const isLoggedIn = await isPageLoggedIn(page);
2500
+ // Check if auth cookie 'token' appeared
2501
+ try {
2502
+ const liveCookies = await page.context().cookies();
2503
+ if (liveCookies.some((c) => c.name === "token")) {
2504
+ return { success: true };
2505
+ }
2506
+ } catch {}
2496
2507
 
2497
- if (isLoggedIn) {
2498
- await page.goto(qwenUrl("/"), {
2499
- waitUntil: "domcontentloaded",
2500
- timeout: config.timeouts.navigation,
2501
- });
2508
+ // Check if page redirected away from /auth and is logged in
2509
+ const currentUrl = page.url();
2510
+ if (!currentUrl.includes("/auth") && !currentUrl.includes("/login")) {
2511
+ if (await isPageLoggedIn(page, 3000)) {
2512
+ return { success: true };
2513
+ }
2514
+ }
2515
+
2516
+ await sleep(1000);
2517
+ }
2518
+
2519
+ // Final check
2520
+ if (await isPageLoggedIn(page, 3000)) {
2502
2521
  return { success: true };
2503
2522
  }
2504
2523