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/reset-cooldowns.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
|
}
|
|
@@ -1353,11 +1353,11 @@ var init_config = __esm({
|
|
|
1353
1353
|
// nothing in this window is dead and should fail fast, retryable).
|
|
1354
1354
|
QWEN_FIRST_CHUNK_TIMEOUT: z.string().default("60000"),
|
|
1355
1355
|
TOTAL_REQUEST_TIMEOUT: z.string().default("600000"),
|
|
1356
|
-
// Mid-stream silence window for thinking models:
|
|
1356
|
+
// Mid-stream silence window for thinking models: 5 min with ZERO upstream
|
|
1357
1357
|
// bytes is a dead stream (WAF swallow / dropped connection) — fail fast and
|
|
1358
1358
|
// let the retry policy rotate accounts. Flowing reasoning chunks RESET this
|
|
1359
1359
|
// timer, so legitimate slow thinking is never cut; only total silence is.
|
|
1360
|
-
REASONING_MODEL_TIMEOUT: z.string().default("
|
|
1360
|
+
REASONING_MODEL_TIMEOUT: z.string().default("300000"),
|
|
1361
1361
|
CACHE_TTL: z.string().default("3600"),
|
|
1362
1362
|
RESPONSE_TTL: z.string().default("1800"),
|
|
1363
1363
|
CACHE_COMPRESSION_ENABLED: z.string().default("true"),
|
|
@@ -2730,6 +2730,44 @@ var init_jwt = __esm({
|
|
|
2730
2730
|
}
|
|
2731
2731
|
});
|
|
2732
2732
|
|
|
2733
|
+
// src/core/process-guard.ts
|
|
2734
|
+
function isPlaywrightAlreadyClosedMessage(message) {
|
|
2735
|
+
if (!message) return false;
|
|
2736
|
+
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");
|
|
2737
|
+
}
|
|
2738
|
+
function isBenignTeardownError(error) {
|
|
2739
|
+
if (!error) return false;
|
|
2740
|
+
const message = error instanceof Error ? error.message : typeof error === "object" && "message" in error ? String(error.message) : String(error);
|
|
2741
|
+
return isPlaywrightAlreadyClosedMessage(message);
|
|
2742
|
+
}
|
|
2743
|
+
function installProcessTeardownGuards(label = "Process") {
|
|
2744
|
+
if (guardsInstalled) return;
|
|
2745
|
+
guardsInstalled = true;
|
|
2746
|
+
process.on("uncaughtException", (error) => {
|
|
2747
|
+
if (isBenignTeardownError(error)) {
|
|
2748
|
+
const msg = error instanceof Error ? error.message : typeof error === "object" && error !== null && "message" in error ? String(error.message) : String(error);
|
|
2749
|
+
console.warn(`\u26A0\uFE0F [${label}] Handled benign driver teardown exception: ${msg}`);
|
|
2750
|
+
return;
|
|
2751
|
+
}
|
|
2752
|
+
console.error(`\u274C [${label}] Uncaught Exception:`, error);
|
|
2753
|
+
});
|
|
2754
|
+
process.on("unhandledRejection", (reason) => {
|
|
2755
|
+
if (isBenignTeardownError(reason)) {
|
|
2756
|
+
const msg = reason instanceof Error ? reason.message : typeof reason === "object" && reason !== null && "message" in reason ? String(reason.message) : String(reason);
|
|
2757
|
+
console.warn(`\u26A0\uFE0F [${label}] Handled benign driver teardown rejection: ${msg}`);
|
|
2758
|
+
return;
|
|
2759
|
+
}
|
|
2760
|
+
console.error(`\u274C [${label}] Unhandled Rejection:`, reason);
|
|
2761
|
+
});
|
|
2762
|
+
}
|
|
2763
|
+
var guardsInstalled;
|
|
2764
|
+
var init_process_guard = __esm({
|
|
2765
|
+
"src/core/process-guard.ts"() {
|
|
2766
|
+
"use strict";
|
|
2767
|
+
guardsInstalled = false;
|
|
2768
|
+
}
|
|
2769
|
+
});
|
|
2770
|
+
|
|
2733
2771
|
// src/clean-cache.ts
|
|
2734
2772
|
var clean_cache_exports = {};
|
|
2735
2773
|
__export(clean_cache_exports, {
|
|
@@ -2898,6 +2936,8 @@ var init_clean_cache = __esm({
|
|
|
2898
2936
|
"src/clean-cache.ts"() {
|
|
2899
2937
|
"use strict";
|
|
2900
2938
|
init_playwright();
|
|
2939
|
+
init_process_guard();
|
|
2940
|
+
installProcessTeardownGuards("CleanCache");
|
|
2901
2941
|
isDirectRun = process.argv[1] && (process.argv[1].endsWith("clean-cache.ts") || process.argv[1].endsWith("clean-cache.js"));
|
|
2902
2942
|
if (isDirectRun) {
|
|
2903
2943
|
main().catch((err) => {
|
|
@@ -3071,15 +3111,18 @@ function loadStorageState(accountId) {
|
|
|
3071
3111
|
return void 0;
|
|
3072
3112
|
}
|
|
3073
3113
|
}
|
|
3074
|
-
async function saveStorageState(context, accountId, timeoutMs =
|
|
3114
|
+
async function saveStorageState(context, accountId, timeoutMs = 1e4) {
|
|
3075
3115
|
try {
|
|
3076
3116
|
const stateFile = getStorageStatePath(accountId);
|
|
3077
3117
|
const dir = path5.dirname(stateFile);
|
|
3078
3118
|
if (!fs8.existsSync(dir)) {
|
|
3079
3119
|
fs8.mkdirSync(dir, { recursive: true });
|
|
3080
3120
|
}
|
|
3121
|
+
const rawPromise = context.storageState({ path: stateFile }).catch(() => {
|
|
3122
|
+
return void 0;
|
|
3123
|
+
});
|
|
3081
3124
|
await withTimeout(
|
|
3082
|
-
|
|
3125
|
+
rawPromise,
|
|
3083
3126
|
timeoutMs,
|
|
3084
3127
|
`storageState timed out after ${timeoutMs}ms`
|
|
3085
3128
|
);
|
|
@@ -3183,6 +3226,10 @@ async function clearVisibleChallenge(page) {
|
|
|
3183
3226
|
"button[aria-label*='Close' i]",
|
|
3184
3227
|
"button[aria-label*='Fechar' i]",
|
|
3185
3228
|
".index-module__whats-new-modal-close",
|
|
3229
|
+
".age-confirmation-modal button",
|
|
3230
|
+
".age-confirmation-modal .qwen-chat-v2-btn-black",
|
|
3231
|
+
"button:has-text('Continuar')",
|
|
3232
|
+
"button:has-text('Continue')",
|
|
3186
3233
|
"button:has-text('Cancel')",
|
|
3187
3234
|
"button:has-text('Cancelar')",
|
|
3188
3235
|
"button:has-text('I understand')",
|
|
@@ -5542,8 +5589,8 @@ var init_playwright = __esm({
|
|
|
5542
5589
|
PLAYWRIGHT_MUTEX_WAIT_MS = 6e4;
|
|
5543
5590
|
ACCOUNT_PAGE_OPERATION_TIMEOUT_MS = config.timeouts.page;
|
|
5544
5591
|
SESSION_PROBE_NAVIGATION_TIMEOUT_MS = 15e3;
|
|
5545
|
-
HEADER_CAPTURE_TRIGGER_GRACE_MS =
|
|
5546
|
-
FIRST_TRIGGER_GRACE_MS =
|
|
5592
|
+
HEADER_CAPTURE_TRIGGER_GRACE_MS = 2e4;
|
|
5593
|
+
FIRST_TRIGGER_GRACE_MS = 12e3;
|
|
5547
5594
|
HEADER_CAPTURE_TRIGGER_ATTEMPTS = 3;
|
|
5548
5595
|
CHAT_INPUT_APPEAR_TIMEOUT_MS = 15e3;
|
|
5549
5596
|
CHAT_INPUT_ACTION_TIMEOUT_MS = 1e4;
|
|
@@ -5659,6 +5706,15 @@ var init_helpers = __esm({
|
|
|
5659
5706
|
}
|
|
5660
5707
|
});
|
|
5661
5708
|
|
|
5709
|
+
// src/utils/overload-detector.ts
|
|
5710
|
+
var OVERLOAD_COOLDOWN_MS;
|
|
5711
|
+
var init_overload_detector = __esm({
|
|
5712
|
+
"src/utils/overload-detector.ts"() {
|
|
5713
|
+
"use strict";
|
|
5714
|
+
OVERLOAD_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
5715
|
+
}
|
|
5716
|
+
});
|
|
5717
|
+
|
|
5662
5718
|
// src/routes/chat/retry-policy.ts
|
|
5663
5719
|
var init_retry_policy = __esm({
|
|
5664
5720
|
"src/routes/chat/retry-policy.ts"() {
|
|
@@ -5669,6 +5725,7 @@ var init_retry_policy = __esm({
|
|
|
5669
5725
|
init_qwen();
|
|
5670
5726
|
init_errors();
|
|
5671
5727
|
init_helpers();
|
|
5728
|
+
init_overload_detector();
|
|
5672
5729
|
init_account_manager();
|
|
5673
5730
|
}
|
|
5674
5731
|
});
|
package/dist/sync-clients.js
CHANGED
|
@@ -183,11 +183,11 @@ var envSchema = z.object({
|
|
|
183
183
|
// nothing in this window is dead and should fail fast, retryable).
|
|
184
184
|
QWEN_FIRST_CHUNK_TIMEOUT: z.string().default("60000"),
|
|
185
185
|
TOTAL_REQUEST_TIMEOUT: z.string().default("600000"),
|
|
186
|
-
// Mid-stream silence window for thinking models:
|
|
186
|
+
// Mid-stream silence window for thinking models: 5 min with ZERO upstream
|
|
187
187
|
// bytes is a dead stream (WAF swallow / dropped connection) — fail fast and
|
|
188
188
|
// let the retry policy rotate accounts. Flowing reasoning chunks RESET this
|
|
189
189
|
// timer, so legitimate slow thinking is never cut; only total silence is.
|
|
190
|
-
REASONING_MODEL_TIMEOUT: z.string().default("
|
|
190
|
+
REASONING_MODEL_TIMEOUT: z.string().default("300000"),
|
|
191
191
|
CACHE_TTL: z.string().default("3600"),
|
|
192
192
|
RESPONSE_TTL: z.string().default("1800"),
|
|
193
193
|
CACHE_COMPRESSION_ENABLED: z.string().default("true"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "qwenproxy-cli",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.2",
|
|
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 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",
|
|
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 src/tests/process-guard-and-resilience.test.ts src/tests/otp-login.test.ts src/tests/overload-detector.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 src/tests/process-guard-and-resilience.test.ts src/tests/otp-login.test.ts src/tests/overload-detector.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/clean-cache.ts
CHANGED
|
@@ -4,6 +4,9 @@ import path from "node:path";
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import { chromium } from "patchright";
|
|
6
6
|
import { pruneAllPlaywrightProfiles, cleanupOrphanProfiles } from "./services/playwright.ts";
|
|
7
|
+
import { installProcessTeardownGuards } from "./core/process-guard.ts";
|
|
8
|
+
|
|
9
|
+
installProcessTeardownGuards("CleanCache");
|
|
7
10
|
|
|
8
11
|
export function formatBytes(bytes: number): string {
|
|
9
12
|
if (bytes < 1024) return `${bytes} B`;
|
package/src/core/accounts.ts
CHANGED
package/src/core/config.ts
CHANGED
|
@@ -102,11 +102,11 @@ const envSchema = z
|
|
|
102
102
|
// nothing in this window is dead and should fail fast, retryable).
|
|
103
103
|
QWEN_FIRST_CHUNK_TIMEOUT: z.string().default("60000"),
|
|
104
104
|
TOTAL_REQUEST_TIMEOUT: z.string().default("600000"),
|
|
105
|
-
// Mid-stream silence window for thinking models:
|
|
105
|
+
// Mid-stream silence window for thinking models: 5 min with ZERO upstream
|
|
106
106
|
// bytes is a dead stream (WAF swallow / dropped connection) — fail fast and
|
|
107
107
|
// let the retry policy rotate accounts. Flowing reasoning chunks RESET this
|
|
108
108
|
// timer, so legitimate slow thinking is never cut; only total silence is.
|
|
109
|
-
REASONING_MODEL_TIMEOUT: z.string().default("
|
|
109
|
+
REASONING_MODEL_TIMEOUT: z.string().default("300000"),
|
|
110
110
|
CACHE_TTL: z.string().default("3600"),
|
|
111
111
|
RESPONSE_TTL: z.string().default("1800"),
|
|
112
112
|
CACHE_COMPRESSION_ENABLED: z.string().default("true"),
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process teardown error guard.
|
|
3
|
+
*
|
|
4
|
+
* Catches unhandled rejections and uncaught exceptions that arise from
|
|
5
|
+
* benign browser/CDP connection closures (e.g. ProtocolError: session closed,
|
|
6
|
+
* Network.setCacheDisabled, target crashed during shutdown) and prevents
|
|
7
|
+
* them from terminating the Node.js process.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export function isPlaywrightAlreadyClosedMessage(message: string): boolean {
|
|
11
|
+
if (!message) return false;
|
|
12
|
+
return (
|
|
13
|
+
message.includes("Target page, context or browser has been closed") ||
|
|
14
|
+
message.includes("Browser has been closed") ||
|
|
15
|
+
message.includes("Target closed") ||
|
|
16
|
+
message.includes("Target crashed") ||
|
|
17
|
+
message.includes("Page crashed") ||
|
|
18
|
+
message.includes("Assertion error") ||
|
|
19
|
+
message.includes("Cannot find parent object") ||
|
|
20
|
+
message.includes("Connection closed") ||
|
|
21
|
+
message.includes("session closed") ||
|
|
22
|
+
message.includes("Session closed") ||
|
|
23
|
+
message.includes("Network.setCacheDisabled") ||
|
|
24
|
+
message.includes("Protocol error") ||
|
|
25
|
+
message.includes("storageState timed out")
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function isBenignTeardownError(error: unknown): boolean {
|
|
30
|
+
if (!error) return false;
|
|
31
|
+
const message =
|
|
32
|
+
error instanceof Error
|
|
33
|
+
? error.message
|
|
34
|
+
: typeof error === "object" && "message" in error
|
|
35
|
+
? String((error as any).message)
|
|
36
|
+
: String(error);
|
|
37
|
+
return isPlaywrightAlreadyClosedMessage(message);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let guardsInstalled = false;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Installs process-wide handlers for uncaughtException and unhandledRejection
|
|
44
|
+
* to guard against asynchronous Playwright/CDP driver teardown crashes.
|
|
45
|
+
*/
|
|
46
|
+
export function installProcessTeardownGuards(label = "Process"): void {
|
|
47
|
+
if (guardsInstalled) return;
|
|
48
|
+
guardsInstalled = true;
|
|
49
|
+
|
|
50
|
+
process.on("uncaughtException", (error: unknown) => {
|
|
51
|
+
if (isBenignTeardownError(error)) {
|
|
52
|
+
const msg =
|
|
53
|
+
error instanceof Error
|
|
54
|
+
? error.message
|
|
55
|
+
: typeof error === "object" && error !== null && "message" in error
|
|
56
|
+
? String((error as any).message)
|
|
57
|
+
: String(error);
|
|
58
|
+
console.warn(`⚠️ [${label}] Handled benign driver teardown exception: ${msg}`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
console.error(`❌ [${label}] Uncaught Exception:`, error);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
process.on("unhandledRejection", (reason: unknown) => {
|
|
65
|
+
if (isBenignTeardownError(reason)) {
|
|
66
|
+
const msg =
|
|
67
|
+
reason instanceof Error
|
|
68
|
+
? reason.message
|
|
69
|
+
: typeof reason === "object" && reason !== null && "message" in reason
|
|
70
|
+
? String((reason as any).message)
|
|
71
|
+
: String(reason);
|
|
72
|
+
console.warn(`⚠️ [${label}] Handled benign driver teardown rejection: ${msg}`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.error(`❌ [${label}] Unhandled Rejection:`, reason);
|
|
76
|
+
});
|
|
77
|
+
}
|
package/src/core/version.ts
CHANGED
package/src/delete-chats.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import "dotenv/config";
|
|
2
|
+
import { installProcessTeardownGuards } from "./core/process-guard.ts";
|
|
2
3
|
import { deleteChatsForConfiguredAccounts } from "./services/chat-cleanup.ts";
|
|
3
4
|
|
|
5
|
+
installProcessTeardownGuards("DeleteChats");
|
|
6
|
+
|
|
4
7
|
async function run(): Promise<void> {
|
|
5
8
|
console.log("🗑️ [DeleteChats] Using Playwright sessions");
|
|
6
9
|
|
package/src/index.ts
CHANGED
|
@@ -16,36 +16,10 @@ if (fs.existsSync(envPath)) {
|
|
|
16
16
|
} else {
|
|
17
17
|
dotenv.config({ quiet: true })
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
process.on('uncaughtException', async (error: unknown) => {
|
|
21
|
-
const { isPlaywrightAlreadyClosedError } = await import('./services/playwright.ts');
|
|
22
|
-
if (isPlaywrightAlreadyClosedError(error)) {
|
|
23
|
-
const msg =
|
|
24
|
-
error instanceof Error
|
|
25
|
-
? error.message
|
|
26
|
-
: typeof error === 'object' && error !== null && 'message' in error
|
|
27
|
-
? String((error as any).message)
|
|
28
|
-
: String(error);
|
|
29
|
-
console.warn(`⚠️ [Playwright] Handled benign driver teardown exception: ${msg}`);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
console.error('❌ [Process] Uncaught Exception:', error);
|
|
33
|
-
});
|
|
19
|
+
import { installProcessTeardownGuards } from './core/process-guard.ts'
|
|
34
20
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (isPlaywrightAlreadyClosedError(reason)) {
|
|
38
|
-
const msg =
|
|
39
|
-
reason instanceof Error
|
|
40
|
-
? reason.message
|
|
41
|
-
: typeof reason === 'object' && reason !== null && 'message' in reason
|
|
42
|
-
? String((reason as any).message)
|
|
43
|
-
: String(reason);
|
|
44
|
-
console.warn(`⚠️ [Playwright] Handled benign driver teardown rejection: ${msg}`);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
console.error('❌ [Process] Unhandled Rejection:', reason);
|
|
48
|
-
});
|
|
21
|
+
// Prevent benign asynchronous driver/browser teardown exceptions from crashing the server
|
|
22
|
+
installProcessTeardownGuards("Playwright");
|
|
49
23
|
import { startServer } from './api/server.js'
|
|
50
24
|
const isTui = process.argv.includes('--tui') || process.env.QWEN_TUI === 'true'
|
|
51
25
|
|
package/src/login.ts
CHANGED
|
@@ -9,8 +9,10 @@ import {
|
|
|
9
9
|
import { maskEmail } from "./core/logger.ts";
|
|
10
10
|
import * as readline from "readline";
|
|
11
11
|
import * as dotenv from "dotenv";
|
|
12
|
+
import { installProcessTeardownGuards } from "./core/process-guard.ts";
|
|
12
13
|
|
|
13
14
|
dotenv.config();
|
|
15
|
+
installProcessTeardownGuards("Login");
|
|
14
16
|
|
|
15
17
|
const rl = readline.createInterface({
|
|
16
18
|
input: process.stdin,
|
|
@@ -48,7 +50,8 @@ async function showMenu() {
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
console.log("\nOptions:");
|
|
51
|
-
console.log(" [A] Add account");
|
|
53
|
+
console.log(" [A] Add account (Password)");
|
|
54
|
+
console.log(" [O] Add account (Passwordless / Email OTP)");
|
|
52
55
|
if (accounts.length > 0) {
|
|
53
56
|
console.log(" [R] Remove an account");
|
|
54
57
|
}
|
|
@@ -62,7 +65,22 @@ async function showMenu() {
|
|
|
62
65
|
}
|
|
63
66
|
|
|
64
67
|
if (choice === "A") {
|
|
65
|
-
|
|
68
|
+
clear();
|
|
69
|
+
console.log("=== Add New Account ===\n");
|
|
70
|
+
console.log("Authentication method:");
|
|
71
|
+
console.log(" [1] Traditional Password (Email + Password)");
|
|
72
|
+
console.log(" [2] Passwordless (Email Verification Code / OTP)\n");
|
|
73
|
+
const method = (await askQuestion("Select method [1/2] (default 1): ")).trim();
|
|
74
|
+
if (method === "2") {
|
|
75
|
+
await addAccountOtpFlow();
|
|
76
|
+
} else {
|
|
77
|
+
await addAccountPasswordFlow();
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (choice === "O") {
|
|
83
|
+
await addAccountOtpFlow();
|
|
66
84
|
continue;
|
|
67
85
|
}
|
|
68
86
|
|
|
@@ -73,9 +91,9 @@ async function showMenu() {
|
|
|
73
91
|
}
|
|
74
92
|
}
|
|
75
93
|
|
|
76
|
-
async function
|
|
94
|
+
async function addAccountPasswordFlow() {
|
|
77
95
|
clear();
|
|
78
|
-
console.log("=== Add New Account ===\n");
|
|
96
|
+
console.log("=== Add New Account (Password Login) ===\n");
|
|
79
97
|
const email = await askQuestion("Email: ");
|
|
80
98
|
if (!email || !email.trim()) {
|
|
81
99
|
console.log("Email is required.");
|
|
@@ -149,6 +167,76 @@ async function addAccountFlow() {
|
|
|
149
167
|
await askQuestion("\nPress Enter to continue...");
|
|
150
168
|
}
|
|
151
169
|
|
|
170
|
+
async function addAccountOtpFlow() {
|
|
171
|
+
clear();
|
|
172
|
+
console.log("=== Add New Account (Passwordless / Email OTP) ===\n");
|
|
173
|
+
const email = await askQuestion("Email: ");
|
|
174
|
+
if (!email || !email.trim()) {
|
|
175
|
+
console.log("Email is required.");
|
|
176
|
+
await askQuestion("Press Enter to continue...");
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const trimmedEmail = email.trim();
|
|
181
|
+
const existingAccounts = listAccounts();
|
|
182
|
+
if (
|
|
183
|
+
existingAccounts.some(
|
|
184
|
+
(a) => a.email.toLowerCase() === trimmedEmail.toLowerCase(),
|
|
185
|
+
)
|
|
186
|
+
) {
|
|
187
|
+
console.log(
|
|
188
|
+
`\n❌ Error: An account with email "${trimmedEmail}" already exists.`,
|
|
189
|
+
);
|
|
190
|
+
await askQuestion("Press Enter to continue...");
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
console.log(
|
|
195
|
+
`\n⏳ Requesting OTP verification code for ${maskEmail(trimmedEmail)}...`,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
const { startEmailOtpLogin, verifyEmailOtpLogin, cancelEmailOtpLogin } =
|
|
199
|
+
await import("./services/playwright.ts");
|
|
200
|
+
|
|
201
|
+
const startRes = await startEmailOtpLogin(trimmedEmail, { headless: false });
|
|
202
|
+
if (!startRes.success || !startRes.sessionId) {
|
|
203
|
+
console.log(
|
|
204
|
+
`\n❌ Failed to request code: ${startRes.error || "Unknown error"}`,
|
|
205
|
+
);
|
|
206
|
+
await askQuestion("Press Enter to continue...");
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console.log(`\n✉️ Verification code sent to ${trimmedEmail}!`);
|
|
211
|
+
console.log("Check your email inbox (and spam folder).\n");
|
|
212
|
+
|
|
213
|
+
while (true) {
|
|
214
|
+
const code = await askQuestion("Enter 6-digit code (or 'C' to cancel): ");
|
|
215
|
+
if (!code || !code.trim()) continue;
|
|
216
|
+
|
|
217
|
+
if (code.trim().toUpperCase() === "C") {
|
|
218
|
+
await cancelEmailOtpLogin(startRes.sessionId);
|
|
219
|
+
console.log("\nLogin cancelled.");
|
|
220
|
+
await askQuestion("Press Enter to continue...");
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
console.log("\n⏳ Verifying code and establishing 30-day session...");
|
|
225
|
+
const verifyRes = await verifyEmailOtpLogin(startRes.sessionId, code.trim());
|
|
226
|
+
if (verifyRes.success && verifyRes.account) {
|
|
227
|
+
console.log(
|
|
228
|
+
`\n✅ Account verified and saved: ${maskEmail(verifyRes.account.email)} (${verifyRes.account.id})`,
|
|
229
|
+
);
|
|
230
|
+
console.log("Passwordless 30-day session active.");
|
|
231
|
+
await askQuestion("\nPress Enter to continue...");
|
|
232
|
+
return;
|
|
233
|
+
} else {
|
|
234
|
+
console.log(`\n❌ ${verifyRes.error || "Invalid code"}`);
|
|
235
|
+
console.log("Please try again or enter 'C' to cancel.\n");
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
152
240
|
async function removeAccountFlow() {
|
|
153
241
|
const accounts = listAccounts();
|
|
154
242
|
if (accounts.length === 0) return;
|
|
@@ -82,8 +82,8 @@ const MAX_ANTI_BOT_ROTATIONS = 1;
|
|
|
82
82
|
* a stuck account page (closed context / WAF) can otherwise hold each browser
|
|
83
83
|
* op for 60s and keep the personalization mutex blocked for minutes.
|
|
84
84
|
*/
|
|
85
|
-
export const PERSONALIZATION_SYNC_DEADLINE_MS =
|
|
86
|
-
export const COLD_ACCOUNT_PERSONALIZATION_SYNC_DEADLINE_MS =
|
|
85
|
+
export const PERSONALIZATION_SYNC_DEADLINE_MS = 90_000;
|
|
86
|
+
export const COLD_ACCOUNT_PERSONALIZATION_SYNC_DEADLINE_MS = 120_000;
|
|
87
87
|
|
|
88
88
|
export function computePersonalizationDeadlineMs(
|
|
89
89
|
accountId: string | undefined,
|
|
@@ -1282,8 +1282,15 @@ async function tryCreateStreamWithRetry(
|
|
|
1282
1282
|
const { isCaptchaRecoveryActive } = await import(
|
|
1283
1283
|
"../../services/captcha-coordinator.ts"
|
|
1284
1284
|
);
|
|
1285
|
-
|
|
1286
|
-
|
|
1285
|
+
const { isPlaywrightInitializing } = await import(
|
|
1286
|
+
"../../services/playwright.ts"
|
|
1287
|
+
);
|
|
1288
|
+
if (
|
|
1289
|
+
currentAccountId &&
|
|
1290
|
+
(isCaptchaRecoveryActive(currentAccountId) ||
|
|
1291
|
+
isPlaywrightInitializing(currentAccountId))
|
|
1292
|
+
) {
|
|
1293
|
+
// Captcha solver is actively solving puzzle or browser is launching/initializing; extend deadline by 30s
|
|
1287
1294
|
acquireDeadlineTimer = setTimeout(checkDeadline, 30_000);
|
|
1288
1295
|
acquireDeadlineTimer.unref?.();
|
|
1289
1296
|
return;
|