qwenproxy-cli 1.0.12 → 1.0.13
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/bin/qwenproxy.js +0 -2
- package/package.json +1 -2
- package/src/api/server.ts +3 -3
- package/src/services/playwright.ts +40 -2
package/bin/qwenproxy.js
CHANGED
|
@@ -46,9 +46,7 @@ if (rawArgs.includes("-h") || rawArgs.includes("--help") || firstArg === "help")
|
|
|
46
46
|
QwenProxy — High-performance AI Coding Gateway & Management TUI
|
|
47
47
|
|
|
48
48
|
Usage:
|
|
49
|
-
qwenproxy [options] [command]
|
|
50
49
|
qpx [options] [command]
|
|
51
|
-
|
|
52
50
|
Commands:
|
|
53
51
|
(default) Launch interactive TUI management dashboard and proxy
|
|
54
52
|
start Run headless HTTP/SSE proxy server
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwenproxy-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.13",
|
|
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": {
|
|
7
|
-
"qwenproxy": "bin/qwenproxy.js",
|
|
8
7
|
"qpx": "bin/qwenproxy.js"
|
|
9
8
|
},
|
|
10
9
|
"files": [
|
package/src/api/server.ts
CHANGED
|
@@ -721,13 +721,13 @@ export async function startServer(options?: {
|
|
|
721
721
|
|
|
722
722
|
for (const account of remainingAccounts) {
|
|
723
723
|
try {
|
|
724
|
-
|
|
724
|
+
const creds = getAccountCredentials(account.id) ?? account;
|
|
725
|
+
// Validate login in background with real unmasked credentials
|
|
725
726
|
const ok = await validateAccountLogin(
|
|
726
|
-
|
|
727
|
+
creds,
|
|
727
728
|
config.playwright.headless,
|
|
728
729
|
config.playwright.browser,
|
|
729
730
|
);
|
|
730
|
-
|
|
731
731
|
if (ok) {
|
|
732
732
|
// Add to priority list only once validated
|
|
733
733
|
ensureAccountInPriority(account.id);
|
|
@@ -1194,11 +1194,26 @@ export async function getBasicHeaders(accountId: string): Promise<{
|
|
|
1194
1194
|
}
|
|
1195
1195
|
}
|
|
1196
1196
|
|
|
1197
|
+
async function resolveAccountCredentials(account: QwenAccount): Promise<QwenAccount> {
|
|
1198
|
+
if (account.password && account.password !== "***") {
|
|
1199
|
+
return account;
|
|
1200
|
+
}
|
|
1201
|
+
try {
|
|
1202
|
+
const { getAccountCredentials } = await import("../core/accounts.ts");
|
|
1203
|
+
const creds = getAccountCredentials(account.id);
|
|
1204
|
+
if (creds && creds.password && creds.password !== "***") {
|
|
1205
|
+
return creds;
|
|
1206
|
+
}
|
|
1207
|
+
} catch {}
|
|
1208
|
+
return account;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1197
1211
|
export async function initPlaywrightForAccount(
|
|
1198
|
-
|
|
1212
|
+
rawAccount: QwenAccount,
|
|
1199
1213
|
headless = true,
|
|
1200
1214
|
browserType: BrowserType = "chromium",
|
|
1201
1215
|
): Promise<void> {
|
|
1216
|
+
const account = await resolveAccountCredentials(rawAccount);
|
|
1202
1217
|
if (accountPages.has(account.id)) {
|
|
1203
1218
|
console.log(
|
|
1204
1219
|
`[Playwright] Already initialized for ${maskEmail(account.email)}`,
|
|
@@ -1404,10 +1419,11 @@ export async function initPlaywrightForAccount(
|
|
|
1404
1419
|
* This is much lighter than full initPlaywrightForAccount (no header capture).
|
|
1405
1420
|
*/
|
|
1406
1421
|
export async function validateAccountLogin(
|
|
1407
|
-
|
|
1422
|
+
rawAccount: QwenAccount,
|
|
1408
1423
|
headless = true,
|
|
1409
1424
|
browserType: BrowserType = "chromium",
|
|
1410
1425
|
): Promise<boolean> {
|
|
1426
|
+
const account = await resolveAccountCredentials(rawAccount);
|
|
1411
1427
|
if (accountPages.has(account.id)) {
|
|
1412
1428
|
// Already initialized, no need to validate
|
|
1413
1429
|
return true;
|
|
@@ -1596,6 +1612,22 @@ async function loginToQwen(
|
|
|
1596
1612
|
email: string,
|
|
1597
1613
|
password: string,
|
|
1598
1614
|
): Promise<boolean> {
|
|
1615
|
+
if (!password || password === "***") {
|
|
1616
|
+
try {
|
|
1617
|
+
const { getAccountCredentials } = await import("../core/accounts.ts");
|
|
1618
|
+
const creds = getAccountCredentials(accountId);
|
|
1619
|
+
if (creds && creds.password && creds.password !== "***") {
|
|
1620
|
+
password = creds.password;
|
|
1621
|
+
} else {
|
|
1622
|
+
console.error(
|
|
1623
|
+
`❌ [Playwright] Cannot login for ${maskEmail(email)}: password is masked ('***') and real credentials not found in store`,
|
|
1624
|
+
);
|
|
1625
|
+
return false;
|
|
1626
|
+
}
|
|
1627
|
+
} catch {
|
|
1628
|
+
return false;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1599
1631
|
const page = accountPages.get(accountId);
|
|
1600
1632
|
if (!page) return false;
|
|
1601
1633
|
|
|
@@ -1827,6 +1859,12 @@ async function loginViaUi(
|
|
|
1827
1859
|
}
|
|
1828
1860
|
await sleep(3000);
|
|
1829
1861
|
|
|
1862
|
+
// If a slider puzzle captcha appeared after submit, solve it automatically
|
|
1863
|
+
await solveBaxiaCaptcha(page, {
|
|
1864
|
+
waitForMs: 2000,
|
|
1865
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
1866
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
1867
|
+
}).catch(() => {});
|
|
1830
1868
|
// Check for UI error elements in DOM (Ant Design errors, alerts, toasts)
|
|
1831
1869
|
const errorSelector = [
|
|
1832
1870
|
".ant-form-item-explain-error",
|