qwenproxy-cli 1.5.0 → 1.5.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 +40 -44
- package/dist/delete-chats.js +91 -44
- package/dist/index.js +87 -121
- package/dist/login.js +37 -44
- package/dist/reset-cooldowns.js +40 -44
- package/dist/sync-clients.js +2 -0
- package/package.json +3 -3
- package/src/api/server.ts +17 -59
- package/src/core/config.ts +2 -0
- package/src/core/version.ts +1 -1
- package/src/routes/chat/streaming.ts +1 -1
- package/src/services/auth-playwright.ts +5 -0
- package/src/services/playwright.ts +40 -49
- package/src/tools/instructions.ts +38 -25
- package/src/tools/parser.ts +7 -0
package/dist/index.js
CHANGED
|
@@ -263,6 +263,7 @@ var init_config = __esm({
|
|
|
263
263
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
264
264
|
// drop out of the warm set and get evicted.
|
|
265
265
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
266
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
266
267
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
267
268
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
268
269
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -411,6 +412,7 @@ var init_config = __esm({
|
|
|
411
412
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
412
413
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
413
414
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
415
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
414
416
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
415
417
|
},
|
|
416
418
|
captcha: {
|
|
@@ -4537,26 +4539,6 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
4537
4539
|
}
|
|
4538
4540
|
} catch {
|
|
4539
4541
|
}
|
|
4540
|
-
try {
|
|
4541
|
-
const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
4542
|
-
method: "GET",
|
|
4543
|
-
credentials: "include",
|
|
4544
|
-
signal: AbortSignal.timeout(3e3)
|
|
4545
|
-
});
|
|
4546
|
-
if (refreshRes.status === 200) {
|
|
4547
|
-
const refreshJson = await refreshRes.json().catch(() => null);
|
|
4548
|
-
if (refreshJson && refreshJson.success === false) {
|
|
4549
|
-
const code = refreshJson.data?.code || refreshJson.code;
|
|
4550
|
-
const details = String(refreshJson.data?.details || "");
|
|
4551
|
-
if (code === "Unauthorized" || details.includes("revogado") || details.includes("revoked")) {
|
|
4552
|
-
return false;
|
|
4553
|
-
}
|
|
4554
|
-
}
|
|
4555
|
-
} else if (refreshRes.status === 401 || refreshRes.status === 403) {
|
|
4556
|
-
return false;
|
|
4557
|
-
}
|
|
4558
|
-
} catch {
|
|
4559
|
-
}
|
|
4560
4542
|
return true;
|
|
4561
4543
|
} catch {
|
|
4562
4544
|
return false;
|
|
@@ -5684,7 +5666,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
5684
5666
|
`\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
|
|
5685
5667
|
);
|
|
5686
5668
|
}
|
|
5687
|
-
if (!options.skipHeaderCapture) {
|
|
5669
|
+
if (!options.skipHeaderCapture && !isAccountHeadersReady(account.id)) {
|
|
5688
5670
|
acctPage.__qwenChatHomeLoaded = true;
|
|
5689
5671
|
await captureQwenHeaders(account.id);
|
|
5690
5672
|
}
|
|
@@ -6014,7 +5996,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
6014
5996
|
);
|
|
6015
5997
|
markAccountRateLimited(
|
|
6016
5998
|
accountId,
|
|
6017
|
-
|
|
5999
|
+
300 * 1e3,
|
|
6018
6000
|
"AuthFailed: All login methods exhausted"
|
|
6019
6001
|
);
|
|
6020
6002
|
return false;
|
|
@@ -6291,38 +6273,49 @@ async function loginViaUi(page, email, password) {
|
|
|
6291
6273
|
try {
|
|
6292
6274
|
const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
|
|
6293
6275
|
const passEl = document.querySelector('input[type="password"], input[name="password"]');
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
|
|
6297
|
-
|
|
6298
|
-
|
|
6299
|
-
|
|
6300
|
-
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6276
|
+
const setReactValue = (el, val) => {
|
|
6277
|
+
const proto = Object.getPrototypeOf(el);
|
|
6278
|
+
const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
|
|
6279
|
+
if (setter) {
|
|
6280
|
+
setter.call(el, val);
|
|
6281
|
+
} else {
|
|
6282
|
+
el.value = val;
|
|
6283
|
+
}
|
|
6284
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
6285
|
+
el.dispatchEvent(new Event("change", { bubbles: true }));
|
|
6286
|
+
el.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
6287
|
+
};
|
|
6288
|
+
if (emailEl) setReactValue(emailEl, emailEl.value);
|
|
6289
|
+
if (passEl) setReactValue(passEl, passEl.value);
|
|
6304
6290
|
} catch {
|
|
6305
6291
|
}
|
|
6306
6292
|
}).catch(() => {
|
|
6307
6293
|
});
|
|
6294
|
+
await sleep2(500);
|
|
6308
6295
|
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")';
|
|
6309
6296
|
const submitButton = page.locator(submitSelector).first();
|
|
6297
|
+
await page.evaluate((sel) => {
|
|
6298
|
+
try {
|
|
6299
|
+
const btn = document.querySelector(sel);
|
|
6300
|
+
if (btn) {
|
|
6301
|
+
btn.removeAttribute("disabled");
|
|
6302
|
+
btn.classList.remove("ant-btn-disabled");
|
|
6303
|
+
btn.click();
|
|
6304
|
+
}
|
|
6305
|
+
} catch {
|
|
6306
|
+
}
|
|
6307
|
+
}, submitSelector).catch(() => {
|
|
6308
|
+
});
|
|
6310
6309
|
try {
|
|
6311
|
-
await
|
|
6312
|
-
timeout:
|
|
6313
|
-
});
|
|
6314
|
-
await submitButton.click();
|
|
6315
|
-
} catch {
|
|
6316
|
-
const isDisabled = await submitButton.isDisabled().catch(() => true);
|
|
6317
|
-
if (!isDisabled) {
|
|
6318
|
-
await submitButton.click({ force: true }).catch(() => {
|
|
6310
|
+
if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
|
|
6311
|
+
await submitButton.click({ force: true, timeout: 2e3 }).catch(() => {
|
|
6319
6312
|
});
|
|
6320
|
-
} else {
|
|
6321
|
-
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
|
|
6322
|
-
return { success: true };
|
|
6323
|
-
}
|
|
6324
6313
|
}
|
|
6314
|
+
} catch {
|
|
6325
6315
|
}
|
|
6316
|
+
const passInput = page.locator(passwordSelector).first();
|
|
6317
|
+
await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
|
|
6318
|
+
});
|
|
6326
6319
|
const postSubmitDeadline = Date.now() + 15e3;
|
|
6327
6320
|
while (Date.now() < postSubmitDeadline) {
|
|
6328
6321
|
if (page.isClosed()) break;
|
|
@@ -8031,6 +8024,11 @@ async function ensurePlaywrightInitialized(accountId) {
|
|
|
8031
8024
|
});
|
|
8032
8025
|
} catch {
|
|
8033
8026
|
}
|
|
8027
|
+
try {
|
|
8028
|
+
const { ensureAccountInPriority: ensureAccountInPriority2 } = await Promise.resolve().then(() => (init_account_priority(), account_priority_exports));
|
|
8029
|
+
ensureAccountInPriority2(accountId);
|
|
8030
|
+
} catch {
|
|
8031
|
+
}
|
|
8034
8032
|
}
|
|
8035
8033
|
async function getBasicHeaders2(accountId) {
|
|
8036
8034
|
if (isAuthMockEnabled()) {
|
|
@@ -14699,12 +14697,12 @@ function buildToolInstructions(toolsJson, toolChoice) {
|
|
|
14699
14697
|
const sampleToolName = typeof firstTool?.function?.name === "string" && firstTool.function.name || typeof firstTool?.name === "string" && firstTool.name || "tool_name";
|
|
14700
14698
|
const properties = firstTool?.function?.parameters?.properties || firstTool?.parameters?.properties;
|
|
14701
14699
|
const firstPropKey = properties && typeof properties === "object" ? Object.keys(properties)[0] : null;
|
|
14702
|
-
|
|
14703
|
-
|
|
14704
|
-
|
|
14705
|
-
|
|
14706
|
-
|
|
14707
|
-
}
|
|
14700
|
+
const sampleArgs1 = firstPropKey ? JSON.stringify({ [firstPropKey]: "value1" }) : "{}";
|
|
14701
|
+
const secondTool = toolList.length > 1 ? toolList[1] : null;
|
|
14702
|
+
const secondToolName = secondTool ? typeof secondTool?.function?.name === "string" && secondTool.function.name || typeof secondTool?.name === "string" && secondTool.name || sampleToolName : null;
|
|
14703
|
+
const secondProperties = secondTool?.function?.parameters?.properties || secondTool?.parameters?.properties;
|
|
14704
|
+
const secondPropKey = secondProperties && typeof secondProperties === "object" ? Object.keys(secondProperties)[0] : null;
|
|
14705
|
+
const sampleArgs2 = secondPropKey ? JSON.stringify({ [secondPropKey]: "value2" }) : "{}";
|
|
14708
14706
|
let forcedInstruction = "";
|
|
14709
14707
|
if (toolChoice && typeof toolChoice === "object" && toolChoice.function?.name) {
|
|
14710
14708
|
forcedInstruction = `
|
|
@@ -14715,32 +14713,30 @@ CRITICAL: You MUST call the tool "${toolChoice.function.name}" in this response.
|
|
|
14715
14713
|
CRITICAL: You MUST call at least one tool from the list above in this response.
|
|
14716
14714
|
`;
|
|
14717
14715
|
}
|
|
14716
|
+
const secondExample = secondToolName ? `
|
|
14717
|
+
${TOOL_CALL_OPEN}
|
|
14718
|
+
{"name": "${secondToolName}", "arguments": ${sampleArgs2}}
|
|
14719
|
+
${TOOL_CALL_CLOSE}` : "";
|
|
14718
14720
|
let instructions = `
|
|
14719
14721
|
|
|
14720
14722
|
# TOOLS AVAILABLE
|
|
14723
|
+
You may call one or more functions to assist with the user query.
|
|
14724
|
+
You are provided with function signatures within <tools></tools> XML tags:
|
|
14725
|
+
<tools>
|
|
14721
14726
|
${manifest}
|
|
14727
|
+
</tools>
|
|
14722
14728
|
${forcedInstruction}
|
|
14723
|
-
[TOOL CALL CONTRACT
|
|
14724
|
-
To
|
|
14725
|
-
When calling multiple independent tools, output consecutive blocks:
|
|
14726
|
-
|
|
14729
|
+
[TOOL CALL CONTRACT]
|
|
14730
|
+
To call a tool, output a JSON object wrapped EXACTLY in ${TOOL_CALL_OPEN} and ${TOOL_CALL_CLOSE} tags:
|
|
14727
14731
|
${TOOL_CALL_OPEN}
|
|
14728
14732
|
{"name": "${sampleToolName}", "arguments": ${sampleArgs1}}
|
|
14729
|
-
${TOOL_CALL_CLOSE}
|
|
14730
|
-
${TOOL_CALL_OPEN}
|
|
14731
|
-
{"name": "${sampleToolName}", "arguments": ${sampleArgs2}}
|
|
14732
|
-
${TOOL_CALL_CLOSE}
|
|
14733
|
+
${TOOL_CALL_CLOSE}${secondExample}
|
|
14733
14734
|
|
|
14734
|
-
|
|
14735
|
-
1.
|
|
14736
|
-
2.
|
|
14737
|
-
3.
|
|
14738
|
-
4.
|
|
14739
|
-
5. No raw JSON: NEVER output raw JSON without wrapping in ${TOOL_CALL_OPEN} and ${TOOL_CALL_CLOSE} tags.
|
|
14740
|
-
6. Clean blocks: Put only valid JSON inside each block \u2014 no markdown fences (\`\`\`json), comments, or explanatory text.
|
|
14741
|
-
7. Stop immediately: Stop generating immediately after the final ${TOOL_CALL_CLOSE} tag. Do not emit trailing dots, ellipsis (......), explanations, or reasoning after the tool calls.
|
|
14742
|
-
8. Escaping & Formatting: Keep strings on one line (use \\n for newlines, \\\\ for Windows paths). Do not split values across lines.
|
|
14743
|
-
9. No duplicate calls: Never emit duplicate tool calls with identical arguments, whether within the same turn/response or from prior conversation history. Every call must perform distinct work.
|
|
14735
|
+
GUIDELINES:
|
|
14736
|
+
1. Tool Selection: The "name" must match a function defined in <tools>; never approximate or invent names.
|
|
14737
|
+
2. Arguments Format: "arguments" must be a valid JSON object matching the function's parameter schema. Put only valid JSON inside each block \u2014 no markdown fences (\`\`\`json), comments, or text.
|
|
14738
|
+
3. Parallel Execution: When multiple operations are needed, emit consecutive ${TOOL_CALL_OPEN} blocks (at most 4 per turn). Each block must be complete and self-contained (never nested, interleaved, or omitted).
|
|
14739
|
+
4. Direct Invocation: Stop generation after the tool call block so the tools can be executed. Never output raw JSON without ${TOOL_CALL_OPEN} tags.
|
|
14744
14740
|
`;
|
|
14745
14741
|
if (toolInstructionsCache.size >= TOOL_CACHE_MAX_ENTRIES) {
|
|
14746
14742
|
toolInstructionsCache.clear();
|
|
@@ -18215,6 +18211,7 @@ var init_parser = __esm({
|
|
|
18215
18211
|
currentOpenTag = TOOL_START_LITERAL;
|
|
18216
18212
|
currentCloseTag = TOOL_END;
|
|
18217
18213
|
emittedToolCallCount = 0;
|
|
18214
|
+
successfulToolCallsCount = 0;
|
|
18218
18215
|
pendingLeadIn = "";
|
|
18219
18216
|
tools = [];
|
|
18220
18217
|
declaredToolNames = [];
|
|
@@ -18422,6 +18419,7 @@ var init_parser = __esm({
|
|
|
18422
18419
|
if (matchesIncrementalCall) {
|
|
18423
18420
|
this.flushPendingToolCallDeltas(result);
|
|
18424
18421
|
this.emittedToolCallCount++;
|
|
18422
|
+
this.successfulToolCallsCount++;
|
|
18425
18423
|
this.pendingLeadIn = "";
|
|
18426
18424
|
incremental.startEmitted = false;
|
|
18427
18425
|
incremental.disabled = true;
|
|
@@ -18430,6 +18428,7 @@ var init_parser = __esm({
|
|
|
18430
18428
|
this.flushPendingToolCallDeltas(result);
|
|
18431
18429
|
result.toolCalls.push(tc);
|
|
18432
18430
|
this.emittedToolCallCount++;
|
|
18431
|
+
this.successfulToolCallsCount++;
|
|
18433
18432
|
this.pendingLeadIn = "";
|
|
18434
18433
|
}
|
|
18435
18434
|
tryRecoverIncrementalToolCall(content) {
|
|
@@ -18889,6 +18888,9 @@ var init_parser = __esm({
|
|
|
18889
18888
|
getEmittedToolCallCount() {
|
|
18890
18889
|
return this.emittedToolCallCount;
|
|
18891
18890
|
}
|
|
18891
|
+
getSuccessfulToolCallCount() {
|
|
18892
|
+
return this.successfulToolCallsCount;
|
|
18893
|
+
}
|
|
18892
18894
|
isInsideTool() {
|
|
18893
18895
|
return this.insideTool;
|
|
18894
18896
|
}
|
|
@@ -21354,7 +21356,7 @@ async function processStreamingResponse(params) {
|
|
|
21354
21356
|
let activeRetryStream = null;
|
|
21355
21357
|
while (malformedRetryCount < maxMalformedRetries) {
|
|
21356
21358
|
if (!toolParser) break;
|
|
21357
|
-
const allToolsFailed = toolParser.getMalformedToolCalls().length > 0 && toolParser.
|
|
21359
|
+
const allToolsFailed = toolParser.getMalformedToolCalls().length > 0 && toolParser.getSuccessfulToolCallCount() === 0;
|
|
21358
21360
|
if (!allToolsFailed) break;
|
|
21359
21361
|
const malformedCalls = toolParser.getMalformedToolCalls();
|
|
21360
21362
|
const malformedCount = malformedCalls.length;
|
|
@@ -25889,7 +25891,7 @@ function getAppVersion() {
|
|
|
25889
25891
|
}
|
|
25890
25892
|
} catch {
|
|
25891
25893
|
}
|
|
25892
|
-
cachedVersion = "v1.5.
|
|
25894
|
+
cachedVersion = "v1.5.2";
|
|
25893
25895
|
return cachedVersion;
|
|
25894
25896
|
}
|
|
25895
25897
|
var cachedVersion;
|
|
@@ -26293,17 +26295,16 @@ async function startServer(options) {
|
|
|
26293
26295
|
);
|
|
26294
26296
|
});
|
|
26295
26297
|
} else if (remainingAccounts.length > 0) {
|
|
26296
|
-
console.log(
|
|
26297
|
-
`\u{1FAB6} [Server] ${remainingAccounts.length} standby account(s) will initialize on demand`
|
|
26298
|
-
);
|
|
26299
26298
|
void (async () => {
|
|
26300
|
-
const { validateAccountLogin: validateAccountLogin2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
26301
26299
|
const { ensureAccountInPriority: ensureAccountInPriority2 } = await Promise.resolve().then(() => (init_account_priority(), account_priority_exports));
|
|
26302
|
-
|
|
26303
|
-
|
|
26304
|
-
|
|
26305
|
-
|
|
26306
|
-
|
|
26300
|
+
const targetWarmTotal = Math.min(
|
|
26301
|
+
config.playwright.startupWarmAccounts,
|
|
26302
|
+
totalAccounts
|
|
26303
|
+
);
|
|
26304
|
+
let currentReadyCount = readyAccountIds.size;
|
|
26305
|
+
if (currentReadyCount < targetWarmTotal && remainingAccounts.length > 0) {
|
|
26306
|
+
for (const reserveAccount of remainingAccounts) {
|
|
26307
|
+
if (currentReadyCount >= targetWarmTotal) break;
|
|
26307
26308
|
try {
|
|
26308
26309
|
const ok = await prepareAccountRuntime(
|
|
26309
26310
|
reserveAccount,
|
|
@@ -26313,12 +26314,12 @@ async function startServer(options) {
|
|
|
26313
26314
|
warmQwenChatPool2
|
|
26314
26315
|
);
|
|
26315
26316
|
if (ok) {
|
|
26317
|
+
readyAccountIds.add(reserveAccount.id);
|
|
26316
26318
|
ensureAccountInPriority2(reserveAccount.id);
|
|
26319
|
+
currentReadyCount++;
|
|
26317
26320
|
console.log(
|
|
26318
|
-
`\u2705 [Server] Reserve account ready (
|
|
26321
|
+
`\u2705 [Server] Reserve account ready (${currentReadyCount}/${totalAccounts}): ${maskEmail(reserveAccount.email)}`
|
|
26319
26322
|
);
|
|
26320
|
-
reserveCandidateIdx++;
|
|
26321
|
-
break;
|
|
26322
26323
|
}
|
|
26323
26324
|
} catch (err) {
|
|
26324
26325
|
console.warn(
|
|
@@ -26326,51 +26327,16 @@ async function startServer(options) {
|
|
|
26326
26327
|
);
|
|
26327
26328
|
}
|
|
26328
26329
|
}
|
|
26329
|
-
accountsToValidate = remainingAccounts.slice(reserveCandidateIdx);
|
|
26330
26330
|
}
|
|
26331
|
-
|
|
26332
|
-
|
|
26333
|
-
for (const account of accountsToValidate) {
|
|
26334
|
-
try {
|
|
26335
|
-
const creds = getAccountCredentials2(account.id) ?? account;
|
|
26336
|
-
const ok = await validateAccountLogin2(
|
|
26337
|
-
creds,
|
|
26338
|
-
config.playwright.headless,
|
|
26339
|
-
config.playwright.browser
|
|
26340
|
-
);
|
|
26341
|
-
if (ok) {
|
|
26342
|
-
ensureAccountInPriority2(account.id);
|
|
26343
|
-
validated++;
|
|
26344
|
-
console.log(
|
|
26345
|
-
`\u2705 [Server] Standby account validated: ${maskEmail(account.email)}`
|
|
26346
|
-
);
|
|
26347
|
-
} else {
|
|
26348
|
-
failed++;
|
|
26349
|
-
console.warn(
|
|
26350
|
-
`\u26A0\uFE0F [Server] Standby account login failed: ${maskEmail(account.email)} (quarantined)`
|
|
26351
|
-
);
|
|
26352
|
-
}
|
|
26353
|
-
} catch (error) {
|
|
26354
|
-
failed++;
|
|
26355
|
-
console.warn(
|
|
26356
|
-
`\u26A0\uFE0F [Server] Standby account validation error: ${maskEmail(account.email)}: ${getErrorMessage2(error)} (quarantined)`
|
|
26357
|
-
);
|
|
26358
|
-
const { markAccountRateLimited: markAccountRateLimited2 } = await Promise.resolve().then(() => (init_account_manager(), account_manager_exports));
|
|
26359
|
-
markAccountRateLimited2(
|
|
26360
|
-
account.id,
|
|
26361
|
-
24 * 3600 * 1e3,
|
|
26362
|
-
`StandbyValidationError: ${getErrorMessage2(error)}`
|
|
26363
|
-
);
|
|
26364
|
-
}
|
|
26365
|
-
}
|
|
26366
|
-
if (validated > 0 || failed > 0) {
|
|
26331
|
+
const standbyCount = totalAccounts - currentReadyCount;
|
|
26332
|
+
if (standbyCount > 0) {
|
|
26367
26333
|
console.log(
|
|
26368
|
-
`\
|
|
26334
|
+
`\u{1FAB6} [Server] ${standbyCount} standby account(s) ready in pool (will initialize on demand when active accounts rotate)`
|
|
26369
26335
|
);
|
|
26370
26336
|
}
|
|
26371
26337
|
})().catch((error) => {
|
|
26372
26338
|
console.warn(
|
|
26373
|
-
`\u274C [Server] Background
|
|
26339
|
+
`\u274C [Server] Background account preparation failed: ${getErrorMessage2(error)}`
|
|
26374
26340
|
);
|
|
26375
26341
|
});
|
|
26376
26342
|
}
|
package/dist/login.js
CHANGED
|
@@ -1200,6 +1200,7 @@ var init_config = __esm({
|
|
|
1200
1200
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
1201
1201
|
// drop out of the warm set and get evicted.
|
|
1202
1202
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
1203
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
1203
1204
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
1204
1205
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
1205
1206
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -1348,6 +1349,7 @@ var init_config = __esm({
|
|
|
1348
1349
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
1349
1350
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
1350
1351
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
1352
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
1351
1353
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
1352
1354
|
},
|
|
1353
1355
|
captcha: {
|
|
@@ -3404,26 +3406,6 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
3404
3406
|
}
|
|
3405
3407
|
} catch {
|
|
3406
3408
|
}
|
|
3407
|
-
try {
|
|
3408
|
-
const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
3409
|
-
method: "GET",
|
|
3410
|
-
credentials: "include",
|
|
3411
|
-
signal: AbortSignal.timeout(3e3)
|
|
3412
|
-
});
|
|
3413
|
-
if (refreshRes.status === 200) {
|
|
3414
|
-
const refreshJson = await refreshRes.json().catch(() => null);
|
|
3415
|
-
if (refreshJson && refreshJson.success === false) {
|
|
3416
|
-
const code = refreshJson.data?.code || refreshJson.code;
|
|
3417
|
-
const details = String(refreshJson.data?.details || "");
|
|
3418
|
-
if (code === "Unauthorized" || details.includes("revogado") || details.includes("revoked")) {
|
|
3419
|
-
return false;
|
|
3420
|
-
}
|
|
3421
|
-
}
|
|
3422
|
-
} else if (refreshRes.status === 401 || refreshRes.status === 403) {
|
|
3423
|
-
return false;
|
|
3424
|
-
}
|
|
3425
|
-
} catch {
|
|
3426
|
-
}
|
|
3427
3409
|
return true;
|
|
3428
3410
|
} catch {
|
|
3429
3411
|
return false;
|
|
@@ -4551,7 +4533,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
4551
4533
|
`\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
|
|
4552
4534
|
);
|
|
4553
4535
|
}
|
|
4554
|
-
if (!options.skipHeaderCapture) {
|
|
4536
|
+
if (!options.skipHeaderCapture && !isAccountHeadersReady(account.id)) {
|
|
4555
4537
|
acctPage.__qwenChatHomeLoaded = true;
|
|
4556
4538
|
await captureQwenHeaders(account.id);
|
|
4557
4539
|
}
|
|
@@ -4881,7 +4863,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4881
4863
|
);
|
|
4882
4864
|
markAccountRateLimited(
|
|
4883
4865
|
accountId,
|
|
4884
|
-
|
|
4866
|
+
300 * 1e3,
|
|
4885
4867
|
"AuthFailed: All login methods exhausted"
|
|
4886
4868
|
);
|
|
4887
4869
|
return false;
|
|
@@ -5158,38 +5140,49 @@ async function loginViaUi(page, email, password) {
|
|
|
5158
5140
|
try {
|
|
5159
5141
|
const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
|
|
5160
5142
|
const passEl = document.querySelector('input[type="password"], input[name="password"]');
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5143
|
+
const setReactValue = (el, val) => {
|
|
5144
|
+
const proto = Object.getPrototypeOf(el);
|
|
5145
|
+
const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
|
|
5146
|
+
if (setter) {
|
|
5147
|
+
setter.call(el, val);
|
|
5148
|
+
} else {
|
|
5149
|
+
el.value = val;
|
|
5150
|
+
}
|
|
5151
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
5152
|
+
el.dispatchEvent(new Event("change", { bubbles: true }));
|
|
5153
|
+
el.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
5154
|
+
};
|
|
5155
|
+
if (emailEl) setReactValue(emailEl, emailEl.value);
|
|
5156
|
+
if (passEl) setReactValue(passEl, passEl.value);
|
|
5171
5157
|
} catch {
|
|
5172
5158
|
}
|
|
5173
5159
|
}).catch(() => {
|
|
5174
5160
|
});
|
|
5161
|
+
await sleep2(500);
|
|
5175
5162
|
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")';
|
|
5176
5163
|
const submitButton = page.locator(submitSelector).first();
|
|
5164
|
+
await page.evaluate((sel) => {
|
|
5165
|
+
try {
|
|
5166
|
+
const btn = document.querySelector(sel);
|
|
5167
|
+
if (btn) {
|
|
5168
|
+
btn.removeAttribute("disabled");
|
|
5169
|
+
btn.classList.remove("ant-btn-disabled");
|
|
5170
|
+
btn.click();
|
|
5171
|
+
}
|
|
5172
|
+
} catch {
|
|
5173
|
+
}
|
|
5174
|
+
}, submitSelector).catch(() => {
|
|
5175
|
+
});
|
|
5177
5176
|
try {
|
|
5178
|
-
await
|
|
5179
|
-
timeout:
|
|
5180
|
-
});
|
|
5181
|
-
await submitButton.click();
|
|
5182
|
-
} catch {
|
|
5183
|
-
const isDisabled = await submitButton.isDisabled().catch(() => true);
|
|
5184
|
-
if (!isDisabled) {
|
|
5185
|
-
await submitButton.click({ force: true }).catch(() => {
|
|
5177
|
+
if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
|
|
5178
|
+
await submitButton.click({ force: true, timeout: 2e3 }).catch(() => {
|
|
5186
5179
|
});
|
|
5187
|
-
} else {
|
|
5188
|
-
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
|
|
5189
|
-
return { success: true };
|
|
5190
|
-
}
|
|
5191
5180
|
}
|
|
5181
|
+
} catch {
|
|
5192
5182
|
}
|
|
5183
|
+
const passInput = page.locator(passwordSelector).first();
|
|
5184
|
+
await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
|
|
5185
|
+
});
|
|
5193
5186
|
const postSubmitDeadline = Date.now() + 15e3;
|
|
5194
5187
|
while (Date.now() < postSubmitDeadline) {
|
|
5195
5188
|
if (page.isClosed()) break;
|
package/dist/reset-cooldowns.js
CHANGED
|
@@ -1174,6 +1174,9 @@ function unmarkAccountHeadersReady(accountId) {
|
|
|
1174
1174
|
if (!accountId) return;
|
|
1175
1175
|
headersReadyAccounts.delete(accountId);
|
|
1176
1176
|
}
|
|
1177
|
+
function isAccountHeadersReady(accountId) {
|
|
1178
|
+
return headersReadyAccounts.has(accountId);
|
|
1179
|
+
}
|
|
1177
1180
|
var cooldowns, headersReadyAccounts;
|
|
1178
1181
|
var init_account_manager = __esm({
|
|
1179
1182
|
"src/core/account-manager.ts"() {
|
|
@@ -1299,6 +1302,7 @@ var init_config = __esm({
|
|
|
1299
1302
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
1300
1303
|
// drop out of the warm set and get evicted.
|
|
1301
1304
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
1305
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
1302
1306
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
1303
1307
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
1304
1308
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -1447,6 +1451,7 @@ var init_config = __esm({
|
|
|
1447
1451
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
1448
1452
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
1449
1453
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
1454
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
1450
1455
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
1451
1456
|
},
|
|
1452
1457
|
captcha: {
|
|
@@ -3121,26 +3126,6 @@ async function isPageLoggedIn(page, timeoutMs = SESSION_PROBE_NAVIGATION_TIMEOUT
|
|
|
3121
3126
|
}
|
|
3122
3127
|
} catch {
|
|
3123
3128
|
}
|
|
3124
|
-
try {
|
|
3125
|
-
const refreshRes = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
|
|
3126
|
-
method: "GET",
|
|
3127
|
-
credentials: "include",
|
|
3128
|
-
signal: AbortSignal.timeout(3e3)
|
|
3129
|
-
});
|
|
3130
|
-
if (refreshRes.status === 200) {
|
|
3131
|
-
const refreshJson = await refreshRes.json().catch(() => null);
|
|
3132
|
-
if (refreshJson && refreshJson.success === false) {
|
|
3133
|
-
const code = refreshJson.data?.code || refreshJson.code;
|
|
3134
|
-
const details = String(refreshJson.data?.details || "");
|
|
3135
|
-
if (code === "Unauthorized" || details.includes("revogado") || details.includes("revoked")) {
|
|
3136
|
-
return false;
|
|
3137
|
-
}
|
|
3138
|
-
}
|
|
3139
|
-
} else if (refreshRes.status === 401 || refreshRes.status === 403) {
|
|
3140
|
-
return false;
|
|
3141
|
-
}
|
|
3142
|
-
} catch {
|
|
3143
|
-
}
|
|
3144
3129
|
return true;
|
|
3145
3130
|
} catch {
|
|
3146
3131
|
return false;
|
|
@@ -3946,7 +3931,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
3946
3931
|
`\u26A0\uFE0F [Playwright] Initial navigation check for ${maskEmail(account.email)}: ${err.message}`
|
|
3947
3932
|
);
|
|
3948
3933
|
}
|
|
3949
|
-
if (!options.skipHeaderCapture) {
|
|
3934
|
+
if (!options.skipHeaderCapture && !isAccountHeadersReady(account.id)) {
|
|
3950
3935
|
acctPage.__qwenChatHomeLoaded = true;
|
|
3951
3936
|
await captureQwenHeaders(account.id);
|
|
3952
3937
|
}
|
|
@@ -4156,7 +4141,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
4156
4141
|
);
|
|
4157
4142
|
markAccountRateLimited(
|
|
4158
4143
|
accountId,
|
|
4159
|
-
|
|
4144
|
+
300 * 1e3,
|
|
4160
4145
|
"AuthFailed: All login methods exhausted"
|
|
4161
4146
|
);
|
|
4162
4147
|
return false;
|
|
@@ -4433,38 +4418,49 @@ async function loginViaUi(page, email, password) {
|
|
|
4433
4418
|
try {
|
|
4434
4419
|
const emailEl = document.querySelector('input[name="email"], input[type="email"], input[type="text"]');
|
|
4435
4420
|
const passEl = document.querySelector('input[type="password"], input[name="password"]');
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4421
|
+
const setReactValue = (el, val) => {
|
|
4422
|
+
const proto = Object.getPrototypeOf(el);
|
|
4423
|
+
const setter = Object.getOwnPropertyDescriptor(proto, "value")?.set;
|
|
4424
|
+
if (setter) {
|
|
4425
|
+
setter.call(el, val);
|
|
4426
|
+
} else {
|
|
4427
|
+
el.value = val;
|
|
4428
|
+
}
|
|
4429
|
+
el.dispatchEvent(new Event("input", { bubbles: true }));
|
|
4430
|
+
el.dispatchEvent(new Event("change", { bubbles: true }));
|
|
4431
|
+
el.dispatchEvent(new Event("blur", { bubbles: true }));
|
|
4432
|
+
};
|
|
4433
|
+
if (emailEl) setReactValue(emailEl, emailEl.value);
|
|
4434
|
+
if (passEl) setReactValue(passEl, passEl.value);
|
|
4446
4435
|
} catch {
|
|
4447
4436
|
}
|
|
4448
4437
|
}).catch(() => {
|
|
4449
4438
|
});
|
|
4439
|
+
await sleep2(500);
|
|
4450
4440
|
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")';
|
|
4451
4441
|
const submitButton = page.locator(submitSelector).first();
|
|
4442
|
+
await page.evaluate((sel) => {
|
|
4443
|
+
try {
|
|
4444
|
+
const btn = document.querySelector(sel);
|
|
4445
|
+
if (btn) {
|
|
4446
|
+
btn.removeAttribute("disabled");
|
|
4447
|
+
btn.classList.remove("ant-btn-disabled");
|
|
4448
|
+
btn.click();
|
|
4449
|
+
}
|
|
4450
|
+
} catch {
|
|
4451
|
+
}
|
|
4452
|
+
}, submitSelector).catch(() => {
|
|
4453
|
+
});
|
|
4452
4454
|
try {
|
|
4453
|
-
await
|
|
4454
|
-
timeout:
|
|
4455
|
-
});
|
|
4456
|
-
await submitButton.click();
|
|
4457
|
-
} catch {
|
|
4458
|
-
const isDisabled = await submitButton.isDisabled().catch(() => true);
|
|
4459
|
-
if (!isDisabled) {
|
|
4460
|
-
await submitButton.click({ force: true }).catch(() => {
|
|
4455
|
+
if (await submitButton.isVisible({ timeout: 2e3 }).catch(() => false)) {
|
|
4456
|
+
await submitButton.click({ force: true, timeout: 2e3 }).catch(() => {
|
|
4461
4457
|
});
|
|
4462
|
-
} else {
|
|
4463
|
-
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 2e3)) {
|
|
4464
|
-
return { success: true };
|
|
4465
|
-
}
|
|
4466
4458
|
}
|
|
4459
|
+
} catch {
|
|
4467
4460
|
}
|
|
4461
|
+
const passInput = page.locator(passwordSelector).first();
|
|
4462
|
+
await passInput.press("Enter", { timeout: 2e3 }).catch(() => {
|
|
4463
|
+
});
|
|
4468
4464
|
const postSubmitDeadline = Date.now() + 15e3;
|
|
4469
4465
|
while (Date.now() < postSubmitDeadline) {
|
|
4470
4466
|
if (page.isClosed()) break;
|
package/dist/sync-clients.js
CHANGED
|
@@ -157,6 +157,7 @@ var envSchema = z.object({
|
|
|
157
157
|
// own context while serving. Accounts in cooldown (rate-limited) sit idle,
|
|
158
158
|
// drop out of the warm set and get evicted.
|
|
159
159
|
PLAYWRIGHT_MAX_ACTIVE_CONTEXTS: z.string().default("2"),
|
|
160
|
+
PLAYWRIGHT_STARTUP_WARM_ACCOUNTS: z.string().default("4"),
|
|
160
161
|
PLAYWRIGHT_PREPARE_ALL_ON_STARTUP: z.string().default("false"),
|
|
161
162
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
162
163
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
@@ -305,6 +306,7 @@ var config = {
|
|
|
305
306
|
jsHeapMb: Math.max(64, parseInt(env.PLAYWRIGHT_JS_HEAP_MB)),
|
|
306
307
|
lowMemoryFlags: env.PLAYWRIGHT_LOW_MEMORY_FLAGS !== "false",
|
|
307
308
|
maxActiveContexts: Math.max(0, parseInt(env.PLAYWRIGHT_MAX_ACTIVE_CONTEXTS)),
|
|
309
|
+
startupWarmAccounts: Math.max(1, parseInt(env.PLAYWRIGHT_STARTUP_WARM_ACCOUNTS)),
|
|
308
310
|
prepareAllOnStartup: env.PLAYWRIGHT_PREPARE_ALL_ON_STARTUP !== "false"
|
|
309
311
|
},
|
|
310
312
|
captcha: {
|