qwenproxy-cli 1.5.1 â 1.5.2
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/dist/clean-cache.js +2 -0
- package/dist/delete-chats.js +53 -0
- package/dist/index.js +23 -52
- package/dist/login.js +2 -0
- package/dist/reset-cooldowns.js +2 -0
- package/dist/sync-clients.js +2 -0
- package/package.json +1 -1
- package/src/api/server.ts +17 -59
- package/src/core/config.ts +2 -0
- package/src/core/version.ts +1 -1
- package/src/services/auth-playwright.ts +5 -0
package/dist/clean-cache.js
CHANGED
|
@@ -965,6 +965,7 @@ var init_config = __esm({
|
|
|
965
965
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
966
966
|
// drop out of the warm set and get evicted.
|
|
967
967
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
968
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
968
969
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
969
970
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
970
971
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -1113,6 +1114,7 @@ var init_config = __esm({
|
|
|
1113
1114
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
1114
1115
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
1115
1116
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
1117
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
1116
1118
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
1117
1119
|
},
|
|
1118
1120
|
captcha: {
|
package/dist/delete-chats.js
CHANGED
|
@@ -1020,6 +1020,7 @@ var init_config = __esm({
|
|
|
1020
1020
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
1021
1021
|
// drop out of the warm set and get evicted.
|
|
1022
1022
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
1023
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
1023
1024
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
1024
1025
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
1025
1026
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -1168,6 +1169,7 @@ var init_config = __esm({
|
|
|
1168
1169
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
1169
1170
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
1170
1171
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
1172
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
1171
1173
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
1172
1174
|
},
|
|
1173
1175
|
captcha: {
|
|
@@ -1901,6 +1903,14 @@ var init_mutex = __esm({
|
|
|
1901
1903
|
});
|
|
1902
1904
|
|
|
1903
1905
|
// src/core/account-priority.ts
|
|
1906
|
+
var account_priority_exports = {};
|
|
1907
|
+
__export(account_priority_exports, {
|
|
1908
|
+
ensureAccountInPriority: () => ensureAccountInPriority,
|
|
1909
|
+
getAccountsByPriority: () => getAccountsByPriority,
|
|
1910
|
+
invalidatePriorityCache: () => invalidatePriorityCache,
|
|
1911
|
+
markAccountFailed: () => markAccountFailed,
|
|
1912
|
+
markAccountSuccessful: () => markAccountSuccessful
|
|
1913
|
+
});
|
|
1904
1914
|
import {
|
|
1905
1915
|
existsSync,
|
|
1906
1916
|
mkdirSync,
|
|
@@ -1910,6 +1920,9 @@ import {
|
|
|
1910
1920
|
function isPersistableAccount(accountId) {
|
|
1911
1921
|
return accountId !== MOCK_ACCOUNT_ID;
|
|
1912
1922
|
}
|
|
1923
|
+
function invalidatePriorityCache() {
|
|
1924
|
+
priorityCache = null;
|
|
1925
|
+
}
|
|
1913
1926
|
function loadPriority() {
|
|
1914
1927
|
if (priorityCache) return priorityCache;
|
|
1915
1928
|
try {
|
|
@@ -1930,6 +1943,41 @@ function loadPriority() {
|
|
|
1930
1943
|
priorityCache = { accountOrder: [], lastUpdated: 0 };
|
|
1931
1944
|
return priorityCache;
|
|
1932
1945
|
}
|
|
1946
|
+
function savePriority(data) {
|
|
1947
|
+
try {
|
|
1948
|
+
mkdirSync(DATA_DIR3, { recursive: true });
|
|
1949
|
+
writeFileSync(PRIORITY_FILE, JSON.stringify(data, null, 2), "utf-8");
|
|
1950
|
+
priorityCache = data;
|
|
1951
|
+
} catch (err) {
|
|
1952
|
+
console.error("\u274C [AccountPriority] Failed to save priority file:", err.message);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
function markAccountSuccessful(accountId) {
|
|
1956
|
+
if (!isPersistableAccount(accountId)) return;
|
|
1957
|
+
const data = loadPriority();
|
|
1958
|
+
data.accountOrder = data.accountOrder.filter((id) => id !== accountId);
|
|
1959
|
+
data.accountOrder.unshift(accountId);
|
|
1960
|
+
data.lastUpdated = Date.now();
|
|
1961
|
+
savePriority(data);
|
|
1962
|
+
}
|
|
1963
|
+
function markAccountFailed(accountId) {
|
|
1964
|
+
if (!isPersistableAccount(accountId)) return;
|
|
1965
|
+
const data = loadPriority();
|
|
1966
|
+
data.accountOrder = data.accountOrder.filter((id) => id !== accountId);
|
|
1967
|
+
data.accountOrder.push(accountId);
|
|
1968
|
+
data.lastUpdated = Date.now();
|
|
1969
|
+
savePriority(data);
|
|
1970
|
+
}
|
|
1971
|
+
function ensureAccountInPriority(accountId) {
|
|
1972
|
+
if (!isPersistableAccount(accountId)) return;
|
|
1973
|
+
const data = loadPriority();
|
|
1974
|
+
if (data.accountOrder.includes(accountId)) {
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1977
|
+
data.accountOrder.push(accountId);
|
|
1978
|
+
data.lastUpdated = Date.now();
|
|
1979
|
+
savePriority(data);
|
|
1980
|
+
}
|
|
1933
1981
|
function getAccountsByPriority(accounts) {
|
|
1934
1982
|
const data = loadPriority();
|
|
1935
1983
|
if (data.accountOrder.length === 0) {
|
|
@@ -6583,6 +6631,11 @@ async function ensurePlaywrightInitialized(accountId) {
|
|
|
6583
6631
|
});
|
|
6584
6632
|
} catch {
|
|
6585
6633
|
}
|
|
6634
|
+
try {
|
|
6635
|
+
const { ensureAccountInPriority: ensureAccountInPriority2 } = await Promise.resolve().then(() => (init_account_priority(), account_priority_exports));
|
|
6636
|
+
ensureAccountInPriority2(accountId);
|
|
6637
|
+
} catch {
|
|
6638
|
+
}
|
|
6586
6639
|
}
|
|
6587
6640
|
async function getBasicHeaders2(accountId) {
|
|
6588
6641
|
if (isAuthMockEnabled()) {
|
package/dist/index.js
CHANGED
|
@@ -263,6 +263,7 @@ var init_config = __esm({
|
|
|
263
263
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
264
264
|
// drop out of the warm set and get evicted.
|
|
265
265
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
266
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
266
267
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
267
268
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
268
269
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -411,6 +412,7 @@ var init_config = __esm({
|
|
|
411
412
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
412
413
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
413
414
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
415
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
414
416
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
415
417
|
},
|
|
416
418
|
captcha: {
|
|
@@ -8022,6 +8024,11 @@ async function ensurePlaywrightInitialized(accountId) {
|
|
|
8022
8024
|
});
|
|
8023
8025
|
} catch {
|
|
8024
8026
|
}
|
|
8027
|
+
try {
|
|
8028
|
+
const { ensureAccountInPriority: ensureAccountInPriority2 } = await Promise.resolve().then(() => (init_account_priority(), account_priority_exports));
|
|
8029
|
+
ensureAccountInPriority2(accountId);
|
|
8030
|
+
} catch {
|
|
8031
|
+
}
|
|
8025
8032
|
}
|
|
8026
8033
|
async function getBasicHeaders2(accountId) {
|
|
8027
8034
|
if (isAuthMockEnabled()) {
|
|
@@ -25884,7 +25891,7 @@ function getAppVersion() {
|
|
|
25884
25891
|
}
|
|
25885
25892
|
} catch {
|
|
25886
25893
|
}
|
|
25887
|
-
cachedVersion = "v1.5.
|
|
25894
|
+
cachedVersion = "v1.5.2";
|
|
25888
25895
|
return cachedVersion;
|
|
25889
25896
|
}
|
|
25890
25897
|
var cachedVersion;
|
|
@@ -26288,17 +26295,16 @@ async function startServer(options) {
|
|
|
26288
26295
|
);
|
|
26289
26296
|
});
|
|
26290
26297
|
} else if (remainingAccounts.length > 0) {
|
|
26291
|
-
console.log(
|
|
26292
|
-
`\u{1FAB6} [Server] ${remainingAccounts.length} standby account(s) will initialize on demand`
|
|
26293
|
-
);
|
|
26294
26298
|
void (async () => {
|
|
26295
|
-
const { validateAccountLogin: validateAccountLogin2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
26296
26299
|
const { ensureAccountInPriority: ensureAccountInPriority2 } = await Promise.resolve().then(() => (init_account_priority(), account_priority_exports));
|
|
26297
|
-
|
|
26298
|
-
|
|
26299
|
-
|
|
26300
|
-
|
|
26301
|
-
|
|
26300
|
+
const targetWarmTotal = Math.min(
|
|
26301
|
+
config.playwright.startupWarmAccounts,
|
|
26302
|
+
totalAccounts
|
|
26303
|
+
);
|
|
26304
|
+
let currentReadyCount = readyAccountIds.size;
|
|
26305
|
+
if (currentReadyCount < targetWarmTotal && remainingAccounts.length > 0) {
|
|
26306
|
+
for (const reserveAccount of remainingAccounts) {
|
|
26307
|
+
if (currentReadyCount >= targetWarmTotal) break;
|
|
26302
26308
|
try {
|
|
26303
26309
|
const ok = await prepareAccountRuntime(
|
|
26304
26310
|
reserveAccount,
|
|
@@ -26308,12 +26314,12 @@ async function startServer(options) {
|
|
|
26308
26314
|
warmQwenChatPool2
|
|
26309
26315
|
);
|
|
26310
26316
|
if (ok) {
|
|
26317
|
+
readyAccountIds.add(reserveAccount.id);
|
|
26311
26318
|
ensureAccountInPriority2(reserveAccount.id);
|
|
26319
|
+
currentReadyCount++;
|
|
26312
26320
|
console.log(
|
|
26313
|
-
`\u2705 [Server] Reserve account ready (
|
|
26321
|
+
`\u2705 [Server] Reserve account ready (${currentReadyCount}/${totalAccounts}): ${maskEmail(reserveAccount.email)}`
|
|
26314
26322
|
);
|
|
26315
|
-
reserveCandidateIdx++;
|
|
26316
|
-
break;
|
|
26317
26323
|
}
|
|
26318
26324
|
} catch (err) {
|
|
26319
26325
|
console.warn(
|
|
@@ -26321,51 +26327,16 @@ async function startServer(options) {
|
|
|
26321
26327
|
);
|
|
26322
26328
|
}
|
|
26323
26329
|
}
|
|
26324
|
-
accountsToValidate = remainingAccounts.slice(reserveCandidateIdx);
|
|
26325
|
-
}
|
|
26326
|
-
let validated = 0;
|
|
26327
|
-
let failed = 0;
|
|
26328
|
-
for (const account of accountsToValidate) {
|
|
26329
|
-
try {
|
|
26330
|
-
const creds = getAccountCredentials2(account.id) ?? account;
|
|
26331
|
-
const ok = await validateAccountLogin2(
|
|
26332
|
-
creds,
|
|
26333
|
-
config.playwright.headless,
|
|
26334
|
-
config.playwright.browser
|
|
26335
|
-
);
|
|
26336
|
-
if (ok) {
|
|
26337
|
-
ensureAccountInPriority2(account.id);
|
|
26338
|
-
validated++;
|
|
26339
|
-
console.log(
|
|
26340
|
-
`\u2705 [Server] Standby account validated: ${maskEmail(account.email)}`
|
|
26341
|
-
);
|
|
26342
|
-
} else {
|
|
26343
|
-
failed++;
|
|
26344
|
-
console.warn(
|
|
26345
|
-
`\u26A0\uFE0F [Server] Standby account login failed: ${maskEmail(account.email)} (quarantined)`
|
|
26346
|
-
);
|
|
26347
|
-
}
|
|
26348
|
-
} catch (error) {
|
|
26349
|
-
failed++;
|
|
26350
|
-
console.warn(
|
|
26351
|
-
`\u26A0\uFE0F [Server] Standby account validation error: ${maskEmail(account.email)}: ${getErrorMessage2(error)} (quarantined)`
|
|
26352
|
-
);
|
|
26353
|
-
const { markAccountRateLimited: markAccountRateLimited2 } = await Promise.resolve().then(() => (init_account_manager(), account_manager_exports));
|
|
26354
|
-
markAccountRateLimited2(
|
|
26355
|
-
account.id,
|
|
26356
|
-
24 * 3600 * 1e3,
|
|
26357
|
-
`StandbyValidationError: ${getErrorMessage2(error)}`
|
|
26358
|
-
);
|
|
26359
|
-
}
|
|
26360
26330
|
}
|
|
26361
|
-
|
|
26331
|
+
const standbyCount = totalAccounts - currentReadyCount;
|
|
26332
|
+
if (standbyCount > 0) {
|
|
26362
26333
|
console.log(
|
|
26363
|
-
`\
|
|
26334
|
+
`\u{1FAB6} [Server] ${standbyCount} standby account(s) ready in pool (will initialize on demand when active accounts rotate)`
|
|
26364
26335
|
);
|
|
26365
26336
|
}
|
|
26366
26337
|
})().catch((error) => {
|
|
26367
26338
|
console.warn(
|
|
26368
|
-
`\u274C [Server] Background
|
|
26339
|
+
`\u274C [Server] Background account preparation failed: ${getErrorMessage2(error)}`
|
|
26369
26340
|
);
|
|
26370
26341
|
});
|
|
26371
26342
|
}
|
package/dist/login.js
CHANGED
|
@@ -1200,6 +1200,7 @@ var init_config = __esm({
|
|
|
1200
1200
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
1201
1201
|
// drop out of the warm set and get evicted.
|
|
1202
1202
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
1203
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
1203
1204
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
1204
1205
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
1205
1206
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -1348,6 +1349,7 @@ var init_config = __esm({
|
|
|
1348
1349
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
1349
1350
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
1350
1351
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
1352
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
1351
1353
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
1352
1354
|
},
|
|
1353
1355
|
captcha: {
|
package/dist/reset-cooldowns.js
CHANGED
|
@@ -1302,6 +1302,7 @@ var init_config = __esm({
|
|
|
1302
1302
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
1303
1303
|
// drop out of the warm set and get evicted.
|
|
1304
1304
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
1305
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
1305
1306
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
1306
1307
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
1307
1308
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -1450,6 +1451,7 @@ var init_config = __esm({
|
|
|
1450
1451
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
1451
1452
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
1452
1453
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
1454
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
1453
1455
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
1454
1456
|
},
|
|
1455
1457
|
captcha: {
|
package/dist/sync-clients.js
CHANGED
|
@@ -157,6 +157,7 @@ var envSchema = z.object({
|
|
|
157
157
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
158
158
|
// drop out of the warm set and get evicted.
|
|
159
159
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
160
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
160
161
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
161
162
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
162
163
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -305,6 +306,7 @@ var config = {
|
|
|
305
306
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
306
307
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
307
308
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
309
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
308
310
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
309
311
|
},
|
|
310
312
|
captcha: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwenproxy-cli",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.2",
|
|
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/api/server.ts
CHANGED
|
@@ -877,23 +877,20 @@ export async function startServer(options?: {
|
|
|
877
877
|
);
|
|
878
878
|
});
|
|
879
879
|
} else if (remainingAccounts.length > 0) {
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
);
|
|
883
|
-
|
|
884
|
-
// In background: warm 1 reserve account (if maxActiveContexts > 1) and
|
|
885
|
-
// validate the rest of the standby accounts
|
|
880
|
+
// In background: warm reserve accounts up to a safe limit (default 4 total ready accounts)
|
|
881
|
+
// to prevent IP-level login flood / anti-bot challenge rate-limits on Alibaba.
|
|
886
882
|
void (async () => {
|
|
887
|
-
const { validateAccountLogin } = await import("../services/playwright.ts");
|
|
888
883
|
const { ensureAccountInPriority } = await import("../core/account-priority.ts");
|
|
889
884
|
|
|
890
|
-
|
|
885
|
+
const targetWarmTotal = Math.min(
|
|
886
|
+
config.playwright.startupWarmAccounts,
|
|
887
|
+
totalAccounts,
|
|
888
|
+
);
|
|
889
|
+
let currentReadyCount = readyAccountIds.size;
|
|
891
890
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
for (; reserveCandidateIdx < remainingAccounts.length; reserveCandidateIdx++) {
|
|
896
|
-
const reserveAccount = remainingAccounts[reserveCandidateIdx];
|
|
891
|
+
if (currentReadyCount < targetWarmTotal && remainingAccounts.length > 0) {
|
|
892
|
+
for (const reserveAccount of remainingAccounts) {
|
|
893
|
+
if (currentReadyCount >= targetWarmTotal) break;
|
|
897
894
|
try {
|
|
898
895
|
const ok = await prepareAccountRuntime(
|
|
899
896
|
reserveAccount,
|
|
@@ -903,12 +900,12 @@ export async function startServer(options?: {
|
|
|
903
900
|
warmQwenChatPool,
|
|
904
901
|
);
|
|
905
902
|
if (ok) {
|
|
903
|
+
readyAccountIds.add(reserveAccount.id);
|
|
906
904
|
ensureAccountInPriority(reserveAccount.id);
|
|
905
|
+
currentReadyCount++;
|
|
907
906
|
console.log(
|
|
908
|
-
`â
[Server] Reserve account ready (
|
|
907
|
+
`â
[Server] Reserve account ready (${currentReadyCount}/${totalAccounts}): ${maskEmail(reserveAccount.email)}`,
|
|
909
908
|
);
|
|
910
|
-
reserveCandidateIdx++;
|
|
911
|
-
break;
|
|
912
909
|
}
|
|
913
910
|
} catch (err) {
|
|
914
911
|
console.warn(
|
|
@@ -916,56 +913,17 @@ export async function startServer(options?: {
|
|
|
916
913
|
);
|
|
917
914
|
}
|
|
918
915
|
}
|
|
919
|
-
accountsToValidate = remainingAccounts.slice(reserveCandidateIdx);
|
|
920
916
|
}
|
|
921
917
|
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
for (const account of accountsToValidate) {
|
|
926
|
-
try {
|
|
927
|
-
const creds = getAccountCredentials(account.id) ?? account;
|
|
928
|
-
// Validate login in background with real unmasked credentials
|
|
929
|
-
const ok = await validateAccountLogin(
|
|
930
|
-
creds,
|
|
931
|
-
config.playwright.headless,
|
|
932
|
-
config.playwright.browser,
|
|
933
|
-
);
|
|
934
|
-
if (ok) {
|
|
935
|
-
// Add to priority list only once validated
|
|
936
|
-
ensureAccountInPriority(account.id);
|
|
937
|
-
validated++;
|
|
938
|
-
console.log(
|
|
939
|
-
`â
[Server] Standby account validated: ${maskEmail(account.email)}`,
|
|
940
|
-
);
|
|
941
|
-
} else {
|
|
942
|
-
failed++;
|
|
943
|
-
console.warn(
|
|
944
|
-
`â ïļ [Server] Standby account login failed: ${maskEmail(account.email)} (quarantined)`,
|
|
945
|
-
);
|
|
946
|
-
}
|
|
947
|
-
} catch (error) {
|
|
948
|
-
failed++;
|
|
949
|
-
console.warn(
|
|
950
|
-
`â ïļ [Server] Standby account validation error: ${maskEmail(account.email)}: ${getErrorMessage(error)} (quarantined)`,
|
|
951
|
-
);
|
|
952
|
-
const { markAccountRateLimited } = await import("../core/account-manager.ts");
|
|
953
|
-
markAccountRateLimited(
|
|
954
|
-
account.id,
|
|
955
|
-
24 * 3600 * 1000,
|
|
956
|
-
`StandbyValidationError: ${getErrorMessage(error)}`,
|
|
957
|
-
);
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
if (validated > 0 || failed > 0) {
|
|
918
|
+
const standbyCount = totalAccounts - currentReadyCount;
|
|
919
|
+
if (standbyCount > 0) {
|
|
962
920
|
console.log(
|
|
963
|
-
|
|
921
|
+
`ðŠķ [Server] ${standbyCount} standby account(s) ready in pool (will initialize on demand when active accounts rotate)`,
|
|
964
922
|
);
|
|
965
923
|
}
|
|
966
924
|
})().catch((error) => {
|
|
967
925
|
console.warn(
|
|
968
|
-
`â [Server] Background
|
|
926
|
+
`â [Server] Background account preparation failed: ${getErrorMessage(error)}`,
|
|
969
927
|
);
|
|
970
928
|
});
|
|
971
929
|
}
|
package/src/core/config.ts
CHANGED
|
@@ -76,6 +76,7 @@ const envSchema = z
|
|
|
76
76
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
77
77
|
// drop out of the warm set and get evicted.
|
|
78
78
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
79
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
79
80
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
80
81
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
81
82
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -235,6 +236,7 @@ export const config = {
|
|
|
235
236
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
236
237
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
237
238
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
239
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
238
240
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false",
|
|
239
241
|
},
|
|
240
242
|
captcha: {
|
package/src/core/version.ts
CHANGED
|
@@ -56,6 +56,11 @@ async function ensurePlaywrightInitialized(accountId: string): Promise<void> {
|
|
|
56
56
|
} catch {
|
|
57
57
|
// Non-fatal: chat creation will still work with default account settings.
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const { ensureAccountInPriority } = await import("../core/account-priority.ts");
|
|
62
|
+
ensureAccountInPriority(accountId);
|
|
63
|
+
} catch {}
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
export async function getBasicHeaders(accountId?: string): Promise<{
|