qwenproxy-cli 1.6.4 → 1.6.5

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.
@@ -1915,6 +1915,7 @@ var init_mutex = __esm({
1915
1915
  locked = false;
1916
1916
  lockedAt = 0;
1917
1917
  lockedByKey = "";
1918
+ epoch = 0;
1918
1919
  async acquire(timeoutMs = 3e5, key = "") {
1919
1920
  const holdLimitMs = this.maxHoldMs;
1920
1921
  if (this.locked && Date.now() - this.lockedAt > holdLimitMs) {
@@ -1925,6 +1926,7 @@ var init_mutex = __esm({
1925
1926
  this.locked = false;
1926
1927
  this.lockedAt = 0;
1927
1928
  this.lockedByKey = "";
1929
+ this.epoch++;
1928
1930
  }
1929
1931
  if (!this.locked) {
1930
1932
  this.locked = true;
@@ -1963,10 +1965,12 @@ var init_mutex = __esm({
1963
1965
  }
1964
1966
  }
1965
1967
  createRelease() {
1968
+ const epoch = this.epoch;
1966
1969
  let released = false;
1967
1970
  return () => {
1968
1971
  if (released) return;
1969
1972
  released = true;
1973
+ if (epoch !== this.epoch) return;
1970
1974
  this.release();
1971
1975
  };
1972
1976
  }
@@ -2906,6 +2910,49 @@ var init_waf_isolation = __esm({
2906
2910
  }
2907
2911
  });
2908
2912
 
2913
+ // src/utils/timezone.ts
2914
+ function formatAsciiTimezone(date = /* @__PURE__ */ new Date()) {
2915
+ const dayName = DAYS[date.getDay()];
2916
+ const monthName = MONTHS[date.getMonth()];
2917
+ const day = String(date.getDate()).padStart(2, "0");
2918
+ const year = date.getFullYear();
2919
+ const hours = String(date.getHours()).padStart(2, "0");
2920
+ const minutes = String(date.getMinutes()).padStart(2, "0");
2921
+ const seconds = String(date.getSeconds()).padStart(2, "0");
2922
+ const offsetMinutes = -date.getTimezoneOffset();
2923
+ const sign = offsetMinutes >= 0 ? "+" : "-";
2924
+ const absOffset = Math.abs(offsetMinutes);
2925
+ const offsetHours = String(Math.floor(absOffset / 60)).padStart(2, "0");
2926
+ const offsetMins = String(absOffset % 60).padStart(2, "0");
2927
+ const tzOffset = `GMT${sign}${offsetHours}${offsetMins}`;
2928
+ return `${dayName} ${monthName} ${day} ${year} ${hours}:${minutes}:${seconds} ${tzOffset}`;
2929
+ }
2930
+ function sanitizeHeaderForFetch(val) {
2931
+ if (typeof val !== "string") return "";
2932
+ return val.replace(/[^\x00-\xFF]/g, "");
2933
+ }
2934
+ var DAYS, MONTHS;
2935
+ var init_timezone = __esm({
2936
+ "src/utils/timezone.ts"() {
2937
+ "use strict";
2938
+ DAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2939
+ MONTHS = [
2940
+ "Jan",
2941
+ "Feb",
2942
+ "Mar",
2943
+ "Apr",
2944
+ "May",
2945
+ "Jun",
2946
+ "Jul",
2947
+ "Aug",
2948
+ "Sep",
2949
+ "Oct",
2950
+ "Nov",
2951
+ "Dec"
2952
+ ];
2953
+ }
2954
+ });
2955
+
2909
2956
  // src/services/qwen-headers.ts
2910
2957
  import { v4 as uuidv4 } from "uuid";
2911
2958
  function getSystemAcceptLanguage(customLocale) {
@@ -2949,8 +2996,8 @@ function buildQwenRequestHeaders(opts) {
2949
2996
  "bx-v": opts.bxV || "2.5.37",
2950
2997
  source: "web",
2951
2998
  version: opts.version || getQwenWebVersion(),
2952
- timezone: opts.extra?.timezone || opts.extra?.Timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
2953
- Timezone: opts.extra?.Timezone || opts.extra?.timezone || (/* @__PURE__ */ new Date()).toString().split(" (")[0],
2999
+ timezone: opts.extra?.timezone || opts.extra?.Timezone || formatAsciiTimezone(),
3000
+ Timezone: opts.extra?.Timezone || opts.extra?.timezone || formatAsciiTimezone(),
2954
3001
  // Use the real browser client-hints when captured (anti-hardcoded); fall
2955
3002
  // back to the static fingerprint otherwise.
2956
3003
  "sec-ch-ua": opts.secChUa || `"Google Chrome";v="${getChromeMajor()}", "Chromium";v="${getChromeMajor()}", "Not.A/Brand";v="99"`,
@@ -2977,6 +3024,7 @@ var init_qwen_headers = __esm({
2977
3024
  init_qwen_url();
2978
3025
  init_config();
2979
3026
  init_fingerprint();
3027
+ init_timezone();
2980
3028
  dynamicWebVersion = null;
2981
3029
  QWEN_WEB_VERSION = config.qwen.webVersion;
2982
3030
  DEFAULT_QWEN_USER_AGENT = getDefaultQwenUserAgent(151);
@@ -4613,6 +4661,22 @@ async function initPlaywrightForAccount(rawAccount, headless = config.playwright
4613
4661
  }
4614
4662
  }
4615
4663
  }
4664
+ const currentCache = getHeaderCache(account.id);
4665
+ const currentCookie = currentCache?.headers?.cookie || "";
4666
+ if (currentCookie && isTokenExpiringSoon(currentCookie, 5)) {
4667
+ try {
4668
+ const refreshRes = await refreshAccountToken(account.id);
4669
+ if (refreshRes.success) {
4670
+ console.log(
4671
+ `\u26A1 [Playwright] Silently refreshed expired token restored from DB for ${maskEmail(account.email)}`
4672
+ );
4673
+ }
4674
+ } catch (err) {
4675
+ console.warn(
4676
+ `\u26A0\uFE0F [Playwright] Failed to proactively refresh expired token from DB for ${maskEmail(account.email)}: ${err?.message || err}`
4677
+ );
4678
+ }
4679
+ }
4616
4680
  return;
4617
4681
  }
4618
4682
  const cookies = await acctContext.cookies();
@@ -4900,7 +4964,7 @@ async function startEmailOtpLogin(email, options = {}) {
4900
4964
  email: normalizedEmail,
4901
4965
  requestId,
4902
4966
  version: getQwenWebVersion() || "0.3.12",
4903
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0]
4967
+ timezone: formatAsciiTimezone()
4904
4968
  }
4905
4969
  ).catch((err) => ({ ok: false, error: err?.message || String(err) }));
4906
4970
  if (!evalRes.ok || evalRes.data?.success !== true) {
@@ -4995,7 +5059,7 @@ async function verifyEmailOtpLogin(sessionId, code) {
4995
5059
  code: cleanCode,
4996
5060
  requestId,
4997
5061
  version: getQwenWebVersion() || "0.3.12",
4998
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0]
5062
+ timezone: formatAsciiTimezone()
4999
5063
  }
5000
5064
  ).catch((err) => ({ ok: false, error: err?.message || String(err) }));
5001
5065
  if (!evalRes.ok || evalRes.data?.success !== true || !evalRes.data?.data) {
@@ -5276,7 +5340,7 @@ async function loginViaApi(page, email, password) {
5276
5340
  const signinUrl = "https://auth.qwen.ai/api/v2/auths/signin";
5277
5341
  const requestId = crypto3.randomUUID();
5278
5342
  const evalRes = await page.evaluate(
5279
- async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2 }) => {
5343
+ async ({ email: email2, password: password2, signinUrl: signinUrl2, requestId: requestId2, tz }) => {
5280
5344
  try {
5281
5345
  const response = await fetch(signinUrl2, {
5282
5346
  method: "POST",
@@ -5288,7 +5352,7 @@ async function loginViaApi(page, email, password) {
5288
5352
  source: "web",
5289
5353
  version: "0.3.11",
5290
5354
  "x-request-origin": "https://chat.qwen.ai",
5291
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
5355
+ timezone: tz,
5292
5356
  "x-request-id": requestId2
5293
5357
  },
5294
5358
  body: JSON.stringify({ email: email2, password: password2 })
@@ -5299,7 +5363,7 @@ async function loginViaApi(page, email, password) {
5299
5363
  return { ok: false, error: e.message };
5300
5364
  }
5301
5365
  },
5302
- { email, password: hashedPassword, signinUrl, requestId }
5366
+ { email, password: hashedPassword, signinUrl, requestId, tz: formatAsciiTimezone() }
5303
5367
  ).catch(() => null);
5304
5368
  let data = evalRes?.data;
5305
5369
  let signinSuccess = Boolean(
@@ -5308,7 +5372,7 @@ async function loginViaApi(page, email, password) {
5308
5372
  if (!signinSuccess && !data?.data?.code) {
5309
5373
  const fallbackUrl = qwenUrl("/api/v2/auths/signin");
5310
5374
  const fallbackRes = await page.evaluate(
5311
- async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2 }) => {
5375
+ async ({ email: email2, password: password2, fallbackUrl: fallbackUrl2, requestId: requestId2, tz }) => {
5312
5376
  try {
5313
5377
  const response = await fetch(fallbackUrl2, {
5314
5378
  method: "POST",
@@ -5319,7 +5383,7 @@ async function loginViaApi(page, email, password) {
5319
5383
  "content-type": "application/json",
5320
5384
  source: "web",
5321
5385
  version: "0.3.11",
5322
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
5386
+ timezone: tz,
5323
5387
  "x-request-id": requestId2
5324
5388
  },
5325
5389
  body: JSON.stringify({ email: email2, password: password2 })
@@ -5330,7 +5394,7 @@ async function loginViaApi(page, email, password) {
5330
5394
  return { ok: false, error: e.message };
5331
5395
  }
5332
5396
  },
5333
- { email, password: hashedPassword, fallbackUrl, requestId }
5397
+ { email, password: hashedPassword, fallbackUrl, requestId, tz: formatAsciiTimezone() }
5334
5398
  ).catch(() => null);
5335
5399
  if (fallbackRes?.data) {
5336
5400
  data = fallbackRes.data;
@@ -5662,7 +5726,7 @@ async function refreshAccountToken(accountId) {
5662
5726
  if (refreshToken) {
5663
5727
  try {
5664
5728
  const refreshResult = await page.evaluate(
5665
- async ({ rTok }) => {
5729
+ async ({ rTok, tz }) => {
5666
5730
  try {
5667
5731
  const response = await fetch("https://auth.qwen.ai/api/v2/auths/refresh", {
5668
5732
  method: "GET",
@@ -5672,7 +5736,7 @@ async function refreshAccountToken(accountId) {
5672
5736
  source: "web",
5673
5737
  version: "0.3.11",
5674
5738
  "x-request-origin": "https://chat.qwen.ai",
5675
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
5739
+ timezone: tz,
5676
5740
  authorization: `Bearer ${rTok}`
5677
5741
  }
5678
5742
  });
@@ -5682,7 +5746,7 @@ async function refreshAccountToken(accountId) {
5682
5746
  return { ok: false, error: e.message };
5683
5747
  }
5684
5748
  },
5685
- { rTok: refreshToken }
5749
+ { rTok: refreshToken, tz: formatAsciiTimezone() }
5686
5750
  );
5687
5751
  const json = refreshResult?.data;
5688
5752
  if (json && json.success === true && json.data) {
@@ -5720,6 +5784,7 @@ async function refreshAccountToken(accountId) {
5720
5784
  const cache = getHeaderCache(accountId);
5721
5785
  cache.headers.cookie = cookieStr;
5722
5786
  cache.lastRefresh = Date.now();
5787
+ cookieCaches.set(accountId, { cookie: cookieStr, timestamp: Date.now() });
5723
5788
  markAccountHeadersReady(accountId);
5724
5789
  saveAuthSession2(accountId, {
5725
5790
  cookie: cookieStr,
@@ -5754,6 +5819,7 @@ async function refreshAccountToken(accountId) {
5754
5819
  const cache = getHeaderCache(accountId);
5755
5820
  cache.headers.cookie = cookieStr;
5756
5821
  cache.lastRefresh = Date.now();
5822
+ cookieCaches.set(accountId, { cookie: cookieStr, timestamp: Date.now() });
5757
5823
  markAccountHeadersReady(accountId);
5758
5824
  saveAuthSession2(accountId, {
5759
5825
  cookie: cookieStr,
@@ -6808,11 +6874,11 @@ async function keepAlivePlaywrightAccount(accountId) {
6808
6874
  const now = Date.now();
6809
6875
  const currentUrl = page.url();
6810
6876
  const lastRefreshAttempt = lastProactiveTokenRefresh.get(accountId) ?? 0;
6811
- const cookie = await getCookies(accountId);
6877
+ const cookie = await getCookies(accountId, true);
6812
6878
  if (cookie && isTokenExpiringSoon(cookie, 5) && now - lastRefreshAttempt > 6e4) {
6813
6879
  lastProactiveTokenRefresh.set(accountId, now);
6814
- console.log(
6815
- `\u{1F493} [SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
6880
+ logger.debug(
6881
+ `[SessionKeeper] Account ${accountId} access token expiring soon (<5m); silently refreshing...`
6816
6882
  );
6817
6883
  const res = await refreshAccountToken(accountId);
6818
6884
  if (res.success) {
@@ -6820,6 +6886,9 @@ async function keepAlivePlaywrightAccount(accountId) {
6820
6886
  touchAccountActivity(accountId);
6821
6887
  return true;
6822
6888
  }
6889
+ logger.warn(
6890
+ `[SessionKeeper] Failed to silently refresh expiring token for ${accountId}: ${res.error || "unknown error"}`
6891
+ );
6823
6892
  }
6824
6893
  const lastNavigation = lastKeepAliveNavigation.get(accountId) ?? 0;
6825
6894
  const shouldNavigate = !currentUrl.startsWith(qwenOrigin()) || now - lastNavigation > config.sessionKeeper.navigationIntervalMs;
@@ -7057,6 +7126,7 @@ var init_playwright = __esm({
7057
7126
  init_qwen_headers();
7058
7127
  init_paths();
7059
7128
  init_jwt();
7129
+ init_timezone();
7060
7130
  requireLocal = createRequire(import.meta.url);
7061
7131
  contextInitHooks = [];
7062
7132
  ACCOUNT_MUTEX_MAX_HOLD_MS = 18e4;
@@ -7070,7 +7140,7 @@ var init_playwright = __esm({
7070
7140
  headerCaches = /* @__PURE__ */ new Map();
7071
7141
  HEADER_CACHE_TTL = 24 * 60 * 60 * 1e3;
7072
7142
  HEADER_REFRESH_THRESHOLD = 0.8;
7073
- COOKIE_CACHE_TTL = 15 * 60 * 1e3;
7143
+ COOKIE_CACHE_TTL = 60 * 1e3;
7074
7144
  cookieCaches = /* @__PURE__ */ new Map();
7075
7145
  lastAccountActivity = /* @__PURE__ */ new Map();
7076
7146
  lastKeepAliveNavigation = /* @__PURE__ */ new Map();
@@ -8442,6 +8512,8 @@ __export(qwen_exports, {
8442
8512
  QwenUpstreamError: () => QwenUpstreamError,
8443
8513
  QwenUpstreamUnavailableError: () => QwenUpstreamUnavailableError,
8444
8514
  RetryableQwenStreamError: () => RetryableQwenStreamError,
8515
+ STREAM_SLOT_MAX_HOLD_MS: () => STREAM_SLOT_MAX_HOLD_MS,
8516
+ acquireAccountStreamLock: () => acquireAccountStreamLock,
8445
8517
  acquireNewQwenChatSession: () => acquireNewQwenChatSession,
8446
8518
  buildCapturedQwenHeaders: () => buildCapturedQwenHeaders,
8447
8519
  buildChatNewBody: () => buildChatNewBody,
@@ -8455,10 +8527,13 @@ __export(qwen_exports, {
8455
8527
  deleteAllQwenChats: () => deleteAllQwenChats,
8456
8528
  deleteSingleQwenChat: () => deleteSingleQwenChat,
8457
8529
  disableNativeTools: () => disableNativeTools,
8530
+ ensureStaleSlotSweeperStarted: () => ensureStaleSlotSweeperStarted,
8458
8531
  fetchQwenModels: () => fetchQwenModels,
8459
8532
  fetchRemoteQwenChats: () => fetchRemoteQwenChats,
8460
8533
  flushLogicalThreadState: () => flushLogicalThreadState,
8534
+ getAccountStreamMutex: () => getAccountStreamMutex,
8461
8535
  getAnyCachedQwenModels: () => getAnyCachedQwenModels,
8536
+ getBrowserFetchHeaders: () => getBrowserFetchHeaders,
8462
8537
  getInFlightPersonalizationCount: () => getInFlightPersonalizationCount,
8463
8538
  getLogicalThreadState: () => getLogicalThreadState,
8464
8539
  getQwenErrorCode: () => getQwenErrorCode,
@@ -8474,6 +8549,8 @@ __export(qwen_exports, {
8474
8549
  requestQwenSettingsDirectFetch: () => requestQwenSettingsDirectFetch,
8475
8550
  requestQwenTextInBrowser: () => requestQwenTextInBrowser,
8476
8551
  setToolCapNotice: () => setToolCapNotice,
8552
+ stopStaleSlotSweeperForTests: () => stopStaleSlotSweeperForTests,
8553
+ sweepStaleAccountStreamSlots: () => sweepStaleAccountStreamSlots,
8477
8554
  syncQwenRequestPersonalization: () => syncQwenRequestPersonalization,
8478
8555
  updateLogicalThreadParent: () => updateLogicalThreadParent,
8479
8556
  updateLogicalThreadState: () => updateLogicalThreadState,
@@ -8760,7 +8837,7 @@ function buildCapturedQwenHeaders(headers, options = {}) {
8760
8837
  function getAccountStreamMutex(accountId) {
8761
8838
  let slots2 = accountStreamMutexes.get(accountId);
8762
8839
  if (!slots2) {
8763
- slots2 = { active: 0, queue: [] };
8840
+ slots2 = { activeSlots: /* @__PURE__ */ new Map(), queue: [] };
8764
8841
  accountStreamMutexes.set(accountId, slots2);
8765
8842
  }
8766
8843
  return slots2;
@@ -8768,27 +8845,71 @@ function getAccountStreamMutex(accountId) {
8768
8845
  function streamSlotCapacity() {
8769
8846
  return Math.max(1, config.concurrency.maxStreamsPerAccount);
8770
8847
  }
8771
- function createStreamSlotRelease(slots2) {
8848
+ function createStreamSlotRelease(slots2, slotId) {
8772
8849
  let released = false;
8773
8850
  return () => {
8774
8851
  if (released) return;
8775
8852
  released = true;
8776
- slots2.active -= 1;
8853
+ slots2.activeSlots.delete(slotId);
8777
8854
  const next = slots2.queue.shift();
8778
8855
  if (next) {
8779
- slots2.active += 1;
8780
- next();
8856
+ const nextId = nextStreamSlotId++;
8857
+ slots2.activeSlots.set(nextId, Date.now());
8858
+ next(createStreamSlotRelease(slots2, nextId));
8781
8859
  }
8782
8860
  };
8783
8861
  }
8862
+ function sweepStaleAccountStreamSlots(maxHoldMs = STREAM_SLOT_MAX_HOLD_MS) {
8863
+ const now = Date.now();
8864
+ let sweptCount = 0;
8865
+ for (const [accountId, slots2] of accountStreamMutexes.entries()) {
8866
+ for (const [slotId, startedAt] of Array.from(slots2.activeSlots.entries())) {
8867
+ if (now - startedAt >= maxHoldMs) {
8868
+ logger.warn(
8869
+ `[Qwen] Force-releasing stale stream slot | account=${accountId} | slotId=${slotId} | heldFor=${now - startedAt}ms | maxHold=${maxHoldMs}ms`
8870
+ );
8871
+ slots2.activeSlots.delete(slotId);
8872
+ sweptCount++;
8873
+ const next = slots2.queue.shift();
8874
+ if (next) {
8875
+ const nextId = nextStreamSlotId++;
8876
+ slots2.activeSlots.set(nextId, now);
8877
+ next(createStreamSlotRelease(slots2, nextId));
8878
+ }
8879
+ }
8880
+ }
8881
+ }
8882
+ return sweptCount;
8883
+ }
8884
+ function ensureStaleSlotSweeperStarted() {
8885
+ if (staleSlotSweeperTimer) return;
8886
+ staleSlotSweeperTimer = setInterval(() => {
8887
+ try {
8888
+ sweepStaleAccountStreamSlots();
8889
+ } catch (err) {
8890
+ logger.error("[Qwen] Error in stale stream slot sweeper", {
8891
+ error: err instanceof Error ? err.message : String(err)
8892
+ });
8893
+ }
8894
+ }, 6e4);
8895
+ staleSlotSweeperTimer.unref();
8896
+ }
8897
+ function stopStaleSlotSweeperForTests() {
8898
+ if (staleSlotSweeperTimer) {
8899
+ clearInterval(staleSlotSweeperTimer);
8900
+ staleSlotSweeperTimer = null;
8901
+ }
8902
+ }
8784
8903
  async function acquireAccountStreamLock(accountId) {
8904
+ ensureStaleSlotSweeperStarted();
8785
8905
  const slots2 = getAccountStreamMutex(accountId);
8786
- if (slots2.active < streamSlotCapacity()) {
8787
- slots2.active += 1;
8788
- return Promise.resolve(createStreamSlotRelease(slots2));
8906
+ if (slots2.activeSlots.size < streamSlotCapacity()) {
8907
+ const slotId = nextStreamSlotId++;
8908
+ slots2.activeSlots.set(slotId, Date.now());
8909
+ return Promise.resolve(createStreamSlotRelease(slots2, slotId));
8789
8910
  }
8790
8911
  return new Promise((resolve) => {
8791
- slots2.queue.push(() => resolve(createStreamSlotRelease(slots2)));
8912
+ slots2.queue.push((releaseFn) => resolve(releaseFn));
8792
8913
  });
8793
8914
  }
8794
8915
  function buildQwenSettingsUpdatePayload(currentSettings, instruction) {
@@ -8880,11 +9001,13 @@ function getBrowserFetchHeaders(headers) {
8880
9001
  "x-request-id",
8881
9002
  "x-accel-buffering"
8882
9003
  ]);
8883
- return Object.fromEntries(
8884
- Object.entries(headers).filter(
8885
- ([name]) => browserAllowedHeaders.has(name.toLowerCase())
8886
- )
8887
- );
9004
+ const result = {};
9005
+ for (const [name, value] of Object.entries(headers)) {
9006
+ if (browserAllowedHeaders.has(name.toLowerCase())) {
9007
+ result[name] = sanitizeHeaderForFetch(String(value ?? ""));
9008
+ }
9009
+ }
9010
+ return result;
8888
9011
  }
8889
9012
  async function requestQwenTextInBrowser(accountId, method, path6, headers, body, options = {}) {
8890
9013
  const url = qwenUrl(path6);
@@ -8905,7 +9028,7 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
8905
9028
  browserHeaders["Content-Type"] = "application/json";
8906
9029
  }
8907
9030
  const evaluateRequest = (page) => page.evaluate(
8908
- async ({ url: url2, method: method2, headers: headers2, body: body2, referrer, timeoutMs }) => {
9031
+ async ({ url: url2, method: method2, headers: headers2, body: body2, referrer, timeoutMs, tz }) => {
8909
9032
  const controller = new AbortController();
8910
9033
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
8911
9034
  try {
@@ -8929,7 +9052,7 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
8929
9052
  source: "web",
8930
9053
  version: "0.3.11",
8931
9054
  "x-request-origin": "https://chat.qwen.ai",
8932
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
9055
+ timezone: tz,
8933
9056
  authorization: `Bearer ${rTok}`
8934
9057
  },
8935
9058
  signal: AbortSignal.timeout(5e3)
@@ -8974,7 +9097,8 @@ async function requestQwenTextInBrowser(accountId, method, path6, headers, body,
8974
9097
  headers: browserHeaders,
8975
9098
  body,
8976
9099
  referrer: options.referrer,
8977
- timeoutMs: options.timeoutMs ?? Math.min(config.timeouts.page, 2e4)
9100
+ timeoutMs: options.timeoutMs ?? Math.min(config.timeouts.page, 2e4),
9101
+ tz: formatAsciiTimezone()
8978
9102
  }
8979
9103
  );
8980
9104
  const recoverOnTimeout = !options.noMutexRecovery;
@@ -9652,7 +9776,7 @@ async function disableNativeTools(accountId) {
9652
9776
  async (page) => {
9653
9777
  const requestId = crypto5.randomUUID();
9654
9778
  const response = await page.evaluate(
9655
- async ({ payload: payload2, timeoutMs, requestId: requestId2 }) => {
9779
+ async ({ payload: payload2, timeoutMs, requestId: requestId2, tz }) => {
9656
9780
  const controller = new AbortController();
9657
9781
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
9658
9782
  try {
@@ -9664,7 +9788,7 @@ async function disableNativeTools(accountId) {
9664
9788
  accept: "application/json, text/plain, */*",
9665
9789
  "content-type": "application/json",
9666
9790
  "x-request-id": requestId2,
9667
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
9791
+ timezone: tz,
9668
9792
  source: "web"
9669
9793
  },
9670
9794
  body: JSON.stringify(payload2),
@@ -9676,7 +9800,7 @@ async function disableNativeTools(accountId) {
9676
9800
  clearTimeout(timeoutId);
9677
9801
  }
9678
9802
  },
9679
- { payload, timeoutMs: config.timeouts.http, requestId }
9803
+ { payload, timeoutMs: config.timeouts.http, requestId, tz: formatAsciiTimezone() }
9680
9804
  );
9681
9805
  return response;
9682
9806
  }
@@ -9893,7 +10017,7 @@ async function deleteSingleQwenChat(accountId, chatId) {
9893
10017
  const requestHeaders = {
9894
10018
  source: "web",
9895
10019
  version: "0.2.89",
9896
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
10020
+ timezone: formatAsciiTimezone(),
9897
10021
  "x-request-id": crypto5.randomUUID(),
9898
10022
  Referer: qwenUrl(`/c/${encodeURIComponent(chatId)}`)
9899
10023
  };
@@ -9937,7 +10061,7 @@ async function fetchRemoteQwenChats(accountId) {
9937
10061
  }
9938
10062
  const requestHeaders = {
9939
10063
  version: "0.2.89",
9940
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
10064
+ timezone: formatAsciiTimezone(),
9941
10065
  "x-request-id": crypto5.randomUUID(),
9942
10066
  Referer: qwenUrl("/settings/chats")
9943
10067
  };
@@ -9989,7 +10113,7 @@ async function fetchQwenModels(accountId) {
9989
10113
  async (page) => {
9990
10114
  const requestId = crypto5.randomUUID();
9991
10115
  const response2 = await page.evaluate(
9992
- async ({ timeoutMs, requestId: requestId2 }) => {
10116
+ async ({ timeoutMs, requestId: requestId2, tz }) => {
9993
10117
  const controller = new AbortController();
9994
10118
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
9995
10119
  try {
@@ -9998,7 +10122,7 @@ async function fetchQwenModels(accountId) {
9998
10122
  headers: {
9999
10123
  accept: "application/json, text/plain, */*",
10000
10124
  "x-request-id": requestId2,
10001
- timezone: (/* @__PURE__ */ new Date()).toString().split(" (")[0],
10125
+ timezone: tz,
10002
10126
  source: "web"
10003
10127
  },
10004
10128
  signal: controller.signal
@@ -10008,7 +10132,7 @@ async function fetchQwenModels(accountId) {
10008
10132
  clearTimeout(timeoutId);
10009
10133
  }
10010
10134
  },
10011
- { timeoutMs: config.timeouts.http, requestId }
10135
+ { timeoutMs: config.timeouts.http, requestId, tz: formatAsciiTimezone() }
10012
10136
  );
10013
10137
  return response2;
10014
10138
  }
@@ -10047,7 +10171,7 @@ async function fetchQwenModels(accountId) {
10047
10171
  bxUa,
10048
10172
  bxUmidtoken,
10049
10173
  extra: {
10050
- timezone: (/* @__PURE__ */ new Date()).toString()
10174
+ timezone: formatAsciiTimezone()
10051
10175
  }
10052
10176
  }),
10053
10177
  void 0,
@@ -10810,7 +10934,7 @@ async function createQwenStreamInternal(prompt, enableThinking, modelId, forcedP
10810
10934
  clearTimeout(timeoutId);
10811
10935
  }
10812
10936
  }
10813
- var sleep4, BROWSER_STREAM_BINDING, BROWSER_ABORTERS_KEY, BROWSER_STREAM_FLUSH_BYTES, BROWSER_STREAM_FLUSH_MS, METADATA_TIMEOUT_PER_PAYLOAD_MB_MS, POST_CAPTCHA_METADATA_GRACE_MS, browserStreamStates, browserStreamBindingPages, browserStreamBindingContexts, MODEL_CACHE_TTL_MS, modelsCache, nativeToolsDisabled, disablingNativeToolsInProgress, lastSyncedPersonalizationHashes, directSettingsFetchConsecutiveFailures, DIRECT_SETTINGS_FETCH_BLOCK_THRESHOLD, directSettingsFetchBlocked, DIRECT_SETTINGS_FETCH_TIMEOUT_MS, activePersonalizationByAccount, accountStreamMutexes, QWEN_SAFE_SETTINGS_PATCH, QWEN_SAFE_SETTINGS_HASH, inFlightPersonalizationSyncs, DISABLE_TOOLS_MAX_RETRIES, DISABLE_TOOLS_BACKOFF_MS, UPSTREAM_RESPONSE_PREVIEW_BYTES;
10937
+ var sleep4, BROWSER_STREAM_BINDING, BROWSER_ABORTERS_KEY, BROWSER_STREAM_FLUSH_BYTES, BROWSER_STREAM_FLUSH_MS, METADATA_TIMEOUT_PER_PAYLOAD_MB_MS, POST_CAPTCHA_METADATA_GRACE_MS, browserStreamStates, browserStreamBindingPages, browserStreamBindingContexts, MODEL_CACHE_TTL_MS, modelsCache, nativeToolsDisabled, disablingNativeToolsInProgress, lastSyncedPersonalizationHashes, directSettingsFetchConsecutiveFailures, DIRECT_SETTINGS_FETCH_BLOCK_THRESHOLD, directSettingsFetchBlocked, DIRECT_SETTINGS_FETCH_TIMEOUT_MS, activePersonalizationByAccount, STREAM_SLOT_MAX_HOLD_MS, accountStreamMutexes, nextStreamSlotId, staleSlotSweeperTimer, QWEN_SAFE_SETTINGS_PATCH, QWEN_SAFE_SETTINGS_HASH, inFlightPersonalizationSyncs, DISABLE_TOOLS_MAX_RETRIES, DISABLE_TOOLS_BACKOFF_MS, UPSTREAM_RESPONSE_PREVIEW_BYTES;
10814
10938
  var init_qwen = __esm({
10815
10939
  "src/services/qwen.ts"() {
10816
10940
  "use strict";
@@ -10828,6 +10952,7 @@ var init_qwen = __esm({
10828
10952
  init_captcha_coordinator();
10829
10953
  init_captcha_solver();
10830
10954
  init_account_concurrency();
10955
+ init_timezone();
10831
10956
  init_qwen_errors();
10832
10957
  init_qwen_thread_state();
10833
10958
  init_qwen_chat_pool();
@@ -10857,7 +10982,10 @@ var init_qwen = __esm({
10857
10982
  directSettingsFetchBlocked = /* @__PURE__ */ new Set();
10858
10983
  DIRECT_SETTINGS_FETCH_TIMEOUT_MS = 1e4;
10859
10984
  activePersonalizationByAccount = /* @__PURE__ */ new Map();
10985
+ STREAM_SLOT_MAX_HOLD_MS = 30 * 60 * 1e3;
10860
10986
  accountStreamMutexes = /* @__PURE__ */ new Map();
10987
+ nextStreamSlotId = 1;
10988
+ staleSlotSweeperTimer = null;
10861
10989
  QWEN_SAFE_SETTINGS_PATCH = {
10862
10990
  ui: {
10863
10991
  autoTags: false,