qwenproxy-cli 1.6.0 → 1.6.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clean-cache.js +54 -7
- package/dist/delete-chats.js +380 -12
- package/dist/index.js +774 -117
- package/dist/login.js +432 -13
- package/dist/reset-cooldowns.js +64 -7
- package/dist/sync-clients.js +2 -2
- package/package.json +3 -3
- package/src/clean-cache.ts +3 -0
- package/src/core/accounts.ts +1 -1
- package/src/core/config.ts +2 -2
- package/src/core/process-guard.ts +77 -0
- package/src/core/version.ts +1 -1
- package/src/delete-chats.ts +3 -0
- package/src/index.ts +3 -29
- package/src/login.ts +92 -4
- package/src/routes/chat/account.ts +11 -4
- package/src/routes/chat/retry-policy.ts +75 -3
- package/src/routes/chat/streaming.ts +68 -1
- package/src/services/chat-cleanup.ts +5 -0
- package/src/services/playwright.ts +384 -6
- package/src/services/qwen.ts +22 -6
- package/src/tui/views/accounts-view.ts +313 -96
- package/src/utils/overload-detector.ts +55 -0
package/dist/clean-cache.js
CHANGED
|
@@ -781,7 +781,7 @@ function addAccountsBatch(entries) {
|
|
|
781
781
|
}
|
|
782
782
|
return { added, skipped, invalid };
|
|
783
783
|
}
|
|
784
|
-
function addAccount(email, password, id) {
|
|
784
|
+
function addAccount(email, password = "", id) {
|
|
785
785
|
if (!email || typeof email !== "string" || email.trim().length === 0) {
|
|
786
786
|
throw new Error("Email is required");
|
|
787
787
|
}
|
|
@@ -1016,11 +1016,11 @@ var init_config = __esm({
|
|
|
1016
1016
|
// nothing in this window is dead and should fail fast, retryable).
|
|
1017
1017
|
QWEN_FIRST_CHUNK_TIMEOUT: z.string().default("60000"),
|
|
1018
1018
|
TOTAL_REQUEST_TIMEOUT: z.string().default("600000"),
|
|
1019
|
-
// Mid-stream silence window for thinking models:
|
|
1019
|
+
// Mid-stream silence window for thinking models: 5 min with ZERO upstream
|
|
1020
1020
|
// bytes is a dead stream (WAF swallow / dropped connection) — fail fast and
|
|
1021
1021
|
// let the retry policy rotate accounts. Flowing reasoning chunks RESET this
|
|
1022
1022
|
// timer, so legitimate slow thinking is never cut; only total silence is.
|
|
1023
|
-
REASONING_MODEL_TIMEOUT: z.string().default("
|
|
1023
|
+
REASONING_MODEL_TIMEOUT: z.string().default("300000"),
|
|
1024
1024
|
CACHE_TTL: z.string().default("3600"),
|
|
1025
1025
|
RESPONSE_TTL: z.string().default("1800"),
|
|
1026
1026
|
CACHE_COMPRESSION_ENABLED: z.string().default("true"),
|
|
@@ -2848,15 +2848,18 @@ function loadStorageState(accountId) {
|
|
|
2848
2848
|
return void 0;
|
|
2849
2849
|
}
|
|
2850
2850
|
}
|
|
2851
|
-
async function saveStorageState(context, accountId, timeoutMs =
|
|
2851
|
+
async function saveStorageState(context, accountId, timeoutMs = 1e4) {
|
|
2852
2852
|
try {
|
|
2853
2853
|
const stateFile = getStorageStatePath(accountId);
|
|
2854
2854
|
const dir = path4.dirname(stateFile);
|
|
2855
2855
|
if (!fs7.existsSync(dir)) {
|
|
2856
2856
|
fs7.mkdirSync(dir, { recursive: true });
|
|
2857
2857
|
}
|
|
2858
|
+
const rawPromise = context.storageState({ path: stateFile }).catch(() => {
|
|
2859
|
+
return void 0;
|
|
2860
|
+
});
|
|
2858
2861
|
await withTimeout(
|
|
2859
|
-
|
|
2862
|
+
rawPromise,
|
|
2860
2863
|
timeoutMs,
|
|
2861
2864
|
`storageState timed out after ${timeoutMs}ms`
|
|
2862
2865
|
);
|
|
@@ -2960,6 +2963,10 @@ async function clearVisibleChallenge(page) {
|
|
|
2960
2963
|
"button[aria-label*='Close' i]",
|
|
2961
2964
|
"button[aria-label*='Fechar' i]",
|
|
2962
2965
|
".index-module__whats-new-modal-close",
|
|
2966
|
+
".age-confirmation-modal button",
|
|
2967
|
+
".age-confirmation-modal .qwen-chat-v2-btn-black",
|
|
2968
|
+
"button:has-text('Continuar')",
|
|
2969
|
+
"button:has-text('Continue')",
|
|
2963
2970
|
"button:has-text('Cancel')",
|
|
2964
2971
|
"button:has-text('Cancelar')",
|
|
2965
2972
|
"button:has-text('I understand')",
|
|
@@ -5319,8 +5326,8 @@ var init_playwright = __esm({
|
|
|
5319
5326
|
PLAYWRIGHT_MUTEX_WAIT_MS = 6e4;
|
|
5320
5327
|
ACCOUNT_PAGE_OPERATION_TIMEOUT_MS = config.timeouts.page;
|
|
5321
5328
|
SESSION_PROBE_NAVIGATION_TIMEOUT_MS = 15e3;
|
|
5322
|
-
HEADER_CAPTURE_TRIGGER_GRACE_MS =
|
|
5323
|
-
FIRST_TRIGGER_GRACE_MS =
|
|
5329
|
+
HEADER_CAPTURE_TRIGGER_GRACE_MS = 2e4;
|
|
5330
|
+
FIRST_TRIGGER_GRACE_MS = 12e3;
|
|
5324
5331
|
HEADER_CAPTURE_TRIGGER_ATTEMPTS = 3;
|
|
5325
5332
|
CHAT_INPUT_APPEAR_TIMEOUT_MS = 15e3;
|
|
5326
5333
|
CHAT_INPUT_ACTION_TIMEOUT_MS = 1e4;
|
|
@@ -5336,6 +5343,44 @@ var init_playwright = __esm({
|
|
|
5336
5343
|
}
|
|
5337
5344
|
});
|
|
5338
5345
|
|
|
5346
|
+
// src/core/process-guard.ts
|
|
5347
|
+
function isPlaywrightAlreadyClosedMessage(message) {
|
|
5348
|
+
if (!message) return false;
|
|
5349
|
+
return message.includes("Target page, context or browser has been closed") || message.includes("Browser has been closed") || message.includes("Target closed") || message.includes("Target crashed") || message.includes("Page crashed") || message.includes("Assertion error") || message.includes("Cannot find parent object") || message.includes("Connection closed") || message.includes("session closed") || message.includes("Session closed") || message.includes("Network.setCacheDisabled") || message.includes("Protocol error") || message.includes("storageState timed out");
|
|
5350
|
+
}
|
|
5351
|
+
function isBenignTeardownError(error) {
|
|
5352
|
+
if (!error) return false;
|
|
5353
|
+
const message = error instanceof Error ? error.message : typeof error === "object" && "message" in error ? String(error.message) : String(error);
|
|
5354
|
+
return isPlaywrightAlreadyClosedMessage(message);
|
|
5355
|
+
}
|
|
5356
|
+
function installProcessTeardownGuards(label = "Process") {
|
|
5357
|
+
if (guardsInstalled) return;
|
|
5358
|
+
guardsInstalled = true;
|
|
5359
|
+
process.on("uncaughtException", (error) => {
|
|
5360
|
+
if (isBenignTeardownError(error)) {
|
|
5361
|
+
const msg = error instanceof Error ? error.message : typeof error === "object" && error !== null && "message" in error ? String(error.message) : String(error);
|
|
5362
|
+
console.warn(`\u26A0\uFE0F [${label}] Handled benign driver teardown exception: ${msg}`);
|
|
5363
|
+
return;
|
|
5364
|
+
}
|
|
5365
|
+
console.error(`\u274C [${label}] Uncaught Exception:`, error);
|
|
5366
|
+
});
|
|
5367
|
+
process.on("unhandledRejection", (reason) => {
|
|
5368
|
+
if (isBenignTeardownError(reason)) {
|
|
5369
|
+
const msg = reason instanceof Error ? reason.message : typeof reason === "object" && reason !== null && "message" in reason ? String(reason.message) : String(reason);
|
|
5370
|
+
console.warn(`\u26A0\uFE0F [${label}] Handled benign driver teardown rejection: ${msg}`);
|
|
5371
|
+
return;
|
|
5372
|
+
}
|
|
5373
|
+
console.error(`\u274C [${label}] Unhandled Rejection:`, reason);
|
|
5374
|
+
});
|
|
5375
|
+
}
|
|
5376
|
+
var guardsInstalled;
|
|
5377
|
+
var init_process_guard = __esm({
|
|
5378
|
+
"src/core/process-guard.ts"() {
|
|
5379
|
+
"use strict";
|
|
5380
|
+
guardsInstalled = false;
|
|
5381
|
+
}
|
|
5382
|
+
});
|
|
5383
|
+
|
|
5339
5384
|
// src/clean-cache.ts
|
|
5340
5385
|
var clean_cache_exports = {};
|
|
5341
5386
|
__export(clean_cache_exports, {
|
|
@@ -5503,6 +5548,8 @@ var isDirectRun;
|
|
|
5503
5548
|
var init_clean_cache = __esm({
|
|
5504
5549
|
"src/clean-cache.ts"() {
|
|
5505
5550
|
init_playwright();
|
|
5551
|
+
init_process_guard();
|
|
5552
|
+
installProcessTeardownGuards("CleanCache");
|
|
5506
5553
|
isDirectRun = process.argv[1] && (process.argv[1].endsWith("clean-cache.ts") || process.argv[1].endsWith("clean-cache.js"));
|
|
5507
5554
|
if (isDirectRun) {
|
|
5508
5555
|
main().catch((err) => {
|
package/dist/delete-chats.js
CHANGED
|
@@ -13,6 +13,44 @@ var __export = (target, all) => {
|
|
|
13
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
// src/core/process-guard.ts
|
|
17
|
+
function isPlaywrightAlreadyClosedMessage(message) {
|
|
18
|
+
if (!message) return false;
|
|
19
|
+
return message.includes("Target page, context or browser has been closed") || message.includes("Browser has been closed") || message.includes("Target closed") || message.includes("Target crashed") || message.includes("Page crashed") || message.includes("Assertion error") || message.includes("Cannot find parent object") || message.includes("Connection closed") || message.includes("session closed") || message.includes("Session closed") || message.includes("Network.setCacheDisabled") || message.includes("Protocol error") || message.includes("storageState timed out");
|
|
20
|
+
}
|
|
21
|
+
function isBenignTeardownError(error) {
|
|
22
|
+
if (!error) return false;
|
|
23
|
+
const message = error instanceof Error ? error.message : typeof error === "object" && "message" in error ? String(error.message) : String(error);
|
|
24
|
+
return isPlaywrightAlreadyClosedMessage(message);
|
|
25
|
+
}
|
|
26
|
+
function installProcessTeardownGuards(label = "Process") {
|
|
27
|
+
if (guardsInstalled) return;
|
|
28
|
+
guardsInstalled = true;
|
|
29
|
+
process.on("uncaughtException", (error) => {
|
|
30
|
+
if (isBenignTeardownError(error)) {
|
|
31
|
+
const msg = error instanceof Error ? error.message : typeof error === "object" && error !== null && "message" in error ? String(error.message) : String(error);
|
|
32
|
+
console.warn(`\u26A0\uFE0F [${label}] Handled benign driver teardown exception: ${msg}`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
console.error(`\u274C [${label}] Uncaught Exception:`, error);
|
|
36
|
+
});
|
|
37
|
+
process.on("unhandledRejection", (reason) => {
|
|
38
|
+
if (isBenignTeardownError(reason)) {
|
|
39
|
+
const msg = reason instanceof Error ? reason.message : typeof reason === "object" && reason !== null && "message" in reason ? String(reason.message) : String(reason);
|
|
40
|
+
console.warn(`\u26A0\uFE0F [${label}] Handled benign driver teardown rejection: ${msg}`);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
console.error(`\u274C [${label}] Unhandled Rejection:`, reason);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
var guardsInstalled;
|
|
47
|
+
var init_process_guard = __esm({
|
|
48
|
+
"src/core/process-guard.ts"() {
|
|
49
|
+
"use strict";
|
|
50
|
+
guardsInstalled = false;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
16
54
|
// src/core/paths.ts
|
|
17
55
|
import fs from "node:fs";
|
|
18
56
|
import path from "node:path";
|
|
@@ -781,7 +819,7 @@ function addAccountsBatch(entries) {
|
|
|
781
819
|
}
|
|
782
820
|
return { added, skipped, invalid };
|
|
783
821
|
}
|
|
784
|
-
function addAccount(email, password, id) {
|
|
822
|
+
function addAccount(email, password = "", id) {
|
|
785
823
|
if (!email || typeof email !== "string" || email.trim().length === 0) {
|
|
786
824
|
throw new Error("Email is required");
|
|
787
825
|
}
|
|
@@ -1071,11 +1109,11 @@ var init_config = __esm({
|
|
|
1071
1109
|
// nothing in this window is dead and should fail fast, retryable).
|
|
1072
1110
|
QWEN_FIRST_CHUNK_TIMEOUT: z.string().default("60000"),
|
|
1073
1111
|
TOTAL_REQUEST_TIMEOUT: z.string().default("600000"),
|
|
1074
|
-
// Mid-stream silence window for thinking models:
|
|
1112
|
+
// Mid-stream silence window for thinking models: 5 min with ZERO upstream
|
|
1075
1113
|
// bytes is a dead stream (WAF swallow / dropped connection) — fail fast and
|
|
1076
1114
|
// let the retry policy rotate accounts. Flowing reasoning chunks RESET this
|
|
1077
1115
|
// timer, so legitimate slow thinking is never cut; only total silence is.
|
|
1078
|
-
REASONING_MODEL_TIMEOUT: z.string().default("
|
|
1116
|
+
REASONING_MODEL_TIMEOUT: z.string().default("300000"),
|
|
1079
1117
|
CACHE_TTL: z.string().default("3600"),
|
|
1080
1118
|
RESPONSE_TTL: z.string().default("1800"),
|
|
1081
1119
|
CACHE_COMPRESSION_ENABLED: z.string().default("true"),
|
|
@@ -3105,6 +3143,8 @@ var init_clean_cache = __esm({
|
|
|
3105
3143
|
"src/clean-cache.ts"() {
|
|
3106
3144
|
"use strict";
|
|
3107
3145
|
init_playwright();
|
|
3146
|
+
init_process_guard();
|
|
3147
|
+
installProcessTeardownGuards("CleanCache");
|
|
3108
3148
|
isDirectRun = process.argv[1] && (process.argv[1].endsWith("clean-cache.ts") || process.argv[1].endsWith("clean-cache.js"));
|
|
3109
3149
|
if (isDirectRun) {
|
|
3110
3150
|
main().catch((err) => {
|
|
@@ -3120,6 +3160,7 @@ var playwright_exports = {};
|
|
|
3120
3160
|
__export(playwright_exports, {
|
|
3121
3161
|
assertAntiBotHeaders: () => assertAntiBotHeaders,
|
|
3122
3162
|
buildChromiumLaunchArgs: () => buildChromiumLaunchArgs,
|
|
3163
|
+
cancelEmailOtpLogin: () => cancelEmailOtpLogin,
|
|
3123
3164
|
captureQwenHeaders: () => captureQwenHeaders,
|
|
3124
3165
|
classifyQwenAuthError: () => classifyQwenAuthError,
|
|
3125
3166
|
cleanupOrphanProfiles: () => cleanupOrphanProfiles,
|
|
@@ -3160,8 +3201,10 @@ __export(playwright_exports, {
|
|
|
3160
3201
|
removePlaywrightProfile: () => removePlaywrightProfile,
|
|
3161
3202
|
saveStorageState: () => saveStorageState,
|
|
3162
3203
|
schedulePlaywrightProfileReset: () => schedulePlaywrightProfileReset,
|
|
3204
|
+
startEmailOtpLogin: () => startEmailOtpLogin,
|
|
3163
3205
|
unregisterPlaywrightAccountForTests: () => unregisterPlaywrightAccountForTests,
|
|
3164
3206
|
validateAccountLogin: () => validateAccountLogin,
|
|
3207
|
+
verifyEmailOtpLogin: () => verifyEmailOtpLogin,
|
|
3165
3208
|
withAccountPage: () => withAccountPage
|
|
3166
3209
|
});
|
|
3167
3210
|
import { chromium as chromium2 } from "patchright";
|
|
@@ -3329,15 +3372,18 @@ function loadStorageState(accountId) {
|
|
|
3329
3372
|
return void 0;
|
|
3330
3373
|
}
|
|
3331
3374
|
}
|
|
3332
|
-
async function saveStorageState(context, accountId, timeoutMs =
|
|
3375
|
+
async function saveStorageState(context, accountId, timeoutMs = 1e4) {
|
|
3333
3376
|
try {
|
|
3334
3377
|
const stateFile = getStorageStatePath(accountId);
|
|
3335
3378
|
const dir = path5.dirname(stateFile);
|
|
3336
3379
|
if (!fs8.existsSync(dir)) {
|
|
3337
3380
|
fs8.mkdirSync(dir, { recursive: true });
|
|
3338
3381
|
}
|
|
3382
|
+
const rawPromise = context.storageState({ path: stateFile }).catch(() => {
|
|
3383
|
+
return void 0;
|
|
3384
|
+
});
|
|
3339
3385
|
await withTimeout(
|
|
3340
|
-
|
|
3386
|
+
rawPromise,
|
|
3341
3387
|
timeoutMs,
|
|
3342
3388
|
`storageState timed out after ${timeoutMs}ms`
|
|
3343
3389
|
);
|
|
@@ -3500,6 +3546,10 @@ async function clearVisibleChallenge(page) {
|
|
|
3500
3546
|
"button[aria-label*='Close' i]",
|
|
3501
3547
|
"button[aria-label*='Fechar' i]",
|
|
3502
3548
|
".index-module__whats-new-modal-close",
|
|
3549
|
+
".age-confirmation-modal button",
|
|
3550
|
+
".age-confirmation-modal .qwen-chat-v2-btn-black",
|
|
3551
|
+
"button:has-text('Continuar')",
|
|
3552
|
+
"button:has-text('Continue')",
|
|
3503
3553
|
"button:has-text('Cancel')",
|
|
3504
3554
|
"button:has-text('Cancelar')",
|
|
3505
3555
|
"button:has-text('I understand')",
|
|
@@ -4694,6 +4744,292 @@ async function validateAccountLogin(rawAccount, headless = true, browserType = "
|
|
|
4694
4744
|
release();
|
|
4695
4745
|
}
|
|
4696
4746
|
}
|
|
4747
|
+
async function startEmailOtpLogin(email, options = {}) {
|
|
4748
|
+
const normalizedEmail = email.trim().toLowerCase();
|
|
4749
|
+
if (!normalizedEmail || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalizedEmail)) {
|
|
4750
|
+
return { success: false, error: "Formato de e-mail inv\xE1lido" };
|
|
4751
|
+
}
|
|
4752
|
+
const { listAccounts: listAccounts2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
4753
|
+
if (listAccounts2().some((a) => a.email.toLowerCase() === normalizedEmail)) {
|
|
4754
|
+
return {
|
|
4755
|
+
success: false,
|
|
4756
|
+
error: `Uma conta com o e-mail "${normalizedEmail}" j\xE1 est\xE1 cadastrada.`
|
|
4757
|
+
};
|
|
4758
|
+
}
|
|
4759
|
+
if (process.env.TEST_MOCK_QWEN_AUTH === "true" && process.env.NODE_ENV !== "production") {
|
|
4760
|
+
const mockSessionId = "mock-otp-" + Date.now();
|
|
4761
|
+
mockOtpSessions.set(mockSessionId, normalizedEmail);
|
|
4762
|
+
return { success: true, sessionId: mockSessionId };
|
|
4763
|
+
}
|
|
4764
|
+
const accountId = crypto3.randomUUID();
|
|
4765
|
+
const sessionId = accountId;
|
|
4766
|
+
const profilePath = getAccountProfilePath(accountId);
|
|
4767
|
+
const fingerprint = getFingerprintProfile(accountId);
|
|
4768
|
+
const browserType = options.browserType ?? config.playwright.browser;
|
|
4769
|
+
const { engine, channel } = resolveBrowserEngine(browserType);
|
|
4770
|
+
const headless = options.headless ?? config.playwright.headless;
|
|
4771
|
+
const launchOptions = {
|
|
4772
|
+
headless,
|
|
4773
|
+
channel,
|
|
4774
|
+
userAgent: fingerprint.userAgent,
|
|
4775
|
+
locale: fingerprint.locale,
|
|
4776
|
+
timezoneId: fingerprint.timezoneId,
|
|
4777
|
+
viewport: fingerprint.viewport,
|
|
4778
|
+
screen: fingerprint.viewport,
|
|
4779
|
+
deviceScaleFactor: 1,
|
|
4780
|
+
isMobile: false,
|
|
4781
|
+
hasTouch: false,
|
|
4782
|
+
colorScheme: "light",
|
|
4783
|
+
extraHTTPHeaders: {
|
|
4784
|
+
"sec-ch-ua": fingerprint.secChUa,
|
|
4785
|
+
"sec-ch-ua-mobile": "?0",
|
|
4786
|
+
"sec-ch-ua-platform": '"Windows"'
|
|
4787
|
+
},
|
|
4788
|
+
ignoreDefaultArgs: ["--enable-automation", "--enable-blink-features"],
|
|
4789
|
+
args: buildChromiumLaunchArgs(fingerprint.viewport)
|
|
4790
|
+
};
|
|
4791
|
+
let acctContext;
|
|
4792
|
+
try {
|
|
4793
|
+
acctContext = await withTimeout(
|
|
4794
|
+
engine.launchPersistentContext(profilePath, launchOptions),
|
|
4795
|
+
3e4,
|
|
4796
|
+
`O navegador n\xE3o iniciou em 30s para a conta ${maskEmail(normalizedEmail)}.`
|
|
4797
|
+
);
|
|
4798
|
+
} catch (launchErr) {
|
|
4799
|
+
if (launchErr?.message?.includes("Executable doesn't exist")) {
|
|
4800
|
+
autoInstallPlaywrightChromium();
|
|
4801
|
+
acctContext = await withTimeout(
|
|
4802
|
+
engine.launchPersistentContext(profilePath, launchOptions),
|
|
4803
|
+
3e4,
|
|
4804
|
+
`O navegador n\xE3o iniciou em 30s para a conta ${maskEmail(normalizedEmail)}.`
|
|
4805
|
+
);
|
|
4806
|
+
} else {
|
|
4807
|
+
return { success: false, error: launchErr?.message || String(launchErr) };
|
|
4808
|
+
}
|
|
4809
|
+
}
|
|
4810
|
+
try {
|
|
4811
|
+
await acctContext.addInitScript(getStealthScript(fingerprint));
|
|
4812
|
+
const existingPages = acctContext.pages().filter((p) => !p.isClosed());
|
|
4813
|
+
const acctPage = existingPages.find((p) => p.url().startsWith(qwenOrigin())) ?? existingPages[0] ?? await acctContext.newPage();
|
|
4814
|
+
await acctPage.goto(qwenUrl("/auth?mode=register"), {
|
|
4815
|
+
waitUntil: "domcontentloaded",
|
|
4816
|
+
timeout: Math.min(config.timeouts.navigation, 2e4)
|
|
4817
|
+
}).catch(() => {
|
|
4818
|
+
});
|
|
4819
|
+
await sleep2(1e3);
|
|
4820
|
+
await clearVisibleChallenge(acctPage);
|
|
4821
|
+
const requestId = crypto3.randomUUID();
|
|
4822
|
+
const evalRes = await acctPage.evaluate(
|
|
4823
|
+
async ({ email: email2, requestId: requestId2, version, timezone }) => {
|
|
4824
|
+
try {
|
|
4825
|
+
const response = await fetch("https://auth.qwen.ai/api/v2/auths/otp/email/request", {
|
|
4826
|
+
method: "POST",
|
|
4827
|
+
credentials: "include",
|
|
4828
|
+
headers: {
|
|
4829
|
+
accept: "application/json, text/plain, */*",
|
|
4830
|
+
"content-type": "application/json",
|
|
4831
|
+
source: "web",
|
|
4832
|
+
version,
|
|
4833
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
4834
|
+
timezone,
|
|
4835
|
+
"x-request-id": requestId2
|
|
4836
|
+
},
|
|
4837
|
+
body: JSON.stringify({
|
|
4838
|
+
identifier: email2,
|
|
4839
|
+
accept_terms: true,
|
|
4840
|
+
language: "pt-BR"
|
|
4841
|
+
})
|
|
4842
|
+
});
|
|
4843
|
+
const json = await response.json().catch(() => null);
|
|
4844
|
+
return { ok: response.ok, status: response.status, data: json };
|
|
4845
|
+
} catch (e) {
|
|
4846
|
+
return { ok: false, error: e.message };
|
|
4847
|
+
}
|
|
4848
|
+
},
|
|
4849
|
+
{
|
|
4850
|
+
email: normalizedEmail,
|
|
4851
|
+
requestId,
|
|
4852
|
+
version: getQwenWebVersion() || "0.3.12",
|
|
4853
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0]
|
|
4854
|
+
}
|
|
4855
|
+
).catch((err) => ({ ok: false, error: err?.message || String(err) }));
|
|
4856
|
+
if (!evalRes.ok || evalRes.data?.success !== true) {
|
|
4857
|
+
const errorMsg = evalRes.data?.data?.details || evalRes.data?.data?.message || evalRes.data?.message || evalRes.error || "Falha ao solicitar c\xF3digo de verifica\xE7\xE3o";
|
|
4858
|
+
await closePlaywrightContextBestEffort(accountId, acctContext).catch(() => {
|
|
4859
|
+
});
|
|
4860
|
+
cleanupPlaywrightAccountState(accountId);
|
|
4861
|
+
return { success: false, error: errorMsg };
|
|
4862
|
+
}
|
|
4863
|
+
const timer = setTimeout(async () => {
|
|
4864
|
+
activeOtpSessions.delete(sessionId);
|
|
4865
|
+
await closePlaywrightContextBestEffort(accountId, acctContext).catch(() => {
|
|
4866
|
+
});
|
|
4867
|
+
cleanupPlaywrightAccountState(accountId);
|
|
4868
|
+
}, 5 * 60 * 1e3);
|
|
4869
|
+
timer.unref?.();
|
|
4870
|
+
activeOtpSessions.set(sessionId, {
|
|
4871
|
+
sessionId,
|
|
4872
|
+
accountId,
|
|
4873
|
+
email: normalizedEmail,
|
|
4874
|
+
context: acctContext,
|
|
4875
|
+
page: acctPage,
|
|
4876
|
+
fingerprint,
|
|
4877
|
+
createdAt: Date.now(),
|
|
4878
|
+
timer
|
|
4879
|
+
});
|
|
4880
|
+
return { success: true, sessionId };
|
|
4881
|
+
} catch (err) {
|
|
4882
|
+
await closePlaywrightContextBestEffort(accountId, acctContext).catch(() => {
|
|
4883
|
+
});
|
|
4884
|
+
cleanupPlaywrightAccountState(accountId);
|
|
4885
|
+
return { success: false, error: err?.message || String(err) };
|
|
4886
|
+
}
|
|
4887
|
+
}
|
|
4888
|
+
async function verifyEmailOtpLogin(sessionId, code) {
|
|
4889
|
+
const cleanCode = code.trim();
|
|
4890
|
+
if (!cleanCode) {
|
|
4891
|
+
return { success: false, error: "C\xF3digo de verifica\xE7\xE3o \xE9 obrigat\xF3rio" };
|
|
4892
|
+
}
|
|
4893
|
+
if (process.env.TEST_MOCK_QWEN_AUTH === "true" && process.env.NODE_ENV !== "production") {
|
|
4894
|
+
const mockEmail = mockOtpSessions.get(sessionId);
|
|
4895
|
+
if (!mockEmail) {
|
|
4896
|
+
return { success: false, error: "Sess\xE3o OTP inv\xE1lida ou expirada" };
|
|
4897
|
+
}
|
|
4898
|
+
if (cleanCode === "000000") {
|
|
4899
|
+
return { success: false, error: "C\xF3digo de verifica\xE7\xE3o incorreto ou expirado" };
|
|
4900
|
+
}
|
|
4901
|
+
const { addAccount: addAccount2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
4902
|
+
const mockAccId = "mock-otp-acc-" + Date.now();
|
|
4903
|
+
const newAccount = addAccount2(mockEmail, "", mockAccId);
|
|
4904
|
+
mockOtpSessions.delete(sessionId);
|
|
4905
|
+
return { success: true, account: newAccount };
|
|
4906
|
+
}
|
|
4907
|
+
const session = activeOtpSessions.get(sessionId);
|
|
4908
|
+
if (!session) {
|
|
4909
|
+
return { success: false, error: "Sess\xE3o OTP expirada ou n\xE3o encontrada. Solicite um novo c\xF3digo." };
|
|
4910
|
+
}
|
|
4911
|
+
if (session.page.isClosed()) {
|
|
4912
|
+
activeOtpSessions.delete(sessionId);
|
|
4913
|
+
return { success: false, error: "Navegador foi fechado. Solicite um novo c\xF3digo." };
|
|
4914
|
+
}
|
|
4915
|
+
const requestId = crypto3.randomUUID();
|
|
4916
|
+
const evalRes = await session.page.evaluate(
|
|
4917
|
+
async ({ email, code: code2, requestId: requestId2, version, timezone }) => {
|
|
4918
|
+
try {
|
|
4919
|
+
const response = await fetch("https://auth.qwen.ai/api/v2/auths/otp/email/verify", {
|
|
4920
|
+
method: "POST",
|
|
4921
|
+
credentials: "include",
|
|
4922
|
+
headers: {
|
|
4923
|
+
accept: "application/json, text/plain, */*",
|
|
4924
|
+
"content-type": "application/json",
|
|
4925
|
+
source: "web",
|
|
4926
|
+
version,
|
|
4927
|
+
"x-request-origin": "https://chat.qwen.ai",
|
|
4928
|
+
timezone,
|
|
4929
|
+
"x-request-id": requestId2
|
|
4930
|
+
},
|
|
4931
|
+
body: JSON.stringify({
|
|
4932
|
+
identifier: email,
|
|
4933
|
+
code: code2,
|
|
4934
|
+
name: null
|
|
4935
|
+
})
|
|
4936
|
+
});
|
|
4937
|
+
const json = await response.json().catch(() => null);
|
|
4938
|
+
return { ok: response.ok, status: response.status, data: json };
|
|
4939
|
+
} catch (e) {
|
|
4940
|
+
return { ok: false, error: e.message };
|
|
4941
|
+
}
|
|
4942
|
+
},
|
|
4943
|
+
{
|
|
4944
|
+
email: session.email,
|
|
4945
|
+
code: cleanCode,
|
|
4946
|
+
requestId,
|
|
4947
|
+
version: getQwenWebVersion() || "0.3.12",
|
|
4948
|
+
timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0]
|
|
4949
|
+
}
|
|
4950
|
+
).catch((err) => ({ ok: false, error: err?.message || String(err) }));
|
|
4951
|
+
if (!evalRes.ok || evalRes.data?.success !== true || !evalRes.data?.data) {
|
|
4952
|
+
const errorMsg = evalRes.data?.data?.details || evalRes.data?.data?.message || evalRes.data?.message || evalRes.error || "C\xF3digo de verifica\xE7\xE3o incorreto ou expirado";
|
|
4953
|
+
return { success: false, error: errorMsg };
|
|
4954
|
+
}
|
|
4955
|
+
const resData = evalRes.data.data;
|
|
4956
|
+
const accessToken = resData.access_token || resData.token;
|
|
4957
|
+
const refreshToken = resData.refresh_token;
|
|
4958
|
+
const userId = resData.id;
|
|
4959
|
+
try {
|
|
4960
|
+
await session.page.evaluate(({ token, rTok }) => {
|
|
4961
|
+
try {
|
|
4962
|
+
localStorage.setItem("token", token);
|
|
4963
|
+
localStorage.setItem("access_token", token);
|
|
4964
|
+
if (rTok) localStorage.setItem("refresh_token", rTok);
|
|
4965
|
+
document.cookie = `token=${encodeURIComponent(token)}; path=/; domain=.qwen.ai; max-age=31536000`;
|
|
4966
|
+
} catch {
|
|
4967
|
+
}
|
|
4968
|
+
}, { token: accessToken, rTok: refreshToken });
|
|
4969
|
+
await session.context.addCookies([
|
|
4970
|
+
{
|
|
4971
|
+
name: "token",
|
|
4972
|
+
value: accessToken,
|
|
4973
|
+
domain: ".qwen.ai",
|
|
4974
|
+
path: "/",
|
|
4975
|
+
expires: Math.floor(Date.now() / 1e3) + 31536e3,
|
|
4976
|
+
httpOnly: false,
|
|
4977
|
+
secure: true,
|
|
4978
|
+
sameSite: "Lax"
|
|
4979
|
+
}
|
|
4980
|
+
]);
|
|
4981
|
+
await session.page.goto(qwenUrl("/"), {
|
|
4982
|
+
waitUntil: "domcontentloaded",
|
|
4983
|
+
timeout: Math.min(config.timeouts.navigation, 15e3)
|
|
4984
|
+
}).catch(() => {
|
|
4985
|
+
});
|
|
4986
|
+
await sleep2(1e3);
|
|
4987
|
+
await saveStorageState(session.context, session.accountId);
|
|
4988
|
+
const { saveAuthSession: saveAuthSession2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4989
|
+
const { parseJwtExpiry: parseJwtExpiry2 } = await Promise.resolve().then(() => (init_jwt(), jwt_exports));
|
|
4990
|
+
const exp = parseJwtExpiry2(accessToken);
|
|
4991
|
+
saveAuthSession2(session.accountId, {
|
|
4992
|
+
cookie: `token=${accessToken}`,
|
|
4993
|
+
userAgent: session.fingerprint.userAgent,
|
|
4994
|
+
bxV: "2.5.37",
|
|
4995
|
+
version: getQwenWebVersion() || "0.3.12",
|
|
4996
|
+
userId: userId || void 0,
|
|
4997
|
+
tokenExpiresAt: exp || void 0,
|
|
4998
|
+
refreshToken: refreshToken || void 0,
|
|
4999
|
+
capturedAt: Date.now()
|
|
5000
|
+
});
|
|
5001
|
+
const { addAccount: addAccount2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
5002
|
+
const newAccount = addAccount2(session.email, "", session.accountId);
|
|
5003
|
+
clearTimeout(session.timer);
|
|
5004
|
+
activeOtpSessions.delete(sessionId);
|
|
5005
|
+
await closePlaywrightContextBestEffort(session.accountId, session.context).catch(() => {
|
|
5006
|
+
});
|
|
5007
|
+
cleanupPlaywrightAccountState(session.accountId);
|
|
5008
|
+
return { success: true, account: newAccount };
|
|
5009
|
+
} catch (err) {
|
|
5010
|
+
clearTimeout(session.timer);
|
|
5011
|
+
activeOtpSessions.delete(sessionId);
|
|
5012
|
+
await closePlaywrightContextBestEffort(session.accountId, session.context).catch(() => {
|
|
5013
|
+
});
|
|
5014
|
+
cleanupPlaywrightAccountState(session.accountId);
|
|
5015
|
+
return { success: false, error: err?.message || String(err) };
|
|
5016
|
+
}
|
|
5017
|
+
}
|
|
5018
|
+
async function cancelEmailOtpLogin(sessionId) {
|
|
5019
|
+
if (process.env.TEST_MOCK_QWEN_AUTH === "true" && process.env.NODE_ENV !== "production") {
|
|
5020
|
+
mockOtpSessions.delete(sessionId);
|
|
5021
|
+
return;
|
|
5022
|
+
}
|
|
5023
|
+
const session = activeOtpSessions.get(sessionId);
|
|
5024
|
+
if (!session) return;
|
|
5025
|
+
clearTimeout(session.timer);
|
|
5026
|
+
activeOtpSessions.delete(sessionId);
|
|
5027
|
+
await closePlaywrightContextBestEffort(session.accountId, session.context).catch(() => {
|
|
5028
|
+
});
|
|
5029
|
+
cleanupPlaywrightAccountState(session.accountId);
|
|
5030
|
+
const { wipeAccountSessionFiles: wipeAccountSessionFiles2 } = await Promise.resolve().then(() => (init_accounts(), accounts_exports));
|
|
5031
|
+
wipeAccountSessionFiles2(session.accountId);
|
|
5032
|
+
}
|
|
4697
5033
|
function classifyQwenAuthError(code, details) {
|
|
4698
5034
|
const c = (code || "").trim().toLowerCase();
|
|
4699
5035
|
const d = (details || "").trim().toLowerCase();
|
|
@@ -6062,7 +6398,7 @@ async function withAccountPage(accountId, fn, timeoutMs = ACCOUNT_PAGE_OPERATION
|
|
|
6062
6398
|
return result;
|
|
6063
6399
|
} catch (error) {
|
|
6064
6400
|
const message = getErrorMessage(error);
|
|
6065
|
-
if (recoverOnTimeout && message.includes("Playwright page operation timed out")) {
|
|
6401
|
+
if (recoverOnTimeout && message.includes("Playwright page operation timed out") && (!page || page.isClosed())) {
|
|
6066
6402
|
console.warn(
|
|
6067
6403
|
`\u23F1\uFE0F [Playwright] Resetting account context after a stuck page operation: ${accountId}`
|
|
6068
6404
|
);
|
|
@@ -6611,7 +6947,7 @@ async function getTokenDiagnostics(accountId) {
|
|
|
6611
6947
|
}
|
|
6612
6948
|
};
|
|
6613
6949
|
}
|
|
6614
|
-
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;
|
|
6950
|
+
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, activeOtpSessions, mockOtpSessions, PROFILE_RESET_TIMEOUT_MS;
|
|
6615
6951
|
var init_playwright = __esm({
|
|
6616
6952
|
"src/services/playwright.ts"() {
|
|
6617
6953
|
"use strict";
|
|
@@ -6656,11 +6992,13 @@ var init_playwright = __esm({
|
|
|
6656
6992
|
PLAYWRIGHT_MUTEX_WAIT_MS = 6e4;
|
|
6657
6993
|
ACCOUNT_PAGE_OPERATION_TIMEOUT_MS = config.timeouts.page;
|
|
6658
6994
|
SESSION_PROBE_NAVIGATION_TIMEOUT_MS = 15e3;
|
|
6659
|
-
HEADER_CAPTURE_TRIGGER_GRACE_MS =
|
|
6660
|
-
FIRST_TRIGGER_GRACE_MS =
|
|
6995
|
+
HEADER_CAPTURE_TRIGGER_GRACE_MS = 2e4;
|
|
6996
|
+
FIRST_TRIGGER_GRACE_MS = 12e3;
|
|
6661
6997
|
HEADER_CAPTURE_TRIGGER_ATTEMPTS = 3;
|
|
6662
6998
|
CHAT_INPUT_APPEAR_TIMEOUT_MS = 15e3;
|
|
6663
6999
|
CHAT_INPUT_ACTION_TIMEOUT_MS = 1e4;
|
|
7000
|
+
activeOtpSessions = /* @__PURE__ */ new Map();
|
|
7001
|
+
mockOtpSessions = /* @__PURE__ */ new Map();
|
|
6664
7002
|
PROFILE_RESET_TIMEOUT_MS = Math.max(9e4, config.timeouts.headers);
|
|
6665
7003
|
setWafContextResetListener((accountId) => {
|
|
6666
7004
|
if (!accountPages.has(accountId)) return;
|
|
@@ -7672,6 +8010,15 @@ var init_helpers = __esm({
|
|
|
7672
8010
|
}
|
|
7673
8011
|
});
|
|
7674
8012
|
|
|
8013
|
+
// src/utils/overload-detector.ts
|
|
8014
|
+
var OVERLOAD_COOLDOWN_MS;
|
|
8015
|
+
var init_overload_detector = __esm({
|
|
8016
|
+
"src/utils/overload-detector.ts"() {
|
|
8017
|
+
"use strict";
|
|
8018
|
+
OVERLOAD_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
8019
|
+
}
|
|
8020
|
+
});
|
|
8021
|
+
|
|
7675
8022
|
// src/routes/chat/retry-policy.ts
|
|
7676
8023
|
var init_retry_policy = __esm({
|
|
7677
8024
|
"src/routes/chat/retry-policy.ts"() {
|
|
@@ -7682,6 +8029,7 @@ var init_retry_policy = __esm({
|
|
|
7682
8029
|
init_qwen();
|
|
7683
8030
|
init_errors();
|
|
7684
8031
|
init_helpers();
|
|
8032
|
+
init_overload_detector();
|
|
7685
8033
|
init_account_manager();
|
|
7686
8034
|
}
|
|
7687
8035
|
});
|
|
@@ -8645,7 +8993,8 @@ async function requestQwenPersonalizationInBrowser(accountId, method, path6, hea
|
|
|
8645
8993
|
payload === void 0 ? void 0 : JSON.stringify(payload),
|
|
8646
8994
|
{
|
|
8647
8995
|
settingsPage: true,
|
|
8648
|
-
referrer: qwenUrl("/settings/personalization")
|
|
8996
|
+
referrer: qwenUrl("/settings/personalization"),
|
|
8997
|
+
noMutexRecovery: true
|
|
8649
8998
|
}
|
|
8650
8999
|
);
|
|
8651
9000
|
const { raw, json } = await readJsonTextResponse(response);
|
|
@@ -9146,8 +9495,9 @@ async function syncQwenRequestPersonalizationInternal(instruction, accountId, me
|
|
|
9146
9495
|
const returnedInstruction = json?.data?.personalization?.instruction;
|
|
9147
9496
|
const returned = textSize(returnedInstruction);
|
|
9148
9497
|
let stored = { chars: null, bytes: null, hash: null };
|
|
9498
|
+
const matchReturned = isEmptyInstruction && (!returnedInstruction || returned.chars === 0) || returned.hash !== null && returned.hash === sent.hash;
|
|
9149
9499
|
let verifyData = null;
|
|
9150
|
-
if (config.qwen.personalizationVerifyGet) {
|
|
9500
|
+
if (config.qwen.personalizationVerifyGet && !matchReturned) {
|
|
9151
9501
|
const { json: verifyJson } = await requestQwenPersonalizationInBrowser(
|
|
9152
9502
|
accountId,
|
|
9153
9503
|
"GET",
|
|
@@ -9157,7 +9507,6 @@ async function syncQwenRequestPersonalizationInternal(instruction, accountId, me
|
|
|
9157
9507
|
verifyData = verifyJson?.data?.personalization;
|
|
9158
9508
|
stored = textSize(verifyData?.instruction);
|
|
9159
9509
|
}
|
|
9160
|
-
const matchReturned = isEmptyInstruction && (!returnedInstruction || returned.chars === 0) || returned.hash !== null && returned.hash === sent.hash;
|
|
9161
9510
|
const matchStored = stored.hash === null ? null : isEmptyInstruction && (!verifyData?.instruction || stored.chars === 0) || stored.hash === sent.hash;
|
|
9162
9511
|
const applied = matchReturned || matchStored === true;
|
|
9163
9512
|
if (syncHash && applied) {
|
|
@@ -9531,6 +9880,17 @@ async function fetchQwenModels(accountId) {
|
|
|
9531
9880
|
);
|
|
9532
9881
|
return cached.models;
|
|
9533
9882
|
}
|
|
9883
|
+
if (accountId && !isAuthMockEnabled() && !isPlaywrightInitialized(accountId)) {
|
|
9884
|
+
for (const [, entry] of modelsCache.entries()) {
|
|
9885
|
+
if (entry && now - entry.fetchedAt < MODEL_CACHE_TTL_MS * 4) {
|
|
9886
|
+
syncModelMetadata(
|
|
9887
|
+
entry.models,
|
|
9888
|
+
accountId
|
|
9889
|
+
);
|
|
9890
|
+
return entry.models;
|
|
9891
|
+
}
|
|
9892
|
+
}
|
|
9893
|
+
}
|
|
9534
9894
|
if (accountId && !isAuthMockEnabled() && isAccountBusy(accountId)) {
|
|
9535
9895
|
try {
|
|
9536
9896
|
const result = await withAccountPage(
|
|
@@ -10454,6 +10814,7 @@ var init_qwen = __esm({
|
|
|
10454
10814
|
});
|
|
10455
10815
|
|
|
10456
10816
|
// src/delete-chats.ts
|
|
10817
|
+
init_process_guard();
|
|
10457
10818
|
import "dotenv/config";
|
|
10458
10819
|
|
|
10459
10820
|
// src/services/chat-cleanup.ts
|
|
@@ -10517,6 +10878,12 @@ async function deleteChatsForConfiguredAccounts(keepBrowserOpen = false) {
|
|
|
10517
10878
|
`\u274C [DeleteChats] [${currentIdx}/${totalCount}] Falha ao apagar conversas de ${maskEmail(account.email)}:`,
|
|
10518
10879
|
error instanceof Error ? error.message : String(error)
|
|
10519
10880
|
);
|
|
10881
|
+
} finally {
|
|
10882
|
+
if (!keepBrowserOpen) {
|
|
10883
|
+
const { closePlaywrightForAccount: closePlaywrightForAccount2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
10884
|
+
await closePlaywrightForAccount2(account.id).catch(() => {
|
|
10885
|
+
});
|
|
10886
|
+
}
|
|
10520
10887
|
}
|
|
10521
10888
|
}
|
|
10522
10889
|
} finally {
|
|
@@ -10537,6 +10904,7 @@ async function deleteChatsForConfiguredAccounts(keepBrowserOpen = false) {
|
|
|
10537
10904
|
}
|
|
10538
10905
|
|
|
10539
10906
|
// src/delete-chats.ts
|
|
10907
|
+
installProcessTeardownGuards("DeleteChats");
|
|
10540
10908
|
async function run() {
|
|
10541
10909
|
console.log("\u{1F5D1}\uFE0F [DeleteChats] Using Playwright sessions");
|
|
10542
10910
|
const result = await deleteChatsForConfiguredAccounts();
|