qwenproxy-cli 1.6.10 → 1.6.12
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 +390 -30
- package/dist/delete-chats.js +946 -445
- package/dist/index.js +612 -100
- package/dist/login.js +417 -51
- package/dist/reset-cooldowns.js +769 -407
- package/dist/sync-clients.js +4 -1
- package/package.json +2 -2
- package/src/api/server.ts +8 -4
- package/src/core/config.ts +4 -1
- package/src/core/model-alias.ts +1 -0
- package/src/core/version.ts +1 -1
- package/src/core/watchdog.ts +4 -3
- package/src/routes/chat/account.ts +12 -0
- package/src/routes/chat/streaming.ts +18 -2
- package/src/services/auth-playwright.ts +3 -2
- package/src/services/captcha-coordinator.ts +41 -11
- package/src/services/captcha-solver.ts +400 -2
- package/src/services/chat-cleanup.ts +11 -2
- package/src/services/playwright.ts +135 -50
- package/src/services/qwen-chat-pool.ts +52 -9
- package/src/services/qwen-headers.ts +18 -1
- package/src/services/qwen.ts +35 -7
- package/src/services/session-keeper.ts +70 -8
package/dist/index.js
CHANGED
|
@@ -266,7 +266,7 @@ var init_config = __esm({
|
|
|
266
266
|
// Version header on Qwen API requests = the deployed web bundle version
|
|
267
267
|
// (fallback when dynamic DOM detection is not yet completed).
|
|
268
268
|
// Override via env when Qwen ships a new bundle.
|
|
269
|
-
QWEN_WEB_VERSION: z.string().default("0.3.
|
|
269
|
+
QWEN_WEB_VERSION: z.string().default("0.3.43"),
|
|
270
270
|
// Controls bx-ua/bx-umidtoken injection on the GENERAL API paths
|
|
271
271
|
// (chats/new, settings): those work without them (live-probed). The
|
|
272
272
|
// completions path is the exception — the 0.2.86 HAR shows the real
|
|
@@ -309,6 +309,7 @@ var init_config = __esm({
|
|
|
309
309
|
CAPTCHA_SOLVER_ENABLED: z.string().default("true"),
|
|
310
310
|
CAPTCHA_SOLVER_MAX_ATTEMPTS: z.string().default("3"),
|
|
311
311
|
CAPTCHA_SOLVER_TIMEOUT_MS: z.string().default("15000"),
|
|
312
|
+
CAPTCHA_SLIDER_TIMEOUT_MS: z.string().default("8000"),
|
|
312
313
|
CAPTCHA_SOLVER_RETRY_DELAY_MS: z.string().default("1000"),
|
|
313
314
|
CAPTCHA_SOLVER_SETTLE_MS: z.string().default("2000"),
|
|
314
315
|
CAPTCHA_ACCOUNT_COOLDOWN_MS: z.string().default("120000"),
|
|
@@ -460,6 +461,8 @@ var init_config = __esm({
|
|
|
460
461
|
enabled: env.CAPTCHA_SOLVER_ENABLED === "true",
|
|
461
462
|
maxAttempts: Math.max(1, Math.min(5, parseInt(env.CAPTCHA_SOLVER_MAX_ATTEMPTS))),
|
|
462
463
|
timeoutMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_TIMEOUT_MS)),
|
|
464
|
+
/** Max wait for a challenge slider to become visible (slow WAF renders). */
|
|
465
|
+
sliderTimeoutMs: Math.max(500, parseInt(env.CAPTCHA_SLIDER_TIMEOUT_MS)),
|
|
463
466
|
retryDelayMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_RETRY_DELAY_MS)),
|
|
464
467
|
settleMs: Math.max(0, parseInt(env.CAPTCHA_SOLVER_SETTLE_MS)),
|
|
465
468
|
/** Rest an account whose challenge could not be cleared before reusing it. */
|
|
@@ -3619,6 +3622,294 @@ function extractBaxiaChallengeUrl(body, baseUrl) {
|
|
|
3619
3622
|
}
|
|
3620
3623
|
return null;
|
|
3621
3624
|
}
|
|
3625
|
+
async function findVisibleLocatorWithin(page, selectors, timeoutMs) {
|
|
3626
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
3627
|
+
while (true) {
|
|
3628
|
+
const found = await findVisibleLocator(page, selectors);
|
|
3629
|
+
if (found) return found;
|
|
3630
|
+
if (Date.now() >= deadline) return null;
|
|
3631
|
+
await sleep(Math.min(150, Math.max(1, deadline - Date.now())));
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3634
|
+
async function waitForHidden(locator, timeoutMs) {
|
|
3635
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
3636
|
+
while (true) {
|
|
3637
|
+
if (!await isVisible(locator)) return true;
|
|
3638
|
+
if (Date.now() >= deadline) return false;
|
|
3639
|
+
await sleep(Math.min(100, Math.max(1, deadline - Date.now())));
|
|
3640
|
+
}
|
|
3641
|
+
}
|
|
3642
|
+
async function computeAliyunPuzzleOffset(page) {
|
|
3643
|
+
return page.evaluate(() => {
|
|
3644
|
+
const background = document.querySelector(
|
|
3645
|
+
"#aliyunCaptcha-img"
|
|
3646
|
+
);
|
|
3647
|
+
const piece = document.querySelector(
|
|
3648
|
+
"#aliyunCaptcha-puzzle"
|
|
3649
|
+
);
|
|
3650
|
+
if (!background || !piece) {
|
|
3651
|
+
return Promise.resolve({ ok: false, reason: "missing puzzle images" });
|
|
3652
|
+
}
|
|
3653
|
+
const compute = () => {
|
|
3654
|
+
try {
|
|
3655
|
+
const width = background.naturalWidth;
|
|
3656
|
+
const height = background.naturalHeight;
|
|
3657
|
+
const pieceWidth = piece.naturalWidth;
|
|
3658
|
+
const pieceHeight = piece.naturalHeight;
|
|
3659
|
+
if (!width || !height || !pieceWidth || !pieceHeight) {
|
|
3660
|
+
return { ok: false, reason: "image dimensions unavailable" };
|
|
3661
|
+
}
|
|
3662
|
+
const backgroundCanvas = document.createElement("canvas");
|
|
3663
|
+
backgroundCanvas.id = "captcha-solver-canvas";
|
|
3664
|
+
backgroundCanvas.width = width;
|
|
3665
|
+
backgroundCanvas.height = height;
|
|
3666
|
+
const backgroundContext = backgroundCanvas.getContext("2d");
|
|
3667
|
+
if (!backgroundContext) {
|
|
3668
|
+
return { ok: false, reason: "no background context" };
|
|
3669
|
+
}
|
|
3670
|
+
const pieceCanvas = document.createElement("canvas");
|
|
3671
|
+
pieceCanvas.id = "captcha-solver-canvas";
|
|
3672
|
+
pieceCanvas.width = pieceWidth;
|
|
3673
|
+
pieceCanvas.height = pieceHeight;
|
|
3674
|
+
const pieceContext = pieceCanvas.getContext("2d");
|
|
3675
|
+
if (!pieceContext) {
|
|
3676
|
+
return { ok: false, reason: "no piece context" };
|
|
3677
|
+
}
|
|
3678
|
+
try {
|
|
3679
|
+
backgroundContext.drawImage(background, 0, 0);
|
|
3680
|
+
} catch {
|
|
3681
|
+
return { ok: false, reason: "background canvas tainted" };
|
|
3682
|
+
}
|
|
3683
|
+
try {
|
|
3684
|
+
pieceContext.drawImage(piece, 0, 0);
|
|
3685
|
+
} catch {
|
|
3686
|
+
return { ok: false, reason: "puzzle canvas tainted" };
|
|
3687
|
+
}
|
|
3688
|
+
const backgroundData = backgroundContext.getImageData(
|
|
3689
|
+
0,
|
|
3690
|
+
0,
|
|
3691
|
+
width,
|
|
3692
|
+
height
|
|
3693
|
+
).data;
|
|
3694
|
+
const pieceData = pieceContext.getImageData(
|
|
3695
|
+
0,
|
|
3696
|
+
0,
|
|
3697
|
+
pieceWidth,
|
|
3698
|
+
pieceHeight
|
|
3699
|
+
).data;
|
|
3700
|
+
let pieceMinX = pieceWidth;
|
|
3701
|
+
let pieceMaxX = -1;
|
|
3702
|
+
let pieceMinY = pieceHeight;
|
|
3703
|
+
let pieceMaxY = -1;
|
|
3704
|
+
for (let y = 0; y < pieceHeight; y++) {
|
|
3705
|
+
for (let x = 0; x < pieceWidth; x++) {
|
|
3706
|
+
if (pieceData[(y * pieceWidth + x) * 4 + 3] > 100) {
|
|
3707
|
+
if (x < pieceMinX) pieceMinX = x;
|
|
3708
|
+
if (x > pieceMaxX) pieceMaxX = x;
|
|
3709
|
+
if (y < pieceMinY) pieceMinY = y;
|
|
3710
|
+
if (y > pieceMaxY) pieceMaxY = y;
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
const puzzleWidth = pieceMaxX - pieceMinX + 1;
|
|
3715
|
+
if (puzzleWidth <= 0) {
|
|
3716
|
+
return { ok: false, reason: "empty puzzle piece" };
|
|
3717
|
+
}
|
|
3718
|
+
const yStart = Math.max(1, Math.min(height - 2, pieceMinY + 5));
|
|
3719
|
+
const yEnd = Math.max(
|
|
3720
|
+
yStart,
|
|
3721
|
+
Math.min(height - 2, pieceMaxY - 5)
|
|
3722
|
+
);
|
|
3723
|
+
const columnGradients = new Float32Array(width);
|
|
3724
|
+
for (let x = 1; x < width - 1; x++) {
|
|
3725
|
+
let gradient = 0;
|
|
3726
|
+
for (let y = yStart; y <= yEnd; y++) {
|
|
3727
|
+
const left = (y * width + x - 1) * 4;
|
|
3728
|
+
const right = (y * width + x + 1) * 4;
|
|
3729
|
+
gradient += Math.abs(backgroundData[right] - backgroundData[left]) + Math.abs(backgroundData[right + 1] - backgroundData[left + 1]) + Math.abs(backgroundData[right + 2] - backgroundData[left + 2]);
|
|
3730
|
+
}
|
|
3731
|
+
columnGradients[x] = gradient;
|
|
3732
|
+
}
|
|
3733
|
+
let bestX = 0;
|
|
3734
|
+
let bestScore = 0;
|
|
3735
|
+
const minCandidateX = 30;
|
|
3736
|
+
const maxCandidateX = width - puzzleWidth - 20;
|
|
3737
|
+
for (let candidateX = minCandidateX; candidateX <= maxCandidateX; candidateX++) {
|
|
3738
|
+
let leftMax = 0;
|
|
3739
|
+
for (let dx = -2; dx <= 2; dx++) {
|
|
3740
|
+
const value = columnGradients[candidateX + pieceMinX + dx] || 0;
|
|
3741
|
+
if (value > leftMax) leftMax = value;
|
|
3742
|
+
}
|
|
3743
|
+
let rightMax = 0;
|
|
3744
|
+
for (let dx = -3; dx <= 1; dx++) {
|
|
3745
|
+
const value = columnGradients[candidateX + pieceMaxX + dx] || 0;
|
|
3746
|
+
if (value > rightMax) rightMax = value;
|
|
3747
|
+
}
|
|
3748
|
+
const score = Math.sqrt(leftMax * rightMax);
|
|
3749
|
+
if (score > bestScore) {
|
|
3750
|
+
bestScore = score;
|
|
3751
|
+
bestX = candidateX;
|
|
3752
|
+
}
|
|
3753
|
+
}
|
|
3754
|
+
if (bestScore <= 0) {
|
|
3755
|
+
return { ok: false, reason: "no matching hole edge" };
|
|
3756
|
+
}
|
|
3757
|
+
return {
|
|
3758
|
+
ok: true,
|
|
3759
|
+
offsetX: bestX - pieceMinX,
|
|
3760
|
+
naturalWidth: width
|
|
3761
|
+
};
|
|
3762
|
+
} catch (error) {
|
|
3763
|
+
return {
|
|
3764
|
+
ok: false,
|
|
3765
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
3766
|
+
};
|
|
3767
|
+
}
|
|
3768
|
+
};
|
|
3769
|
+
return new Promise((resolve) => {
|
|
3770
|
+
if (background.complete && piece.complete) {
|
|
3771
|
+
resolve(compute());
|
|
3772
|
+
return;
|
|
3773
|
+
}
|
|
3774
|
+
let settled = false;
|
|
3775
|
+
const finish = () => {
|
|
3776
|
+
if (settled) return;
|
|
3777
|
+
settled = true;
|
|
3778
|
+
resolve(compute());
|
|
3779
|
+
};
|
|
3780
|
+
const fail = () => {
|
|
3781
|
+
if (settled) return;
|
|
3782
|
+
settled = true;
|
|
3783
|
+
resolve({ ok: false, reason: "puzzle image load error" });
|
|
3784
|
+
};
|
|
3785
|
+
background.addEventListener("load", finish, { once: true });
|
|
3786
|
+
piece.addEventListener("load", finish, { once: true });
|
|
3787
|
+
background.addEventListener("error", fail, { once: true });
|
|
3788
|
+
piece.addEventListener("error", fail, { once: true });
|
|
3789
|
+
setTimeout(() => {
|
|
3790
|
+
if (settled) return;
|
|
3791
|
+
settled = true;
|
|
3792
|
+
resolve({ ok: false, reason: "puzzle image load timeout" });
|
|
3793
|
+
}, 2e3);
|
|
3794
|
+
});
|
|
3795
|
+
});
|
|
3796
|
+
}
|
|
3797
|
+
async function solveAliyunWafCaptcha(page, options = {}) {
|
|
3798
|
+
const waitForMs = Math.max(0, options.waitForMs ?? 0);
|
|
3799
|
+
const maxAttempts = Math.max(
|
|
3800
|
+
1,
|
|
3801
|
+
Math.min(5, options.maxAttempts ?? DEFAULT_MAX_ATTEMPTS)
|
|
3802
|
+
);
|
|
3803
|
+
const retryDelayMs = Math.max(
|
|
3804
|
+
0,
|
|
3805
|
+
options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS
|
|
3806
|
+
);
|
|
3807
|
+
const settleMs = Math.max(0, options.settleMs ?? DEFAULT_SETTLE_MS);
|
|
3808
|
+
const sliderTimeoutMs = Math.max(
|
|
3809
|
+
500,
|
|
3810
|
+
options.sliderTimeoutMs ?? DEFAULT_SLIDER_TIMEOUT_MS
|
|
3811
|
+
);
|
|
3812
|
+
const detected = await findVisibleLocatorWithin(
|
|
3813
|
+
page,
|
|
3814
|
+
ALIYUN_WAF_BLOCK_SELECTORS,
|
|
3815
|
+
waitForMs
|
|
3816
|
+
);
|
|
3817
|
+
if (!detected) return false;
|
|
3818
|
+
return withCaptchaMouseLock(async () => {
|
|
3819
|
+
const block = detected.locator;
|
|
3820
|
+
if (!await isVisible(block)) return false;
|
|
3821
|
+
logBaxiaCaptcha("aliyun_detected", { selector: detected.selector });
|
|
3822
|
+
let lastReason = "unknown";
|
|
3823
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
3824
|
+
try {
|
|
3825
|
+
const offset = await computeAliyunPuzzleOffset(page);
|
|
3826
|
+
if (!offset.ok || typeof offset.offsetX !== "number" || typeof offset.naturalWidth !== "number" || offset.naturalWidth <= 0) {
|
|
3827
|
+
lastReason = offset.reason || "offset_unavailable";
|
|
3828
|
+
logBaxiaCaptcha("aliyun_offset_failed", {
|
|
3829
|
+
attempt,
|
|
3830
|
+
reason: lastReason
|
|
3831
|
+
});
|
|
3832
|
+
} else {
|
|
3833
|
+
const slider = page.locator(ALIYUN_PUZZLE_SLIDER_SELECTOR).first();
|
|
3834
|
+
const track = page.locator(ALIYUN_PUZZLE_TRACK_SELECTOR).first();
|
|
3835
|
+
await slider.waitFor({ state: "visible", timeout: sliderTimeoutMs });
|
|
3836
|
+
const [sliderBox, trackBox] = await Promise.all([
|
|
3837
|
+
slider.boundingBox(),
|
|
3838
|
+
track.boundingBox()
|
|
3839
|
+
]);
|
|
3840
|
+
if (!sliderBox || !trackBox || trackBox.width <= 0) {
|
|
3841
|
+
lastReason = "bounds_unavailable";
|
|
3842
|
+
logBaxiaCaptcha("aliyun_offset_failed", {
|
|
3843
|
+
attempt,
|
|
3844
|
+
reason: lastReason
|
|
3845
|
+
});
|
|
3846
|
+
} else {
|
|
3847
|
+
const scale = trackBox.width / offset.naturalWidth;
|
|
3848
|
+
const dragDistance = Math.round(offset.offsetX * scale);
|
|
3849
|
+
logBaxiaCaptcha("aliyun_geometry", {
|
|
3850
|
+
attempt,
|
|
3851
|
+
offset: offset.offsetX,
|
|
3852
|
+
scale: Number(scale.toFixed(2)),
|
|
3853
|
+
distance: dragDistance
|
|
3854
|
+
});
|
|
3855
|
+
if (dragDistance <= 0) {
|
|
3856
|
+
lastReason = "non_positive_distance";
|
|
3857
|
+
} else {
|
|
3858
|
+
const startX = sliderBox.x + sliderBox.width / 2;
|
|
3859
|
+
const startY = sliderBox.y + sliderBox.height / 2;
|
|
3860
|
+
await humanDrag(
|
|
3861
|
+
page,
|
|
3862
|
+
startX,
|
|
3863
|
+
startY,
|
|
3864
|
+
startX + dragDistance,
|
|
3865
|
+
startY
|
|
3866
|
+
);
|
|
3867
|
+
if (await waitForHidden(block, settleMs)) {
|
|
3868
|
+
logBaxiaCaptcha(
|
|
3869
|
+
"aliyun_solve_succeeded",
|
|
3870
|
+
{ attempt, distance: dragDistance },
|
|
3871
|
+
true
|
|
3872
|
+
);
|
|
3873
|
+
return true;
|
|
3874
|
+
}
|
|
3875
|
+
lastReason = "not_solved";
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3878
|
+
}
|
|
3879
|
+
} catch (error) {
|
|
3880
|
+
lastReason = error instanceof Error ? error.name : "UnknownError";
|
|
3881
|
+
logBaxiaCaptcha("aliyun_offset_failed", {
|
|
3882
|
+
attempt,
|
|
3883
|
+
error: lastReason,
|
|
3884
|
+
detail: sanitizeCaptchaErrorDetail(error)
|
|
3885
|
+
});
|
|
3886
|
+
}
|
|
3887
|
+
if (attempt < maxAttempts && retryDelayMs > 0) {
|
|
3888
|
+
await sleep(retryDelayMs);
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
logBaxiaCaptcha(
|
|
3892
|
+
"aliyun_solve_failed",
|
|
3893
|
+
{ attempts: maxAttempts, reason: lastReason },
|
|
3894
|
+
true
|
|
3895
|
+
);
|
|
3896
|
+
return false;
|
|
3897
|
+
});
|
|
3898
|
+
}
|
|
3899
|
+
async function solveVisibleCaptcha(page, options = {}) {
|
|
3900
|
+
if (typeof page.isClosed === "function" && page.isClosed()) return false;
|
|
3901
|
+
const totalWaitMs = Math.max(0, options.waitForMs ?? 0);
|
|
3902
|
+
const aliyunWaitMs = Math.min(totalWaitMs, ALIYUN_PROBE_MAX_WAIT_MS);
|
|
3903
|
+
const startedAt = Date.now();
|
|
3904
|
+
if (await solveAliyunWafCaptcha(page, { ...options, waitForMs: aliyunWaitMs })) {
|
|
3905
|
+
return true;
|
|
3906
|
+
}
|
|
3907
|
+
const remainingWaitMs = Math.max(
|
|
3908
|
+
0,
|
|
3909
|
+
totalWaitMs - (Date.now() - startedAt)
|
|
3910
|
+
);
|
|
3911
|
+
return solveBaxiaCaptcha(page, { ...options, waitForMs: remainingWaitMs });
|
|
3912
|
+
}
|
|
3622
3913
|
async function isVisible(locator) {
|
|
3623
3914
|
return locator.isVisible().catch(() => false);
|
|
3624
3915
|
}
|
|
@@ -3888,7 +4179,7 @@ function startBaxiaCaptchaWatcher(page, timeoutMs, options = {}) {
|
|
|
3888
4179
|
promise
|
|
3889
4180
|
};
|
|
3890
4181
|
}
|
|
3891
|
-
var BAXIA_DIALOG_SELECTOR, BAXIA_CONTENT_SELECTOR, CAPTCHA_EVENT_EMOJI, captchaDebugEnabled, BAXIA_IFRAME_SELECTORS, BAXIA_DOCUMENT_SELECTORS, BAXIA_IFRAME_SELECTOR, BAXIA_SLIDER_SELECTOR, BAXIA_TRACK_SELECTOR, BAXIA_SUCCESS_SELECTOR, BAXIA_RELOAD_SELECTOR, DEFAULT_MAX_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_SETTLE_MS, DEFAULT_SLIDER_TIMEOUT_MS, captchaMouseLock;
|
|
4182
|
+
var BAXIA_DIALOG_SELECTOR, BAXIA_CONTENT_SELECTOR, CAPTCHA_EVENT_EMOJI, captchaDebugEnabled, BAXIA_IFRAME_SELECTORS, BAXIA_DOCUMENT_SELECTORS, BAXIA_IFRAME_SELECTOR, BAXIA_SLIDER_SELECTOR, BAXIA_TRACK_SELECTOR, BAXIA_SUCCESS_SELECTOR, BAXIA_RELOAD_SELECTOR, DEFAULT_MAX_ATTEMPTS, DEFAULT_RETRY_DELAY_MS, DEFAULT_SETTLE_MS, DEFAULT_SLIDER_TIMEOUT_MS, ALIYUN_WAF_CAPTCHA_SELECTOR, ALIYUN_WAF_CAPTCHA_WIDGET, ALIYUN_WAF_BLOCK_SELECTORS, ALIYUN_PUZZLE_SLIDER_SELECTOR, ALIYUN_PUZZLE_TRACK_SELECTOR, ALIYUN_PROBE_MAX_WAIT_MS, captchaMouseLock;
|
|
3892
4183
|
var init_captcha_solver = __esm({
|
|
3893
4184
|
"src/services/captcha-solver.ts"() {
|
|
3894
4185
|
"use strict";
|
|
@@ -3914,14 +4205,20 @@ var init_captcha_solver = __esm({
|
|
|
3914
4205
|
solve_failed: "\u274C",
|
|
3915
4206
|
recovery_succeeded: "\u2705",
|
|
3916
4207
|
recovery_not_solved: "\u26A0\uFE0F",
|
|
3917
|
-
recovery_failed: "\u274C"
|
|
4208
|
+
recovery_failed: "\u274C",
|
|
4209
|
+
aliyun_detected: "\u{1F9E9}",
|
|
4210
|
+
aliyun_offset_failed: "\u{1F4D0}",
|
|
4211
|
+
aliyun_geometry: "\u{1F4D0}",
|
|
4212
|
+
aliyun_solve_succeeded: "\u2705",
|
|
4213
|
+
aliyun_solve_failed: "\u274C"
|
|
3918
4214
|
};
|
|
3919
4215
|
captchaDebugEnabled = process.env.CAPTCHA_DEBUG === "true";
|
|
3920
4216
|
BAXIA_IFRAME_SELECTORS = [
|
|
3921
4217
|
`${BAXIA_DIALOG_SELECTOR} ${BAXIA_CONTENT_SELECTOR} iframe`,
|
|
3922
4218
|
`${BAXIA_CONTENT_SELECTOR} iframe`,
|
|
3923
4219
|
"iframe#baxia-dialog-content",
|
|
3924
|
-
'iframe[src*="_____tmd_____/punish"]'
|
|
4220
|
+
'iframe[src*="_____tmd_____/punish"]',
|
|
4221
|
+
'iframe[src*="nocaptcha"]'
|
|
3925
4222
|
];
|
|
3926
4223
|
BAXIA_DOCUMENT_SELECTORS = [
|
|
3927
4224
|
"#nocaptcha",
|
|
@@ -3929,14 +4226,23 @@ var init_captcha_solver = __esm({
|
|
|
3929
4226
|
"#baxia-punish"
|
|
3930
4227
|
];
|
|
3931
4228
|
BAXIA_IFRAME_SELECTOR = BAXIA_IFRAME_SELECTORS.join(", ");
|
|
3932
|
-
BAXIA_SLIDER_SELECTOR =
|
|
3933
|
-
BAXIA_TRACK_SELECTOR =
|
|
4229
|
+
BAXIA_SLIDER_SELECTOR = '#nc_1_n1z, .nc_1_n1z, .btn_slide, .nc_iconfont.btn_slide, span[id*="_n1z"], .nc_wrapper .btn_slide, ._nc .btn_slide, .nc-container .btn_slide';
|
|
4230
|
+
BAXIA_TRACK_SELECTOR = '#nc_1_n1t, .nc_scale, span[id*="_n1t"], .nc_wrapper .nc_scale, ._nc .nc_scale, .nc-container .nc_scale';
|
|
3934
4231
|
BAXIA_SUCCESS_SELECTOR = '.btn_ok, .nc_ok, .nc_success, .nc_result, .nc_wrapper.nc-success, .nc_wrapper.success, [data-nc-lang="SUCCESS"], [data-nc-lang="success"], #nc-loading-circle';
|
|
3935
4232
|
BAXIA_RELOAD_SELECTOR = '#nc_1_refresh1, .errloading a, .nc-container .errloading a, .btn_refresh, .clickCaptcha_text .btn_refresh, [data-nc-lang="REFRESH"], a[id*="refresh"]';
|
|
3936
4233
|
DEFAULT_MAX_ATTEMPTS = 3;
|
|
3937
4234
|
DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
3938
4235
|
DEFAULT_SETTLE_MS = 2e3;
|
|
3939
4236
|
DEFAULT_SLIDER_TIMEOUT_MS = 8e3;
|
|
4237
|
+
ALIYUN_WAF_CAPTCHA_SELECTOR = "#waf_nc_block";
|
|
4238
|
+
ALIYUN_WAF_CAPTCHA_WIDGET = "#aliyunCaptcha-window-embed";
|
|
4239
|
+
ALIYUN_WAF_BLOCK_SELECTORS = [
|
|
4240
|
+
ALIYUN_WAF_CAPTCHA_SELECTOR,
|
|
4241
|
+
ALIYUN_WAF_CAPTCHA_WIDGET
|
|
4242
|
+
];
|
|
4243
|
+
ALIYUN_PUZZLE_SLIDER_SELECTOR = "#aliyunCaptcha-sliding-slider";
|
|
4244
|
+
ALIYUN_PUZZLE_TRACK_SELECTOR = "#aliyunCaptcha-sliding-body";
|
|
4245
|
+
ALIYUN_PROBE_MAX_WAIT_MS = 2e3;
|
|
3940
4246
|
captchaMouseLock = Promise.resolve();
|
|
3941
4247
|
}
|
|
3942
4248
|
});
|
|
@@ -4090,6 +4396,14 @@ function updateQwenWebVersion(version) {
|
|
|
4090
4396
|
function getQwenWebVersion() {
|
|
4091
4397
|
return dynamicWebVersion || config.qwen.webVersion;
|
|
4092
4398
|
}
|
|
4399
|
+
function updateQwenBxVersion(version) {
|
|
4400
|
+
if (version && typeof version === "string" && /^\d+\.\d+\.\d+/.test(version)) {
|
|
4401
|
+
dynamicBxVersion = version.trim();
|
|
4402
|
+
}
|
|
4403
|
+
}
|
|
4404
|
+
function getQwenBxVersion() {
|
|
4405
|
+
return dynamicBxVersion || config.auth.bxV;
|
|
4406
|
+
}
|
|
4093
4407
|
function buildQwenRequestHeaders(opts) {
|
|
4094
4408
|
const headers = {
|
|
4095
4409
|
...opts.extra ?? {},
|
|
@@ -4106,7 +4420,7 @@ function buildQwenRequestHeaders(opts) {
|
|
|
4106
4420
|
Connection: "keep-alive",
|
|
4107
4421
|
"User-Agent": opts.userAgent || getDefaultQwenUserAgent(),
|
|
4108
4422
|
"X-Request-Id": uuidv4(),
|
|
4109
|
-
"bx-v": opts.bxV ||
|
|
4423
|
+
"bx-v": opts.bxV || getQwenBxVersion(),
|
|
4110
4424
|
source: "web",
|
|
4111
4425
|
version: opts.version || getQwenWebVersion(),
|
|
4112
4426
|
timezone: opts.extra?.timezone || opts.extra?.Timezone || formatAsciiTimezone(),
|
|
@@ -4130,7 +4444,7 @@ function buildQwenRequestHeaders(opts) {
|
|
|
4130
4444
|
}
|
|
4131
4445
|
return headers;
|
|
4132
4446
|
}
|
|
4133
|
-
var dynamicWebVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
|
|
4447
|
+
var dynamicWebVersion, dynamicBxVersion, QWEN_WEB_VERSION, DEFAULT_QWEN_USER_AGENT, QWEN_TIMEZONE_HEADER;
|
|
4134
4448
|
var init_qwen_headers = __esm({
|
|
4135
4449
|
"src/services/qwen-headers.ts"() {
|
|
4136
4450
|
"use strict";
|
|
@@ -4139,6 +4453,7 @@ var init_qwen_headers = __esm({
|
|
|
4139
4453
|
init_fingerprint();
|
|
4140
4454
|
init_timezone();
|
|
4141
4455
|
dynamicWebVersion = null;
|
|
4456
|
+
dynamicBxVersion = null;
|
|
4142
4457
|
QWEN_WEB_VERSION = config.qwen.webVersion;
|
|
4143
4458
|
DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
|
|
4144
4459
|
QWEN_TIMEZONE_HEADER = (/* @__PURE__ */ new Date()).toString().split(" (")[0];
|
|
@@ -4752,11 +5067,12 @@ async function getOrLaunchSharedBrowser(browserType = "chromium", headless = con
|
|
|
4752
5067
|
async function clearVisibleChallenge(page) {
|
|
4753
5068
|
if (page.isClosed()) return;
|
|
4754
5069
|
if (config.captcha.enabled) {
|
|
4755
|
-
await
|
|
5070
|
+
await solveVisibleCaptcha(page, {
|
|
4756
5071
|
waitForMs: 0,
|
|
4757
5072
|
maxAttempts: config.captcha.maxAttempts,
|
|
4758
5073
|
retryDelayMs: config.captcha.retryDelayMs,
|
|
4759
|
-
settleMs: config.captcha.settleMs
|
|
5074
|
+
settleMs: config.captcha.settleMs,
|
|
5075
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
4760
5076
|
}).catch(() => false);
|
|
4761
5077
|
}
|
|
4762
5078
|
try {
|
|
@@ -5369,6 +5685,7 @@ async function getBasicHeaders(accountId) {
|
|
|
5369
5685
|
mobile = data.mobile ? "?1" : "?0";
|
|
5370
5686
|
}
|
|
5371
5687
|
let bundleVersion = null;
|
|
5688
|
+
let baxiaVersion = null;
|
|
5372
5689
|
try {
|
|
5373
5690
|
const el = document.querySelector('link[href*="qwen-chat-fe"], script[src*="qwen-chat-fe"], img[src*="qwen-chat-fe"]');
|
|
5374
5691
|
const src = el ? el.getAttribute("href") || el.getAttribute("src") || "" : "";
|
|
@@ -5376,7 +5693,14 @@ async function getBasicHeaders(accountId) {
|
|
|
5376
5693
|
if (match) bundleVersion = match[1];
|
|
5377
5694
|
} catch {
|
|
5378
5695
|
}
|
|
5379
|
-
|
|
5696
|
+
try {
|
|
5697
|
+
const baxia = window.baxiaCommon;
|
|
5698
|
+
if (typeof baxia?.version === "string") {
|
|
5699
|
+
baxiaVersion = baxia.version;
|
|
5700
|
+
}
|
|
5701
|
+
} catch {
|
|
5702
|
+
}
|
|
5703
|
+
return { ua, secChUa, platform, mobile, bundleVersion, baxiaVersion };
|
|
5380
5704
|
}),
|
|
5381
5705
|
config.timeouts.page,
|
|
5382
5706
|
`User-agent lookup timed out for ${accountId}`
|
|
@@ -5385,6 +5709,9 @@ async function getBasicHeaders(accountId) {
|
|
|
5385
5709
|
if (nav.bundleVersion) {
|
|
5386
5710
|
updateQwenWebVersion(nav.bundleVersion);
|
|
5387
5711
|
}
|
|
5712
|
+
if (nav.baxiaVersion) {
|
|
5713
|
+
updateQwenBxVersion(nav.baxiaVersion);
|
|
5714
|
+
}
|
|
5388
5715
|
cachedUserAgents.set(accountId, userAgent);
|
|
5389
5716
|
const hints = getHeaderCache(accountId).headers;
|
|
5390
5717
|
clientHints = {
|
|
@@ -5416,7 +5743,7 @@ async function getBasicHeaders(accountId) {
|
|
|
5416
5743
|
markAccountHeadersReady(accountId);
|
|
5417
5744
|
const bxUa2 = cache3.headers["bx-ua"];
|
|
5418
5745
|
const bxUmidtoken2 = cache3.headers["bx-umidtoken"];
|
|
5419
|
-
const bxV2 = cache3.headers["bx-v"] ||
|
|
5746
|
+
const bxV2 = cache3.headers["bx-v"] || getQwenBxVersion();
|
|
5420
5747
|
const cookie2 = await getCookies(accountId);
|
|
5421
5748
|
return { cookie: cookie2, userAgent, bxV: bxV2, bxUa: bxUa2, bxUmidtoken: bxUmidtoken2, ...clientHints };
|
|
5422
5749
|
}
|
|
@@ -5427,7 +5754,7 @@ async function getBasicHeaders(accountId) {
|
|
|
5427
5754
|
cookieCaches.set(accountId, { cookie: cookie2, timestamp: Date.now() });
|
|
5428
5755
|
const bxUa2 = cache3.headers["bx-ua"];
|
|
5429
5756
|
const bxUmidtoken2 = cache3.headers["bx-umidtoken"];
|
|
5430
|
-
const bxV2 = cache3.headers["bx-v"] ||
|
|
5757
|
+
const bxV2 = cache3.headers["bx-v"] || getQwenBxVersion();
|
|
5431
5758
|
cache3.lastRefresh = Date.now();
|
|
5432
5759
|
markAccountHeadersReady(accountId);
|
|
5433
5760
|
console.log(
|
|
@@ -5447,14 +5774,15 @@ async function getBasicHeaders(accountId) {
|
|
|
5447
5774
|
`\u26A0\uFE0F [Playwright] Header refresh failed for ${accountId}; retaining the previous valid cache: ${getErrorMessage(error)}`
|
|
5448
5775
|
);
|
|
5449
5776
|
}
|
|
5450
|
-
} else if (hadUsableHeaders && headersAge > HEADER_CACHE_TTL * HEADER_REFRESH_THRESHOLD && !cache3.refreshInProgress
|
|
5451
|
-
|
|
5777
|
+
} else if (hadUsableHeaders && headersAge > HEADER_CACHE_TTL * HEADER_REFRESH_THRESHOLD && !cache3.refreshInProgress && // Header capture types into the chat input and sends a probe message on
|
|
5778
|
+
// the account's page. Doing that while the account is serving a stream
|
|
5779
|
+
// would mutate the live conversation (and can navigate the SPA), so the
|
|
5780
|
+
// proactive refresh waits until the account has no active lease.
|
|
5781
|
+
!hasActiveAccountLease(accountId)) {
|
|
5452
5782
|
refreshHeadersInternal(accountId).catch((error) => {
|
|
5453
5783
|
console.warn(
|
|
5454
5784
|
`\u26A0\uFE0F [Playwright] Background header refresh failed for ${accountId}: ${getErrorMessage(error)}`
|
|
5455
5785
|
);
|
|
5456
|
-
}).finally(() => {
|
|
5457
|
-
cache3.refreshInProgress = false;
|
|
5458
5786
|
});
|
|
5459
5787
|
}
|
|
5460
5788
|
if (!hasRequiredQwenHeaders(cache3.headers)) {
|
|
@@ -5501,6 +5829,9 @@ async function getBasicHeaders(accountId) {
|
|
|
5501
5829
|
if (persisted.version) {
|
|
5502
5830
|
updateQwenWebVersion(persisted.version);
|
|
5503
5831
|
}
|
|
5832
|
+
if (persisted.bxV) {
|
|
5833
|
+
updateQwenBxVersion(persisted.bxV);
|
|
5834
|
+
}
|
|
5504
5835
|
cache3.lastRefresh = persisted.capturedAt;
|
|
5505
5836
|
markAccountHeadersReady(accountId);
|
|
5506
5837
|
}
|
|
@@ -5528,7 +5859,7 @@ async function getBasicHeaders(accountId) {
|
|
|
5528
5859
|
markAccountHeadersReady(accountId);
|
|
5529
5860
|
const bxUa = cache3.headers["bx-ua"];
|
|
5530
5861
|
const bxUmidtoken = cache3.headers["bx-umidtoken"];
|
|
5531
|
-
const bxV = cache3.headers["bx-v"] ||
|
|
5862
|
+
const bxV = cache3.headers["bx-v"] || getQwenBxVersion();
|
|
5532
5863
|
cookieCaches.delete(accountId);
|
|
5533
5864
|
const cookie = await getCookies(accountId, true);
|
|
5534
5865
|
if (cache3.headers) {
|
|
@@ -5592,8 +5923,12 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
5592
5923
|
if (accountPages.has(account.id)) {
|
|
5593
5924
|
return;
|
|
5594
5925
|
}
|
|
5595
|
-
|
|
5596
|
-
|
|
5926
|
+
if (config.playwright.maxActiveContexts > 0) {
|
|
5927
|
+
await evictIdlePlaywrightContextsToLimit(
|
|
5928
|
+
Math.max(1, config.playwright.maxActiveContexts - 1)
|
|
5929
|
+
).catch(() => {
|
|
5930
|
+
});
|
|
5931
|
+
}
|
|
5597
5932
|
const profilePath = getAccountProfilePath(account.id);
|
|
5598
5933
|
const fingerprint = getFingerprintProfile(account.id);
|
|
5599
5934
|
const { engine, channel } = resolveBrowserEngine(browserType);
|
|
@@ -5769,6 +6104,9 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
5769
6104
|
if (persisted.version) {
|
|
5770
6105
|
updateQwenWebVersion(persisted.version);
|
|
5771
6106
|
}
|
|
6107
|
+
if (persisted.bxV) {
|
|
6108
|
+
updateQwenBxVersion(persisted.bxV);
|
|
6109
|
+
}
|
|
5772
6110
|
cache3.lastRefresh = persisted.capturedAt;
|
|
5773
6111
|
markAccountHeadersReady(account.id);
|
|
5774
6112
|
restoredFromDb = true;
|
|
@@ -5862,7 +6200,7 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
5862
6200
|
if (!acctPage.isClosed()) {
|
|
5863
6201
|
try {
|
|
5864
6202
|
const currentUrl = new URL(acctPage.url());
|
|
5865
|
-
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname
|
|
6203
|
+
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname.includes("/auth") || currentUrl.pathname.includes("/login") || currentUrl.pathname.includes("_____tmd_____")) {
|
|
5866
6204
|
await acctPage.goto(qwenUrl("/"), {
|
|
5867
6205
|
waitUntil: "domcontentloaded",
|
|
5868
6206
|
timeout: config.timeouts.navigation
|
|
@@ -5880,6 +6218,8 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
|
|
|
5880
6218
|
} finally {
|
|
5881
6219
|
release();
|
|
5882
6220
|
}
|
|
6221
|
+
await evictIdlePlaywrightContextsToLimit().catch(() => {
|
|
6222
|
+
});
|
|
5883
6223
|
})();
|
|
5884
6224
|
try {
|
|
5885
6225
|
await initPromise;
|
|
@@ -6116,7 +6456,7 @@ async function startEmailOtpLogin(email, options = {}) {
|
|
|
6116
6456
|
{
|
|
6117
6457
|
email: normalizedEmail,
|
|
6118
6458
|
requestId,
|
|
6119
|
-
version: getQwenWebVersion()
|
|
6459
|
+
version: getQwenWebVersion(),
|
|
6120
6460
|
timezone: formatAsciiTimezone()
|
|
6121
6461
|
}
|
|
6122
6462
|
).catch((err) => ({ ok: false, error: err?.message || String(err) }));
|
|
@@ -6211,7 +6551,7 @@ async function verifyEmailOtpLogin(sessionId, code) {
|
|
|
6211
6551
|
email: session.email,
|
|
6212
6552
|
code: cleanCode,
|
|
6213
6553
|
requestId,
|
|
6214
|
-
version: getQwenWebVersion()
|
|
6554
|
+
version: getQwenWebVersion(),
|
|
6215
6555
|
timezone: formatAsciiTimezone()
|
|
6216
6556
|
}
|
|
6217
6557
|
).catch((err) => ({ ok: false, error: err?.message || String(err) }));
|
|
@@ -6258,8 +6598,8 @@ async function verifyEmailOtpLogin(sessionId, code) {
|
|
|
6258
6598
|
saveAuthSession2(session.accountId, {
|
|
6259
6599
|
cookie: `token=${accessToken}`,
|
|
6260
6600
|
userAgent: session.fingerprint.userAgent,
|
|
6261
|
-
bxV:
|
|
6262
|
-
version: getQwenWebVersion()
|
|
6601
|
+
bxV: getQwenBxVersion(),
|
|
6602
|
+
version: getQwenWebVersion(),
|
|
6263
6603
|
userId: userId || void 0,
|
|
6264
6604
|
tokenExpiresAt: exp || void 0,
|
|
6265
6605
|
refreshToken: refreshToken || void 0,
|
|
@@ -6369,7 +6709,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
6369
6709
|
saveAuthSession2(accountId, {
|
|
6370
6710
|
cookie: cookieStr,
|
|
6371
6711
|
userAgent: cache3.headers["user-agent"] || "",
|
|
6372
|
-
bxV: cache3.headers["bx-v"] ||
|
|
6712
|
+
bxV: cache3.headers["bx-v"] || getQwenBxVersion(),
|
|
6373
6713
|
bxUa: cache3.headers["bx-ua"] || "",
|
|
6374
6714
|
bxUmidtoken: cache3.headers["bx-umidtoken"] || "",
|
|
6375
6715
|
secChUa: cache3.headers["sec-ch-ua"] || void 0,
|
|
@@ -6441,7 +6781,7 @@ async function loginToQwen(accountId, email, password) {
|
|
|
6441
6781
|
saveAuthSession2(accountId, {
|
|
6442
6782
|
cookie: cookieStr,
|
|
6443
6783
|
userAgent: cache3.headers["user-agent"] || "",
|
|
6444
|
-
bxV: cache3.headers["bx-v"] ||
|
|
6784
|
+
bxV: cache3.headers["bx-v"] || getQwenBxVersion(),
|
|
6445
6785
|
bxUa: cache3.headers["bx-ua"] || "",
|
|
6446
6786
|
bxUmidtoken: cache3.headers["bx-umidtoken"] || "",
|
|
6447
6787
|
secChUa: cache3.headers["sec-ch-ua"] || void 0,
|
|
@@ -6512,7 +6852,7 @@ async function loginViaApi(page, email, password) {
|
|
|
6512
6852
|
}
|
|
6513
6853
|
const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
|
|
6514
6854
|
const requestId = crypto5.randomUUID();
|
|
6515
|
-
const webVersion = getQwenWebVersion()
|
|
6855
|
+
const webVersion = getQwenWebVersion();
|
|
6516
6856
|
const evalRes = await page.evaluate(
|
|
6517
6857
|
async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz, version }) => {
|
|
6518
6858
|
try {
|
|
@@ -6684,6 +7024,15 @@ async function loginViaUi(page, email, password) {
|
|
|
6684
7024
|
if (!page.url().includes("/auth") && await isPageLoggedIn(page, 3e3).catch(() => false)) {
|
|
6685
7025
|
return { success: true };
|
|
6686
7026
|
}
|
|
7027
|
+
if (config.captcha.enabled) {
|
|
7028
|
+
await solveVisibleCaptcha(page, {
|
|
7029
|
+
waitForMs: 1500,
|
|
7030
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
7031
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
7032
|
+
settleMs: config.captcha.settleMs,
|
|
7033
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
7034
|
+
}).catch(() => false);
|
|
7035
|
+
}
|
|
6687
7036
|
const emailSelector = [
|
|
6688
7037
|
'input[type="email"]',
|
|
6689
7038
|
'input[name="email"]',
|
|
@@ -6839,10 +7188,11 @@ async function loginViaUi(page, email, password) {
|
|
|
6839
7188
|
while (Date.now() < postSubmitDeadline) {
|
|
6840
7189
|
if (page.isClosed()) break;
|
|
6841
7190
|
if (config.captcha.enabled) {
|
|
6842
|
-
await
|
|
7191
|
+
await solveVisibleCaptcha(page, {
|
|
6843
7192
|
waitForMs: 1500,
|
|
6844
7193
|
maxAttempts: config.captcha.maxAttempts,
|
|
6845
|
-
retryDelayMs: config.captcha.retryDelayMs
|
|
7194
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
7195
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
6846
7196
|
}).catch(() => {
|
|
6847
7197
|
});
|
|
6848
7198
|
}
|
|
@@ -6965,7 +7315,7 @@ async function refreshAccountToken(accountId) {
|
|
|
6965
7315
|
}
|
|
6966
7316
|
if (refreshToken) {
|
|
6967
7317
|
try {
|
|
6968
|
-
const webVersion = getQwenWebVersion()
|
|
7318
|
+
const webVersion = getQwenWebVersion();
|
|
6969
7319
|
const refreshResult = await page.evaluate(
|
|
6970
7320
|
async ({ rTok, tz, version }) => {
|
|
6971
7321
|
try {
|
|
@@ -7030,7 +7380,7 @@ async function refreshAccountToken(accountId) {
|
|
|
7030
7380
|
saveAuthSession2(accountId, {
|
|
7031
7381
|
cookie: cookieStr,
|
|
7032
7382
|
userAgent: cache3.headers["user-agent"] || session?.userAgent || "",
|
|
7033
|
-
bxV: cache3.headers["bx-v"] || session?.bxV ||
|
|
7383
|
+
bxV: cache3.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
|
|
7034
7384
|
bxUa: cache3.headers["bx-ua"] || session?.bxUa || "",
|
|
7035
7385
|
bxUmidtoken: cache3.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
7036
7386
|
secChUa: cache3.headers["sec-ch-ua"] || session?.secChUa,
|
|
@@ -7065,7 +7415,7 @@ async function refreshAccountToken(accountId) {
|
|
|
7065
7415
|
saveAuthSession2(accountId, {
|
|
7066
7416
|
cookie: cookieStr,
|
|
7067
7417
|
userAgent: cache3.headers["user-agent"] || session?.userAgent || "",
|
|
7068
|
-
bxV: cache3.headers["bx-v"] || session?.bxV ||
|
|
7418
|
+
bxV: cache3.headers["bx-v"] || session?.bxV || getQwenBxVersion(),
|
|
7069
7419
|
bxUa: cache3.headers["bx-ua"] || session?.bxUa || "",
|
|
7070
7420
|
bxUmidtoken: cache3.headers["bx-umidtoken"] || session?.bxUmidtoken || "",
|
|
7071
7421
|
secChUa: cache3.headers["sec-ch-ua"] || session?.secChUa,
|
|
@@ -7213,7 +7563,7 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
7213
7563
|
cookie: reqHeaders["cookie"] || "",
|
|
7214
7564
|
"bx-ua": reqHeaders["bx-ua"] || "",
|
|
7215
7565
|
"bx-umidtoken": reqHeaders["bx-umidtoken"] || "",
|
|
7216
|
-
"bx-v": reqHeaders["bx-v"] ||
|
|
7566
|
+
"bx-v": reqHeaders["bx-v"] || getQwenBxVersion(),
|
|
7217
7567
|
"user-agent": reqHeaders["user-agent"] || "",
|
|
7218
7568
|
"x-request-id": reqHeaders["x-request-id"] || "",
|
|
7219
7569
|
"version": reqHeaders["version"] || "",
|
|
@@ -7245,6 +7595,9 @@ async function captureQwenHeaders(accountId, pageOverride, timeoutMs = config.ti
|
|
|
7245
7595
|
if (capturedHeaders["version"]) {
|
|
7246
7596
|
updateQwenWebVersion(capturedHeaders["version"]);
|
|
7247
7597
|
}
|
|
7598
|
+
if (capturedHeaders["bx-v"]) {
|
|
7599
|
+
updateQwenBxVersion(capturedHeaders["bx-v"]);
|
|
7600
|
+
}
|
|
7248
7601
|
markAccountHeadersReady(accountId);
|
|
7249
7602
|
cache3.lastRefresh = Date.now();
|
|
7250
7603
|
cookieCaches.delete(accountId);
|
|
@@ -7648,19 +8001,26 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
7648
8001
|
await executeReauth();
|
|
7649
8002
|
} else {
|
|
7650
8003
|
try {
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
8004
|
+
const currentUrl = typeof page.url === "function" ? page.url() : "";
|
|
8005
|
+
const needsNavigation = !currentUrl.startsWith(qwenOrigin()) || currentUrl.includes("/auth") || currentUrl.includes("/login") || currentUrl.includes("_____tmd_____");
|
|
8006
|
+
if (needsNavigation) {
|
|
8007
|
+
await page.goto(qwenUrl("/"), {
|
|
8008
|
+
waitUntil: "domcontentloaded",
|
|
8009
|
+
timeout: Math.min(
|
|
8010
|
+
config.timeouts.navigation,
|
|
8011
|
+
boundedTimeoutMs,
|
|
8012
|
+
SESSION_PROBE_NAVIGATION_TIMEOUT_MS
|
|
8013
|
+
)
|
|
8014
|
+
});
|
|
8015
|
+
await sleep2(2e3);
|
|
8016
|
+
}
|
|
8017
|
+
const url = typeof page.url === "function" ? page.url() : "";
|
|
7661
8018
|
const isAuthUrl = url.includes("auth") || url.includes("login");
|
|
7662
8019
|
if (isAuthUrl) {
|
|
7663
|
-
await
|
|
8020
|
+
const refreshed = await refreshAccountToken(accountId);
|
|
8021
|
+
if (!refreshed.success) {
|
|
8022
|
+
await executeReauth();
|
|
8023
|
+
}
|
|
7664
8024
|
}
|
|
7665
8025
|
} catch (navErr) {
|
|
7666
8026
|
console.warn(
|
|
@@ -7695,7 +8055,7 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
7695
8055
|
saveAuthSession2(accountId, {
|
|
7696
8056
|
cookie: cookieStr,
|
|
7697
8057
|
userAgent: cache3.headers["user-agent"] || "",
|
|
7698
|
-
bxV: cache3.headers["bx-v"] ||
|
|
8058
|
+
bxV: cache3.headers["bx-v"] || getQwenBxVersion(),
|
|
7699
8059
|
bxUa: cache3.headers["bx-ua"] || "",
|
|
7700
8060
|
bxUmidtoken: cache3.headers["bx-umidtoken"] || "",
|
|
7701
8061
|
secChUa: cache3.headers["sec-ch-ua"] || void 0,
|
|
@@ -7717,7 +8077,7 @@ async function refreshHeadersInternal(accountId, timeoutMs = config.timeouts.hea
|
|
|
7717
8077
|
if (capturedPage && !capturedPage.isClosed()) {
|
|
7718
8078
|
try {
|
|
7719
8079
|
const currentUrl = new URL(capturedPage.url());
|
|
7720
|
-
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname
|
|
8080
|
+
if (currentUrl.origin !== qwenOrigin() || currentUrl.pathname.includes("/auth") || currentUrl.pathname.includes("/login") || currentUrl.pathname.includes("_____tmd_____")) {
|
|
7721
8081
|
await capturedPage.goto(qwenUrl("/"), {
|
|
7722
8082
|
waitUntil: "domcontentloaded",
|
|
7723
8083
|
timeout: Math.min(config.timeouts.navigation, boundedTimeoutMs)
|
|
@@ -8033,7 +8393,11 @@ function priorityOrderForEviction(accountIds) {
|
|
|
8033
8393
|
const ranked = getAccountsByPriority(accountIds.map((id) => ({ id })));
|
|
8034
8394
|
const rank = /* @__PURE__ */ new Map();
|
|
8035
8395
|
for (const [index, account] of ranked.entries()) {
|
|
8036
|
-
|
|
8396
|
+
if (getAccountCooldownInfo(account.id)) {
|
|
8397
|
+
rank.set(account.id, Number.MAX_SAFE_INTEGER);
|
|
8398
|
+
} else {
|
|
8399
|
+
rank.set(account.id, index);
|
|
8400
|
+
}
|
|
8037
8401
|
}
|
|
8038
8402
|
return orderContextsForEviction(
|
|
8039
8403
|
accountIds,
|
|
@@ -8070,14 +8434,15 @@ async function closeIdlePlaywrightAccounts(idleMs) {
|
|
|
8070
8434
|
}
|
|
8071
8435
|
return closed;
|
|
8072
8436
|
}
|
|
8073
|
-
async function evictIdlePlaywrightContextsToLimit() {
|
|
8074
|
-
const
|
|
8075
|
-
if (
|
|
8437
|
+
async function evictIdlePlaywrightContextsToLimit(targetLimit) {
|
|
8438
|
+
const configuredMax = config.playwright.maxActiveContexts;
|
|
8439
|
+
if (configuredMax <= 0) return 0;
|
|
8440
|
+
const max = targetLimit !== void 0 ? Math.max(0, targetLimit) : configuredMax;
|
|
8076
8441
|
if (accountPages.size <= max) return 0;
|
|
8077
8442
|
const candidates = priorityOrderForEviction(
|
|
8078
8443
|
Array.from(accountPages.keys()).filter((accountId) => {
|
|
8079
8444
|
if (isAccountServingStream(accountId)) return false;
|
|
8080
|
-
if (
|
|
8445
|
+
if (hasActiveAccountLease(accountId)) return false;
|
|
8081
8446
|
const mutex = accountMutexes.get(accountId);
|
|
8082
8447
|
return mutex?.isIdle();
|
|
8083
8448
|
})
|
|
@@ -8090,6 +8455,7 @@ async function evictIdlePlaywrightContextsToLimit() {
|
|
|
8090
8455
|
for (const candidate of candidates) {
|
|
8091
8456
|
if (accountPages.size <= max) break;
|
|
8092
8457
|
if (isAccountServingStream(candidate.accountId)) continue;
|
|
8458
|
+
if (hasActiveAccountLease(candidate.accountId)) continue;
|
|
8093
8459
|
const mutex = accountMutexes.get(candidate.accountId);
|
|
8094
8460
|
if (!mutex?.isIdle()) continue;
|
|
8095
8461
|
await closePlaywrightForAccount(candidate.accountId).catch((error) => {
|
|
@@ -8520,12 +8886,13 @@ var init_watchdog = __esm({
|
|
|
8520
8886
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
8521
8887
|
this.emit("recovery:ram:freed");
|
|
8522
8888
|
try {
|
|
8523
|
-
const { closeIdlePlaywrightAccounts: closeIdlePlaywrightAccounts2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
8889
|
+
const { closeIdlePlaywrightAccounts: closeIdlePlaywrightAccounts2, evictIdlePlaywrightContextsToLimit: evictIdlePlaywrightContextsToLimit2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
8890
|
+
const evicted = await evictIdlePlaywrightContextsToLimit2(1);
|
|
8524
8891
|
const closed = await closeIdlePlaywrightAccounts2(
|
|
8525
8892
|
config.sessionKeeper.idleMs
|
|
8526
8893
|
);
|
|
8527
|
-
if (closed > 0) {
|
|
8528
|
-
this.emit("recovery:ram:contexts-closed", closed);
|
|
8894
|
+
if (evicted + closed > 0) {
|
|
8895
|
+
this.emit("recovery:ram:contexts-closed", evicted + closed);
|
|
8529
8896
|
}
|
|
8530
8897
|
} catch {
|
|
8531
8898
|
}
|
|
@@ -8691,13 +9058,13 @@ async function getBasicHeaders2(accountId) {
|
|
|
8691
9058
|
return {
|
|
8692
9059
|
cookie: "token=mock",
|
|
8693
9060
|
userAgent: "mock",
|
|
8694
|
-
bxV:
|
|
9061
|
+
bxV: getQwenBxVersion(),
|
|
8695
9062
|
bxUa: "mock-bx-ua",
|
|
8696
9063
|
bxUmidtoken: "mock-bx-umidtoken",
|
|
8697
9064
|
secChUa: "",
|
|
8698
9065
|
secChUaMobile: "?0",
|
|
8699
9066
|
secChUaPlatform: "",
|
|
8700
|
-
version:
|
|
9067
|
+
version: getQwenWebVersion()
|
|
8701
9068
|
};
|
|
8702
9069
|
}
|
|
8703
9070
|
const resolvedAccountId = accountId ?? loadAccounts()[0]?.id;
|
|
@@ -8758,6 +9125,7 @@ var init_auth_playwright = __esm({
|
|
|
8758
9125
|
init_errors();
|
|
8759
9126
|
init_accounts();
|
|
8760
9127
|
init_config();
|
|
9128
|
+
init_qwen_headers();
|
|
8761
9129
|
init_playwright();
|
|
8762
9130
|
init_jwt();
|
|
8763
9131
|
}
|
|
@@ -8882,6 +9250,7 @@ var init_model_alias = __esm({
|
|
|
8882
9250
|
DEFAULT_FALLBACK_MODELS = [
|
|
8883
9251
|
"qwen3.8-max",
|
|
8884
9252
|
"qwen3.7-plus",
|
|
9253
|
+
"qwen4.0-max-preview",
|
|
8885
9254
|
"qwen3.8-omni-flash",
|
|
8886
9255
|
"qwen3.7-max",
|
|
8887
9256
|
"qwen3.6-plus",
|
|
@@ -9208,6 +9577,7 @@ var init_model_registry = __esm({
|
|
|
9208
9577
|
var captcha_coordinator_exports = {};
|
|
9209
9578
|
__export(captcha_coordinator_exports, {
|
|
9210
9579
|
isCaptchaRecoveryActive: () => isCaptchaRecoveryActive,
|
|
9580
|
+
isCaptchaRecoveryInBackoff: () => isCaptchaRecoveryInBackoff,
|
|
9211
9581
|
recoverBaxiaCaptcha: () => recoverBaxiaCaptcha,
|
|
9212
9582
|
solveChallengeOnPage: () => solveChallengeOnPage
|
|
9213
9583
|
});
|
|
@@ -9227,9 +9597,10 @@ async function solveChallengeOnPage(page, challengeUrl, waitForMs = config.captc
|
|
|
9227
9597
|
const solverOptions = {
|
|
9228
9598
|
maxAttempts: config.captcha.maxAttempts,
|
|
9229
9599
|
retryDelayMs: config.captcha.retryDelayMs,
|
|
9230
|
-
settleMs: config.captcha.settleMs
|
|
9600
|
+
settleMs: config.captcha.settleMs,
|
|
9601
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
9231
9602
|
};
|
|
9232
|
-
if (await
|
|
9603
|
+
if (await solveVisibleCaptcha(page, { ...solverOptions, waitForMs: 0 })) {
|
|
9233
9604
|
return true;
|
|
9234
9605
|
}
|
|
9235
9606
|
logBaxiaCaptcha(
|
|
@@ -9239,13 +9610,18 @@ async function solveChallengeOnPage(page, challengeUrl, waitForMs = config.captc
|
|
|
9239
9610
|
);
|
|
9240
9611
|
await gotoBestEffort(page, challengeUrl ?? qwenUrl("/"));
|
|
9241
9612
|
try {
|
|
9242
|
-
return await
|
|
9613
|
+
return await solveVisibleCaptcha(page, { ...solverOptions, waitForMs });
|
|
9243
9614
|
} finally {
|
|
9244
9615
|
if (page.url().includes(CHALLENGE_PATH_MARKER)) {
|
|
9245
9616
|
await gotoBestEffort(page, qwenUrl("/"));
|
|
9246
9617
|
}
|
|
9247
9618
|
}
|
|
9248
9619
|
}
|
|
9620
|
+
function isCaptchaRecoveryInBackoff(accountId) {
|
|
9621
|
+
if (!accountId) return false;
|
|
9622
|
+
const lastFailure = lastFailedRecoveryAt.get(accountId) ?? 0;
|
|
9623
|
+
return Date.now() - lastFailure < FAILED_RECOVERY_BACKOFF_MS;
|
|
9624
|
+
}
|
|
9249
9625
|
async function recoverBaxiaCaptcha(accountId, label, options = {}) {
|
|
9250
9626
|
if (!config.captcha.enabled || !accountId) return false;
|
|
9251
9627
|
const solver = "baxia";
|
|
@@ -9263,17 +9639,35 @@ async function recoverBaxiaCaptcha(accountId, label, options = {}) {
|
|
|
9263
9639
|
const challengeUrl = options.challengeBody ? extractBaxiaChallengeUrl(options.challengeBody, config.qwen.baseUrl) : null;
|
|
9264
9640
|
activeCaptchaRecoveries.add(accountId);
|
|
9265
9641
|
try {
|
|
9266
|
-
const {
|
|
9267
|
-
|
|
9268
|
-
accountId,
|
|
9269
|
-
"Account stream interrupted by captcha challenge recovery"
|
|
9270
|
-
);
|
|
9271
|
-
} catch {
|
|
9272
|
-
}
|
|
9273
|
-
try {
|
|
9642
|
+
const { hasActiveBrowserStreamsForAccount: hasActiveBrowserStreamsForAccount2 } = await Promise.resolve().then(() => (init_qwen(), qwen_exports));
|
|
9643
|
+
const hasConcurrentStream = hasActiveBrowserStreamsForAccount2(accountId);
|
|
9274
9644
|
const solved = await withAccountPage(
|
|
9275
9645
|
accountId,
|
|
9276
|
-
(page) =>
|
|
9646
|
+
async (page) => {
|
|
9647
|
+
if (hasConcurrentStream) {
|
|
9648
|
+
const solverOptions = {
|
|
9649
|
+
maxAttempts: config.captcha.maxAttempts,
|
|
9650
|
+
retryDelayMs: config.captcha.retryDelayMs,
|
|
9651
|
+
settleMs: config.captcha.settleMs,
|
|
9652
|
+
sliderTimeoutMs: config.captcha.sliderTimeoutMs
|
|
9653
|
+
};
|
|
9654
|
+
if (await solveVisibleCaptcha(page, { ...solverOptions, waitForMs: 0 })) {
|
|
9655
|
+
return true;
|
|
9656
|
+
}
|
|
9657
|
+
const ctx = typeof page.context === "function" ? page.context() : null;
|
|
9658
|
+
if (ctx && typeof ctx.newPage === "function") {
|
|
9659
|
+
const tempPage = await ctx.newPage();
|
|
9660
|
+
try {
|
|
9661
|
+
return await solveChallengeOnPage(tempPage, challengeUrl);
|
|
9662
|
+
} finally {
|
|
9663
|
+
await tempPage.close({ runBeforeUnload: false }).catch(() => {
|
|
9664
|
+
});
|
|
9665
|
+
}
|
|
9666
|
+
}
|
|
9667
|
+
return false;
|
|
9668
|
+
}
|
|
9669
|
+
return await solveChallengeOnPage(page, challengeUrl);
|
|
9670
|
+
},
|
|
9277
9671
|
solverOperationTimeoutMs,
|
|
9278
9672
|
solverOperationTimeoutMs,
|
|
9279
9673
|
false
|
|
@@ -11574,7 +11968,7 @@ var init_media_generation = __esm({
|
|
|
11574
11968
|
|
|
11575
11969
|
// src/services/qwen-chat-pool.ts
|
|
11576
11970
|
import crypto6 from "crypto";
|
|
11577
|
-
async function createQwenChatSession(headers, model, accountId, chatMode = "thread") {
|
|
11971
|
+
async function createQwenChatSession(headers, model, accountId, chatMode = "thread", captchaRecoveryAttempts = 1) {
|
|
11578
11972
|
if (isAuthMockEnabled()) {
|
|
11579
11973
|
return process.env.TEST_SESSION_ID || "mock-session";
|
|
11580
11974
|
}
|
|
@@ -11602,16 +11996,29 @@ async function createQwenChatSession(headers, model, accountId, chatMode = "thre
|
|
|
11602
11996
|
if (!chatId || typeof chatId !== "string") {
|
|
11603
11997
|
const rawLower = raw.toLowerCase();
|
|
11604
11998
|
if (looksLikeAntiBotChallengeText(raw)) {
|
|
11605
|
-
|
|
11606
|
-
|
|
11607
|
-
|
|
11608
|
-
|
|
11609
|
-
|
|
11610
|
-
|
|
11611
|
-
|
|
11999
|
+
if (captchaRecoveryAttempts > 0) {
|
|
12000
|
+
try {
|
|
12001
|
+
const { recoverBaxiaCaptcha: recoverBaxiaCaptcha2 } = await Promise.resolve().then(() => (init_captcha_coordinator(), captcha_coordinator_exports));
|
|
12002
|
+
const solved = await recoverBaxiaCaptcha2(accountId, "createQwenChatSession", {
|
|
12003
|
+
challengeBody: raw
|
|
12004
|
+
});
|
|
12005
|
+
if (solved) {
|
|
12006
|
+
return createQwenChatSession(
|
|
12007
|
+
headers,
|
|
12008
|
+
model,
|
|
12009
|
+
accountId,
|
|
12010
|
+
chatMode,
|
|
12011
|
+
captchaRecoveryAttempts - 1
|
|
12012
|
+
);
|
|
12013
|
+
}
|
|
12014
|
+
} catch {
|
|
11612
12015
|
}
|
|
11613
|
-
} catch {
|
|
11614
12016
|
}
|
|
12017
|
+
throw new QwenUpstreamError(
|
|
12018
|
+
`Qwen create chat blocked by WAF challenge: ${raw.substring(0, 300)}`,
|
|
12019
|
+
"FAIL_SYS_USER_VALIDATE",
|
|
12020
|
+
403
|
|
12021
|
+
);
|
|
11615
12022
|
}
|
|
11616
12023
|
const isUnauthorized = json?.data?.code?.toLowerCase() === "unauthorized" || json?.code?.toLowerCase() === "unauthorized" || rawLower.includes("unauthorized") || rawLower.includes("permission to access") || rawLower.includes("token has expired") || rawLower.includes("401");
|
|
11617
12024
|
if (isUnauthorized) {
|
|
@@ -11788,6 +12195,20 @@ async function refillQwenChatPool(headers, model, accountId) {
|
|
|
11788
12195
|
console.warn(
|
|
11789
12196
|
`[WarmPool] Account ${accountId || "global"} rate-limited during chat creation. Marked for cooldown.`
|
|
11790
12197
|
);
|
|
12198
|
+
} else if (accountId && (err.upstreamCode === "FAIL_SYS_USER_VALIDATE" || err.upstreamCode === "RGV587_ERROR" || /_____tmd_____|rgv587_error|fail_sys_user_validate/i.test(
|
|
12199
|
+
err.message
|
|
12200
|
+
))) {
|
|
12201
|
+
const existing = getAccountCooldownInfo(accountId);
|
|
12202
|
+
if (existing?.reason === "WafChallenge") {
|
|
12203
|
+
console.warn(
|
|
12204
|
+
`[WarmPool] Account ${accountId} still on WAF quarantine (${Math.ceil(existing.remainingMs / 1e3)}s left); skipping re-escalation.`
|
|
12205
|
+
);
|
|
12206
|
+
} else {
|
|
12207
|
+
const block = recordWafHardBlock(accountId);
|
|
12208
|
+
console.warn(
|
|
12209
|
+
`[WarmPool] Unsolved WAF challenge on ${accountId} during chat creation; quarantined ${Math.ceil(block.cooldownMs / 1e3)}s and rotated the fingerprint.`
|
|
12210
|
+
);
|
|
12211
|
+
}
|
|
11791
12212
|
}
|
|
11792
12213
|
}
|
|
11793
12214
|
if (isToolcallDebugEnabled()) {
|
|
@@ -11823,6 +12244,7 @@ var init_qwen_chat_pool = __esm({
|
|
|
11823
12244
|
init_config();
|
|
11824
12245
|
init_logger();
|
|
11825
12246
|
init_account_manager();
|
|
12247
|
+
init_waf_isolation();
|
|
11826
12248
|
init_model_alias();
|
|
11827
12249
|
init_qwen_url();
|
|
11828
12250
|
init_qwen_errors();
|
|
@@ -11872,6 +12294,7 @@ __export(qwen_exports, {
|
|
|
11872
12294
|
getLogicalThreadState: () => getLogicalThreadState,
|
|
11873
12295
|
getQwenErrorCode: () => getQwenErrorCode,
|
|
11874
12296
|
getSessionParent: () => getSessionParent,
|
|
12297
|
+
hasActiveBrowserStreamsForAccount: () => hasActiveBrowserStreamsForAccount,
|
|
11875
12298
|
invalidateLogicalThreadParent: () => invalidateLogicalThreadParent,
|
|
11876
12299
|
isChatSessionActive: () => isChatSessionActive,
|
|
11877
12300
|
isRetryableFetchErrorMessage: () => isRetryableFetchErrorMessage,
|
|
@@ -11893,6 +12316,14 @@ __export(qwen_exports, {
|
|
|
11893
12316
|
});
|
|
11894
12317
|
import crypto7 from "crypto";
|
|
11895
12318
|
import { v4 as uuidv43 } from "uuid";
|
|
12319
|
+
function hasActiveBrowserStreamsForAccount(accountId) {
|
|
12320
|
+
for (const state of browserStreamStates.values()) {
|
|
12321
|
+
if (state.accountId === accountId && !state.done) {
|
|
12322
|
+
return true;
|
|
12323
|
+
}
|
|
12324
|
+
}
|
|
12325
|
+
return false;
|
|
12326
|
+
}
|
|
11896
12327
|
function abortActiveBrowserStreamsForAccount(accountId, reason = "Account browser stream interrupted (page context unloaded)") {
|
|
11897
12328
|
let count = 0;
|
|
11898
12329
|
for (const [requestId, state] of browserStreamStates) {
|
|
@@ -12383,7 +12814,7 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
|
|
|
12383
12814
|
browserHeaders["Content-Type"] = "application/json";
|
|
12384
12815
|
}
|
|
12385
12816
|
const evaluateRequest = (page) => page.evaluate(
|
|
12386
|
-
async ({ url: url2, method: method2, headers: headers2, body: body2, referrer, timeoutMs, tz }) => {
|
|
12817
|
+
async ({ url: url2, method: method2, headers: headers2, body: body2, referrer, timeoutMs, tz, version }) => {
|
|
12387
12818
|
const controller = new AbortController();
|
|
12388
12819
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
12389
12820
|
try {
|
|
@@ -12405,7 +12836,7 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
|
|
|
12405
12836
|
headers: {
|
|
12406
12837
|
accept: "application/json, text/plain, */*",
|
|
12407
12838
|
source: "web",
|
|
12408
|
-
version
|
|
12839
|
+
version,
|
|
12409
12840
|
"x-request-origin": "https://chat.qwen.ai",
|
|
12410
12841
|
timezone: tz,
|
|
12411
12842
|
authorization: `Bearer ${rTok}`
|
|
@@ -12453,7 +12884,8 @@ async function requestQwenTextInBrowser(accountId, method, path21, headers, body
|
|
|
12453
12884
|
body,
|
|
12454
12885
|
referrer: options.referrer,
|
|
12455
12886
|
timeoutMs: options.timeoutMs ?? Math.min(config.timeouts.page, 2e4),
|
|
12456
|
-
tz: formatAsciiTimezone()
|
|
12887
|
+
tz: formatAsciiTimezone(),
|
|
12888
|
+
version: getQwenWebVersion()
|
|
12457
12889
|
}
|
|
12458
12890
|
);
|
|
12459
12891
|
const recoverOnTimeout = !options.noMutexRecovery;
|
|
@@ -12670,7 +13102,7 @@ async function createQwenBrowserResponse(accountId, url, method, headers, body,
|
|
|
12670
13102
|
const onFrameNavigated = (frame) => {
|
|
12671
13103
|
if (!settled && typeof page.mainFrame === "function" && frame === page.mainFrame()) {
|
|
12672
13104
|
const url2 = typeof frame.url === "function" ? frame.url() : String(frame.url || "");
|
|
12673
|
-
if (url2.startsWith(qwenOrigin()) && !url2.includes("/auth") && !url2.includes("_____tmd_____") && !url2.includes("/punish")) {
|
|
13105
|
+
if (url2.startsWith(qwenOrigin()) && !url2.includes("/auth") && !url2.includes("/login") && !url2.includes("_____tmd_____") && !url2.includes("/punish")) {
|
|
12674
13106
|
return;
|
|
12675
13107
|
}
|
|
12676
13108
|
handleBrowserStreamEvent(requestId, {
|
|
@@ -12691,10 +13123,12 @@ async function createQwenBrowserResponse(accountId, url, method, headers, body,
|
|
|
12691
13123
|
};
|
|
12692
13124
|
page.on("framenavigated", onFrameNavigated);
|
|
12693
13125
|
page.on("close", onPageClosed);
|
|
13126
|
+
page.on("crash", onPageClosed);
|
|
12694
13127
|
pageCleanup = () => {
|
|
12695
13128
|
try {
|
|
12696
13129
|
page.off?.("framenavigated", onFrameNavigated);
|
|
12697
13130
|
page.off?.("close", onPageClosed);
|
|
13131
|
+
page.off?.("crash", onPageClosed);
|
|
12698
13132
|
} catch {
|
|
12699
13133
|
}
|
|
12700
13134
|
};
|
|
@@ -13408,7 +13842,7 @@ async function deleteSingleQwenChat(accountId, chatId) {
|
|
|
13408
13842
|
}
|
|
13409
13843
|
const requestHeaders = {
|
|
13410
13844
|
source: "web",
|
|
13411
|
-
version: getQwenWebVersion()
|
|
13845
|
+
version: getQwenWebVersion(),
|
|
13412
13846
|
timezone: formatAsciiTimezone(),
|
|
13413
13847
|
"x-request-id": crypto7.randomUUID(),
|
|
13414
13848
|
Referer: qwenUrl(`/c/${encodeURIComponent(chatId)}`)
|
|
@@ -13452,7 +13886,7 @@ async function fetchRemoteQwenChats(accountId) {
|
|
|
13452
13886
|
return [];
|
|
13453
13887
|
}
|
|
13454
13888
|
const requestHeaders = {
|
|
13455
|
-
version: getQwenWebVersion()
|
|
13889
|
+
version: getQwenWebVersion(),
|
|
13456
13890
|
timezone: formatAsciiTimezone(),
|
|
13457
13891
|
"x-request-id": crypto7.randomUUID(),
|
|
13458
13892
|
Referer: qwenUrl("/settings/chats")
|
|
@@ -16843,7 +17277,16 @@ async function deleteChatsForAccountId(accountId) {
|
|
|
16843
17277
|
if (!credentials) {
|
|
16844
17278
|
throw new Error(`Credenciais da conta ${account.email} n\xE3o encontradas.`);
|
|
16845
17279
|
}
|
|
16846
|
-
|
|
17280
|
+
const wasInitialized = isPlaywrightInitialized(account.id);
|
|
17281
|
+
try {
|
|
17282
|
+
return await deleteChatsForAccount(credentials);
|
|
17283
|
+
} finally {
|
|
17284
|
+
if (!wasInitialized && !isAuthMockEnabled()) {
|
|
17285
|
+
const { closePlaywrightForAccount: closePlaywrightForAccount2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
17286
|
+
await closePlaywrightForAccount2(account.id).catch(() => {
|
|
17287
|
+
});
|
|
17288
|
+
}
|
|
17289
|
+
}
|
|
16847
17290
|
}
|
|
16848
17291
|
async function deleteChatsForConfiguredAccounts(keepBrowserOpen = false) {
|
|
16849
17292
|
const accounts = loadAccounts();
|
|
@@ -16858,6 +17301,7 @@ async function deleteChatsForConfiguredAccounts(keepBrowserOpen = false) {
|
|
|
16858
17301
|
const account = accounts[i];
|
|
16859
17302
|
const currentIdx = i + 1;
|
|
16860
17303
|
const totalCount = accounts.length;
|
|
17304
|
+
const wasInitialized = isPlaywrightInitialized(account.id);
|
|
16861
17305
|
try {
|
|
16862
17306
|
const ok = await deleteChatsForAccount(account, currentIdx, totalCount);
|
|
16863
17307
|
if (ok) succeeded++;
|
|
@@ -16867,7 +17311,7 @@ async function deleteChatsForConfiguredAccounts(keepBrowserOpen = false) {
|
|
|
16867
17311
|
error instanceof Error ? error.message : String(error)
|
|
16868
17312
|
);
|
|
16869
17313
|
} finally {
|
|
16870
|
-
if (!keepBrowserOpen) {
|
|
17314
|
+
if ((!keepBrowserOpen || !wasInitialized) && !isAuthMockEnabled()) {
|
|
16871
17315
|
const { closePlaywrightForAccount: closePlaywrightForAccount2 } = await Promise.resolve().then(() => (init_playwright(), playwright_exports));
|
|
16872
17316
|
await closePlaywrightForAccount2(account.id).catch(() => {
|
|
16873
17317
|
});
|
|
@@ -18154,6 +18598,9 @@ ${loopReminder}` : truncation.prompt;
|
|
|
18154
18598
|
if (policy.reason === "corrupted_chat_history") {
|
|
18155
18599
|
invalidateLogicalThreadParent(params.sessionId);
|
|
18156
18600
|
}
|
|
18601
|
+
if (policy.reason === "anti_bot" && isCaptchaRecoveryInBackoff(currentAccountId)) {
|
|
18602
|
+
return { success: false, error: err };
|
|
18603
|
+
}
|
|
18157
18604
|
const retryInvalidInputOnSameAccount = shouldRetryInvalidInputOnSameAccount(
|
|
18158
18605
|
policy.reason,
|
|
18159
18606
|
invalidInputSameAccountRetried
|
|
@@ -18342,6 +18789,7 @@ var init_account = __esm({
|
|
|
18342
18789
|
init_account_manager();
|
|
18343
18790
|
init_account_priority();
|
|
18344
18791
|
init_waf_isolation();
|
|
18792
|
+
init_captcha_coordinator();
|
|
18345
18793
|
init_accounts();
|
|
18346
18794
|
init_config();
|
|
18347
18795
|
init_errors();
|
|
@@ -21965,8 +22413,8 @@ async function processStreamingResponse(params) {
|
|
|
21965
22413
|
);
|
|
21966
22414
|
};
|
|
21967
22415
|
const emitAnswerText = async (textChunk) => {
|
|
21968
|
-
if (textChunk) emittedModelOutput = true;
|
|
21969
22416
|
if (!toolParser) {
|
|
22417
|
+
if (textChunk) emittedModelOutput = true;
|
|
21970
22418
|
finalContent += textChunk;
|
|
21971
22419
|
writeDeltaEvent({ content: textChunk });
|
|
21972
22420
|
return;
|
|
@@ -22342,6 +22790,23 @@ async function processStreamingResponse(params) {
|
|
|
22342
22790
|
if (fastMatch) {
|
|
22343
22791
|
const unescaped = fastMatch[1].replace(/\\n/g, "\n").replace(/\\t/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\");
|
|
22344
22792
|
if (unescaped) {
|
|
22793
|
+
if (!emittedModelOutput && isOverloadMessage(unescaped)) {
|
|
22794
|
+
const overloadErr = toRetryableStreamError(
|
|
22795
|
+
"server_overloaded",
|
|
22796
|
+
unescaped,
|
|
22797
|
+
{
|
|
22798
|
+
switchAccount: true,
|
|
22799
|
+
forceNewChat: true,
|
|
22800
|
+
reason: "server_busy",
|
|
22801
|
+
accountCooldownMs: OVERLOAD_COOLDOWN_MS,
|
|
22802
|
+
accountCooldownReason: "ServerOverloaded"
|
|
22803
|
+
}
|
|
22804
|
+
);
|
|
22805
|
+
if (await recoverFromStreamError(overloadErr)) {
|
|
22806
|
+
break;
|
|
22807
|
+
}
|
|
22808
|
+
throw overloadErr;
|
|
22809
|
+
}
|
|
22345
22810
|
const result = getIncrementalDelta(
|
|
22346
22811
|
lastRawContent,
|
|
22347
22812
|
unescaped,
|
|
@@ -22476,7 +22941,6 @@ async function processStreamingResponse(params) {
|
|
|
22476
22941
|
if (foundStr && vStr !== "") {
|
|
22477
22942
|
if (vStr === "FINISHED") continue;
|
|
22478
22943
|
if (isThinkingChunk) {
|
|
22479
|
-
emittedModelOutput = true;
|
|
22480
22944
|
reasoningBuffer += vStr;
|
|
22481
22945
|
writeDeltaEvent({ reasoning_content: vStr });
|
|
22482
22946
|
} else {
|
|
@@ -27111,11 +27575,42 @@ var init_server_log_buffer = __esm({
|
|
|
27111
27575
|
// src/services/session-keeper.ts
|
|
27112
27576
|
var session_keeper_exports = {};
|
|
27113
27577
|
__export(session_keeper_exports, {
|
|
27578
|
+
computeSessionKeeperBackoffMs: () => computeSessionKeeperBackoffMs,
|
|
27579
|
+
isSessionKeeperAccountBackedOff: () => isSessionKeeperAccountBackedOff,
|
|
27114
27580
|
isSessionKeeperRunning: () => isSessionKeeperRunning,
|
|
27581
|
+
resetSessionKeeperRetryStateForTests: () => resetSessionKeeperRetryStateForTests,
|
|
27115
27582
|
runSessionKeeperOnceForTesting: () => runSessionKeeperOnceForTesting,
|
|
27116
27583
|
startSessionKeeper: () => startSessionKeeper,
|
|
27117
27584
|
stopSessionKeeper: () => stopSessionKeeper
|
|
27118
27585
|
});
|
|
27586
|
+
function computeSessionKeeperBackoffMs(failures) {
|
|
27587
|
+
const exponent = Math.max(0, Math.min(failures - 1, 8));
|
|
27588
|
+
return Math.min(
|
|
27589
|
+
KEEP_ALIVE_BACKOFF_MAX_MS,
|
|
27590
|
+
KEEP_ALIVE_BACKOFF_BASE_MS * 2 ** exponent
|
|
27591
|
+
);
|
|
27592
|
+
}
|
|
27593
|
+
function isKeepAliveBackedOff(accountId) {
|
|
27594
|
+
const state = keepAliveRetries.get(accountId);
|
|
27595
|
+
return Boolean(state && Date.now() < state.nextAttemptAt);
|
|
27596
|
+
}
|
|
27597
|
+
function recordKeepAliveFailure(accountId) {
|
|
27598
|
+
const state = keepAliveRetries.get(accountId) ?? {
|
|
27599
|
+
failures: 0,
|
|
27600
|
+
nextAttemptAt: 0
|
|
27601
|
+
};
|
|
27602
|
+
state.failures += 1;
|
|
27603
|
+
const backoffMs = computeSessionKeeperBackoffMs(state.failures);
|
|
27604
|
+
state.nextAttemptAt = Date.now() + backoffMs;
|
|
27605
|
+
keepAliveRetries.set(accountId, state);
|
|
27606
|
+
return backoffMs;
|
|
27607
|
+
}
|
|
27608
|
+
function resetSessionKeeperRetryStateForTests() {
|
|
27609
|
+
keepAliveRetries.clear();
|
|
27610
|
+
}
|
|
27611
|
+
function isSessionKeeperAccountBackedOff(accountId) {
|
|
27612
|
+
return isKeepAliveBackedOff(accountId);
|
|
27613
|
+
}
|
|
27119
27614
|
function isSessionKeeperRunning() {
|
|
27120
27615
|
return running;
|
|
27121
27616
|
}
|
|
@@ -27126,13 +27621,25 @@ async function runKeepAliveCycle() {
|
|
|
27126
27621
|
if (config.sessionKeeper.enabled) {
|
|
27127
27622
|
const accountIds = getActivePlaywrightAccountIds();
|
|
27128
27623
|
for (const accountId of accountIds) {
|
|
27129
|
-
|
|
27130
|
-
|
|
27131
|
-
|
|
27132
|
-
|
|
27133
|
-
|
|
27134
|
-
)
|
|
27135
|
-
|
|
27624
|
+
if (isKeepAliveBackedOff(accountId)) {
|
|
27625
|
+
continue;
|
|
27626
|
+
}
|
|
27627
|
+
try {
|
|
27628
|
+
const keptAlive = await keepAlivePlaywrightAccount(accountId);
|
|
27629
|
+
if (keptAlive) {
|
|
27630
|
+
keepAliveRetries.delete(accountId);
|
|
27631
|
+
}
|
|
27632
|
+
} catch (error) {
|
|
27633
|
+
if (isPlaywrightAlreadyClosedError(error)) {
|
|
27634
|
+
keepAliveRetries.delete(accountId);
|
|
27635
|
+
} else {
|
|
27636
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
27637
|
+
const backoffMs = recordKeepAliveFailure(accountId);
|
|
27638
|
+
console.warn(
|
|
27639
|
+
`[SessionKeeper] Keep-alive failed for ${accountId}: ${message} (retry in ${Math.round(backoffMs / 1e3)}s)`
|
|
27640
|
+
);
|
|
27641
|
+
}
|
|
27642
|
+
}
|
|
27136
27643
|
await sleep(humanDelay(250, 900));
|
|
27137
27644
|
}
|
|
27138
27645
|
}
|
|
@@ -27172,11 +27679,12 @@ function stopSessionKeeper() {
|
|
|
27172
27679
|
intervalId = null;
|
|
27173
27680
|
}
|
|
27174
27681
|
cycleInProgress = false;
|
|
27682
|
+
keepAliveRetries.clear();
|
|
27175
27683
|
}
|
|
27176
27684
|
async function runSessionKeeperOnceForTesting() {
|
|
27177
27685
|
await runKeepAliveCycle();
|
|
27178
27686
|
}
|
|
27179
|
-
var running, intervalId, cycleInProgress;
|
|
27687
|
+
var running, intervalId, cycleInProgress, KEEP_ALIVE_BACKOFF_BASE_MS, KEEP_ALIVE_BACKOFF_MAX_MS, keepAliveRetries;
|
|
27180
27688
|
var init_session_keeper = __esm({
|
|
27181
27689
|
"src/services/session-keeper.ts"() {
|
|
27182
27690
|
"use strict";
|
|
@@ -27186,6 +27694,9 @@ var init_session_keeper = __esm({
|
|
|
27186
27694
|
running = false;
|
|
27187
27695
|
intervalId = null;
|
|
27188
27696
|
cycleInProgress = false;
|
|
27697
|
+
KEEP_ALIVE_BACKOFF_BASE_MS = 2e3;
|
|
27698
|
+
KEEP_ALIVE_BACKOFF_MAX_MS = 5 * 6e4;
|
|
27699
|
+
keepAliveRetries = /* @__PURE__ */ new Map();
|
|
27189
27700
|
}
|
|
27190
27701
|
});
|
|
27191
27702
|
|
|
@@ -27211,7 +27722,7 @@ function getAppVersion() {
|
|
|
27211
27722
|
}
|
|
27212
27723
|
} catch {
|
|
27213
27724
|
}
|
|
27214
|
-
cachedVersion = "v1.6.
|
|
27725
|
+
cachedVersion = "v1.6.12";
|
|
27215
27726
|
return cachedVersion;
|
|
27216
27727
|
}
|
|
27217
27728
|
var cachedVersion;
|
|
@@ -27617,10 +28128,11 @@ async function startServer(options) {
|
|
|
27617
28128
|
} else if (remainingAccounts.length > 0) {
|
|
27618
28129
|
void (async () => {
|
|
27619
28130
|
const { ensureAccountInPriority: ensureAccountInPriority2 } = await Promise.resolve().then(() => (init_account_priority(), account_priority_exports));
|
|
27620
|
-
const
|
|
28131
|
+
const maxWarmCap = config.playwright.maxActiveContexts > 0 ? Math.min(
|
|
27621
28132
|
config.playwright.startupWarmAccounts,
|
|
27622
|
-
|
|
27623
|
-
);
|
|
28133
|
+
config.playwright.maxActiveContexts
|
|
28134
|
+
) : config.playwright.startupWarmAccounts;
|
|
28135
|
+
const targetWarmTotal = Math.min(maxWarmCap, totalAccounts);
|
|
27624
28136
|
let currentReadyCount = readyAccountIds.size;
|
|
27625
28137
|
if (currentReadyCount < targetWarmTotal && remainingAccounts.length > 0) {
|
|
27626
28138
|
for (const reserveAccount of remainingAccounts) {
|