qwenproxy-cli 1.6.2 → 1.6.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.
- package/dist/clean-cache.js +70 -2
- package/dist/delete-chats.js +90 -4
- package/dist/index.js +55 -14
- package/dist/login.js +45 -4
- package/dist/reset-cooldowns.js +70 -2
- package/package.json +1 -1
- package/src/core/version.ts +1 -1
- package/src/routes/chat/retry-policy.ts +15 -15
- package/src/services/playwright.ts +58 -10
package/dist/clean-cache.js
CHANGED
|
@@ -14,6 +14,25 @@ var __export = (target, all) => {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// src/core/paths.ts
|
|
17
|
+
var paths_exports = {};
|
|
18
|
+
__export(paths_exports, {
|
|
19
|
+
ensureDataDirs: () => ensureDataDirs,
|
|
20
|
+
getAccountPriorityPath: () => getAccountPriorityPath,
|
|
21
|
+
getAccountProfilePath: () => getAccountProfilePath,
|
|
22
|
+
getDataDir: () => getDataDir,
|
|
23
|
+
getDbDir: () => getDbDir,
|
|
24
|
+
getDbPath: () => getDbPath,
|
|
25
|
+
getEncryptionKeyPath: () => getEncryptionKeyPath,
|
|
26
|
+
getEnvFilePath: () => getEnvFilePath,
|
|
27
|
+
getLogsDir: () => getLogsDir,
|
|
28
|
+
getOsGlobalDataDir: () => getOsGlobalDataDir,
|
|
29
|
+
getProfilesDir: () => getProfilesDir,
|
|
30
|
+
getServerLogFilePath: () => getServerLogFilePath,
|
|
31
|
+
getSyncStatePath: () => getSyncStatePath,
|
|
32
|
+
getTuiSettingsPath: () => getTuiSettingsPath,
|
|
33
|
+
isRunningUnderNodeTest: () => isRunningUnderNodeTest,
|
|
34
|
+
resolveDataDir: () => resolveDataDir
|
|
35
|
+
});
|
|
17
36
|
import fs from "node:fs";
|
|
18
37
|
import path from "node:path";
|
|
19
38
|
import os from "node:os";
|
|
@@ -78,6 +97,12 @@ function getAccountProfilePath(accountId, customDataDir) {
|
|
|
78
97
|
function getAccountPriorityPath(customDataDir) {
|
|
79
98
|
return path.join(customDataDir || getDataDir(), "account-priority.json");
|
|
80
99
|
}
|
|
100
|
+
function getSyncStatePath(customDataDir) {
|
|
101
|
+
return path.join(customDataDir || getDataDir(), "sync-state.json");
|
|
102
|
+
}
|
|
103
|
+
function getTuiSettingsPath(customDataDir) {
|
|
104
|
+
return path.join(customDataDir || getDataDir(), "tui-settings.json");
|
|
105
|
+
}
|
|
81
106
|
function getEnvFilePath(customDataDir) {
|
|
82
107
|
if (isRunningUnderNodeTest()) {
|
|
83
108
|
return path.join(customDataDir || getDataDir(), ".env");
|
|
@@ -88,6 +113,26 @@ function getEnvFilePath(customDataDir) {
|
|
|
88
113
|
}
|
|
89
114
|
return path.join(customDataDir || getDataDir(), ".env");
|
|
90
115
|
}
|
|
116
|
+
function getLogsDir(customDataDir) {
|
|
117
|
+
return path.join(customDataDir || getDataDir(), "logs");
|
|
118
|
+
}
|
|
119
|
+
function getServerLogFilePath(customDataDir) {
|
|
120
|
+
return path.join(getLogsDir(customDataDir), "server.log");
|
|
121
|
+
}
|
|
122
|
+
function ensureDataDirs(targetDataDir) {
|
|
123
|
+
const root = targetDataDir || getDataDir();
|
|
124
|
+
const dbDir = getDbDir(root);
|
|
125
|
+
const profilesDir = getProfilesDir(root);
|
|
126
|
+
const logsDir = getLogsDir(root);
|
|
127
|
+
try {
|
|
128
|
+
if (!fs.existsSync(root)) fs.mkdirSync(root, { recursive: true });
|
|
129
|
+
if (!fs.existsSync(dbDir)) fs.mkdirSync(dbDir, { recursive: true });
|
|
130
|
+
if (!fs.existsSync(profilesDir)) fs.mkdirSync(profilesDir, { recursive: true });
|
|
131
|
+
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.error(`[Paths] Error ensuring data directories at ${root}:`, err?.message || String(err));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
91
136
|
var init_paths = __esm({
|
|
92
137
|
"src/core/paths.ts"() {
|
|
93
138
|
"use strict";
|
|
@@ -4470,7 +4515,24 @@ async function refreshAccountToken(accountId) {
|
|
|
4470
4515
|
return { success: false, error: "Could not refresh or re-authenticate token" };
|
|
4471
4516
|
}
|
|
4472
4517
|
async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
|
|
4473
|
-
|
|
4518
|
+
let page = pageOverride ?? accountPages.get(accountId);
|
|
4519
|
+
if (!page || page.isClosed()) {
|
|
4520
|
+
const { isRunningUnderNodeTest: isRunningUnderNodeTest3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
4521
|
+
if (!isRunningUnderNodeTest3()) {
|
|
4522
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
4523
|
+
const creds = getAccountCredentials2(accountId);
|
|
4524
|
+
if (creds) {
|
|
4525
|
+
await initPlaywrightForAccount(
|
|
4526
|
+
creds,
|
|
4527
|
+
config.playwright.headless,
|
|
4528
|
+
config.playwright.browser,
|
|
4529
|
+
{ skipHeaderCapture: true }
|
|
4530
|
+
).catch(() => {
|
|
4531
|
+
});
|
|
4532
|
+
page = accountPages.get(accountId);
|
|
4533
|
+
}
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4474
4536
|
if (!page || page.isClosed()) {
|
|
4475
4537
|
throw new Error(`Playwright page unavailable for header capture: ${accountId}`);
|
|
4476
4538
|
}
|
|
@@ -5171,8 +5233,10 @@ async function evictIdlePlaywrightContextsToLimit() {
|
|
|
5171
5233
|
if (accountPages.size <= max) return 0;
|
|
5172
5234
|
const candidates = priorityOrderForEviction(
|
|
5173
5235
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
5236
|
+
if (isAccountServingStream(accountId)) return false;
|
|
5237
|
+
if (isAccountRecentlyActive(accountId, 3e4)) return false;
|
|
5174
5238
|
const mutex = accountMutexes.get(accountId);
|
|
5175
|
-
return mutex?.isIdle()
|
|
5239
|
+
return mutex?.isIdle();
|
|
5176
5240
|
})
|
|
5177
5241
|
).map((accountId) => ({
|
|
5178
5242
|
accountId,
|
|
@@ -5285,6 +5349,10 @@ async function closePlaywrightForAccount(accountId) {
|
|
|
5285
5349
|
release();
|
|
5286
5350
|
}
|
|
5287
5351
|
}
|
|
5352
|
+
function isAccountRecentlyActive(accountId, maxIdleMs = 3e5) {
|
|
5353
|
+
const last = lastAccountActivity.get(accountId) ?? 0;
|
|
5354
|
+
return last > 0 && Date.now() - last < maxIdleMs;
|
|
5355
|
+
}
|
|
5288
5356
|
var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, inFlightAccountInits, headerCaches, HEADER_CACHE_TTL, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, lastProactiveTokenRefresh, profileResetQueue, profileResetChain, closingAllPlaywright, sleep2, HEADER_CAPTURE_SETTLE_MS, PLAYWRIGHT_MUTEX_WAIT_MS, ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, SESSION_PROBE_NAVIGATION_TIMEOUT_MS, HEADER_CAPTURE_TRIGGER_GRACE_MS, FIRST_TRIGGER_GRACE_MS, HEADER_CAPTURE_TRIGGER_ATTEMPTS, CHAT_INPUT_APPEAR_TIMEOUT_MS, CHAT_INPUT_ACTION_TIMEOUT_MS, PROFILE_RESET_TIMEOUT_MS;
|
|
5289
5357
|
var init_playwright = __esm({
|
|
5290
5358
|
"src/services/playwright.ts"() {
|
package/dist/delete-chats.js
CHANGED
|
@@ -52,6 +52,25 @@ var init_process_guard = __esm({
|
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
// src/core/paths.ts
|
|
55
|
+
var paths_exports = {};
|
|
56
|
+
__export(paths_exports, {
|
|
57
|
+
ensureDataDirs: () => ensureDataDirs,
|
|
58
|
+
getAccountPriorityPath: () => getAccountPriorityPath,
|
|
59
|
+
getAccountProfilePath: () => getAccountProfilePath,
|
|
60
|
+
getDataDir: () => getDataDir,
|
|
61
|
+
getDbDir: () => getDbDir,
|
|
62
|
+
getDbPath: () => getDbPath,
|
|
63
|
+
getEncryptionKeyPath: () => getEncryptionKeyPath,
|
|
64
|
+
getEnvFilePath: () => getEnvFilePath,
|
|
65
|
+
getLogsDir: () => getLogsDir,
|
|
66
|
+
getOsGlobalDataDir: () => getOsGlobalDataDir,
|
|
67
|
+
getProfilesDir: () => getProfilesDir,
|
|
68
|
+
getServerLogFilePath: () => getServerLogFilePath,
|
|
69
|
+
getSyncStatePath: () => getSyncStatePath,
|
|
70
|
+
getTuiSettingsPath: () => getTuiSettingsPath,
|
|
71
|
+
isRunningUnderNodeTest: () => isRunningUnderNodeTest,
|
|
72
|
+
resolveDataDir: () => resolveDataDir
|
|
73
|
+
});
|
|
55
74
|
import fs from "node:fs";
|
|
56
75
|
import path from "node:path";
|
|
57
76
|
import os from "node:os";
|
|
@@ -116,6 +135,12 @@ function getAccountProfilePath(accountId, customDataDir) {
|
|
|
116
135
|
function getAccountPriorityPath(customDataDir) {
|
|
117
136
|
return path.join(customDataDir || getDataDir(), "account-priority.json");
|
|
118
137
|
}
|
|
138
|
+
function getSyncStatePath(customDataDir) {
|
|
139
|
+
return path.join(customDataDir || getDataDir(), "sync-state.json");
|
|
140
|
+
}
|
|
141
|
+
function getTuiSettingsPath(customDataDir) {
|
|
142
|
+
return path.join(customDataDir || getDataDir(), "tui-settings.json");
|
|
143
|
+
}
|
|
119
144
|
function getEnvFilePath(customDataDir) {
|
|
120
145
|
if (isRunningUnderNodeTest()) {
|
|
121
146
|
return path.join(customDataDir || getDataDir(), ".env");
|
|
@@ -126,6 +151,26 @@ function getEnvFilePath(customDataDir) {
|
|
|
126
151
|
}
|
|
127
152
|
return path.join(customDataDir || getDataDir(), ".env");
|
|
128
153
|
}
|
|
154
|
+
function getLogsDir(customDataDir) {
|
|
155
|
+
return path.join(customDataDir || getDataDir(), "logs");
|
|
156
|
+
}
|
|
157
|
+
function getServerLogFilePath(customDataDir) {
|
|
158
|
+
return path.join(getLogsDir(customDataDir), "server.log");
|
|
159
|
+
}
|
|
160
|
+
function ensureDataDirs(targetDataDir) {
|
|
161
|
+
const root = targetDataDir || getDataDir();
|
|
162
|
+
const dbDir = getDbDir(root);
|
|
163
|
+
const profilesDir = getProfilesDir(root);
|
|
164
|
+
const logsDir = getLogsDir(root);
|
|
165
|
+
try {
|
|
166
|
+
if (!fs.existsSync(root)) fs.mkdirSync(root, { recursive: true });
|
|
167
|
+
if (!fs.existsSync(dbDir)) fs.mkdirSync(dbDir, { recursive: true });
|
|
168
|
+
if (!fs.existsSync(profilesDir)) fs.mkdirSync(profilesDir, { recursive: true });
|
|
169
|
+
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
|
|
170
|
+
} catch (err) {
|
|
171
|
+
console.error(`[Paths] Error ensuring data directories at ${root}:`, err?.message || String(err));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
129
174
|
var init_paths = __esm({
|
|
130
175
|
"src/core/paths.ts"() {
|
|
131
176
|
"use strict";
|
|
@@ -5727,7 +5772,24 @@ async function refreshAccountToken(accountId) {
|
|
|
5727
5772
|
return { success: false, error: "Could not refresh or re-authenticate token" };
|
|
5728
5773
|
}
|
|
5729
5774
|
async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
|
|
5730
|
-
|
|
5775
|
+
let page = pageOverride ?? accountPages.get(accountId);
|
|
5776
|
+
if (!page || page.isClosed()) {
|
|
5777
|
+
const { isRunningUnderNodeTest: isRunningUnderNodeTest4 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
5778
|
+
if (!isRunningUnderNodeTest4()) {
|
|
5779
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
5780
|
+
const creds = getAccountCredentials2(accountId);
|
|
5781
|
+
if (creds) {
|
|
5782
|
+
await initPlaywrightForAccount(
|
|
5783
|
+
creds,
|
|
5784
|
+
config.playwright.headless,
|
|
5785
|
+
config.playwright.browser,
|
|
5786
|
+
{ skipHeaderCapture: true }
|
|
5787
|
+
).catch(() => {
|
|
5788
|
+
});
|
|
5789
|
+
page = accountPages.get(accountId);
|
|
5790
|
+
}
|
|
5791
|
+
}
|
|
5792
|
+
}
|
|
5731
5793
|
if (!page || page.isClosed()) {
|
|
5732
5794
|
throw new Error(`Playwright page unavailable for header capture: ${accountId}`);
|
|
5733
5795
|
}
|
|
@@ -6370,16 +6432,38 @@ async function refreshHeaders(accountId, timeoutMs = config.timeouts.headers, fo
|
|
|
6370
6432
|
release();
|
|
6371
6433
|
}
|
|
6372
6434
|
}
|
|
6373
|
-
async function
|
|
6435
|
+
async function ensureAccountPageAvailable(accountId) {
|
|
6374
6436
|
const inFlightInit = inFlightAccountInits.get(accountId);
|
|
6375
6437
|
if (inFlightInit) {
|
|
6376
6438
|
await inFlightInit.catch(() => {
|
|
6377
6439
|
});
|
|
6378
6440
|
}
|
|
6379
|
-
|
|
6441
|
+
let page = accountPages.get(accountId);
|
|
6442
|
+
if (page && !page.isClosed()) {
|
|
6443
|
+
return page;
|
|
6444
|
+
}
|
|
6445
|
+
const { isRunningUnderNodeTest: isRunningUnderNodeTest4 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
6446
|
+
if (isRunningUnderNodeTest4()) {
|
|
6447
|
+
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
6448
|
+
}
|
|
6449
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
6450
|
+
const creds = getAccountCredentials2(accountId);
|
|
6451
|
+
if (!creds) {
|
|
6452
|
+
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
6453
|
+
}
|
|
6454
|
+
await initPlaywrightForAccount(
|
|
6455
|
+
creds,
|
|
6456
|
+
config.playwright.headless,
|
|
6457
|
+
config.playwright.browser
|
|
6458
|
+
);
|
|
6459
|
+
page = accountPages.get(accountId);
|
|
6380
6460
|
if (!page || page.isClosed()) {
|
|
6381
6461
|
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
6382
6462
|
}
|
|
6463
|
+
return page;
|
|
6464
|
+
}
|
|
6465
|
+
async function withAccountPage(accountId, fn, timeoutMs = ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, mutexTimeoutMs = PLAYWRIGHT_MUTEX_WAIT_MS, recoverOnTimeout = true) {
|
|
6466
|
+
const page = await ensureAccountPageAvailable(accountId);
|
|
6383
6467
|
const release = await acquireAccountMutex(
|
|
6384
6468
|
accountId,
|
|
6385
6469
|
`page:${accountId.substring(0, 12)}`,
|
|
@@ -6680,8 +6764,10 @@ async function evictIdlePlaywrightContextsToLimit() {
|
|
|
6680
6764
|
if (accountPages.size <= max) return 0;
|
|
6681
6765
|
const candidates = priorityOrderForEviction(
|
|
6682
6766
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
6767
|
+
if (isAccountServingStream(accountId)) return false;
|
|
6768
|
+
if (isAccountRecentlyActive(accountId, 3e4)) return false;
|
|
6683
6769
|
const mutex = accountMutexes.get(accountId);
|
|
6684
|
-
return mutex?.isIdle()
|
|
6770
|
+
return mutex?.isIdle();
|
|
6685
6771
|
})
|
|
6686
6772
|
).map((accountId) => ({
|
|
6687
6773
|
accountId,
|
package/dist/index.js
CHANGED
|
@@ -6882,7 +6882,24 @@ async function refreshAccountToken(accountId) {
|
|
|
6882
6882
|
return { success: false, error: "Could not refresh or re-authenticate token" };
|
|
6883
6883
|
}
|
|
6884
6884
|
async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
|
|
6885
|
-
|
|
6885
|
+
let page = pageOverride ?? accountPages.get(accountId);
|
|
6886
|
+
if (!page || page.isClosed()) {
|
|
6887
|
+
const { isRunningUnderNodeTest: isRunningUnderNodeTest4 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
6888
|
+
if (!isRunningUnderNodeTest4()) {
|
|
6889
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
6890
|
+
const creds = getAccountCredentials2(accountId);
|
|
6891
|
+
if (creds) {
|
|
6892
|
+
await initPlaywrightForAccount(
|
|
6893
|
+
creds,
|
|
6894
|
+
config.playwright.headless,
|
|
6895
|
+
config.playwright.browser,
|
|
6896
|
+
{ skipHeaderCapture: true }
|
|
6897
|
+
).catch(() => {
|
|
6898
|
+
});
|
|
6899
|
+
page = accountPages.get(accountId);
|
|
6900
|
+
}
|
|
6901
|
+
}
|
|
6902
|
+
}
|
|
6886
6903
|
if (!page || page.isClosed()) {
|
|
6887
6904
|
throw new Error(`Playwright page unavailable for header capture: ${accountId}`);
|
|
6888
6905
|
}
|
|
@@ -7525,16 +7542,38 @@ async function refreshHeaders(accountId, timeoutMs = config.timeouts.headers, fo
|
|
|
7525
7542
|
release();
|
|
7526
7543
|
}
|
|
7527
7544
|
}
|
|
7528
|
-
async function
|
|
7545
|
+
async function ensureAccountPageAvailable(accountId) {
|
|
7529
7546
|
const inFlightInit = inFlightAccountInits.get(accountId);
|
|
7530
7547
|
if (inFlightInit) {
|
|
7531
7548
|
await inFlightInit.catch(() => {
|
|
7532
7549
|
});
|
|
7533
7550
|
}
|
|
7534
|
-
|
|
7551
|
+
let page = accountPages.get(accountId);
|
|
7552
|
+
if (page && !page.isClosed()) {
|
|
7553
|
+
return page;
|
|
7554
|
+
}
|
|
7555
|
+
const { isRunningUnderNodeTest: isRunningUnderNodeTest4 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
7556
|
+
if (isRunningUnderNodeTest4()) {
|
|
7557
|
+
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
7558
|
+
}
|
|
7559
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
7560
|
+
const creds = getAccountCredentials2(accountId);
|
|
7561
|
+
if (!creds) {
|
|
7562
|
+
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
7563
|
+
}
|
|
7564
|
+
await initPlaywrightForAccount(
|
|
7565
|
+
creds,
|
|
7566
|
+
config.playwright.headless,
|
|
7567
|
+
config.playwright.browser
|
|
7568
|
+
);
|
|
7569
|
+
page = accountPages.get(accountId);
|
|
7535
7570
|
if (!page || page.isClosed()) {
|
|
7536
7571
|
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
7537
7572
|
}
|
|
7573
|
+
return page;
|
|
7574
|
+
}
|
|
7575
|
+
async function withAccountPage(accountId, fn, timeoutMs = ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, mutexTimeoutMs = PLAYWRIGHT_MUTEX_WAIT_MS, recoverOnTimeout = true) {
|
|
7576
|
+
const page = await ensureAccountPageAvailable(accountId);
|
|
7538
7577
|
const release = await acquireAccountMutex(
|
|
7539
7578
|
accountId,
|
|
7540
7579
|
`page:${accountId.substring(0, 12)}`,
|
|
@@ -7835,8 +7874,10 @@ async function evictIdlePlaywrightContextsToLimit() {
|
|
|
7835
7874
|
if (accountPages.size <= max) return 0;
|
|
7836
7875
|
const candidates = priorityOrderForEviction(
|
|
7837
7876
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
7877
|
+
if (isAccountServingStream(accountId)) return false;
|
|
7878
|
+
if (isAccountRecentlyActive(accountId, 3e4)) return false;
|
|
7838
7879
|
const mutex = accountMutexes.get(accountId);
|
|
7839
|
-
return mutex?.isIdle()
|
|
7880
|
+
return mutex?.isIdle();
|
|
7840
7881
|
})
|
|
7841
7882
|
).map((accountId) => ({
|
|
7842
7883
|
accountId,
|
|
@@ -9827,6 +9868,15 @@ function classifyRetryAction(err, options) {
|
|
|
9827
9868
|
if (isTerminalLocalError(err)) {
|
|
9828
9869
|
return makeRetryAction("terminal_local", { retryable: false });
|
|
9829
9870
|
}
|
|
9871
|
+
if (err instanceof PersonalizationSyncError) {
|
|
9872
|
+
return makeRetryAction("personalization_sync_failed", {
|
|
9873
|
+
switchAccount: true,
|
|
9874
|
+
forceNewChat: true,
|
|
9875
|
+
retryAfterMs: baseDelayMs,
|
|
9876
|
+
accountCooldownMs: 0,
|
|
9877
|
+
accountCooldownReason: "PersonalizationFailed"
|
|
9878
|
+
});
|
|
9879
|
+
}
|
|
9830
9880
|
const message = errMessage(err).toLowerCase();
|
|
9831
9881
|
const code = errCode(err).toLowerCase();
|
|
9832
9882
|
if (isAccountInitializationError(err)) {
|
|
@@ -9843,15 +9893,6 @@ function classifyRetryAction(err, options) {
|
|
|
9843
9893
|
retryAfterMs: Math.min(baseDelayMs, 1e3)
|
|
9844
9894
|
});
|
|
9845
9895
|
}
|
|
9846
|
-
if (err instanceof PersonalizationSyncError) {
|
|
9847
|
-
return makeRetryAction("personalization_sync_failed", {
|
|
9848
|
-
switchAccount: true,
|
|
9849
|
-
forceNewChat: true,
|
|
9850
|
-
retryAfterMs: baseDelayMs,
|
|
9851
|
-
accountCooldownMs: 0,
|
|
9852
|
-
accountCooldownReason: "PersonalizationFailed"
|
|
9853
|
-
});
|
|
9854
|
-
}
|
|
9855
9896
|
if (code === "createchatinvalidresponse" || code === "createchatfailed" || code === "unauthorized" || message.includes("401 n\xE3o autorizado") || message.includes("n\xE3o tem permiss\xE3o para acessar") || message.includes("401 unauthorized") || message.includes('"code":"unauthorized"') || message.includes('"code": "unauthorized"') || message.includes("token has expired")) {
|
|
9856
9897
|
return makeRetryAction("account_initialization_failed", {
|
|
9857
9898
|
switchAccount: true,
|
|
@@ -26782,7 +26823,7 @@ function getAppVersion() {
|
|
|
26782
26823
|
}
|
|
26783
26824
|
} catch {
|
|
26784
26825
|
}
|
|
26785
|
-
cachedVersion = "v1.6.
|
|
26826
|
+
cachedVersion = "v1.6.3";
|
|
26786
26827
|
return cachedVersion;
|
|
26787
26828
|
}
|
|
26788
26829
|
var cachedVersion;
|
package/dist/login.js
CHANGED
|
@@ -5749,7 +5749,24 @@ async function refreshAccountToken(accountId) {
|
|
|
5749
5749
|
return { success: false, error: "Could not refresh or re-authenticate token" };
|
|
5750
5750
|
}
|
|
5751
5751
|
async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
|
|
5752
|
-
|
|
5752
|
+
let page = pageOverride ?? accountPages.get(accountId);
|
|
5753
|
+
if (!page || page.isClosed()) {
|
|
5754
|
+
const { isRunningUnderNodeTest: isRunningUnderNodeTest3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
5755
|
+
if (!isRunningUnderNodeTest3()) {
|
|
5756
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
5757
|
+
const creds = getAccountCredentials2(accountId);
|
|
5758
|
+
if (creds) {
|
|
5759
|
+
await initPlaywrightForAccount(
|
|
5760
|
+
creds,
|
|
5761
|
+
config.playwright.headless,
|
|
5762
|
+
config.playwright.browser,
|
|
5763
|
+
{ skipHeaderCapture: true }
|
|
5764
|
+
).catch(() => {
|
|
5765
|
+
});
|
|
5766
|
+
page = accountPages.get(accountId);
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
5769
|
+
}
|
|
5753
5770
|
if (!page || page.isClosed()) {
|
|
5754
5771
|
throw new Error(`Playwright page unavailable for header capture: ${accountId}`);
|
|
5755
5772
|
}
|
|
@@ -6392,16 +6409,38 @@ async function refreshHeaders(accountId, timeoutMs = config.timeouts.headers, fo
|
|
|
6392
6409
|
release();
|
|
6393
6410
|
}
|
|
6394
6411
|
}
|
|
6395
|
-
async function
|
|
6412
|
+
async function ensureAccountPageAvailable(accountId) {
|
|
6396
6413
|
const inFlightInit = inFlightAccountInits.get(accountId);
|
|
6397
6414
|
if (inFlightInit) {
|
|
6398
6415
|
await inFlightInit.catch(() => {
|
|
6399
6416
|
});
|
|
6400
6417
|
}
|
|
6401
|
-
|
|
6418
|
+
let page = accountPages.get(accountId);
|
|
6419
|
+
if (page && !page.isClosed()) {
|
|
6420
|
+
return page;
|
|
6421
|
+
}
|
|
6422
|
+
const { isRunningUnderNodeTest: isRunningUnderNodeTest3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
6423
|
+
if (isRunningUnderNodeTest3()) {
|
|
6424
|
+
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
6425
|
+
}
|
|
6426
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
6427
|
+
const creds = getAccountCredentials2(accountId);
|
|
6428
|
+
if (!creds) {
|
|
6429
|
+
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
6430
|
+
}
|
|
6431
|
+
await initPlaywrightForAccount(
|
|
6432
|
+
creds,
|
|
6433
|
+
config.playwright.headless,
|
|
6434
|
+
config.playwright.browser
|
|
6435
|
+
);
|
|
6436
|
+
page = accountPages.get(accountId);
|
|
6402
6437
|
if (!page || page.isClosed()) {
|
|
6403
6438
|
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
6404
6439
|
}
|
|
6440
|
+
return page;
|
|
6441
|
+
}
|
|
6442
|
+
async function withAccountPage(accountId, fn, timeoutMs = ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, mutexTimeoutMs = PLAYWRIGHT_MUTEX_WAIT_MS, recoverOnTimeout = true) {
|
|
6443
|
+
const page = await ensureAccountPageAvailable(accountId);
|
|
6405
6444
|
const release = await acquireAccountMutex(
|
|
6406
6445
|
accountId,
|
|
6407
6446
|
`page:${accountId.substring(0, 12)}`,
|
|
@@ -6702,8 +6741,10 @@ async function evictIdlePlaywrightContextsToLimit() {
|
|
|
6702
6741
|
if (accountPages.size <= max) return 0;
|
|
6703
6742
|
const candidates = priorityOrderForEviction(
|
|
6704
6743
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
6744
|
+
if (isAccountServingStream(accountId)) return false;
|
|
6745
|
+
if (isAccountRecentlyActive(accountId, 3e4)) return false;
|
|
6705
6746
|
const mutex = accountMutexes.get(accountId);
|
|
6706
|
-
return mutex?.isIdle()
|
|
6747
|
+
return mutex?.isIdle();
|
|
6707
6748
|
})
|
|
6708
6749
|
).map((accountId) => ({
|
|
6709
6750
|
accountId,
|
package/dist/reset-cooldowns.js
CHANGED
|
@@ -14,6 +14,25 @@ var __export = (target, all) => {
|
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
// src/core/paths.ts
|
|
17
|
+
var paths_exports = {};
|
|
18
|
+
__export(paths_exports, {
|
|
19
|
+
ensureDataDirs: () => ensureDataDirs,
|
|
20
|
+
getAccountPriorityPath: () => getAccountPriorityPath,
|
|
21
|
+
getAccountProfilePath: () => getAccountProfilePath,
|
|
22
|
+
getDataDir: () => getDataDir,
|
|
23
|
+
getDbDir: () => getDbDir,
|
|
24
|
+
getDbPath: () => getDbPath,
|
|
25
|
+
getEncryptionKeyPath: () => getEncryptionKeyPath,
|
|
26
|
+
getEnvFilePath: () => getEnvFilePath,
|
|
27
|
+
getLogsDir: () => getLogsDir,
|
|
28
|
+
getOsGlobalDataDir: () => getOsGlobalDataDir,
|
|
29
|
+
getProfilesDir: () => getProfilesDir,
|
|
30
|
+
getServerLogFilePath: () => getServerLogFilePath,
|
|
31
|
+
getSyncStatePath: () => getSyncStatePath,
|
|
32
|
+
getTuiSettingsPath: () => getTuiSettingsPath,
|
|
33
|
+
isRunningUnderNodeTest: () => isRunningUnderNodeTest,
|
|
34
|
+
resolveDataDir: () => resolveDataDir
|
|
35
|
+
});
|
|
17
36
|
import fs from "node:fs";
|
|
18
37
|
import path from "node:path";
|
|
19
38
|
import os from "node:os";
|
|
@@ -78,6 +97,12 @@ function getAccountProfilePath(accountId, customDataDir) {
|
|
|
78
97
|
function getAccountPriorityPath(customDataDir) {
|
|
79
98
|
return path.join(customDataDir || getDataDir(), "account-priority.json");
|
|
80
99
|
}
|
|
100
|
+
function getSyncStatePath(customDataDir) {
|
|
101
|
+
return path.join(customDataDir || getDataDir(), "sync-state.json");
|
|
102
|
+
}
|
|
103
|
+
function getTuiSettingsPath(customDataDir) {
|
|
104
|
+
return path.join(customDataDir || getDataDir(), "tui-settings.json");
|
|
105
|
+
}
|
|
81
106
|
function getEnvFilePath(customDataDir) {
|
|
82
107
|
if (isRunningUnderNodeTest()) {
|
|
83
108
|
return path.join(customDataDir || getDataDir(), ".env");
|
|
@@ -88,6 +113,26 @@ function getEnvFilePath(customDataDir) {
|
|
|
88
113
|
}
|
|
89
114
|
return path.join(customDataDir || getDataDir(), ".env");
|
|
90
115
|
}
|
|
116
|
+
function getLogsDir(customDataDir) {
|
|
117
|
+
return path.join(customDataDir || getDataDir(), "logs");
|
|
118
|
+
}
|
|
119
|
+
function getServerLogFilePath(customDataDir) {
|
|
120
|
+
return path.join(getLogsDir(customDataDir), "server.log");
|
|
121
|
+
}
|
|
122
|
+
function ensureDataDirs(targetDataDir) {
|
|
123
|
+
const root = targetDataDir || getDataDir();
|
|
124
|
+
const dbDir = getDbDir(root);
|
|
125
|
+
const profilesDir = getProfilesDir(root);
|
|
126
|
+
const logsDir = getLogsDir(root);
|
|
127
|
+
try {
|
|
128
|
+
if (!fs.existsSync(root)) fs.mkdirSync(root, { recursive: true });
|
|
129
|
+
if (!fs.existsSync(dbDir)) fs.mkdirSync(dbDir, { recursive: true });
|
|
130
|
+
if (!fs.existsSync(profilesDir)) fs.mkdirSync(profilesDir, { recursive: true });
|
|
131
|
+
if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.error(`[Paths] Error ensuring data directories at ${root}:`, err?.message || String(err));
|
|
134
|
+
}
|
|
135
|
+
}
|
|
91
136
|
var init_paths = __esm({
|
|
92
137
|
"src/core/paths.ts"() {
|
|
93
138
|
"use strict";
|
|
@@ -4733,7 +4778,24 @@ async function refreshAccountToken(accountId) {
|
|
|
4733
4778
|
return { success: false, error: "Could not refresh or re-authenticate token" };
|
|
4734
4779
|
}
|
|
4735
4780
|
async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
|
|
4736
|
-
|
|
4781
|
+
let page = pageOverride ?? accountPages.get(accountId);
|
|
4782
|
+
if (!page || page.isClosed()) {
|
|
4783
|
+
const { isRunningUnderNodeTest: isRunningUnderNodeTest3 } = await Promise.resolve().then(() => (init_paths(), paths_exports));
|
|
4784
|
+
if (!isRunningUnderNodeTest3()) {
|
|
4785
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
4786
|
+
const creds = getAccountCredentials2(accountId);
|
|
4787
|
+
if (creds) {
|
|
4788
|
+
await initPlaywrightForAccount(
|
|
4789
|
+
creds,
|
|
4790
|
+
config.playwright.headless,
|
|
4791
|
+
config.playwright.browser,
|
|
4792
|
+
{ skipHeaderCapture: true }
|
|
4793
|
+
).catch(() => {
|
|
4794
|
+
});
|
|
4795
|
+
page = accountPages.get(accountId);
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4737
4799
|
if (!page || page.isClosed()) {
|
|
4738
4800
|
throw new Error(`Playwright page unavailable for header capture: ${accountId}`);
|
|
4739
4801
|
}
|
|
@@ -5434,8 +5496,10 @@ async function evictIdlePlaywrightContextsToLimit() {
|
|
|
5434
5496
|
if (accountPages.size <= max) return 0;
|
|
5435
5497
|
const candidates = priorityOrderForEviction(
|
|
5436
5498
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
5499
|
+
if (isAccountServingStream(accountId)) return false;
|
|
5500
|
+
if (isAccountRecentlyActive(accountId, 3e4)) return false;
|
|
5437
5501
|
const mutex = accountMutexes.get(accountId);
|
|
5438
|
-
return mutex?.isIdle()
|
|
5502
|
+
return mutex?.isIdle();
|
|
5439
5503
|
})
|
|
5440
5504
|
).map((accountId) => ({
|
|
5441
5505
|
accountId,
|
|
@@ -5548,6 +5612,10 @@ async function closePlaywrightForAccount(accountId) {
|
|
|
5548
5612
|
release();
|
|
5549
5613
|
}
|
|
5550
5614
|
}
|
|
5615
|
+
function isAccountRecentlyActive(accountId, maxIdleMs = 3e5) {
|
|
5616
|
+
const last = lastAccountActivity.get(accountId) ?? 0;
|
|
5617
|
+
return last > 0 && Date.now() - last < maxIdleMs;
|
|
5618
|
+
}
|
|
5551
5619
|
var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, inFlightAccountInits, headerCaches, HEADER_CACHE_TTL, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, lastProactiveTokenRefresh, profileResetQueue, profileResetChain, closingAllPlaywright, sleep2, HEADER_CAPTURE_SETTLE_MS, PLAYWRIGHT_MUTEX_WAIT_MS, ACCOUNT_PAGE_OPERATION_TIMEOUT_MS, SESSION_PROBE_NAVIGATION_TIMEOUT_MS, HEADER_CAPTURE_TRIGGER_GRACE_MS, FIRST_TRIGGER_GRACE_MS, HEADER_CAPTURE_TRIGGER_ATTEMPTS, CHAT_INPUT_APPEAR_TIMEOUT_MS, CHAT_INPUT_ACTION_TIMEOUT_MS, PROFILE_RESET_TIMEOUT_MS;
|
|
5552
5620
|
var init_playwright = __esm({
|
|
5553
5621
|
"src/services/playwright.ts"() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwenproxy-cli",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.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": {
|
package/src/core/version.ts
CHANGED
|
@@ -499,6 +499,21 @@ export function classifyRetryAction(
|
|
|
499
499
|
return makeRetryAction("terminal_local", { retryable: false });
|
|
500
500
|
}
|
|
501
501
|
|
|
502
|
+
// Agent instructions ride ONLY the account-level personalization. An
|
|
503
|
+
// unconfirmed sync means this account cannot serve the request as-is —
|
|
504
|
+
// rotate to another account (each attempt re-syncs on its own account).
|
|
505
|
+
// Do NOT park the account with a 300s cooldown: rotation across accounts
|
|
506
|
+
// is already guarded by triedAccounts, preventing pool collapse.
|
|
507
|
+
if (err instanceof PersonalizationSyncError) {
|
|
508
|
+
return makeRetryAction("personalization_sync_failed", {
|
|
509
|
+
switchAccount: true,
|
|
510
|
+
forceNewChat: true,
|
|
511
|
+
retryAfterMs: baseDelayMs,
|
|
512
|
+
accountCooldownMs: 0,
|
|
513
|
+
accountCooldownReason: "PersonalizationFailed",
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
|
|
502
517
|
const message = errMessage(err).toLowerCase();
|
|
503
518
|
const code = errCode(err).toLowerCase();
|
|
504
519
|
if (isAccountInitializationError(err)) {
|
|
@@ -521,21 +536,6 @@ export function classifyRetryAction(
|
|
|
521
536
|
});
|
|
522
537
|
}
|
|
523
538
|
|
|
524
|
-
// Agent instructions ride ONLY the account-level personalization. An
|
|
525
|
-
// unconfirmed sync means this account cannot serve the request as-is —
|
|
526
|
-
// rotate to another account (each attempt re-syncs on its own account).
|
|
527
|
-
// Do NOT park the account with a 300s cooldown: rotation across accounts
|
|
528
|
-
// is already guarded by triedAccounts, preventing pool collapse.
|
|
529
|
-
if (err instanceof PersonalizationSyncError) {
|
|
530
|
-
return makeRetryAction("personalization_sync_failed", {
|
|
531
|
-
switchAccount: true,
|
|
532
|
-
forceNewChat: true,
|
|
533
|
-
retryAfterMs: baseDelayMs,
|
|
534
|
-
accountCooldownMs: 0,
|
|
535
|
-
accountCooldownReason: "PersonalizationFailed",
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
|
|
539
539
|
// Upstream 401 / Unauthorized on chat creation or API requests:
|
|
540
540
|
// Access token expired (15m window). Rotate without locking into a 300s cooldown
|
|
541
541
|
// so the account can immediately be renewed via refresh_token.
|
|
@@ -3242,7 +3242,24 @@ export async function captureQwenHeaders(
|
|
|
3242
3242
|
timeoutMs = config.timeouts.headers,
|
|
3243
3243
|
triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS,
|
|
3244
3244
|
): Promise<void> {
|
|
3245
|
-
|
|
3245
|
+
let page = pageOverride ?? accountPages.get(accountId);
|
|
3246
|
+
if (!page || page.isClosed()) {
|
|
3247
|
+
const { isRunningUnderNodeTest } = await import("../core/paths.ts");
|
|
3248
|
+
if (!isRunningUnderNodeTest()) {
|
|
3249
|
+
const { getAccountCredentials } = await import("../core/accounts.ts");
|
|
3250
|
+
const creds = getAccountCredentials(accountId);
|
|
3251
|
+
if (creds) {
|
|
3252
|
+
await initPlaywrightForAccount(
|
|
3253
|
+
creds,
|
|
3254
|
+
config.playwright.headless,
|
|
3255
|
+
config.playwright.browser,
|
|
3256
|
+
{ skipHeaderCapture: true },
|
|
3257
|
+
).catch(() => {});
|
|
3258
|
+
page = accountPages.get(accountId);
|
|
3259
|
+
}
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3246
3263
|
if (!page || page.isClosed()) {
|
|
3247
3264
|
throw new Error(`Playwright page unavailable for header capture: ${accountId}`);
|
|
3248
3265
|
}
|
|
@@ -4100,22 +4117,51 @@ export async function refreshHeaders(
|
|
|
4100
4117
|
* Run work against the account Playwright page under the per-account mutex.
|
|
4101
4118
|
* Used by captcha recovery so it cannot race header capture / login.
|
|
4102
4119
|
*/
|
|
4103
|
-
|
|
4104
|
-
accountId: string,
|
|
4105
|
-
fn: (page: Page) => Promise<T>,
|
|
4106
|
-
timeoutMs = ACCOUNT_PAGE_OPERATION_TIMEOUT_MS,
|
|
4107
|
-
mutexTimeoutMs = PLAYWRIGHT_MUTEX_WAIT_MS,
|
|
4108
|
-
recoverOnTimeout = true,
|
|
4109
|
-
): Promise<T> {
|
|
4120
|
+
async function ensureAccountPageAvailable(accountId: string): Promise<Page> {
|
|
4110
4121
|
const inFlightInit = inFlightAccountInits.get(accountId);
|
|
4111
4122
|
if (inFlightInit) {
|
|
4112
4123
|
await inFlightInit.catch(() => {});
|
|
4113
4124
|
}
|
|
4114
4125
|
|
|
4115
|
-
|
|
4126
|
+
let page = accountPages.get(accountId);
|
|
4127
|
+
if (page && !page.isClosed()) {
|
|
4128
|
+
return page;
|
|
4129
|
+
}
|
|
4130
|
+
|
|
4131
|
+
// Under Node.js test suites, preserve strict mock failure contract
|
|
4132
|
+
const { isRunningUnderNodeTest } = await import("../core/paths.ts");
|
|
4133
|
+
if (isRunningUnderNodeTest()) {
|
|
4134
|
+
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
4135
|
+
}
|
|
4136
|
+
|
|
4137
|
+
// Lazy boot / recovery: if the account was evicted or in standby, initialize it transparently on demand
|
|
4138
|
+
const { getAccountCredentials } = await import("../core/accounts.ts");
|
|
4139
|
+
const creds = getAccountCredentials(accountId);
|
|
4140
|
+
if (!creds) {
|
|
4141
|
+
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
await initPlaywrightForAccount(
|
|
4145
|
+
creds,
|
|
4146
|
+
config.playwright.headless,
|
|
4147
|
+
config.playwright.browser,
|
|
4148
|
+
);
|
|
4149
|
+
|
|
4150
|
+
page = accountPages.get(accountId);
|
|
4116
4151
|
if (!page || page.isClosed()) {
|
|
4117
4152
|
throw new Error(`Playwright page unavailable for account: ${accountId}`);
|
|
4118
4153
|
}
|
|
4154
|
+
return page;
|
|
4155
|
+
}
|
|
4156
|
+
|
|
4157
|
+
export async function withAccountPage<T>(
|
|
4158
|
+
accountId: string,
|
|
4159
|
+
fn: (page: Page) => Promise<T>,
|
|
4160
|
+
timeoutMs = ACCOUNT_PAGE_OPERATION_TIMEOUT_MS,
|
|
4161
|
+
mutexTimeoutMs = PLAYWRIGHT_MUTEX_WAIT_MS,
|
|
4162
|
+
recoverOnTimeout = true,
|
|
4163
|
+
): Promise<T> {
|
|
4164
|
+
const page = await ensureAccountPageAvailable(accountId);
|
|
4119
4165
|
const release = await acquireAccountMutex(
|
|
4120
4166
|
accountId,
|
|
4121
4167
|
`page:${accountId.substring(0, 12)}`,
|
|
@@ -4542,8 +4588,10 @@ export async function evictIdlePlaywrightContextsToLimit(): Promise<number> {
|
|
|
4542
4588
|
|
|
4543
4589
|
const candidates = priorityOrderForEviction(
|
|
4544
4590
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
4591
|
+
if (isAccountServingStream(accountId)) return false;
|
|
4592
|
+
if (isAccountRecentlyActive(accountId, 30_000)) return false;
|
|
4545
4593
|
const mutex = accountMutexes.get(accountId);
|
|
4546
|
-
return mutex?.isIdle()
|
|
4594
|
+
return mutex?.isIdle();
|
|
4547
4595
|
}),
|
|
4548
4596
|
).map((accountId) => ({
|
|
4549
4597
|
accountId,
|