qwenproxy-cli 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.pt-BR.md +7 -5
- package/dist/clean-cache.js +167 -68
- package/dist/delete-chats.js +212 -88
- package/dist/index.js +392 -267
- package/dist/login.js +172 -73
- package/dist/reset-cooldowns.js +167 -68
- package/dist/sync-clients.js +136 -126
- package/package.json +8 -6
- package/src/core/config.ts +13 -0
- package/src/core/version.ts +1 -1
- package/src/routes/chat/index.ts +1 -0
- package/src/services/playwright.ts +137 -43
- package/src/services/qwen.ts +47 -19
package/dist/delete-chats.js
CHANGED
|
@@ -925,6 +925,8 @@ var init_errors = __esm({
|
|
|
925
925
|
});
|
|
926
926
|
|
|
927
927
|
// src/core/config.ts
|
|
928
|
+
import fs6 from "node:fs";
|
|
929
|
+
import dotenv from "dotenv";
|
|
928
930
|
import { z } from "zod";
|
|
929
931
|
function isStatelessChatMode(mode) {
|
|
930
932
|
if (!mode) return false;
|
|
@@ -954,6 +956,15 @@ var envSchema, env, config;
|
|
|
954
956
|
var init_config = __esm({
|
|
955
957
|
"src/core/config.ts"() {
|
|
956
958
|
"use strict";
|
|
959
|
+
init_paths();
|
|
960
|
+
if (!isRunningUnderNodeTest()) {
|
|
961
|
+
const envPath = getEnvFilePath();
|
|
962
|
+
if (fs6.existsSync(envPath)) {
|
|
963
|
+
dotenv.config({ path: envPath, quiet: true });
|
|
964
|
+
} else {
|
|
965
|
+
dotenv.config({ quiet: true });
|
|
966
|
+
}
|
|
967
|
+
}
|
|
957
968
|
envSchema = z.object({
|
|
958
969
|
PORT: z.string().regex(/^\d+$/, "PORT must be a number").refine((value) => {
|
|
959
970
|
const port = Number(value);
|
|
@@ -2833,7 +2844,7 @@ __export(clean_cache_exports, {
|
|
|
2833
2844
|
getDirStats: () => getDirStats
|
|
2834
2845
|
});
|
|
2835
2846
|
import "dotenv/config";
|
|
2836
|
-
import
|
|
2847
|
+
import fs7 from "node:fs";
|
|
2837
2848
|
import path4 from "node:path";
|
|
2838
2849
|
import os3 from "node:os";
|
|
2839
2850
|
import { chromium } from "patchright";
|
|
@@ -2848,14 +2859,14 @@ function getDirStats(dir) {
|
|
|
2848
2859
|
let files = 0;
|
|
2849
2860
|
function walk(d) {
|
|
2850
2861
|
try {
|
|
2851
|
-
const entries =
|
|
2862
|
+
const entries = fs7.readdirSync(d, { withFileTypes: true });
|
|
2852
2863
|
for (const e of entries) {
|
|
2853
2864
|
const full = path4.join(d, e.name);
|
|
2854
2865
|
if (e.isDirectory()) {
|
|
2855
2866
|
walk(full);
|
|
2856
2867
|
} else if (e.isFile()) {
|
|
2857
2868
|
try {
|
|
2858
|
-
bytes +=
|
|
2869
|
+
bytes += fs7.statSync(full).size;
|
|
2859
2870
|
files++;
|
|
2860
2871
|
} catch {
|
|
2861
2872
|
}
|
|
@@ -2884,17 +2895,17 @@ async function cleanPlaywrightBrowsers(cleanUnused) {
|
|
|
2884
2895
|
}
|
|
2885
2896
|
} catch {
|
|
2886
2897
|
}
|
|
2887
|
-
if (!msPlaywrightDir || !
|
|
2898
|
+
if (!msPlaywrightDir || !fs7.existsSync(msPlaywrightDir)) {
|
|
2888
2899
|
const defaultPlaywrightDir = process.env.PLAYWRIGHT_BROWSERS_PATH || (process.platform === "win32" ? path4.join(os3.homedir(), "AppData", "Local", "ms-playwright") : process.platform === "darwin" ? path4.join(os3.homedir(), "Library", "Caches", "ms-playwright") : path4.join(os3.homedir(), ".cache", "ms-playwright"));
|
|
2889
|
-
if (
|
|
2900
|
+
if (fs7.existsSync(defaultPlaywrightDir)) {
|
|
2890
2901
|
msPlaywrightDir = defaultPlaywrightDir;
|
|
2891
2902
|
}
|
|
2892
2903
|
}
|
|
2893
2904
|
const unusedDirs = [];
|
|
2894
2905
|
let freedBytes = 0;
|
|
2895
|
-
if (msPlaywrightDir &&
|
|
2906
|
+
if (msPlaywrightDir && fs7.existsSync(msPlaywrightDir)) {
|
|
2896
2907
|
try {
|
|
2897
|
-
const entries =
|
|
2908
|
+
const entries = fs7.readdirSync(msPlaywrightDir, { withFileTypes: true });
|
|
2898
2909
|
for (const entry of entries) {
|
|
2899
2910
|
if (!entry.isDirectory()) continue;
|
|
2900
2911
|
const folderName = entry.name;
|
|
@@ -2917,7 +2928,7 @@ async function cleanPlaywrightBrowsers(cleanUnused) {
|
|
|
2917
2928
|
if (cleanUnused && unusedDirs.length > 0) {
|
|
2918
2929
|
for (const item of unusedDirs) {
|
|
2919
2930
|
try {
|
|
2920
|
-
|
|
2931
|
+
fs7.rmSync(item.path, { recursive: true, force: true });
|
|
2921
2932
|
freedBytes += item.bytes;
|
|
2922
2933
|
} catch (err) {
|
|
2923
2934
|
console.warn(`[CleanCache] Warning: could not remove ${item.name}:`, err);
|
|
@@ -3053,7 +3064,7 @@ __export(playwright_exports, {
|
|
|
3053
3064
|
});
|
|
3054
3065
|
import { chromium as chromium2 } from "patchright";
|
|
3055
3066
|
import path5 from "path";
|
|
3056
|
-
import
|
|
3067
|
+
import fs8 from "fs";
|
|
3057
3068
|
import crypto3 from "crypto";
|
|
3058
3069
|
import { spawnSync } from "child_process";
|
|
3059
3070
|
import { createRequire } from "module";
|
|
@@ -3067,7 +3078,7 @@ function autoInstallPlaywrightChromium() {
|
|
|
3067
3078
|
try {
|
|
3068
3079
|
const patchrightEntry = requireLocal.resolve("patchright");
|
|
3069
3080
|
const cliPath = path5.join(path5.dirname(patchrightEntry), "cli.js");
|
|
3070
|
-
if (
|
|
3081
|
+
if (fs8.existsSync(cliPath)) {
|
|
3071
3082
|
console.log("\u23F3 [Playwright] Navegador Chromium n\xE3o encontrado. Instalando automaticamente...");
|
|
3072
3083
|
const res2 = spawnSync(process.execPath, [cliPath, "install", "chromium"], {
|
|
3073
3084
|
stdio: "inherit",
|
|
@@ -3203,10 +3214,10 @@ function getStorageStatePath(accountId) {
|
|
|
3203
3214
|
function loadStorageState(accountId) {
|
|
3204
3215
|
const p1 = getStorageStatePath(accountId);
|
|
3205
3216
|
const p2 = path5.join(path5.dirname(p1), `${accountId}_state.json`);
|
|
3206
|
-
const chosenPath =
|
|
3217
|
+
const chosenPath = fs8.existsSync(p1) ? p1 : fs8.existsSync(p2) ? p2 : void 0;
|
|
3207
3218
|
if (!chosenPath) return void 0;
|
|
3208
3219
|
try {
|
|
3209
|
-
const raw =
|
|
3220
|
+
const raw = fs8.readFileSync(chosenPath, "utf8");
|
|
3210
3221
|
const state = JSON.parse(raw);
|
|
3211
3222
|
if (!state || typeof state !== "object" || !Array.isArray(state.cookies)) {
|
|
3212
3223
|
return void 0;
|
|
@@ -3220,8 +3231,8 @@ async function saveStorageState(context, accountId, timeoutMs = 5e3) {
|
|
|
3220
3231
|
try {
|
|
3221
3232
|
const stateFile = getStorageStatePath(accountId);
|
|
3222
3233
|
const dir = path5.dirname(stateFile);
|
|
3223
|
-
if (!
|
|
3224
|
-
|
|
3234
|
+
if (!fs8.existsSync(dir)) {
|
|
3235
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
3225
3236
|
}
|
|
3226
3237
|
await withTimeout(
|
|
3227
3238
|
context.storageState({ path: stateFile }),
|
|
@@ -3330,7 +3341,7 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
3330
3341
|
return false;
|
|
3331
3342
|
}
|
|
3332
3343
|
}
|
|
3333
|
-
async function getOrLaunchSharedBrowser(browserType = "chromium", headless =
|
|
3344
|
+
async function getOrLaunchSharedBrowser(browserType = "chromium", headless = config.playwright.headless) {
|
|
3334
3345
|
if (sharedBrowser && sharedBrowser.isConnected()) {
|
|
3335
3346
|
return sharedBrowser;
|
|
3336
3347
|
}
|
|
@@ -3390,13 +3401,40 @@ async function getOrLaunchSharedBrowser(browserType = "chromium", headless = tru
|
|
|
3390
3401
|
}
|
|
3391
3402
|
}
|
|
3392
3403
|
async function clearVisibleChallenge(page) {
|
|
3393
|
-
if (
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3404
|
+
if (page.isClosed()) return;
|
|
3405
|
+
if (config.captcha.enabled) {
|
|
3406
|
+
await solveBaxiaCaptcha(page, {
|
|
3407
|
+
waitForMs: 0,
|
|
3408
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
3409
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
3410
|
+
settleMs: config.captcha.settleMs
|
|
3411
|
+
}).catch(() => false);
|
|
3412
|
+
}
|
|
3413
|
+
try {
|
|
3414
|
+
const modalCloseSelectors = [
|
|
3415
|
+
".ant-modal-close",
|
|
3416
|
+
".ant-modal-close-x",
|
|
3417
|
+
"button.ant-modal-close",
|
|
3418
|
+
"button[aria-label*='Close' i]",
|
|
3419
|
+
"button[aria-label*='Fechar' i]",
|
|
3420
|
+
".index-module__whats-new-modal-close",
|
|
3421
|
+
"button:has-text('Cancel')",
|
|
3422
|
+
"button:has-text('Cancelar')",
|
|
3423
|
+
"button:has-text('I understand')",
|
|
3424
|
+
"button:has-text('Entendi')",
|
|
3425
|
+
"button:has-text('OK')"
|
|
3426
|
+
];
|
|
3427
|
+
for (const sel of modalCloseSelectors) {
|
|
3428
|
+
if (page.isClosed()) return;
|
|
3429
|
+
const btn = page.locator(sel).first();
|
|
3430
|
+
if (await btn.isVisible({ timeout: 150 }).catch(() => false)) {
|
|
3431
|
+
await btn.click({ timeout: 500 }).catch(() => {
|
|
3432
|
+
});
|
|
3433
|
+
await sleep2(200);
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
} catch {
|
|
3437
|
+
}
|
|
3400
3438
|
}
|
|
3401
3439
|
function getErrorMessage(error) {
|
|
3402
3440
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -3824,6 +3862,21 @@ function getStealthScript(profile) {
|
|
|
3824
3862
|
spoofedFunctions.add(window.performance.getEntriesByType);
|
|
3825
3863
|
}
|
|
3826
3864
|
} catch(e) {}
|
|
3865
|
+
|
|
3866
|
+
// --- Auto-resolve birthday compliance & eliminate false logout markers ---
|
|
3867
|
+
try {
|
|
3868
|
+
localStorage.removeItem("qwen_token_logged_out_marker");
|
|
3869
|
+
const b = localStorage.getItem("qwen_account_birthday");
|
|
3870
|
+
if (b) {
|
|
3871
|
+
try {
|
|
3872
|
+
const parsed = JSON.parse(b);
|
|
3873
|
+
if (!parsed.birthday) {
|
|
3874
|
+
parsed.birthday = "1995-06-15";
|
|
3875
|
+
localStorage.setItem("qwen_account_birthday", JSON.stringify(parsed));
|
|
3876
|
+
}
|
|
3877
|
+
} catch {}
|
|
3878
|
+
}
|
|
3879
|
+
} catch(e) {}
|
|
3827
3880
|
})();
|
|
3828
3881
|
`;
|
|
3829
3882
|
}
|
|
@@ -4122,7 +4175,7 @@ async function resolveAccountCredentials(account) {
|
|
|
4122
4175
|
}
|
|
4123
4176
|
return account;
|
|
4124
4177
|
}
|
|
4125
|
-
async function initPlaywrightForAccount(rawAccount, headless =
|
|
4178
|
+
async function initPlaywrightForAccount(rawAccount, headless = config.playwright.headless, browserType = "chromium", options = {}) {
|
|
4126
4179
|
const account = await resolveAccountCredentials(rawAccount);
|
|
4127
4180
|
if (accountPages.has(account.id)) {
|
|
4128
4181
|
console.log(
|
|
@@ -4248,7 +4301,7 @@ async function initPlaywrightForAccount(rawAccount, headless = true, browserType
|
|
|
4248
4301
|
const storageState = loadStorageState(account.id);
|
|
4249
4302
|
if (storageState) {
|
|
4250
4303
|
try {
|
|
4251
|
-
const raw =
|
|
4304
|
+
const raw = fs8.readFileSync(storageState, "utf8");
|
|
4252
4305
|
const parsed = JSON.parse(raw);
|
|
4253
4306
|
if (Array.isArray(parsed.cookies) && parsed.cookies.length > 0) {
|
|
4254
4307
|
const currentCookies = await acctContext.cookies();
|
|
@@ -4335,11 +4388,19 @@ async function initPlaywrightForAccount(rawAccount, headless = true, browserType
|
|
|
4335
4388
|
}
|
|
4336
4389
|
if (restoredFromDb) {
|
|
4337
4390
|
if (!acctPage.isClosed() && (acctPage.url() === "about:blank" || !acctPage.url().startsWith(qwenOrigin()))) {
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4391
|
+
try {
|
|
4392
|
+
await acctPage.goto(qwenUrl("/"), {
|
|
4393
|
+
waitUntil: "domcontentloaded",
|
|
4394
|
+
timeout: config.timeouts.navigation
|
|
4395
|
+
});
|
|
4396
|
+
await sleep2(300);
|
|
4397
|
+
} catch (err) {
|
|
4398
|
+
if (!err?.message?.includes("ERR_ABORTED")) {
|
|
4399
|
+
console.warn(
|
|
4400
|
+
`\u26A0\uFE0F [Playwright] Background navigation warning for ${maskEmail(account.email)}: ${err.message}`
|
|
4401
|
+
);
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4343
4404
|
}
|
|
4344
4405
|
return;
|
|
4345
4406
|
}
|
|
@@ -4460,7 +4521,7 @@ async function validateAccountLogin(rawAccount, headless = true, browserType = "
|
|
|
4460
4521
|
const storageState = loadStorageState(account.id);
|
|
4461
4522
|
if (storageState) {
|
|
4462
4523
|
try {
|
|
4463
|
-
const raw =
|
|
4524
|
+
const raw = fs8.readFileSync(storageState, "utf8");
|
|
4464
4525
|
const parsed = JSON.parse(raw);
|
|
4465
4526
|
if (Array.isArray(parsed.cookies) && parsed.cookies.length > 0) {
|
|
4466
4527
|
const currentCookies = await acctContext.cookies();
|
|
@@ -4579,18 +4640,34 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4579
4640
|
const apiResult = await loginViaApi(page, email, password);
|
|
4580
4641
|
if (apiResult.success) {
|
|
4581
4642
|
cookieCaches.delete(accountId);
|
|
4582
|
-
|
|
4583
|
-
if (cache) {
|
|
4584
|
-
cache.headers = {};
|
|
4585
|
-
cache.lastRefresh = 0;
|
|
4586
|
-
}
|
|
4587
|
-
unmarkAccountHeadersReady(accountId);
|
|
4643
|
+
await saveStorageState(page.context(), accountId);
|
|
4588
4644
|
try {
|
|
4589
|
-
const
|
|
4590
|
-
|
|
4645
|
+
const liveCookies = await page.context().cookies();
|
|
4646
|
+
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
4647
|
+
if (tokenCookie) {
|
|
4648
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
4649
|
+
const cache = getHeaderCache(accountId);
|
|
4650
|
+
cache.headers.cookie = cookieStr;
|
|
4651
|
+
cache.lastRefresh = Date.now();
|
|
4652
|
+
markAccountHeadersReady(accountId);
|
|
4653
|
+
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4654
|
+
const exp = parseJwtExpiry(tokenCookie.value);
|
|
4655
|
+
saveAuthSession2(accountId, {
|
|
4656
|
+
cookie: cookieStr,
|
|
4657
|
+
userAgent: cache.headers["user-agent"] || "",
|
|
4658
|
+
bxV: cache.headers["bx-v"] || "2.5.37",
|
|
4659
|
+
bxUa: cache.headers["bx-ua"] || "",
|
|
4660
|
+
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
4661
|
+
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
4662
|
+
secChUaMobile: cache.headers["sec-ch-ua-mobile"] || void 0,
|
|
4663
|
+
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
|
|
4664
|
+
version: cache.headers["version"] || void 0,
|
|
4665
|
+
tokenExpiresAt: exp || void 0,
|
|
4666
|
+
capturedAt: Date.now()
|
|
4667
|
+
});
|
|
4668
|
+
}
|
|
4591
4669
|
} catch {
|
|
4592
4670
|
}
|
|
4593
|
-
await saveStorageState(page.context(), accountId);
|
|
4594
4671
|
return true;
|
|
4595
4672
|
}
|
|
4596
4673
|
if (apiResult.permanentFailure) {
|
|
@@ -4607,18 +4684,34 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4607
4684
|
const uiResult = await loginViaUi(page, email, password);
|
|
4608
4685
|
if (uiResult.success) {
|
|
4609
4686
|
cookieCaches.delete(accountId);
|
|
4610
|
-
|
|
4611
|
-
if (cache) {
|
|
4612
|
-
cache.headers = {};
|
|
4613
|
-
cache.lastRefresh = 0;
|
|
4614
|
-
}
|
|
4615
|
-
unmarkAccountHeadersReady(accountId);
|
|
4687
|
+
await saveStorageState(page.context(), accountId);
|
|
4616
4688
|
try {
|
|
4617
|
-
const
|
|
4618
|
-
|
|
4689
|
+
const liveCookies = await page.context().cookies();
|
|
4690
|
+
const tokenCookie = liveCookies.find((c) => c.name === "token");
|
|
4691
|
+
if (tokenCookie) {
|
|
4692
|
+
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
4693
|
+
const cache = getHeaderCache(accountId);
|
|
4694
|
+
cache.headers.cookie = cookieStr;
|
|
4695
|
+
cache.lastRefresh = Date.now();
|
|
4696
|
+
markAccountHeadersReady(accountId);
|
|
4697
|
+
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4698
|
+
const exp = parseJwtExpiry(tokenCookie.value);
|
|
4699
|
+
saveAuthSession2(accountId, {
|
|
4700
|
+
cookie: cookieStr,
|
|
4701
|
+
userAgent: cache.headers["user-agent"] || "",
|
|
4702
|
+
bxV: cache.headers["bx-v"] || "2.5.37",
|
|
4703
|
+
bxUa: cache.headers["bx-ua"] || "",
|
|
4704
|
+
bxUmidtoken: cache.headers["bx-umidtoken"] || "",
|
|
4705
|
+
secChUa: cache.headers["sec-ch-ua"] || void 0,
|
|
4706
|
+
secChUaMobile: cache.headers["sec-ch-ua-mobile"] || void 0,
|
|
4707
|
+
secChUaPlatform: cache.headers["sec-ch-ua-platform"] || void 0,
|
|
4708
|
+
version: cache.headers["version"] || void 0,
|
|
4709
|
+
tokenExpiresAt: exp || void 0,
|
|
4710
|
+
capturedAt: Date.now()
|
|
4711
|
+
});
|
|
4712
|
+
}
|
|
4619
4713
|
} catch {
|
|
4620
4714
|
}
|
|
4621
|
-
await saveStorageState(page.context(), accountId);
|
|
4622
4715
|
return true;
|
|
4623
4716
|
}
|
|
4624
4717
|
if (uiResult.permanentFailure) {
|
|
@@ -4817,10 +4910,16 @@ async function loginViaUi(page, email, password) {
|
|
|
4817
4910
|
);
|
|
4818
4911
|
return { success: false, reason: "Campo de e-mail n\xE3o encontrado (poss\xEDvel captcha)" };
|
|
4819
4912
|
}
|
|
4913
|
+
await clearVisibleChallenge(page);
|
|
4914
|
+
const findPasswordModeButton = () => {
|
|
4915
|
+
return page.locator('button, [role="button"], a, div').filter({
|
|
4916
|
+
hasText: /(?:log\s*in\s*with\s*(?:a\s*)?password|fazer\s*login\s*com\s*senha|entrar\s*com\s*(?:uma\s*)?senha|iniciar\s*sesi[oó]n\s*con\s*contrase[nñ]a|密码登录)/i
|
|
4917
|
+
}).first();
|
|
4918
|
+
};
|
|
4820
4919
|
try {
|
|
4821
|
-
const pwdModeBtn =
|
|
4822
|
-
if (await pwdModeBtn.isVisible({ timeout:
|
|
4823
|
-
await pwdModeBtn.click().catch(() => {
|
|
4920
|
+
const pwdModeBtn = findPasswordModeButton();
|
|
4921
|
+
if (await pwdModeBtn.isVisible({ timeout: 2e3 }).catch(() => false)) {
|
|
4922
|
+
await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
|
|
4824
4923
|
});
|
|
4825
4924
|
await sleep2(500);
|
|
4826
4925
|
}
|
|
@@ -4829,9 +4928,9 @@ async function loginViaUi(page, email, password) {
|
|
|
4829
4928
|
await page.fill(emailSelector, email);
|
|
4830
4929
|
await sleep2(300);
|
|
4831
4930
|
try {
|
|
4832
|
-
const pwdModeBtn =
|
|
4833
|
-
if (await pwdModeBtn.isVisible({ timeout:
|
|
4834
|
-
await pwdModeBtn.click().catch(() => {
|
|
4931
|
+
const pwdModeBtn = findPasswordModeButton();
|
|
4932
|
+
if (await pwdModeBtn.isVisible({ timeout: 1500 }).catch(() => false)) {
|
|
4933
|
+
await pwdModeBtn.click({ timeout: 2e3 }).catch(() => {
|
|
4835
4934
|
});
|
|
4836
4935
|
await sleep2(500);
|
|
4837
4936
|
}
|
|
@@ -4856,7 +4955,7 @@ async function loginViaUi(page, email, password) {
|
|
|
4856
4955
|
}
|
|
4857
4956
|
await page.fill(passwordSelector, password);
|
|
4858
4957
|
await sleep2(500);
|
|
4859
|
-
const submitSelector = 'button.qwenchat-auth-pc-submit-button, button[type="submit"], button:has-text("Log in"), button:has-text("Sign in")';
|
|
4958
|
+
const submitSelector = 'button.qwenchat-auth-pc-submit-button, button[type="submit"], button:has-text("Log in"), button:has-text("Sign in"), button:has-text("Fazer login"), button:has-text("Entrar"), button:has-text("Iniciar sesi\xF3n"), button:has-text("\u767B\u5F55")';
|
|
4860
4959
|
const submitButton = page.locator(submitSelector).first();
|
|
4861
4960
|
try {
|
|
4862
4961
|
await page.waitForSelector('button[type="submit"]:not([disabled])', {
|
|
@@ -5461,7 +5560,7 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
5461
5560
|
await executeReauth();
|
|
5462
5561
|
}
|
|
5463
5562
|
}
|
|
5464
|
-
if (
|
|
5563
|
+
if (hasRequiredQwenHeaders(cache.headers)) {
|
|
5465
5564
|
const liveCookies = await page.context().cookies();
|
|
5466
5565
|
if (liveCookies.some((c) => c.name === "token")) {
|
|
5467
5566
|
const cookieStr = liveCookies.map((c) => `${c.name}=${c.value}`).join("; ");
|
|
@@ -5577,12 +5676,12 @@ async function resetPlaywrightProfileLocked(accountId) {
|
|
|
5577
5676
|
removePlaywrightProfile(profilePath);
|
|
5578
5677
|
const stateFile2 = path5.join(path5.dirname(profilePath), `${accountId}_state.json`);
|
|
5579
5678
|
try {
|
|
5580
|
-
|
|
5679
|
+
fs8.rmSync(stateFile2, { force: true });
|
|
5581
5680
|
} catch {
|
|
5582
5681
|
}
|
|
5583
5682
|
}
|
|
5584
5683
|
function removePlaywrightProfile(profilePath, rmSyncOverride) {
|
|
5585
|
-
const doRemove = rmSyncOverride ?? ((p, opts) =>
|
|
5684
|
+
const doRemove = rmSyncOverride ?? ((p, opts) => fs8.rmSync(p, opts));
|
|
5586
5685
|
try {
|
|
5587
5686
|
doRemove(profilePath, { recursive: true, force: true });
|
|
5588
5687
|
} catch (error) {
|
|
@@ -5591,7 +5690,7 @@ function removePlaywrightProfile(profilePath, rmSyncOverride) {
|
|
|
5591
5690
|
if (message.includes("EPERM") || message.includes("EBUSY") || message.includes("Permission denied")) {
|
|
5592
5691
|
try {
|
|
5593
5692
|
const stalePath = `${profilePath}.stale-${Date.now()}`;
|
|
5594
|
-
|
|
5693
|
+
fs8.renameSync(profilePath, stalePath);
|
|
5595
5694
|
} catch {
|
|
5596
5695
|
}
|
|
5597
5696
|
return;
|
|
@@ -5614,23 +5713,23 @@ function prunePlaywrightProfileCaches(profilePath) {
|
|
|
5614
5713
|
let freedFiles = 0;
|
|
5615
5714
|
try {
|
|
5616
5715
|
const defaultDir = path5.join(profilePath, "Default");
|
|
5617
|
-
if (!
|
|
5716
|
+
if (!fs8.existsSync(defaultDir)) {
|
|
5618
5717
|
return { freedBytes, freedFiles };
|
|
5619
5718
|
}
|
|
5620
5719
|
for (const dirName of transientDirNames) {
|
|
5621
5720
|
const targetDir = path5.join(defaultDir, dirName);
|
|
5622
|
-
if (
|
|
5721
|
+
if (fs8.existsSync(targetDir)) {
|
|
5623
5722
|
try {
|
|
5624
5723
|
const countAndRemove = (d) => {
|
|
5625
5724
|
try {
|
|
5626
|
-
const entries =
|
|
5725
|
+
const entries = fs8.readdirSync(d, { withFileTypes: true });
|
|
5627
5726
|
for (const e of entries) {
|
|
5628
5727
|
const full = path5.join(d, e.name);
|
|
5629
5728
|
if (e.isDirectory()) {
|
|
5630
5729
|
countAndRemove(full);
|
|
5631
5730
|
} else if (e.isFile()) {
|
|
5632
5731
|
try {
|
|
5633
|
-
freedBytes +=
|
|
5732
|
+
freedBytes += fs8.statSync(full).size;
|
|
5634
5733
|
freedFiles++;
|
|
5635
5734
|
} catch {
|
|
5636
5735
|
}
|
|
@@ -5640,7 +5739,7 @@ function prunePlaywrightProfileCaches(profilePath) {
|
|
|
5640
5739
|
}
|
|
5641
5740
|
};
|
|
5642
5741
|
countAndRemove(targetDir);
|
|
5643
|
-
|
|
5742
|
+
fs8.rmSync(targetDir, { recursive: true, force: true });
|
|
5644
5743
|
} catch {
|
|
5645
5744
|
}
|
|
5646
5745
|
}
|
|
@@ -5654,10 +5753,10 @@ function pruneAllPlaywrightProfiles(baseDir = getProfilesDir()) {
|
|
|
5654
5753
|
let totalFreedFiles = 0;
|
|
5655
5754
|
let profilesCleaned = 0;
|
|
5656
5755
|
try {
|
|
5657
|
-
if (!
|
|
5756
|
+
if (!fs8.existsSync(baseDir)) {
|
|
5658
5757
|
return { totalFreedBytes, totalFreedFiles, profilesCleaned };
|
|
5659
5758
|
}
|
|
5660
|
-
const entries =
|
|
5759
|
+
const entries = fs8.readdirSync(baseDir, { withFileTypes: true });
|
|
5661
5760
|
for (const entry of entries) {
|
|
5662
5761
|
if (entry.isDirectory()) {
|
|
5663
5762
|
const profilePath = path5.join(baseDir, entry.name);
|
|
@@ -5677,11 +5776,11 @@ function cleanupOrphanProfiles(baseDir = getProfilesDir(), activeAccountIds) {
|
|
|
5677
5776
|
let removedCount = 0;
|
|
5678
5777
|
let freedBytes = 0;
|
|
5679
5778
|
try {
|
|
5680
|
-
if (!
|
|
5779
|
+
if (!fs8.existsSync(baseDir)) {
|
|
5681
5780
|
return { removedCount, freedBytes };
|
|
5682
5781
|
}
|
|
5683
5782
|
const activeIds = activeAccountIds ?? new Set(loadAccounts().map((a) => a.id));
|
|
5684
|
-
const entries =
|
|
5783
|
+
const entries = fs8.readdirSync(baseDir, { withFileTypes: true });
|
|
5685
5784
|
for (const entry of entries) {
|
|
5686
5785
|
if (!entry.isDirectory()) continue;
|
|
5687
5786
|
const isStale = entry.name.includes(".stale-");
|
|
@@ -5692,13 +5791,13 @@ function cleanupOrphanProfiles(baseDir = getProfilesDir(), activeAccountIds) {
|
|
|
5692
5791
|
let bytes = 0;
|
|
5693
5792
|
const countSize = (d) => {
|
|
5694
5793
|
try {
|
|
5695
|
-
const subEntries =
|
|
5794
|
+
const subEntries = fs8.readdirSync(d, { withFileTypes: true });
|
|
5696
5795
|
for (const e of subEntries) {
|
|
5697
5796
|
const full = path5.join(d, e.name);
|
|
5698
5797
|
if (e.isDirectory()) countSize(full);
|
|
5699
5798
|
else if (e.isFile()) {
|
|
5700
5799
|
try {
|
|
5701
|
-
bytes +=
|
|
5800
|
+
bytes += fs8.statSync(full).size;
|
|
5702
5801
|
} catch {
|
|
5703
5802
|
}
|
|
5704
5803
|
}
|
|
@@ -5708,7 +5807,7 @@ function cleanupOrphanProfiles(baseDir = getProfilesDir(), activeAccountIds) {
|
|
|
5708
5807
|
};
|
|
5709
5808
|
countSize(targetPath);
|
|
5710
5809
|
removePlaywrightProfile(targetPath);
|
|
5711
|
-
if (!
|
|
5810
|
+
if (!fs8.existsSync(targetPath)) {
|
|
5712
5811
|
removedCount++;
|
|
5713
5812
|
freedBytes += bytes;
|
|
5714
5813
|
}
|
|
@@ -7871,10 +7970,17 @@ async function withQwenBrowserPage(accountId, fn, targetPath, operationTimeoutMs
|
|
|
7871
7970
|
}
|
|
7872
7971
|
const needsNavigation = currentOrigin !== targetOrigin || normalizedTargetPath !== null && currentPath !== normalizedTargetPath;
|
|
7873
7972
|
if (needsNavigation) {
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7973
|
+
try {
|
|
7974
|
+
await page.goto(targetUrl, {
|
|
7975
|
+
waitUntil: "domcontentloaded",
|
|
7976
|
+
timeout: Math.min(config.timeouts.navigation, operationTimeoutMs)
|
|
7977
|
+
});
|
|
7978
|
+
} catch (err) {
|
|
7979
|
+
if (err?.message?.includes("ERR_ABORTED") && page.url().startsWith(targetOrigin)) {
|
|
7980
|
+
} else {
|
|
7981
|
+
throw err;
|
|
7982
|
+
}
|
|
7983
|
+
}
|
|
7878
7984
|
}
|
|
7879
7985
|
return fn(page);
|
|
7880
7986
|
},
|
|
@@ -7926,7 +8032,7 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
7926
8032
|
const controller = new AbortController();
|
|
7927
8033
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
7928
8034
|
try {
|
|
7929
|
-
|
|
8035
|
+
let response2 = await fetch(url2, {
|
|
7930
8036
|
method: method2,
|
|
7931
8037
|
credentials: "include",
|
|
7932
8038
|
headers: headers2,
|
|
@@ -7934,6 +8040,36 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
|
|
|
7934
8040
|
signal: controller.signal,
|
|
7935
8041
|
...referrer ? { referrer } : {}
|
|
7936
8042
|
});
|
|
8043
|
+
if (response2.status === 401) {
|
|
8044
|
+
try {
|
|
8045
|
+
const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
8046
|
+
method: "GET",
|
|
8047
|
+
credentials: "include",
|
|
8048
|
+
signal: AbortSignal.timeout(3e3)
|
|
8049
|
+
});
|
|
8050
|
+
if (refreshRes.status === 200) {
|
|
8051
|
+
const refreshJson = await refreshRes.json().catch(() => null);
|
|
8052
|
+
if (refreshJson && refreshJson.success === true && refreshJson.data?.token) {
|
|
8053
|
+
const freshTok = refreshJson.data.token;
|
|
8054
|
+
localStorage.setItem("token", freshTok);
|
|
8055
|
+
document.cookie = `token=${encodeURIComponent(freshTok)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
8056
|
+
if (headers2["authorization"] || headers2["Authorization"]) {
|
|
8057
|
+
headers2["authorization"] = `Bearer ${freshTok}`;
|
|
8058
|
+
headers2["Authorization"] = `Bearer ${freshTok}`;
|
|
8059
|
+
}
|
|
8060
|
+
response2 = await fetch(url2, {
|
|
8061
|
+
method: method2,
|
|
8062
|
+
credentials: "include",
|
|
8063
|
+
headers: headers2,
|
|
8064
|
+
body: body2,
|
|
8065
|
+
signal: controller.signal,
|
|
8066
|
+
...referrer ? { referrer } : {}
|
|
8067
|
+
});
|
|
8068
|
+
}
|
|
8069
|
+
}
|
|
8070
|
+
} catch {
|
|
8071
|
+
}
|
|
8072
|
+
}
|
|
7937
8073
|
return {
|
|
7938
8074
|
status: response2.status,
|
|
7939
8075
|
contentType: response2.headers.get("content-type") || "",
|
|
@@ -8035,18 +8171,6 @@ async function requestQwenSettingsDirectFetch(accountId, method, path6, headers,
|
|
|
8035
8171
|
}
|
|
8036
8172
|
}
|
|
8037
8173
|
async function requestQwenPersonalizationInBrowser(accountId, method, path6, headers, payload) {
|
|
8038
|
-
if (!config.qwen.browserOnlyFetch && !isAuthMockEnabled()) {
|
|
8039
|
-
const direct = await requestQwenSettingsDirectFetch(
|
|
8040
|
-
accountId,
|
|
8041
|
-
method,
|
|
8042
|
-
path6,
|
|
8043
|
-
headers,
|
|
8044
|
-
payload
|
|
8045
|
-
);
|
|
8046
|
-
if (direct) {
|
|
8047
|
-
return direct;
|
|
8048
|
-
}
|
|
8049
|
-
}
|
|
8050
8174
|
const response = await requestQwenTextInBrowser(
|
|
8051
8175
|
accountId,
|
|
8052
8176
|
method,
|