qwenproxy-cli 1.0.22 → 1.0.23

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwenproxy-cli",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
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": {
@@ -10,32 +10,52 @@ import {
10
10
  closeAllPlaywright,
11
11
  } from "./playwright.ts";
12
12
  import { isAuthMockEnabled } from "./auth-playwright.ts";
13
+ import { maskEmail } from "../core/logger.ts";
13
14
  export interface DeleteChatsResult {
14
15
  attempted: number;
15
16
  succeeded: number;
16
17
  mode: "accounts";
17
18
  }
18
19
 
19
- async function ensurePlaywrightSession(account: QwenAccount): Promise<void> {
20
+ async function ensurePlaywrightSession(
21
+ account: QwenAccount,
22
+ index = 1,
23
+ total = 1,
24
+ ): Promise<void> {
20
25
  if (isPlaywrightInitialized(account.id) || isAuthMockEnabled()) return;
21
26
 
22
27
  const credentials = getAccountCredentials(account.id);
23
28
  if (!credentials) {
24
- throw new Error(`Account ${account.id} credentials not found`);
29
+ throw new Error(`Credenciais da conta ${account.id} não encontradas.`);
25
30
  }
26
31
 
27
32
  console.log(
28
- `[DeleteChats] Initializing Playwright session for ${account.email}...`,
33
+ `[DeleteChats] [${index}/${total}] Abrindo navegador para ${maskEmail(account.email)}...`,
29
34
  );
30
- await initPlaywrightForAccount(credentials);
35
+ await initPlaywrightForAccount(credentials, true, "chromium", {
36
+ skipHeaderCapture: true,
37
+ });
31
38
  console.log(
32
- `✅ [DeleteChats] Playwright session ready for ${account.email}.`,
39
+ `✅ [DeleteChats] [${index}/${total}] Sessão pronta para ${maskEmail(account.email)}.`,
33
40
  );
34
41
  }
35
42
 
36
- export async function deleteChatsForAccount(account: QwenAccount): Promise<boolean> {
37
- await ensurePlaywrightSession(account);
38
- return deleteAllQwenChats(account.id);
43
+ export async function deleteChatsForAccount(
44
+ account: QwenAccount,
45
+ index = 1,
46
+ total = 1,
47
+ ): Promise<boolean> {
48
+ await ensurePlaywrightSession(account, index, total);
49
+ console.log(
50
+ `🗑️ [DeleteChats] [${index}/${total}] Apagando conversas remotas de ${maskEmail(account.email)}...`,
51
+ );
52
+ const ok = await deleteAllQwenChats(account.id);
53
+ if (ok) {
54
+ console.log(
55
+ `✅ [DeleteChats] [${index}/${total}] Conversas apagadas com sucesso para ${maskEmail(account.email)}.`,
56
+ );
57
+ }
58
+ return ok;
39
59
  }
40
60
 
41
61
  export async function deleteChatsForAccountId(accountId: string): Promise<boolean> {
@@ -65,13 +85,16 @@ export async function deleteChatsForConfiguredAccounts(keepBrowserOpen = false):
65
85
  let succeeded = 0;
66
86
 
67
87
  try {
68
- for (const account of accounts) {
88
+ for (let i = 0; i < accounts.length; i++) {
89
+ const account = accounts[i];
90
+ const currentIdx = i + 1;
91
+ const totalCount = accounts.length;
69
92
  try {
70
- const ok = await deleteChatsForAccount(account);
93
+ const ok = await deleteChatsForAccount(account, currentIdx, totalCount);
71
94
  if (ok) succeeded++;
72
95
  } catch (error) {
73
96
  console.error(
74
- `[DeleteChats] Failed to delete chats for ${account.email}:`,
97
+ `❌ [DeleteChats] [${currentIdx}/${totalCount}] Falha ao apagar conversas de ${maskEmail(account.email)}:`,
75
98
  error instanceof Error ? error.message : String(error),
76
99
  );
77
100
  }
@@ -1290,6 +1290,7 @@ export async function initPlaywrightForAccount(
1290
1290
  rawAccount: QwenAccount,
1291
1291
  headless = true,
1292
1292
  browserType: BrowserType = "chromium",
1293
+ options: { skipHeaderCapture?: boolean } = {},
1293
1294
  ): Promise<void> {
1294
1295
  const account = await resolveAccountCredentials(rawAccount);
1295
1296
  if (accountPages.has(account.id)) {
@@ -1346,11 +1347,19 @@ export async function initPlaywrightForAccount(
1346
1347
 
1347
1348
  let acctContext: BrowserContext;
1348
1349
  try {
1349
- acctContext = await engine.launchPersistentContext(profilePath, launchOptions);
1350
+ acctContext = await withTimeout(
1351
+ engine.launchPersistentContext(profilePath, launchOptions),
1352
+ 30_000,
1353
+ `O navegador não iniciou em 30s para a conta ${maskEmail(account.email)}. Se o QwenProxy estiver rodando em outro terminal, feche-o antes de executar este comando.`,
1354
+ );
1350
1355
  } catch (launchErr: any) {
1351
1356
  if (launchErr?.message?.includes("Executable doesn't exist")) {
1352
1357
  autoInstallPlaywrightChromium();
1353
- acctContext = await engine.launchPersistentContext(profilePath, launchOptions);
1358
+ acctContext = await withTimeout(
1359
+ engine.launchPersistentContext(profilePath, launchOptions),
1360
+ 30_000,
1361
+ `O navegador não iniciou em 30s para a conta ${maskEmail(account.email)}.`,
1362
+ );
1354
1363
  } else {
1355
1364
  throw launchErr;
1356
1365
  }
@@ -1472,7 +1481,9 @@ export async function initPlaywrightForAccount(
1472
1481
  );
1473
1482
  throw validationError;
1474
1483
  }
1475
- await captureQwenHeaders(account.id);
1484
+ if (!options.skipHeaderCapture) {
1485
+ await captureQwenHeaders(account.id);
1486
+ }
1476
1487
 
1477
1488
  // Header capture may leave the UI on a generated chat page. Return the
1478
1489
  // primary tab to the canonical chat home.
@@ -1559,11 +1570,19 @@ export async function validateAccountLogin(
1559
1570
 
1560
1571
  let acctContext: BrowserContext;
1561
1572
  try {
1562
- acctContext = await engine.launchPersistentContext(profilePath, launchOptions);
1573
+ acctContext = await withTimeout(
1574
+ engine.launchPersistentContext(profilePath, launchOptions),
1575
+ 30_000,
1576
+ `O navegador não iniciou em 30s para a conta ${maskEmail(account.email)}. Se o QwenProxy estiver rodando em outro terminal, feche-o antes de executar este comando.`,
1577
+ );
1563
1578
  } catch (launchErr: any) {
1564
1579
  if (launchErr?.message?.includes("Executable doesn't exist")) {
1565
1580
  autoInstallPlaywrightChromium();
1566
- acctContext = await engine.launchPersistentContext(profilePath, launchOptions);
1581
+ acctContext = await withTimeout(
1582
+ engine.launchPersistentContext(profilePath, launchOptions),
1583
+ 30_000,
1584
+ `O navegador não iniciou em 30s para a conta ${maskEmail(account.email)}.`,
1585
+ );
1567
1586
  } else {
1568
1587
  throw launchErr;
1569
1588
  }
@@ -1916,14 +1916,31 @@ function formatPublicQwenModel(model: Record<string, unknown>): PublicQwenModel
1916
1916
  }
1917
1917
 
1918
1918
  export async function deleteAllQwenChats(accountId?: string): Promise<boolean> {
1919
- const { headers } = await getQwenHeaders(false, accountId);
1919
+ let requestHeaders: Record<string, string>;
1920
+ if (isAuthMockEnabled()) {
1921
+ const { headers } = await getQwenHeaders(false, accountId);
1922
+ requestHeaders = buildCapturedQwenHeaders(headers, {
1923
+ referer: qwenUrl("/settings/chats"),
1924
+ });
1925
+ } else {
1926
+ // In live mode, requestQwenTextInBrowser executes inside the authenticated
1927
+ // browser page where session cookies are attached automatically.
1928
+ // Bypassing getQwenHeaders avoids triggering captureQwenHeaders (which sends
1929
+ // a dummy chat completion to intercept anti-fraud tokens not needed for deletions).
1930
+ requestHeaders = {
1931
+ source: "web",
1932
+ version: "0.2.89",
1933
+ timezone: new Date().toString().split(" (")[0],
1934
+ "x-request-id": crypto.randomUUID(),
1935
+ Referer: qwenUrl("/settings/chats"),
1936
+ };
1937
+ }
1938
+
1920
1939
  const response = await requestQwenTextInBrowser(
1921
1940
  accountId,
1922
1941
  "DELETE",
1923
1942
  "/api/v2/chats/",
1924
- buildCapturedQwenHeaders(headers, {
1925
- referer: qwenUrl("/settings/chats"),
1926
- }),
1943
+ requestHeaders,
1927
1944
  undefined,
1928
1945
  { referrer: qwenUrl("/settings/chats") },
1929
1946
  );