qwenproxy-cli 1.6.3 → 1.6.5
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 +76 -12
- package/dist/delete-chats.js +182 -49
- package/dist/index.js +245 -64
- package/dist/login.js +90 -19
- package/dist/reset-cooldowns.js +79 -13
- package/package.json +1 -1
- package/src/core/mutex.ts +4 -0
- package/src/core/version.ts +1 -1
- package/src/routes/anthropic/translate.ts +15 -7
- package/src/routes/chat/helpers.ts +4 -2
- package/src/routes/chat/retry-policy.ts +3 -1
- package/src/routes/chat/streaming.ts +32 -10
- package/src/routes/responses/adapter.ts +4 -1
- package/src/services/context-meter.ts +1 -1
- package/src/services/playwright.ts +55 -21
- package/src/services/qwen-headers.ts +3 -2
- package/src/services/qwen.ts +88 -31
- package/src/tools/tool-call-heuristics.ts +88 -0
- package/src/utils/timezone.ts +56 -0
package/dist/clean-cache.js
CHANGED
|
@@ -1814,6 +1814,7 @@ var init_mutex = __esm({
|
|
|
1814
1814
|
locked = false;
|
|
1815
1815
|
lockedAt = 0;
|
|
1816
1816
|
lockedByKey = "";
|
|
1817
|
+
epoch = 0;
|
|
1817
1818
|
async acquire(timeoutMs = 3e5, key = "") {
|
|
1818
1819
|
const holdLimitMs = this.maxHoldMs;
|
|
1819
1820
|
if (this.locked && Date.now() - this.lockedAt > holdLimitMs) {
|
|
@@ -1824,6 +1825,7 @@ var init_mutex = __esm({
|
|
|
1824
1825
|
this.locked = false;
|
|
1825
1826
|
this.lockedAt = 0;
|
|
1826
1827
|
this.lockedByKey = "";
|
|
1828
|
+
this.epoch++;
|
|
1827
1829
|
}
|
|
1828
1830
|
if (!this.locked) {
|
|
1829
1831
|
this.locked = true;
|
|
@@ -1862,10 +1864,12 @@ var init_mutex = __esm({
|
|
|
1862
1864
|
}
|
|
1863
1865
|
}
|
|
1864
1866
|
createRelease() {
|
|
1867
|
+
const epoch = this.epoch;
|
|
1865
1868
|
let released = false;
|
|
1866
1869
|
return () => {
|
|
1867
1870
|
if (released) return;
|
|
1868
1871
|
released = true;
|
|
1872
|
+
if (epoch !== this.epoch) return;
|
|
1869
1873
|
this.release();
|
|
1870
1874
|
};
|
|
1871
1875
|
}
|
|
@@ -2673,6 +2677,45 @@ var init_waf_isolation = __esm({
|
|
|
2673
2677
|
}
|
|
2674
2678
|
});
|
|
2675
2679
|
|
|
2680
|
+
// src/utils/timezone.ts
|
|
2681
|
+
function formatAsciiTimezone(date = /* @__PURE__ */ new Date()) {
|
|
2682
|
+
const dayName = DAYS[date.getDay()];
|
|
2683
|
+
const monthName = MONTHS[date.getMonth()];
|
|
2684
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
2685
|
+
const year = date.getFullYear();
|
|
2686
|
+
const hours = String(date.getHours()).padStart(2, "0");
|
|
2687
|
+
const minutes = String(date.getMinutes()).padStart(2, "0");
|
|
2688
|
+
const seconds = String(date.getSeconds()).padStart(2, "0");
|
|
2689
|
+
const offsetMinutes = -date.getTimezoneOffset();
|
|
2690
|
+
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
2691
|
+
const absOffset = Math.abs(offsetMinutes);
|
|
2692
|
+
const offsetHours = String(Math.floor(absOffset / 60)).padStart(2, "0");
|
|
2693
|
+
const offsetMins = String(absOffset % 60).padStart(2, "0");
|
|
2694
|
+
const tzOffset = `GMT${sign}${offsetHours}${offsetMins}`;
|
|
2695
|
+
return `${dayName} ${monthName} ${day} ${year} ${hours}:${minutes}:${seconds} ${tzOffset}`;
|
|
2696
|
+
}
|
|
2697
|
+
var DAYS, MONTHS;
|
|
2698
|
+
var init_timezone = __esm({
|
|
2699
|
+
"src/utils/timezone.ts"() {
|
|
2700
|
+
"use strict";
|
|
2701
|
+
DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
2702
|
+
MONTHS = [
|
|
2703
|
+
"Jan",
|
|
2704
|
+
"Feb",
|
|
2705
|
+
"Mar",
|
|
2706
|
+
"Apr",
|
|
2707
|
+
"May",
|
|
2708
|
+
"Jun",
|
|
2709
|
+
"Jul",
|
|
2710
|
+
"Aug",
|
|
2711
|
+
"Sep",
|
|
2712
|
+
"Oct",
|
|
2713
|
+
"Nov",
|
|
2714
|
+
"Dec"
|
|
2715
|
+
];
|
|
2716
|
+
}
|
|
2717
|
+
});
|
|
2718
|
+
|
|
2676
2719
|
// src/services/qwen-headers.ts
|
|
2677
2720
|
import { v4 as uuidv4 } from "uuid";
|
|
2678
2721
|
function getDefaultQwenUserAgent(major = getChromeMajor()) {
|
|
@@ -2690,6 +2733,7 @@ var init_qwen_headers = __esm({
|
|
|
2690
2733
|
init_qwen_url();
|
|
2691
2734
|
init_config();
|
|
2692
2735
|
init_fingerprint();
|
|
2736
|
+
init_timezone();
|
|
2693
2737
|
dynamicWebVersion = null;
|
|
2694
2738
|
QWEN_WEB_VERSION = config.qwen.webVersion;
|
|
2695
2739
|
DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
|
|
@@ -2841,9 +2885,10 @@ function getAccountMutex(accountId) {
|
|
|
2841
2885
|
async function recoverStuckAccountMutex(accountId, mutex, key) {
|
|
2842
2886
|
if (accountMutexes.get(accountId) !== mutex) return;
|
|
2843
2887
|
const lockState = mutex.state();
|
|
2844
|
-
|
|
2888
|
+
const minLockTimeout = Math.max(PLAYWRIGHT_MUTEX_WAIT_MS, config.timeouts.headers);
|
|
2889
|
+
if (lockState.heldForMs < minLockTimeout || lockState.heldBy.startsWith("init:") || lockState.heldBy.startsWith("headers:") || lockState.heldBy.startsWith("refresh:") || lockState.heldBy.startsWith("profile-reset:") || isAccountServingStream(accountId)) {
|
|
2845
2890
|
logger.warn(
|
|
2846
|
-
`[Playwright] Skipping destructive mutex recovery | account=${accountId} | heldBy=${lockState.heldBy} | heldFor=${lockState.heldForMs}ms | limit=${
|
|
2891
|
+
`[Playwright] Skipping destructive mutex recovery | account=${accountId} | heldBy=${lockState.heldBy} | heldFor=${lockState.heldForMs}ms | limit=${minLockTimeout}ms | servingStream=${isAccountServingStream(accountId)}`
|
|
2847
2892
|
);
|
|
2848
2893
|
return;
|
|
2849
2894
|
}
|
|
@@ -3757,6 +3802,22 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
3757
3802
|
}
|
|
3758
3803
|
}
|
|
3759
3804
|
}
|
|
3805
|
+
const currentCache = getHeaderCache(account.id);
|
|
3806
|
+
const currentCookie = currentCache?.headers?.cookie || "";
|
|
3807
|
+
if (currentCookie && isTokenExpiringSoon(currentCookie, 5)) {
|
|
3808
|
+
try {
|
|
3809
|
+
const refreshRes = await refreshAccountToken(account.id);
|
|
3810
|
+
if (refreshRes.success) {
|
|
3811
|
+
console.log(
|
|
3812
|
+
`\u26A1 [Playwright] Silently refreshed expired token restored from DB for ${maskEmail(account.email)}`
|
|
3813
|
+
);
|
|
3814
|
+
}
|
|
3815
|
+
} catch (err) {
|
|
3816
|
+
console.warn(
|
|
3817
|
+
`\u26A0\uFE0F [Playwright] Failed to proactively refresh expired token from DB for ${maskEmail(account.email)}: ${err?.message || err}`
|
|
3818
|
+
);
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3760
3821
|
return;
|
|
3761
3822
|
}
|
|
3762
3823
|
const cookies = await acctContext.cookies();
|
|
@@ -4014,7 +4075,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4014
4075
|
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
4015
4076
|
const requestId = crypto3.randomUUID();
|
|
4016
4077
|
const evalRes = await page.evaluate(
|
|
4017
|
-
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
|
|
4078
|
+
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz }) => {
|
|
4018
4079
|
try {
|
|
4019
4080
|
const response = await fetch(signinUrl2, {
|
|
4020
4081
|
method: "POST",
|
|
@@ -4026,7 +4087,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4026
4087
|
source: "web",
|
|
4027
4088
|
version: "0.3.11",
|
|
4028
4089
|
"x-request-origin": "https://chat.qwen.ai",
|
|
4029
|
-
timezone:
|
|
4090
|
+
timezone: tz,
|
|
4030
4091
|
"x-request-id": requestId2
|
|
4031
4092
|
},
|
|
4032
4093
|
body: JSON.stringify({ email: email2, password: password2 })
|
|
@@ -4037,7 +4098,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4037
4098
|
return { ok: false, error: e.message };
|
|
4038
4099
|
}
|
|
4039
4100
|
},
|
|
4040
|
-
{ email, password: hashedPassword, signinUrl, requestId }
|
|
4101
|
+
{ email, password: hashedPassword, signinUrl, requestId, tz: formatAsciiTimezone() }
|
|
4041
4102
|
).catch(() => null);
|
|
4042
4103
|
let data = evalRes?.data;
|
|
4043
4104
|
let signinSuccess = Boolean(
|
|
@@ -4046,7 +4107,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4046
4107
|
if (!signinSuccess && !data?.data?.code) {
|
|
4047
4108
|
const fallbackUrl = qwenUrl("/api/v2/auths/signin");
|
|
4048
4109
|
const fallbackRes = await page.evaluate(
|
|
4049
|
-
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
|
|
4110
|
+
async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz }) => {
|
|
4050
4111
|
try {
|
|
4051
4112
|
const response = await fetch(fallbackUrl2, {
|
|
4052
4113
|
method: "POST",
|
|
@@ -4057,7 +4118,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4057
4118
|
"content-type": "application/json",
|
|
4058
4119
|
source: "web",
|
|
4059
4120
|
version: "0.3.11",
|
|
4060
|
-
timezone:
|
|
4121
|
+
timezone: tz,
|
|
4061
4122
|
"x-request-id": requestId2
|
|
4062
4123
|
},
|
|
4063
4124
|
body: JSON.stringify({ email: email2, password: password2 })
|
|
@@ -4068,7 +4129,7 @@ async function loginViaApi(page, email, password) {
|
|
|
4068
4129
|
return { ok: false, error: e.message };
|
|
4069
4130
|
}
|
|
4070
4131
|
},
|
|
4071
|
-
{ email, password: hashedPassword, fallbackUrl, requestId }
|
|
4132
|
+
{ email, password: hashedPassword, fallbackUrl, requestId, tz: formatAsciiTimezone() }
|
|
4072
4133
|
).catch(() => null);
|
|
4073
4134
|
if (fallbackRes?.data) {
|
|
4074
4135
|
data = fallbackRes.data;
|
|
@@ -4400,7 +4461,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4400
4461
|
if (refreshToken) {
|
|
4401
4462
|
try {
|
|
4402
4463
|
const refreshResult = await page.evaluate(
|
|
4403
|
-
async ({ rTok }) => {
|
|
4464
|
+
async ({ rTok, tz }) => {
|
|
4404
4465
|
try {
|
|
4405
4466
|
const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
4406
4467
|
method: "GET",
|
|
@@ -4410,7 +4471,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4410
4471
|
source: "web",
|
|
4411
4472
|
version: "0.3.11",
|
|
4412
4473
|
"x-request-origin": "https://chat.qwen.ai",
|
|
4413
|
-
timezone:
|
|
4474
|
+
timezone: tz,
|
|
4414
4475
|
authorization: `Bearer ${rTok}`
|
|
4415
4476
|
}
|
|
4416
4477
|
});
|
|
@@ -4420,7 +4481,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4420
4481
|
return { ok: false, error: e.message };
|
|
4421
4482
|
}
|
|
4422
4483
|
},
|
|
4423
|
-
{ rTok: refreshToken }
|
|
4484
|
+
{ rTok: refreshToken, tz: formatAsciiTimezone() }
|
|
4424
4485
|
);
|
|
4425
4486
|
const json = refreshResult?.data;
|
|
4426
4487
|
if (json && json.success === true && json.data) {
|
|
@@ -4458,6 +4519,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4458
4519
|
const cache = getHeaderCache(accountId);
|
|
4459
4520
|
cache.headers.cookie = cookieStr;
|
|
4460
4521
|
cache.lastRefresh = Date.now();
|
|
4522
|
+
cookieCaches.set(accountId, { cookie: cookieStr, timestamp: Date.now() });
|
|
4461
4523
|
markAccountHeadersReady(accountId);
|
|
4462
4524
|
saveAuthSession2(accountId, {
|
|
4463
4525
|
cookie: cookieStr,
|
|
@@ -4492,6 +4554,7 @@ async function refreshAccountToken(accountId) {
|
|
|
4492
4554
|
const cache = getHeaderCache(accountId);
|
|
4493
4555
|
cache.headers.cookie = cookieStr;
|
|
4494
4556
|
cache.lastRefresh = Date.now();
|
|
4557
|
+
cookieCaches.set(accountId, { cookie: cookieStr, timestamp: Date.now() });
|
|
4495
4558
|
markAccountHeadersReady(accountId);
|
|
4496
4559
|
saveAuthSession2(accountId, {
|
|
4497
4560
|
cookie: cookieStr,
|
|
@@ -5372,6 +5435,7 @@ var init_playwright = __esm({
|
|
|
5372
5435
|
init_qwen_headers();
|
|
5373
5436
|
init_paths();
|
|
5374
5437
|
init_jwt();
|
|
5438
|
+
init_timezone();
|
|
5375
5439
|
requireLocal = createRequire(import.meta.url);
|
|
5376
5440
|
contextInitHooks = [];
|
|
5377
5441
|
ACCOUNT_MUTEX_MAX_HOLD_MS = 18e4;
|
|
@@ -5381,7 +5445,7 @@ var init_playwright = __esm({
|
|
|
5381
5445
|
inFlightAccountInits = /* @__PURE__ */ new Map();
|
|
5382
5446
|
headerCaches = /* @__PURE__ */ new Map();
|
|
5383
5447
|
HEADER_CACHE_TTL = 24 * 60 * 60 * 1e3;
|
|
5384
|
-
COOKIE_CACHE_TTL =
|
|
5448
|
+
COOKIE_CACHE_TTL = 60 * 1e3;
|
|
5385
5449
|
cookieCaches = /* @__PURE__ */ new Map();
|
|
5386
5450
|
lastAccountActivity = /* @__PURE__ */ new Map();
|
|
5387
5451
|
lastKeepAliveNavigation = /* @__PURE__ */ new Map();
|