qwenproxy-cli 1.2.7 → 1.2.8
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 +1 -1
- package/src/core/accounts.ts +37 -18
- package/src/core/server-log-buffer.ts +5 -3
- package/src/services/playwright.ts +5 -7
- package/src/services/qwen.ts +27 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwenproxy-cli",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.8",
|
|
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": {
|
package/src/core/accounts.ts
CHANGED
|
@@ -23,12 +23,30 @@ function parseEnvAccounts(): QwenAccount[] {
|
|
|
23
23
|
const envAccounts = process.env.QWEN_ACCOUNTS;
|
|
24
24
|
if (!envAccounts) return [];
|
|
25
25
|
|
|
26
|
-
const
|
|
26
|
+
const clean = (s: string) => s.trim().replace(/^[,;\s"'`]+|[,;\s"'`]+$/g, "").trim();
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
const lines = envAccounts.split(/[\r\n;]+/);
|
|
29
|
+
const rawEntries: string[] = [];
|
|
30
|
+
|
|
31
|
+
for (const rawLine of lines) {
|
|
32
|
+
const line = clean(rawLine);
|
|
33
|
+
if (!line || line.startsWith("#") || line.startsWith("//")) continue;
|
|
34
|
+
|
|
35
|
+
// Check if line contains multiple accounts separated by comma (e.g. "a@b.com:p1, c@d.com:p2")
|
|
36
|
+
if (line.includes(",") && (line.match(/@/g) || []).length > 1) {
|
|
37
|
+
for (const seg of line.split(",")) {
|
|
38
|
+
const trimmed = clean(seg);
|
|
39
|
+
if (trimmed) rawEntries.push(trimmed);
|
|
40
|
+
}
|
|
41
|
+
} else {
|
|
42
|
+
const trimmed = clean(line);
|
|
43
|
+
if (trimmed) rawEntries.push(trimmed);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return rawEntries
|
|
30
48
|
.map((entry, index) => {
|
|
31
|
-
const trimmed = entry
|
|
49
|
+
const trimmed = clean(entry);
|
|
32
50
|
const colonIdx = trimmed.indexOf(":");
|
|
33
51
|
if (colonIdx === -1) {
|
|
34
52
|
console.warn(
|
|
@@ -36,8 +54,8 @@ function parseEnvAccounts(): QwenAccount[] {
|
|
|
36
54
|
);
|
|
37
55
|
return null;
|
|
38
56
|
}
|
|
39
|
-
const email = trimmed.substring(0, colonIdx);
|
|
40
|
-
const password = trimmed.substring(colonIdx + 1);
|
|
57
|
+
const email = clean(trimmed.substring(0, colonIdx));
|
|
58
|
+
const password = clean(trimmed.substring(colonIdx + 1));
|
|
41
59
|
if (!email || !password) {
|
|
42
60
|
console.warn(
|
|
43
61
|
`[Accounts] Invalid QWEN_ACCOUNTS entry at index ${index}: "${trimmed}"`,
|
|
@@ -46,8 +64,8 @@ function parseEnvAccounts(): QwenAccount[] {
|
|
|
46
64
|
}
|
|
47
65
|
return {
|
|
48
66
|
id: generateId(email),
|
|
49
|
-
email
|
|
50
|
-
password
|
|
67
|
+
email,
|
|
68
|
+
password,
|
|
51
69
|
};
|
|
52
70
|
})
|
|
53
71
|
.filter((a): a is QwenAccount => a !== null);
|
|
@@ -160,26 +178,27 @@ export function parseBatchAccounts(rawInput: string): {
|
|
|
160
178
|
let email = "";
|
|
161
179
|
let password = "";
|
|
162
180
|
|
|
181
|
+
const clean = (s: string) => s.trim().replace(/^[,;\s"'`]+|[,;\s"'`]+$/g, "").trim();
|
|
163
182
|
if (seg.includes("---")) {
|
|
164
183
|
const parts = seg.split("---");
|
|
165
|
-
email = parts[0]
|
|
166
|
-
password = parts.slice(1).join("---")
|
|
184
|
+
email = clean(parts[0]);
|
|
185
|
+
password = clean(parts.slice(1).join("---"));
|
|
167
186
|
} else if (seg.includes("\t")) {
|
|
168
187
|
const parts = seg.split("\t");
|
|
169
|
-
email = parts[0]
|
|
170
|
-
password = parts.slice(1).join("\t")
|
|
188
|
+
email = clean(parts[0]);
|
|
189
|
+
password = clean(parts.slice(1).join("\t"));
|
|
171
190
|
} else if (seg.includes(" | ")) {
|
|
172
191
|
const parts = seg.split(" | ");
|
|
173
|
-
email = parts[0]
|
|
174
|
-
password = parts.slice(1).join(" | ")
|
|
192
|
+
email = clean(parts[0]);
|
|
193
|
+
password = clean(parts.slice(1).join(" | "));
|
|
175
194
|
} else if (seg.includes(":")) {
|
|
176
195
|
const colonIdx = seg.indexOf(":");
|
|
177
|
-
email = seg.slice(0, colonIdx)
|
|
178
|
-
password = seg.slice(colonIdx + 1)
|
|
196
|
+
email = clean(seg.slice(0, colonIdx));
|
|
197
|
+
password = clean(seg.slice(colonIdx + 1));
|
|
179
198
|
} else if (seg.includes(",")) {
|
|
180
199
|
const commaIdx = seg.indexOf(",");
|
|
181
|
-
email = seg.slice(0, commaIdx)
|
|
182
|
-
password = seg.slice(commaIdx + 1)
|
|
200
|
+
email = clean(seg.slice(0, commaIdx));
|
|
201
|
+
password = clean(seg.slice(commaIdx + 1));
|
|
183
202
|
} else {
|
|
184
203
|
invalid.push(seg);
|
|
185
204
|
continue;
|
|
@@ -80,9 +80,11 @@ export function recordServerLog(level: "INFO" | "WARN" | "ERROR", text: string):
|
|
|
80
80
|
.replace(/([\u{1F300}-\u{1FAFF}\u{2600}-\u{27BF}\u{2300}-\u{23FF}]\uFE0F?)\s{2,}/gu, "$1 ");
|
|
81
81
|
if (!line) continue;
|
|
82
82
|
|
|
83
|
-
// Prevent identical
|
|
84
|
-
const
|
|
85
|
-
|
|
83
|
+
// Prevent identical duplicate logs within the same second window
|
|
84
|
+
const isDuplicate = logHistory
|
|
85
|
+
.slice(-10)
|
|
86
|
+
.some((entry) => entry.time === time && entry.level === level && entry.message === line);
|
|
87
|
+
if (isDuplicate) {
|
|
86
88
|
continue;
|
|
87
89
|
}
|
|
88
90
|
|
|
@@ -352,10 +352,7 @@ export async function isPageLoggedIn(
|
|
|
352
352
|
const res = await fetch("/api/v1/auths/", { method: "GET" });
|
|
353
353
|
return res.status === 200;
|
|
354
354
|
} catch {
|
|
355
|
-
|
|
356
|
-
".header-right-auth-button, button.header-right-auth-button, a[href*='/auth'], a[href*='/login']",
|
|
357
|
-
);
|
|
358
|
-
return !btn || (btn as HTMLElement).offsetWidth === 0;
|
|
355
|
+
return false;
|
|
359
356
|
}
|
|
360
357
|
})
|
|
361
358
|
.catch(() => false);
|
|
@@ -1844,8 +1841,9 @@ async function loginViaApi(
|
|
|
1844
1841
|
.digest("hex");
|
|
1845
1842
|
const signinUrl = qwenUrl("/api/v2/auths/signin");
|
|
1846
1843
|
|
|
1844
|
+
const requestId = crypto.randomUUID();
|
|
1847
1845
|
const result = await page.evaluate(
|
|
1848
|
-
async ({ email, password, signinUrl }) => {
|
|
1846
|
+
async ({ email, password, signinUrl, requestId }) => {
|
|
1849
1847
|
try {
|
|
1850
1848
|
const response = await fetch(signinUrl, {
|
|
1851
1849
|
method: "POST",
|
|
@@ -1855,7 +1853,7 @@ async function loginViaApi(
|
|
|
1855
1853
|
"content-type": "application/json",
|
|
1856
1854
|
source: "web",
|
|
1857
1855
|
timezone: new Date().toString().split(" (")[0],
|
|
1858
|
-
"x-request-id":
|
|
1856
|
+
"x-request-id": requestId,
|
|
1859
1857
|
},
|
|
1860
1858
|
body: JSON.stringify({ email, password, login_type: "email" }),
|
|
1861
1859
|
});
|
|
@@ -1865,7 +1863,7 @@ async function loginViaApi(
|
|
|
1865
1863
|
return { ok: false, error: e.message };
|
|
1866
1864
|
}
|
|
1867
1865
|
},
|
|
1868
|
-
{ email, password: hashedPassword, signinUrl },
|
|
1866
|
+
{ email, password: hashedPassword, signinUrl, requestId },
|
|
1869
1867
|
);
|
|
1870
1868
|
|
|
1871
1869
|
if (result.data) {
|
package/src/services/qwen.ts
CHANGED
|
@@ -1793,8 +1793,9 @@ export async function disableNativeTools(accountId?: string): Promise<void> {
|
|
|
1793
1793
|
const result = await withAccountPage(
|
|
1794
1794
|
accountId,
|
|
1795
1795
|
async (page) => {
|
|
1796
|
+
const requestId = crypto.randomUUID();
|
|
1796
1797
|
const response = await page.evaluate(
|
|
1797
|
-
async ({ payload, timeoutMs }: { payload: any; timeoutMs: number }) => {
|
|
1798
|
+
async ({ payload, timeoutMs, requestId }: { payload: any; timeoutMs: number; requestId: string }) => {
|
|
1798
1799
|
const controller = new AbortController();
|
|
1799
1800
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
1800
1801
|
try {
|
|
@@ -1805,7 +1806,7 @@ export async function disableNativeTools(accountId?: string): Promise<void> {
|
|
|
1805
1806
|
headers: {
|
|
1806
1807
|
accept: "application/json, text/plain, */*",
|
|
1807
1808
|
"content-type": "application/json",
|
|
1808
|
-
"x-request-id":
|
|
1809
|
+
"x-request-id": requestId,
|
|
1809
1810
|
timezone: new Date().toString().split(" (")[0],
|
|
1810
1811
|
source: "web",
|
|
1811
1812
|
},
|
|
@@ -1818,7 +1819,7 @@ export async function disableNativeTools(accountId?: string): Promise<void> {
|
|
|
1818
1819
|
clearTimeout(timeoutId);
|
|
1819
1820
|
}
|
|
1820
1821
|
},
|
|
1821
|
-
{ payload, timeoutMs: config.timeouts.http },
|
|
1822
|
+
{ payload, timeoutMs: config.timeouts.http, requestId },
|
|
1822
1823
|
);
|
|
1823
1824
|
return response;
|
|
1824
1825
|
},
|
|
@@ -2152,25 +2153,29 @@ export async function fetchQwenModels(
|
|
|
2152
2153
|
const result = await withAccountPage(
|
|
2153
2154
|
accountId,
|
|
2154
2155
|
async (page) => {
|
|
2155
|
-
const
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
const
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2156
|
+
const requestId = crypto.randomUUID();
|
|
2157
|
+
const response = await page.evaluate(
|
|
2158
|
+
async ({ timeoutMs, requestId }: { timeoutMs: number; requestId: string }) => {
|
|
2159
|
+
const controller = new AbortController();
|
|
2160
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
2161
|
+
try {
|
|
2162
|
+
const resp = await fetch("https://chat.qwen.ai/api/models", {
|
|
2163
|
+
method: "GET",
|
|
2164
|
+
headers: {
|
|
2165
|
+
accept: "application/json, text/plain, */*",
|
|
2166
|
+
"x-request-id": requestId,
|
|
2167
|
+
timezone: new Date().toString().split(" (")[0],
|
|
2168
|
+
source: "web",
|
|
2169
|
+
},
|
|
2170
|
+
signal: controller.signal,
|
|
2171
|
+
});
|
|
2172
|
+
return { status: resp.status, body: await resp.text() };
|
|
2173
|
+
} finally {
|
|
2174
|
+
clearTimeout(timeoutId);
|
|
2175
|
+
}
|
|
2176
|
+
},
|
|
2177
|
+
{ timeoutMs: config.timeouts.http, requestId },
|
|
2178
|
+
);
|
|
2174
2179
|
return response;
|
|
2175
2180
|
},
|
|
2176
2181
|
);
|