qwenproxy-cli 1.5.2 → 1.6.0
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 +205 -22
- package/dist/delete-chats.js +199 -36
- package/dist/index.js +492 -57
- package/dist/login.js +95 -24
- package/dist/reset-cooldowns.js +205 -22
- package/package.json +3 -3
- package/src/api/server.ts +1 -0
- package/src/core/daily-usage.ts +276 -0
- package/src/core/database.ts +27 -1
- package/src/core/version.ts +1 -1
- package/src/routes/chat/account.ts +43 -10
- package/src/routes/chat/index.ts +1 -1
- package/src/routes/chat/streaming.ts +31 -3
- package/src/services/captcha-coordinator.ts +12 -7
- package/src/services/playwright.ts +76 -24
- package/src/services/qwen.ts +130 -16
- package/src/tui/proxy-client.ts +11 -1
- package/src/tui/types.ts +11 -0
- package/src/tui/views/accounts-view.ts +19 -2
- package/src/tui/views/status-view.ts +37 -4
package/dist/login.js
CHANGED
|
@@ -341,7 +341,26 @@ function runMigrations(db2) {
|
|
|
341
341
|
instruction_hash TEXT NOT NULL,
|
|
342
342
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
343
343
|
);
|
|
344
|
+
|
|
345
|
+
CREATE TABLE IF NOT EXISTS account_daily_usage (
|
|
346
|
+
account_id TEXT NOT NULL,
|
|
347
|
+
date_utc TEXT NOT NULL,
|
|
348
|
+
prompt_tokens INTEGER NOT NULL DEFAULT 0,
|
|
349
|
+
completion_tokens INTEGER NOT NULL DEFAULT 0,
|
|
350
|
+
weighted_tokens REAL NOT NULL DEFAULT 0,
|
|
351
|
+
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
352
|
+
turns_count INTEGER NOT NULL DEFAULT 0,
|
|
353
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
354
|
+
PRIMARY KEY (account_id, date_utc)
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
CREATE INDEX IF NOT EXISTS idx_daily_usage_date ON account_daily_usage(date_utc);
|
|
344
358
|
`);
|
|
359
|
+
try {
|
|
360
|
+
db2.exec(`ALTER TABLE account_daily_usage ADD COLUMN weighted_tokens REAL DEFAULT 0;`);
|
|
361
|
+
} catch (err) {
|
|
362
|
+
if (!isDuplicateColumnError(err)) throw err;
|
|
363
|
+
}
|
|
345
364
|
try {
|
|
346
365
|
db2.exec(
|
|
347
366
|
`ALTER TABLE accounts ADD COLUMN cooldown_until INTEGER DEFAULT 0;`
|
|
@@ -442,7 +461,11 @@ function saveAuthSession(accountId, session) {
|
|
|
442
461
|
) VALUES (
|
|
443
462
|
?, ?, ?, ?, ?, ?,
|
|
444
463
|
?, ?, ?, ?,
|
|
445
|
-
?,
|
|
464
|
+
COALESCE(?, (SELECT user_id FROM qwen_auth_sessions WHERE account_id = ?)),
|
|
465
|
+
?,
|
|
466
|
+
COALESCE(?, (SELECT refresh_token FROM qwen_auth_sessions WHERE account_id = ?)),
|
|
467
|
+
?,
|
|
468
|
+
datetime('now')
|
|
446
469
|
)
|
|
447
470
|
`);
|
|
448
471
|
stmt.run(
|
|
@@ -457,8 +480,10 @@ function saveAuthSession(accountId, session) {
|
|
|
457
480
|
session.secChUaPlatform || null,
|
|
458
481
|
session.version || null,
|
|
459
482
|
session.userId || null,
|
|
483
|
+
accountId,
|
|
460
484
|
session.tokenExpiresAt || null,
|
|
461
485
|
session.refreshToken || null,
|
|
486
|
+
accountId,
|
|
462
487
|
session.capturedAt ?? Date.now()
|
|
463
488
|
);
|
|
464
489
|
}
|
|
@@ -4061,6 +4086,11 @@ async function getBasicHeaders(accountId) {
|
|
|
4061
4086
|
if (!page) {
|
|
4062
4087
|
throw new Error(`Playwright not initialized for account: ${accountId}`);
|
|
4063
4088
|
}
|
|
4089
|
+
const inFlightInit = inFlightAccountInits.get(accountId);
|
|
4090
|
+
if (inFlightInit) {
|
|
4091
|
+
await inFlightInit.catch(() => {
|
|
4092
|
+
});
|
|
4093
|
+
}
|
|
4064
4094
|
const release = await acquireAccountMutex(
|
|
4065
4095
|
accountId,
|
|
4066
4096
|
`headers:${accountId.substring(0, 12)}`
|
|
@@ -5535,6 +5565,11 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
5535
5565
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5536
5566
|
const { parseJwtExpiry: parseJwtExpiry2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
|
|
5537
5567
|
const tokenExpiry = parseJwtExpiry2(capturedHeaders.cookie);
|
|
5568
|
+
let rTok;
|
|
5569
|
+
try {
|
|
5570
|
+
rTok = (await page.evaluate(() => localStorage.getItem("refresh_token") || "")).trim() || void 0;
|
|
5571
|
+
} catch {
|
|
5572
|
+
}
|
|
5538
5573
|
saveAuthSession2(accountId, {
|
|
5539
5574
|
cookie: capturedHeaders.cookie,
|
|
5540
5575
|
userAgent: capturedHeaders["user-agent"],
|
|
@@ -5546,6 +5581,7 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
5546
5581
|
secChUaPlatform: capturedHeaders["sec-ch-ua-platform"],
|
|
5547
5582
|
version: capturedHeaders["version"],
|
|
5548
5583
|
tokenExpiresAt: tokenExpiry || void 0,
|
|
5584
|
+
refreshToken: rTok,
|
|
5549
5585
|
capturedAt: Date.now()
|
|
5550
5586
|
});
|
|
5551
5587
|
} catch {
|
|
@@ -5577,38 +5613,57 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
5577
5613
|
const isAuthUrl = currentUrl.includes("/auth") || currentUrl.includes("/login");
|
|
5578
5614
|
const isSuspectedGuest = isAuthUrl || attempt >= 2 && !await isPageLoggedIn(page, 5e3);
|
|
5579
5615
|
if (isSuspectedGuest) {
|
|
5580
|
-
const
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
`\u26A0\uFE0F [Playwright] Session expired or guest state detected during header capture for ${accountId}; re-authenticating...`
|
|
5616
|
+
const silentRefresh = await refreshAccountToken(accountId);
|
|
5617
|
+
if (silentRefresh.success) {
|
|
5618
|
+
console.log(
|
|
5619
|
+
`\u26A1 [Playwright] Token refreshed silently during header capture for ${accountId}`
|
|
5585
5620
|
);
|
|
5586
|
-
|
|
5587
|
-
const ok = await loginToQwen(accountId, creds.email, creds.password);
|
|
5588
|
-
if (ok) {
|
|
5621
|
+
if (isAuthUrl) {
|
|
5589
5622
|
await page.goto(qwenUrl("/"), {
|
|
5590
5623
|
waitUntil: "domcontentloaded",
|
|
5591
5624
|
timeout: Math.min(config.timeouts.navigation, timeoutMs)
|
|
5592
5625
|
});
|
|
5593
|
-
await sleep2(
|
|
5626
|
+
await sleep2(1500);
|
|
5594
5627
|
}
|
|
5595
|
-
if (
|
|
5628
|
+
if (await isPageLoggedIn(page, 5e3)) {
|
|
5629
|
+
armOverallDeadline();
|
|
5630
|
+
}
|
|
5631
|
+
}
|
|
5632
|
+
const stillSuspected = !silentRefresh.success || !await isPageLoggedIn(page, 2e3);
|
|
5633
|
+
if (stillSuspected) {
|
|
5634
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
5635
|
+
const creds = getAccountCredentials2(accountId);
|
|
5636
|
+
if (creds && creds.email && creds.password) {
|
|
5637
|
+
console.warn(
|
|
5638
|
+
`\u26A0\uFE0F [Playwright] Session expired or guest state detected during header capture for ${accountId}; re-authenticating...`
|
|
5639
|
+
);
|
|
5640
|
+
armOverallDeadline();
|
|
5641
|
+
const ok = await loginToQwen(accountId, creds.email, creds.password);
|
|
5642
|
+
if (ok) {
|
|
5643
|
+
await page.goto(qwenUrl("/"), {
|
|
5644
|
+
waitUntil: "domcontentloaded",
|
|
5645
|
+
timeout: Math.min(config.timeouts.navigation, timeoutMs)
|
|
5646
|
+
});
|
|
5647
|
+
await sleep2(2e3);
|
|
5648
|
+
}
|
|
5649
|
+
if (!ok || !await isPageLoggedIn(page, 6e3)) {
|
|
5650
|
+
settle(
|
|
5651
|
+
new Error(
|
|
5652
|
+
`Header capture failed for ${accountId}: re-login after session expiry did not succeed`
|
|
5653
|
+
)
|
|
5654
|
+
);
|
|
5655
|
+
return;
|
|
5656
|
+
}
|
|
5657
|
+
armOverallDeadline();
|
|
5658
|
+
if (settled || page.isClosed()) return;
|
|
5659
|
+
} else {
|
|
5596
5660
|
settle(
|
|
5597
5661
|
new Error(
|
|
5598
|
-
`Header capture failed for ${accountId}: re-login
|
|
5662
|
+
`Header capture failed for ${accountId}: session expired and no credentials available for re-login (run 'qpx login')`
|
|
5599
5663
|
)
|
|
5600
5664
|
);
|
|
5601
5665
|
return;
|
|
5602
5666
|
}
|
|
5603
|
-
armOverallDeadline();
|
|
5604
|
-
if (settled || page.isClosed()) return;
|
|
5605
|
-
} else {
|
|
5606
|
-
settle(
|
|
5607
|
-
new Error(
|
|
5608
|
-
`Header capture failed for ${accountId}: session expired and no credentials available for re-login (run 'qpx login')`
|
|
5609
|
-
)
|
|
5610
|
-
);
|
|
5611
|
-
return;
|
|
5612
5667
|
}
|
|
5613
5668
|
}
|
|
5614
5669
|
if (settled || page.isClosed()) return;
|
|
@@ -5924,7 +5979,13 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
5924
5979
|
`[Playwright] Navigation check failed during refresh for ${accountId}:`,
|
|
5925
5980
|
navErr.message
|
|
5926
5981
|
);
|
|
5927
|
-
await
|
|
5982
|
+
if (await isPageLoggedIn(page, 3e3)) {
|
|
5983
|
+
} else {
|
|
5984
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
5985
|
+
if (!refreshed.success) {
|
|
5986
|
+
await executeReauth();
|
|
5987
|
+
}
|
|
5988
|
+
}
|
|
5928
5989
|
}
|
|
5929
5990
|
}
|
|
5930
5991
|
if (hasRequiredQwenHeaders(cache.headers)) {
|
|
@@ -5938,6 +5999,11 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
5938
5999
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5939
6000
|
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
5940
6001
|
const exp = tokenCookie ? parseJwtExpiry(tokenCookie.value) : void 0;
|
|
6002
|
+
let rTok;
|
|
6003
|
+
try {
|
|
6004
|
+
rTok = (await page.evaluate(() => localStorage.getItem("refresh_token") || "")).trim() || void 0;
|
|
6005
|
+
} catch {
|
|
6006
|
+
}
|
|
5941
6007
|
saveAuthSession2(accountId, {
|
|
5942
6008
|
cookie: cookieStr,
|
|
5943
6009
|
userAgent: cache.headers["user-agent"] || "",
|
|
@@ -5949,6 +6015,7 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
5949
6015
|
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
|
|
5950
6016
|
version: cache.headers["version"] || void 0,
|
|
5951
6017
|
tokenExpiresAt: exp || void 0,
|
|
6018
|
+
refreshToken: rTok,
|
|
5952
6019
|
capturedAt: Date.now()
|
|
5953
6020
|
});
|
|
5954
6021
|
} catch {
|
|
@@ -6335,8 +6402,10 @@ async function keepAlivePlaywrightAccount(accountId) {
|
|
|
6335
6402
|
if (!page || page.isClosed()) return false;
|
|
6336
6403
|
const now = Date.now();
|
|
6337
6404
|
const currentUrl = page.url();
|
|
6405
|
+
const lastRefreshAttempt = lastProactiveTokenRefresh.get(accountId) ?? 0;
|
|
6338
6406
|
const cookie = await getCookies(accountId);
|
|
6339
|
-
if (cookie && isTokenExpiringSoon(cookie, 5)) {
|
|
6407
|
+
if (cookie && isTokenExpiringSoon(cookie, 5) && now - lastRefreshAttempt > 6e4) {
|
|
6408
|
+
lastProactiveTokenRefresh.set(accountId, now);
|
|
6340
6409
|
console.log(
|
|
6341
6410
|
`\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
|
|
6342
6411
|
);
|
|
@@ -6380,6 +6449,7 @@ function cleanupPlaywrightAccountState(accountId) {
|
|
|
6380
6449
|
cookieCaches.delete(accountId);
|
|
6381
6450
|
lastAccountActivity.delete(accountId);
|
|
6382
6451
|
lastKeepAliveNavigation.delete(accountId);
|
|
6452
|
+
lastProactiveTokenRefresh.delete(accountId);
|
|
6383
6453
|
clearFingerprintCache(accountId);
|
|
6384
6454
|
unmarkAccountHeadersReady(accountId);
|
|
6385
6455
|
}
|
|
@@ -6563,7 +6633,7 @@ async function getTokenDiagnostics(accountId) {
|
|
|
6563
6633
|
}
|
|
6564
6634
|
};
|
|
6565
6635
|
}
|
|
6566
|
-
var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, cachedUserAgents, inFlightAccountInits, sharedBrowser, sharedBrowserPromise, headerCaches, HEADER_CACHE_TTL, HEADER_REFRESH_THRESHOLD, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, 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;
|
|
6636
|
+
var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, cachedUserAgents, inFlightAccountInits, sharedBrowser, sharedBrowserPromise, headerCaches, HEADER_CACHE_TTL, HEADER_REFRESH_THRESHOLD, 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;
|
|
6567
6637
|
var init_playwright = __esm({
|
|
6568
6638
|
"src/services/playwright.ts"() {
|
|
6569
6639
|
"use strict";
|
|
@@ -6599,6 +6669,7 @@ var init_playwright = __esm({
|
|
|
6599
6669
|
cookieCaches = /* @__PURE__ */ new Map();
|
|
6600
6670
|
lastAccountActivity = /* @__PURE__ */ new Map();
|
|
6601
6671
|
lastKeepAliveNavigation = /* @__PURE__ */ new Map();
|
|
6672
|
+
lastProactiveTokenRefresh = /* @__PURE__ */ new Map();
|
|
6602
6673
|
profileResetQueue = /* @__PURE__ */ new Map();
|
|
6603
6674
|
profileResetChain = Promise.resolve();
|
|
6604
6675
|
closingAllPlaywright = false;
|
package/dist/reset-cooldowns.js
CHANGED
|
@@ -296,7 +296,26 @@ function runMigrations(db2) {
|
|
|
296
296
|
instruction_hash TEXT NOT NULL,
|
|
297
297
|
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
298
298
|
);
|
|
299
|
+
|
|
300
|
+
CREATE TABLE IF NOT EXISTS account_daily_usage (
|
|
301
|
+
account_id TEXT NOT NULL,
|
|
302
|
+
date_utc TEXT NOT NULL,
|
|
303
|
+
prompt_tokens INTEGER NOT NULL DEFAULT 0,
|
|
304
|
+
completion_tokens INTEGER NOT NULL DEFAULT 0,
|
|
305
|
+
weighted_tokens REAL NOT NULL DEFAULT 0,
|
|
306
|
+
total_tokens INTEGER NOT NULL DEFAULT 0,
|
|
307
|
+
turns_count INTEGER NOT NULL DEFAULT 0,
|
|
308
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
309
|
+
PRIMARY KEY (account_id, date_utc)
|
|
310
|
+
);
|
|
311
|
+
|
|
312
|
+
CREATE INDEX IF NOT EXISTS idx_daily_usage_date ON account_daily_usage(date_utc);
|
|
299
313
|
`);
|
|
314
|
+
try {
|
|
315
|
+
db2.exec(`ALTER TABLE account_daily_usage ADD COLUMN weighted_tokens REAL DEFAULT 0;`);
|
|
316
|
+
} catch (err) {
|
|
317
|
+
if (!isDuplicateColumnError(err)) throw err;
|
|
318
|
+
}
|
|
300
319
|
try {
|
|
301
320
|
db2.exec(
|
|
302
321
|
`ALTER TABLE accounts ADD COLUMN cooldown_until INTEGER DEFAULT 0;`
|
|
@@ -397,7 +416,11 @@ function saveAuthSession(accountId, session) {
|
|
|
397
416
|
) VALUES (
|
|
398
417
|
?, ?, ?, ?, ?, ?,
|
|
399
418
|
?, ?, ?, ?,
|
|
400
|
-
?,
|
|
419
|
+
COALESCE(?, (SELECT user_id FROM qwen_auth_sessions WHERE account_id = ?)),
|
|
420
|
+
?,
|
|
421
|
+
COALESCE(?, (SELECT refresh_token FROM qwen_auth_sessions WHERE account_id = ?)),
|
|
422
|
+
?,
|
|
423
|
+
datetime('now')
|
|
401
424
|
)
|
|
402
425
|
`);
|
|
403
426
|
stmt.run(
|
|
@@ -412,8 +435,10 @@ function saveAuthSession(accountId, session) {
|
|
|
412
435
|
session.secChUaPlatform || null,
|
|
413
436
|
session.version || null,
|
|
414
437
|
session.userId || null,
|
|
438
|
+
accountId,
|
|
415
439
|
session.tokenExpiresAt || null,
|
|
416
440
|
session.refreshToken || null,
|
|
441
|
+
accountId,
|
|
417
442
|
session.capturedAt ?? Date.now()
|
|
418
443
|
);
|
|
419
444
|
}
|
|
@@ -4529,6 +4554,137 @@ async function loginViaUi(page, email, password) {
|
|
|
4529
4554
|
return { success: false, reason: err?.message || String(err) };
|
|
4530
4555
|
}
|
|
4531
4556
|
}
|
|
4557
|
+
async function refreshAccountToken(accountId) {
|
|
4558
|
+
const page = accountPages.get(accountId);
|
|
4559
|
+
if (!page || page.isClosed()) {
|
|
4560
|
+
return { success: false, error: "Account page not active" };
|
|
4561
|
+
}
|
|
4562
|
+
const { getValidAuthSession: getValidAuthSession2, saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4563
|
+
const session = getValidAuthSession2(accountId);
|
|
4564
|
+
let refreshToken = session?.refreshToken;
|
|
4565
|
+
if (!refreshToken) {
|
|
4566
|
+
try {
|
|
4567
|
+
refreshToken = await page.evaluate(() => localStorage.getItem("refresh_token") || "") || void 0;
|
|
4568
|
+
} catch {
|
|
4569
|
+
}
|
|
4570
|
+
}
|
|
4571
|
+
if (refreshToken) {
|
|
4572
|
+
try {
|
|
4573
|
+
const refreshResult = await page.evaluate(
|
|
4574
|
+
async ({ rTok }) => {
|
|
4575
|
+
try {
|
|
4576
|
+
const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
4577
|
+
method: "GET",
|
|
4578
|
+
credentials: "include",
|
|
4579
|
+
headers: {
|
|
4580
|
+
accept: "application/json, text/plain, */*",
|
|
4581
|
+
source: "web",
|
|
4582
|
+
version: "0.3.11",
|
|
4583
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
4584
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
|
|
4585
|
+
authorization: `Bearer ${rTok}`
|
|
4586
|
+
}
|
|
4587
|
+
});
|
|
4588
|
+
const json2 = await response.json().catch(() => null);
|
|
4589
|
+
return { ok: response.ok, status: response.status, data: json2 };
|
|
4590
|
+
} catch (e) {
|
|
4591
|
+
return { ok: false, error: e.message };
|
|
4592
|
+
}
|
|
4593
|
+
},
|
|
4594
|
+
{ rTok: refreshToken }
|
|
4595
|
+
);
|
|
4596
|
+
const json = refreshResult?.data;
|
|
4597
|
+
if (json && json.success === true && json.data) {
|
|
4598
|
+
const newAccessToken = json.data.access_token || json.data.token;
|
|
4599
|
+
const newRefreshToken = json.data.refresh_token || refreshToken;
|
|
4600
|
+
if (newAccessToken) {
|
|
4601
|
+
await page.context().addCookies([
|
|
4602
|
+
{
|
|
4603
|
+
name: "token",
|
|
4604
|
+
value: newAccessToken,
|
|
4605
|
+
domain: ".qwen.ai",
|
|
4606
|
+
path: "/",
|
|
4607
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
4608
|
+
httpOnly: false,
|
|
4609
|
+
secure: true,
|
|
4610
|
+
sameSite: "Lax"
|
|
4611
|
+
}
|
|
4612
|
+
]);
|
|
4613
|
+
await page.evaluate(
|
|
4614
|
+
({ tok, rTok }) => {
|
|
4615
|
+
try {
|
|
4616
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
4617
|
+
localStorage.setItem("token", tok);
|
|
4618
|
+
localStorage.setItem("access_token", tok);
|
|
4619
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
4620
|
+
document.cookie = `token=${encodeURIComponent(tok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
4621
|
+
} catch {
|
|
4622
|
+
}
|
|
4623
|
+
},
|
|
4624
|
+
{ tok: newAccessToken, rTok: newRefreshToken }
|
|
4625
|
+
).catch(() => {
|
|
4626
|
+
});
|
|
4627
|
+
const liveCookies = await page.context().cookies();
|
|
4628
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
4629
|
+
const cache = getHeaderCache(accountId);
|
|
4630
|
+
cache.headers.cookie = cookieStr;
|
|
4631
|
+
cache.lastRefresh = Date.now();
|
|
4632
|
+
markAccountHeadersReady(accountId);
|
|
4633
|
+
saveAuthSession2(accountId, {
|
|
4634
|
+
cookie: cookieStr,
|
|
4635
|
+
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
4636
|
+
bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
|
|
4637
|
+
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
4638
|
+
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
4639
|
+
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
4640
|
+
secChUaMobile: cache.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
|
|
4641
|
+
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
|
|
4642
|
+
version: cache.headers["version"] || session?.version,
|
|
4643
|
+
userId: session?.userId,
|
|
4644
|
+
tokenExpiresAt: parseJwtExpiry(newAccessToken) || void 0,
|
|
4645
|
+
refreshToken: newRefreshToken,
|
|
4646
|
+
capturedAt: Date.now()
|
|
4647
|
+
});
|
|
4648
|
+
return { success: true, token: newAccessToken };
|
|
4649
|
+
}
|
|
4650
|
+
}
|
|
4651
|
+
} catch {
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
4655
|
+
const creds = getAccountCredentials2(accountId);
|
|
4656
|
+
if (creds && creds.email && creds.password) {
|
|
4657
|
+
const apiResult = await loginViaApi(page, creds.email, creds.password);
|
|
4658
|
+
if (apiResult.success) {
|
|
4659
|
+
const liveCookies = await page.context().cookies();
|
|
4660
|
+
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
4661
|
+
if (tokenCookie) {
|
|
4662
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
4663
|
+
const cache = getHeaderCache(accountId);
|
|
4664
|
+
cache.headers.cookie = cookieStr;
|
|
4665
|
+
cache.lastRefresh = Date.now();
|
|
4666
|
+
markAccountHeadersReady(accountId);
|
|
4667
|
+
saveAuthSession2(accountId, {
|
|
4668
|
+
cookie: cookieStr,
|
|
4669
|
+
userAgent: cache.headers["user-agent"] || session?.userAgent || "",
|
|
4670
|
+
bxV: cache.headers["bx-v"] || session?.bxV || "2.5.37",
|
|
4671
|
+
bxUa: cache.headers["bx-ua"] || session?.bxUa || "",
|
|
4672
|
+
bxUmidtoken: cache.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
4673
|
+
secChUa: cache.headers["sec-ch-ua"] || session?.secChUa,
|
|
4674
|
+
secChUaMobile: cache.headers["sec-ch-ua-mobile"] || session?.secChUaMobile,
|
|
4675
|
+
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || session?.secChUaPlatform,
|
|
4676
|
+
version: cache.headers["version"] || session?.version,
|
|
4677
|
+
userId: session?.userId,
|
|
4678
|
+
tokenExpiresAt: parseJwtExpiry(tokenCookie.value) || void 0,
|
|
4679
|
+
refreshToken: apiResult.refreshToken,
|
|
4680
|
+
capturedAt: Date.now()
|
|
4681
|
+
});
|
|
4682
|
+
return { success: true, token: tokenCookie.value };
|
|
4683
|
+
}
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
return { success: false, error: "Could not refresh or re-authenticate token" };
|
|
4687
|
+
}
|
|
4532
4688
|
async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.timeouts.headers, triggerGraceMs = HEADER_CAPTURE_TRIGGER_GRACE_MS) {
|
|
4533
4689
|
const page = pageOverride ?? accountPages.get(accountId);
|
|
4534
4690
|
if (!page || page.isClosed()) {
|
|
@@ -4682,6 +4838,11 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
4682
4838
|
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4683
4839
|
const { parseJwtExpiry: parseJwtExpiry2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
|
|
4684
4840
|
const tokenExpiry = parseJwtExpiry2(capturedHeaders.cookie);
|
|
4841
|
+
let rTok;
|
|
4842
|
+
try {
|
|
4843
|
+
rTok = (await page.evaluate(() => localStorage.getItem("refresh_token") || "")).trim() || void 0;
|
|
4844
|
+
} catch {
|
|
4845
|
+
}
|
|
4685
4846
|
saveAuthSession2(accountId, {
|
|
4686
4847
|
cookie: capturedHeaders.cookie,
|
|
4687
4848
|
userAgent: capturedHeaders["user-agent"],
|
|
@@ -4693,6 +4854,7 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
4693
4854
|
secChUaPlatform: capturedHeaders["sec-ch-ua-platform"],
|
|
4694
4855
|
version: capturedHeaders["version"],
|
|
4695
4856
|
tokenExpiresAt: tokenExpiry || void 0,
|
|
4857
|
+
refreshToken: rTok,
|
|
4696
4858
|
capturedAt: Date.now()
|
|
4697
4859
|
});
|
|
4698
4860
|
} catch {
|
|
@@ -4724,38 +4886,57 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
4724
4886
|
const isAuthUrl = currentUrl.includes("/auth") || currentUrl.includes("/login");
|
|
4725
4887
|
const isSuspectedGuest = isAuthUrl || attempt >= 2 && !await isPageLoggedIn(page, 5e3);
|
|
4726
4888
|
if (isSuspectedGuest) {
|
|
4727
|
-
const
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
`\u26A0\uFE0F [Playwright] Session expired or guest state detected during header capture for ${accountId}; re-authenticating...`
|
|
4889
|
+
const silentRefresh = await refreshAccountToken(accountId);
|
|
4890
|
+
if (silentRefresh.success) {
|
|
4891
|
+
console.log(
|
|
4892
|
+
`\u26A1 [Playwright] Token refreshed silently during header capture for ${accountId}`
|
|
4732
4893
|
);
|
|
4733
|
-
|
|
4734
|
-
const ok = await loginToQwen(accountId, creds.email, creds.password);
|
|
4735
|
-
if (ok) {
|
|
4894
|
+
if (isAuthUrl) {
|
|
4736
4895
|
await page.goto(qwenUrl("/"), {
|
|
4737
4896
|
waitUntil: "domcontentloaded",
|
|
4738
4897
|
timeout: Math.min(config.timeouts.navigation, timeoutMs)
|
|
4739
4898
|
});
|
|
4740
|
-
await sleep2(
|
|
4899
|
+
await sleep2(1500);
|
|
4900
|
+
}
|
|
4901
|
+
if (await isPageLoggedIn(page, 5e3)) {
|
|
4902
|
+
armOverallDeadline();
|
|
4741
4903
|
}
|
|
4742
|
-
|
|
4904
|
+
}
|
|
4905
|
+
const stillSuspected = !silentRefresh.success || !await isPageLoggedIn(page, 2e3);
|
|
4906
|
+
if (stillSuspected) {
|
|
4907
|
+
const { getAccountCredentials: getAccountCredentials2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
4908
|
+
const creds = getAccountCredentials2(accountId);
|
|
4909
|
+
if (creds && creds.email && creds.password) {
|
|
4910
|
+
console.warn(
|
|
4911
|
+
`\u26A0\uFE0F [Playwright] Session expired or guest state detected during header capture for ${accountId}; re-authenticating...`
|
|
4912
|
+
);
|
|
4913
|
+
armOverallDeadline();
|
|
4914
|
+
const ok = await loginToQwen(accountId, creds.email, creds.password);
|
|
4915
|
+
if (ok) {
|
|
4916
|
+
await page.goto(qwenUrl("/"), {
|
|
4917
|
+
waitUntil: "domcontentloaded",
|
|
4918
|
+
timeout: Math.min(config.timeouts.navigation, timeoutMs)
|
|
4919
|
+
});
|
|
4920
|
+
await sleep2(2e3);
|
|
4921
|
+
}
|
|
4922
|
+
if (!ok || !await isPageLoggedIn(page, 6e3)) {
|
|
4923
|
+
settle(
|
|
4924
|
+
new Error(
|
|
4925
|
+
`Header capture failed for ${accountId}: re-login after session expiry did not succeed`
|
|
4926
|
+
)
|
|
4927
|
+
);
|
|
4928
|
+
return;
|
|
4929
|
+
}
|
|
4930
|
+
armOverallDeadline();
|
|
4931
|
+
if (settled || page.isClosed()) return;
|
|
4932
|
+
} else {
|
|
4743
4933
|
settle(
|
|
4744
4934
|
new Error(
|
|
4745
|
-
`Header capture failed for ${accountId}: re-login
|
|
4935
|
+
`Header capture failed for ${accountId}: session expired and no credentials available for re-login (run 'qpx login')`
|
|
4746
4936
|
)
|
|
4747
4937
|
);
|
|
4748
4938
|
return;
|
|
4749
4939
|
}
|
|
4750
|
-
armOverallDeadline();
|
|
4751
|
-
if (settled || page.isClosed()) return;
|
|
4752
|
-
} else {
|
|
4753
|
-
settle(
|
|
4754
|
-
new Error(
|
|
4755
|
-
`Header capture failed for ${accountId}: session expired and no credentials available for re-login (run 'qpx login')`
|
|
4756
|
-
)
|
|
4757
|
-
);
|
|
4758
|
-
return;
|
|
4759
4940
|
}
|
|
4760
4941
|
}
|
|
4761
4942
|
if (settled || page.isClosed()) return;
|
|
@@ -5245,6 +5426,7 @@ function cleanupPlaywrightAccountState(accountId) {
|
|
|
5245
5426
|
cookieCaches.delete(accountId);
|
|
5246
5427
|
lastAccountActivity.delete(accountId);
|
|
5247
5428
|
lastKeepAliveNavigation.delete(accountId);
|
|
5429
|
+
lastProactiveTokenRefresh.delete(accountId);
|
|
5248
5430
|
clearFingerprintCache(accountId);
|
|
5249
5431
|
unmarkAccountHeadersReady(accountId);
|
|
5250
5432
|
}
|
|
@@ -5319,7 +5501,7 @@ async function closePlaywrightForAccount(accountId) {
|
|
|
5319
5501
|
release();
|
|
5320
5502
|
}
|
|
5321
5503
|
}
|
|
5322
|
-
var requireLocal, contextInitHooks, ACCOUNT_MUTEX_MAX_HOLD_MS, accountMutexes, accountContexts, accountPages, inFlightAccountInits, headerCaches, HEADER_CACHE_TTL, COOKIE_CACHE_TTL, cookieCaches, lastAccountActivity, lastKeepAliveNavigation, 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;
|
|
5504
|
+
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;
|
|
5323
5505
|
var init_playwright = __esm({
|
|
5324
5506
|
"src/services/playwright.ts"() {
|
|
5325
5507
|
"use strict";
|
|
@@ -5351,6 +5533,7 @@ var init_playwright = __esm({
|
|
|
5351
5533
|
cookieCaches = /* @__PURE__ */ new Map();
|
|
5352
5534
|
lastAccountActivity = /* @__PURE__ */ new Map();
|
|
5353
5535
|
lastKeepAliveNavigation = /* @__PURE__ */ new Map();
|
|
5536
|
+
lastProactiveTokenRefresh = /* @__PURE__ */ new Map();
|
|
5354
5537
|
profileResetQueue = /* @__PURE__ */ new Map();
|
|
5355
5538
|
profileResetChain = Promise.resolve();
|
|
5356
5539
|
closingAllPlaywright = false;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwenproxy-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
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": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"reset": "npx tsx src/reset-cooldowns.ts",
|
|
30
30
|
"purge": "npx tsx src/delete-chats.ts",
|
|
31
31
|
"test": "npm run test:mock && npm run test:live",
|
|
32
|
-
"test:mock": "tsx --test --test-concurrency=1 --env-file=.env.test src/tests/account-concurrency.test.ts src/tests/concurrency-latest-wins.test.ts src/tests/mutex.test.ts src/tests/context-truncation.test.ts src/tests/streaming-thinking-summary.test.ts src/tests/tool-call-guard.test.ts src/tests/utils-logger-full.test.ts src/tests/logger-toolcall-errors.test.ts src/tests/logger-toolcall-disabled.test.ts src/tests/utils-json-full.test.ts src/tests/utils-session-guard-full.test.ts src/tests/core-logic-full.test.ts src/tests/core-logic-accounts.test.ts src/tests/chat-validation-full.test.ts src/tests/chat-logic-full.test.ts src/tests/account-stickiness.test.ts src/tests/accounts-security.test.ts src/tests/advanced.test.ts src/tests/auth-playwright.test.ts src/tests/auth-session-persistence.test.ts src/tests/captcha-solver.test.ts src/tests/cache-scan-regex.test.ts src/tests/chat-cleanup.test.ts src/tests/chat-cleanup-auto.test.ts src/tests/chromium-args.test.ts src/tests/config-current.test.ts src/tests/context-meter.test.ts src/tests/concurrency.test.ts src/tests/delta.test.ts src/tests/fingerprint.test.ts src/tests/human-behavior.test.ts src/tests/index.test.ts src/tests/json-recovery.test.ts src/tests/jsonFix.test.ts src/tests/memory-cache.test.ts src/tests/model-alias.test.ts src/tests/model-registry-thinking.test.ts src/tests/models-endpoint.test.ts src/tests/multimodal.test.ts src/tests/oss-upload.test.ts src/tests/parser.test.ts src/tests/personalization-flow.test.ts src/tests/personalization-required.test.ts src/tests/retry-policy.test.ts src/tests/rotation.test.ts src/tests/server-lifecycle.test.ts src/tests/session-keeper.test.ts src/tests/session-state.test.ts src/tests/single-account-mode.test.ts src/tests/stream-retry.test.ts src/tests/tool-calls-endpoint.test.ts src/tests/tool-instructions-cache.test.ts src/tests/session-id.test.ts src/tests/watchdog-ram.test.ts src/tests/tool-recovery-t1t2.test.ts src/tests/abort-silent-t4.test.ts src/tests/t3-close-tag-escape.test.ts src/tests/t5-tool-cap.test.ts src/tests/logger-redaction.test.ts src/tests/stall-timeout-retryable.test.ts src/tests/t6-missing-quote-array-close.test.ts src/tests/watchdog-rss.test.ts src/tests/logical-thread-batch.test.ts src/tests/chat-pool-style.test.ts src/tests/queue-wait-cap.test.ts src/tests/context-eviction-order.test.ts src/tests/chat-in-progress-settle.test.ts src/tests/stream-lock-leak.test.ts src/tests/stream-semaphore.test.ts src/tests/waf-isolation.test.ts src/tests/legacy-completions.test.ts src/tests/response-format.test.ts src/tests/cors-headers.test.ts src/tests/local-auth.test.ts src/tests/safe-remote-url.test.ts src/tests/stream-lock-terminal-cancel.test.ts src/tests/parser-truncated-tool-call.test.ts src/tests/metrics-prometheus.test.ts src/tests/context-death-cleanup.test.ts src/tests/personalization-direct-fetch.test.ts src/tests/completion-headers-parity.test.ts src/tests/parallel-escape-repro.test.ts src/tests/chat-in-progress-scale-cost.test.ts src/tests/temp-chat-mode.test.ts src/tests/profile-reset.test.ts src/tests/error-classification.test.ts src/tests/quota-cooldown.test.ts src/tests/account-ready-gate.test.ts src/tests/tool-cap-notice.test.ts src/tests/interaction-flows.test.ts src/tests/headers-gate-cooldown-fallback.test.ts src/tests/unwrapped-tool-calls.test.ts src/tests/anthropic.test.ts src/tests/sync-clients.test.ts src/tests/sync-top10-clients.test.ts src/tests/cli.test.ts src/tests/paths.test.ts src/tests/tool-manifest.test.ts src/tests/tui.test.ts src/tests/tui-settings.test.ts src/tests/personalization-deadline.test.ts src/tests/update-cli.test.ts src/tests/batch-accounts.test.ts src/tests/shared-browser.test.ts src/tests/auth-credential-classification.test.ts src/tests/responses-api.test.ts src/tests/media-generation.test.ts src/tests/infer-tool-name.test.ts src/tests/native-session-headers.test.ts src/tests/omni-thinking.test.ts src/tests/protect-stuck-mutex.test.ts src/tests/stream-error-notice.test.ts src/tests/parser-deep-coverage.test.ts src/tests/tui-logs-copy.test.ts src/tests/auth-jwt-and-validation.test.ts src/tests/tui-port-and-key-modal.test.ts src/tests/verify-zero-fake-cooldown.test.ts",
|
|
33
|
-
"test:mock:fast": "tsx --test --test-concurrency=2 --env-file=.env.test src/tests/account-concurrency.test.ts src/tests/concurrency-latest-wins.test.ts src/tests/mutex.test.ts src/tests/context-truncation.test.ts src/tests/streaming-thinking-summary.test.ts src/tests/tool-call-guard.test.ts src/tests/utils-logger-full.test.ts src/tests/logger-toolcall-errors.test.ts src/tests/logger-toolcall-disabled.test.ts src/tests/utils-json-full.test.ts src/tests/utils-session-guard-full.test.ts src/tests/core-logic-full.test.ts src/tests/core-logic-accounts.test.ts src/tests/chat-validation-full.test.ts src/tests/chat-logic-full.test.ts src/tests/account-stickiness.test.ts src/tests/accounts-security.test.ts src/tests/advanced.test.ts src/tests/auth-playwright.test.ts src/tests/auth-session-persistence.test.ts src/tests/captcha-solver.test.ts src/tests/cache-scan-regex.test.ts src/tests/chat-cleanup.test.ts src/tests/chat-cleanup-auto.test.ts src/tests/chromium-args.test.ts src/tests/config-current.test.ts src/tests/context-meter.test.ts src/tests/concurrency.test.ts src/tests/delta.test.ts src/tests/fingerprint.test.ts src/tests/human-behavior.test.ts src/tests/index.test.ts src/tests/json-recovery.test.ts src/tests/jsonFix.test.ts src/tests/memory-cache.test.ts src/tests/model-alias.test.ts src/tests/model-registry-thinking.test.ts src/tests/models-endpoint.test.ts src/tests/multimodal.test.ts src/tests/oss-upload.test.ts src/tests/parser.test.ts src/tests/personalization-flow.test.ts src/tests/personalization-required.test.ts src/tests/retry-policy.test.ts src/tests/rotation.test.ts src/tests/server-lifecycle.test.ts src/tests/session-keeper.test.ts src/tests/session-state.test.ts src/tests/single-account-mode.test.ts src/tests/stream-retry.test.ts src/tests/tool-calls-endpoint.test.ts src/tests/tool-instructions-cache.test.ts src/tests/session-id.test.ts src/tests/watchdog-ram.test.ts src/tests/tool-recovery-t1t2.test.ts src/tests/abort-silent-t4.test.ts src/tests/t3-close-tag-escape.test.ts src/tests/t5-tool-cap.test.ts src/tests/logger-redaction.test.ts src/tests/stall-timeout-retryable.test.ts src/tests/t6-missing-quote-array-close.test.ts src/tests/watchdog-rss.test.ts src/tests/logical-thread-batch.test.ts src/tests/chat-pool-style.test.ts src/tests/queue-wait-cap.test.ts src/tests/context-eviction-order.test.ts src/tests/chat-in-progress-settle.test.ts src/tests/stream-lock-leak.test.ts src/tests/stream-semaphore.test.ts src/tests/waf-isolation.test.ts src/tests/legacy-completions.test.ts src/tests/response-format.test.ts src/tests/cors-headers.test.ts src/tests/local-auth.test.ts src/tests/safe-remote-url.test.ts src/tests/stream-lock-terminal-cancel.test.ts src/tests/parser-truncated-tool-call.test.ts src/tests/metrics-prometheus.test.ts src/tests/context-death-cleanup.test.ts src/tests/personalization-direct-fetch.test.ts src/tests/completion-headers-parity.test.ts src/tests/parallel-escape-repro.test.ts src/tests/chat-in-progress-scale-cost.test.ts src/tests/temp-chat-mode.test.ts src/tests/profile-reset.test.ts src/tests/error-classification.test.ts src/tests/quota-cooldown.test.ts src/tests/account-ready-gate.test.ts src/tests/tool-cap-notice.test.ts src/tests/interaction-flows.test.ts src/tests/headers-gate-cooldown-fallback.test.ts src/tests/unwrapped-tool-calls.test.ts src/tests/anthropic.test.ts src/tests/sync-clients.test.ts src/tests/sync-top10-clients.test.ts src/tests/cli.test.ts src/tests/paths.test.ts src/tests/tool-manifest.test.ts src/tests/tui.test.ts src/tests/tui-settings.test.ts src/tests/personalization-deadline.test.ts src/tests/update-cli.test.ts src/tests/batch-accounts.test.ts src/tests/shared-browser.test.ts src/tests/auth-credential-classification.test.ts src/tests/responses-api.test.ts src/tests/media-generation.test.ts src/tests/infer-tool-name.test.ts src/tests/native-session-headers.test.ts src/tests/omni-thinking.test.ts src/tests/protect-stuck-mutex.test.ts src/tests/stream-error-notice.test.ts src/tests/parser-deep-coverage.test.ts src/tests/tui-logs-copy.test.ts src/tests/auth-jwt-and-validation.test.ts src/tests/tui-port-and-key-modal.test.ts src/tests/verify-zero-fake-cooldown.test.ts",
|
|
32
|
+
"test:mock": "tsx --test --test-concurrency=1 --env-file=.env.test src/tests/account-concurrency.test.ts src/tests/concurrency-latest-wins.test.ts src/tests/mutex.test.ts src/tests/context-truncation.test.ts src/tests/streaming-thinking-summary.test.ts src/tests/tool-call-guard.test.ts src/tests/utils-logger-full.test.ts src/tests/logger-toolcall-errors.test.ts src/tests/logger-toolcall-disabled.test.ts src/tests/utils-json-full.test.ts src/tests/utils-session-guard-full.test.ts src/tests/core-logic-full.test.ts src/tests/core-logic-accounts.test.ts src/tests/chat-validation-full.test.ts src/tests/chat-logic-full.test.ts src/tests/account-stickiness.test.ts src/tests/accounts-security.test.ts src/tests/advanced.test.ts src/tests/auth-playwright.test.ts src/tests/auth-session-persistence.test.ts src/tests/captcha-solver.test.ts src/tests/cache-scan-regex.test.ts src/tests/chat-cleanup.test.ts src/tests/chat-cleanup-auto.test.ts src/tests/chromium-args.test.ts src/tests/config-current.test.ts src/tests/context-meter.test.ts src/tests/concurrency.test.ts src/tests/delta.test.ts src/tests/fingerprint.test.ts src/tests/human-behavior.test.ts src/tests/index.test.ts src/tests/json-recovery.test.ts src/tests/jsonFix.test.ts src/tests/memory-cache.test.ts src/tests/model-alias.test.ts src/tests/model-registry-thinking.test.ts src/tests/models-endpoint.test.ts src/tests/multimodal.test.ts src/tests/oss-upload.test.ts src/tests/parser.test.ts src/tests/personalization-flow.test.ts src/tests/personalization-required.test.ts src/tests/retry-policy.test.ts src/tests/rotation.test.ts src/tests/server-lifecycle.test.ts src/tests/session-keeper.test.ts src/tests/session-state.test.ts src/tests/single-account-mode.test.ts src/tests/stream-retry.test.ts src/tests/tool-calls-endpoint.test.ts src/tests/tool-instructions-cache.test.ts src/tests/session-id.test.ts src/tests/watchdog-ram.test.ts src/tests/tool-recovery-t1t2.test.ts src/tests/abort-silent-t4.test.ts src/tests/t3-close-tag-escape.test.ts src/tests/t5-tool-cap.test.ts src/tests/logger-redaction.test.ts src/tests/stall-timeout-retryable.test.ts src/tests/t6-missing-quote-array-close.test.ts src/tests/watchdog-rss.test.ts src/tests/logical-thread-batch.test.ts src/tests/chat-pool-style.test.ts src/tests/queue-wait-cap.test.ts src/tests/context-eviction-order.test.ts src/tests/chat-in-progress-settle.test.ts src/tests/stream-lock-leak.test.ts src/tests/stream-semaphore.test.ts src/tests/waf-isolation.test.ts src/tests/legacy-completions.test.ts src/tests/response-format.test.ts src/tests/cors-headers.test.ts src/tests/local-auth.test.ts src/tests/safe-remote-url.test.ts src/tests/stream-lock-terminal-cancel.test.ts src/tests/parser-truncated-tool-call.test.ts src/tests/metrics-prometheus.test.ts src/tests/context-death-cleanup.test.ts src/tests/personalization-direct-fetch.test.ts src/tests/completion-headers-parity.test.ts src/tests/parallel-escape-repro.test.ts src/tests/chat-in-progress-scale-cost.test.ts src/tests/temp-chat-mode.test.ts src/tests/profile-reset.test.ts src/tests/error-classification.test.ts src/tests/quota-cooldown.test.ts src/tests/account-ready-gate.test.ts src/tests/tool-cap-notice.test.ts src/tests/interaction-flows.test.ts src/tests/headers-gate-cooldown-fallback.test.ts src/tests/unwrapped-tool-calls.test.ts src/tests/anthropic.test.ts src/tests/sync-clients.test.ts src/tests/sync-top10-clients.test.ts src/tests/cli.test.ts src/tests/paths.test.ts src/tests/tool-manifest.test.ts src/tests/tui.test.ts src/tests/tui-settings.test.ts src/tests/personalization-deadline.test.ts src/tests/update-cli.test.ts src/tests/batch-accounts.test.ts src/tests/shared-browser.test.ts src/tests/auth-credential-classification.test.ts src/tests/responses-api.test.ts src/tests/media-generation.test.ts src/tests/infer-tool-name.test.ts src/tests/native-session-headers.test.ts src/tests/omni-thinking.test.ts src/tests/protect-stuck-mutex.test.ts src/tests/stream-error-notice.test.ts src/tests/parser-deep-coverage.test.ts src/tests/tui-logs-copy.test.ts src/tests/auth-jwt-and-validation.test.ts src/tests/tui-port-and-key-modal.test.ts src/tests/verify-zero-fake-cooldown.test.ts src/tests/auth-session-refresh-preservation.test.ts src/tests/personalization-in-flight-dedup.test.ts src/tests/daily-usage.test.ts src/tests/resilience-enhancements.test.ts src/tests/pool-quota-failover.test.ts",
|
|
33
|
+
"test:mock:fast": "tsx --test --test-concurrency=2 --env-file=.env.test src/tests/account-concurrency.test.ts src/tests/concurrency-latest-wins.test.ts src/tests/mutex.test.ts src/tests/context-truncation.test.ts src/tests/streaming-thinking-summary.test.ts src/tests/tool-call-guard.test.ts src/tests/utils-logger-full.test.ts src/tests/logger-toolcall-errors.test.ts src/tests/logger-toolcall-disabled.test.ts src/tests/utils-json-full.test.ts src/tests/utils-session-guard-full.test.ts src/tests/core-logic-full.test.ts src/tests/core-logic-accounts.test.ts src/tests/chat-validation-full.test.ts src/tests/chat-logic-full.test.ts src/tests/account-stickiness.test.ts src/tests/accounts-security.test.ts src/tests/advanced.test.ts src/tests/auth-playwright.test.ts src/tests/auth-session-persistence.test.ts src/tests/captcha-solver.test.ts src/tests/cache-scan-regex.test.ts src/tests/chat-cleanup.test.ts src/tests/chat-cleanup-auto.test.ts src/tests/chromium-args.test.ts src/tests/config-current.test.ts src/tests/context-meter.test.ts src/tests/concurrency.test.ts src/tests/delta.test.ts src/tests/fingerprint.test.ts src/tests/human-behavior.test.ts src/tests/index.test.ts src/tests/json-recovery.test.ts src/tests/jsonFix.test.ts src/tests/memory-cache.test.ts src/tests/model-alias.test.ts src/tests/model-registry-thinking.test.ts src/tests/models-endpoint.test.ts src/tests/multimodal.test.ts src/tests/oss-upload.test.ts src/tests/parser.test.ts src/tests/personalization-flow.test.ts src/tests/personalization-required.test.ts src/tests/retry-policy.test.ts src/tests/rotation.test.ts src/tests/server-lifecycle.test.ts src/tests/session-keeper.test.ts src/tests/session-state.test.ts src/tests/single-account-mode.test.ts src/tests/stream-retry.test.ts src/tests/tool-calls-endpoint.test.ts src/tests/tool-instructions-cache.test.ts src/tests/session-id.test.ts src/tests/watchdog-ram.test.ts src/tests/tool-recovery-t1t2.test.ts src/tests/abort-silent-t4.test.ts src/tests/t3-close-tag-escape.test.ts src/tests/t5-tool-cap.test.ts src/tests/logger-redaction.test.ts src/tests/stall-timeout-retryable.test.ts src/tests/t6-missing-quote-array-close.test.ts src/tests/watchdog-rss.test.ts src/tests/logical-thread-batch.test.ts src/tests/chat-pool-style.test.ts src/tests/queue-wait-cap.test.ts src/tests/context-eviction-order.test.ts src/tests/chat-in-progress-settle.test.ts src/tests/stream-lock-leak.test.ts src/tests/stream-semaphore.test.ts src/tests/waf-isolation.test.ts src/tests/legacy-completions.test.ts src/tests/response-format.test.ts src/tests/cors-headers.test.ts src/tests/local-auth.test.ts src/tests/safe-remote-url.test.ts src/tests/stream-lock-terminal-cancel.test.ts src/tests/parser-truncated-tool-call.test.ts src/tests/metrics-prometheus.test.ts src/tests/context-death-cleanup.test.ts src/tests/personalization-direct-fetch.test.ts src/tests/completion-headers-parity.test.ts src/tests/parallel-escape-repro.test.ts src/tests/chat-in-progress-scale-cost.test.ts src/tests/temp-chat-mode.test.ts src/tests/profile-reset.test.ts src/tests/error-classification.test.ts src/tests/quota-cooldown.test.ts src/tests/account-ready-gate.test.ts src/tests/tool-cap-notice.test.ts src/tests/interaction-flows.test.ts src/tests/headers-gate-cooldown-fallback.test.ts src/tests/unwrapped-tool-calls.test.ts src/tests/anthropic.test.ts src/tests/sync-clients.test.ts src/tests/sync-top10-clients.test.ts src/tests/cli.test.ts src/tests/paths.test.ts src/tests/tool-manifest.test.ts src/tests/tui.test.ts src/tests/tui-settings.test.ts src/tests/personalization-deadline.test.ts src/tests/update-cli.test.ts src/tests/batch-accounts.test.ts src/tests/shared-browser.test.ts src/tests/auth-credential-classification.test.ts src/tests/responses-api.test.ts src/tests/media-generation.test.ts src/tests/infer-tool-name.test.ts src/tests/native-session-headers.test.ts src/tests/omni-thinking.test.ts src/tests/protect-stuck-mutex.test.ts src/tests/stream-error-notice.test.ts src/tests/parser-deep-coverage.test.ts src/tests/tui-logs-copy.test.ts src/tests/auth-jwt-and-validation.test.ts src/tests/tui-port-and-key-modal.test.ts src/tests/verify-zero-fake-cooldown.test.ts src/tests/auth-session-refresh-preservation.test.ts src/tests/personalization-in-flight-dedup.test.ts src/tests/daily-usage.test.ts src/tests/resilience-enhancements.test.ts src/tests/pool-quota-failover.test.ts",
|
|
34
34
|
"test:live": "tsx --test src/tests/concurrentChat.test.ts src/tests/agenticStress.test.ts",
|
|
35
35
|
"test:stress": "npx tsx src/benchmarks/stress-test.ts",
|
|
36
36
|
"test:stress:personalization": "npx tsx src/benchmarks/stress-test-personalization.ts",
|
package/src/api/server.ts
CHANGED
|
@@ -371,6 +371,7 @@ app.get("/health", async (c) => {
|
|
|
371
371
|
captchasSolved: Number(metrics.get("captcha.solves.succeeded")?.value ?? 0),
|
|
372
372
|
chatsCleaned: Number(metrics.get("chats.cleaned")?.value ?? 0),
|
|
373
373
|
},
|
|
374
|
+
dailyUsage: (await import("../core/daily-usage.ts")).getPoolDailyUsageSummary(),
|
|
374
375
|
});
|
|
375
376
|
});
|
|
376
377
|
|