qwenproxy-cli 1.0.17 → 1.0.18

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwenproxy-cli",
3
- "version": "1.0.17",
3
+ "version": "1.0.18",
4
4
  "description": "High-performance OpenAI & Anthropic compatible API gateway for Qwen with multi-account rotation, interactive TUI, and resilient tool calling.",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
package/src/index.ts CHANGED
@@ -14,41 +14,35 @@ if (fs.existsSync(envPath)) {
14
14
  dotenv.config({ quiet: true })
15
15
  }
16
16
  // Prevent benign asynchronous driver/browser teardown exceptions from crashing the server
17
- process.on('uncaughtException', (error: unknown) => {
18
- const msg = error instanceof Error ? error.message : String(error)
19
- if (
20
- msg.includes('Cannot find parent object') ||
21
- msg.includes('Target page, context or browser has been closed') ||
22
- msg.includes('Browser has been closed') ||
23
- msg.includes('Target closed') ||
24
- msg.includes('Target crashed') ||
25
- msg.includes('Page crashed') ||
26
- msg.includes('Assertion error') ||
27
- msg.includes('Connection closed')
28
- ) {
29
- console.warn(`⚠️ [Playwright] Handled benign driver teardown exception: ${msg}`)
30
- return
17
+ process.on('uncaughtException', async (error: unknown) => {
18
+ const { isPlaywrightAlreadyClosedError } = await import('./services/playwright.ts');
19
+ if (isPlaywrightAlreadyClosedError(error)) {
20
+ const msg =
21
+ error instanceof Error
22
+ ? error.message
23
+ : typeof error === 'object' && error !== null && 'message' in error
24
+ ? String((error as any).message)
25
+ : String(error);
26
+ console.warn(`⚠️ [Playwright] Handled benign driver teardown exception: ${msg}`);
27
+ return;
31
28
  }
32
- console.error('❌ [Process] Uncaught Exception:', error)
33
- })
29
+ console.error('❌ [Process] Uncaught Exception:', error);
30
+ });
34
31
 
35
- process.on('unhandledRejection', (reason: unknown) => {
36
- const msg = reason instanceof Error ? reason.message : String(reason)
37
- if (
38
- msg.includes('Cannot find parent object') ||
39
- msg.includes('Target page, context or browser has been closed') ||
40
- msg.includes('Browser has been closed') ||
41
- msg.includes('Target closed') ||
42
- msg.includes('Target crashed') ||
43
- msg.includes('Page crashed') ||
44
- msg.includes('Assertion error') ||
45
- msg.includes('Connection closed')
46
- ) {
47
- console.warn(`⚠️ [Playwright] Handled benign driver teardown rejection: ${msg}`)
48
- return
32
+ process.on('unhandledRejection', async (reason: unknown) => {
33
+ const { isPlaywrightAlreadyClosedError } = await import('./services/playwright.ts');
34
+ if (isPlaywrightAlreadyClosedError(reason)) {
35
+ const msg =
36
+ reason instanceof Error
37
+ ? reason.message
38
+ : typeof reason === 'object' && reason !== null && 'message' in reason
39
+ ? String((reason as any).message)
40
+ : String(reason);
41
+ console.warn(`⚠️ [Playwright] Handled benign driver teardown rejection: ${msg}`);
42
+ return;
49
43
  }
50
- console.error('❌ [Process] Unhandled Rejection:', reason)
51
- })
44
+ console.error('❌ [Process] Unhandled Rejection:', reason);
45
+ });
52
46
  import { startServer } from './api/server.js'
53
47
  const isTui = process.argv.includes('--tui') || process.env.QWEN_TUI === 'true'
54
48
 
@@ -492,7 +492,7 @@ function isAccountServingStream(accountId: string): boolean {
492
492
  return true;
493
493
  }
494
494
 
495
- function getStealthScript(profile: FingerprintProfile): string {
495
+ export function getStealthScript(profile: FingerprintProfile): string {
496
496
  const profileJson = JSON.stringify(profile).replace(/</g, "\\u003c");
497
497
  return `
498
498
  (function() {
@@ -740,6 +740,14 @@ function getStealthScript(profile: FingerprintProfile): string {
740
740
  function makeMime(desc, suffixes, type) {
741
741
  return { description: desc, suffixes: suffixes, type: type };
742
742
  }
743
+ function attachPlugin(mime, plugin) {
744
+ Object.defineProperty(mime, 'enabledPlugin', {
745
+ value: plugin,
746
+ enumerable: false,
747
+ configurable: true,
748
+ writable: true,
749
+ });
750
+ }
743
751
  const pdfMime = makeMime('Portable Document Format', 'pdf', 'application/pdf');
744
752
  const pdfxMime = makeMime('Portable Document Format', 'pdf', 'text/pdf');
745
753
  const pdfPlugin = {
@@ -750,8 +758,8 @@ function getStealthScript(profile: FingerprintProfile): string {
750
758
  0: pdfMime,
751
759
  1: pdfxMime,
752
760
  };
753
- pdfMime.enabledPlugin = pdfPlugin;
754
- pdfxMime.enabledPlugin = pdfPlugin;
761
+ attachPlugin(pdfMime, pdfPlugin);
762
+ attachPlugin(pdfxMime, pdfPlugin);
755
763
 
756
764
  const chromePdfMime = makeMime('Portable Document Format', 'pdf', 'application/pdf');
757
765
  const chromePdfMime2 = makeMime('Portable Document Format', 'pdf', 'text/pdf');
@@ -763,8 +771,8 @@ function getStealthScript(profile: FingerprintProfile): string {
763
771
  0: chromePdfMime,
764
772
  1: chromePdfMime2,
765
773
  };
766
- chromePdfMime.enabledPlugin = chromePdfPlugin;
767
- chromePdfMime2.enabledPlugin = chromePdfPlugin;
774
+ attachPlugin(chromePdfMime, chromePdfPlugin);
775
+ attachPlugin(chromePdfMime2, chromePdfPlugin);
768
776
 
769
777
  const nativePlugin = {
770
778
  name: 'Native Client',
@@ -774,9 +782,8 @@ function getStealthScript(profile: FingerprintProfile): string {
774
782
  0: makeMime('Native Client Executable', '', 'application/x-nacl'),
775
783
  1: makeMime('Portable Native Client Executable', '', 'application/x-pnacl'),
776
784
  };
777
- nativePlugin[0].enabledPlugin = nativePlugin;
778
- nativePlugin[1].enabledPlugin = nativePlugin;
779
-
785
+ attachPlugin(nativePlugin[0], nativePlugin);
786
+ attachPlugin(nativePlugin[1], nativePlugin);
780
787
  const pluginsList = [pdfPlugin, chromePdfPlugin, nativePlugin];
781
788
  const mimeList = [pdfMime, pdfxMime, chromePdfMime, chromePdfMime2, nativePlugin[0], nativePlugin[1]];
782
789
 
@@ -3078,7 +3085,13 @@ async function closePlaywrightForAccountLocked(
3078
3085
  * that must not be logged as keep-alive failures.
3079
3086
  */
3080
3087
  export function isPlaywrightAlreadyClosedError(error: unknown): boolean {
3081
- const message = error instanceof Error ? error.message : String(error);
3088
+ if (!error) return false;
3089
+ const message =
3090
+ error instanceof Error
3091
+ ? error.message
3092
+ : typeof error === "object" && "message" in error
3093
+ ? String((error as any).message)
3094
+ : String(error);
3082
3095
  return (
3083
3096
  message.includes("Target page, context or browser has been closed") ||
3084
3097
  message.includes("Browser has been closed") ||
@@ -3087,7 +3100,11 @@ export function isPlaywrightAlreadyClosedError(error: unknown): boolean {
3087
3100
  message.includes("Page crashed") ||
3088
3101
  message.includes("Assertion error") ||
3089
3102
  message.includes("Cannot find parent object") ||
3090
- message.includes("Connection closed")
3103
+ message.includes("Connection closed") ||
3104
+ message.includes("session closed") ||
3105
+ message.includes("Session closed") ||
3106
+ message.includes("Network.setCacheDisabled") ||
3107
+ message.includes("Protocol error")
3091
3108
  );
3092
3109
  }
3093
3110
 
@@ -962,7 +962,7 @@ function repairCommonMalformedToolJson(content: string): string {
962
962
  // a bare-word value, so inserting the quote is safe (true/false/null and
963
963
  // numbers are excluded). The trailing `\"` escapes are preserved, so the
964
964
  // model's closing quote still terminates the string.
965
- /([,{]\s*"[a-zA-Z_][a-zA-Z0-9_]*"\s*:\s*)(?=(?!true|false|null)[A-Za-z_])/g,
965
+ /([,{]\s*"[a-zA-Z_][a-zA-Z0-9_]*"\s*:\s*)(?=(?!true|false|null|\d|\[|\{|")[^\s])/g,
966
966
  '$1"',
967
967
  );
968
968
  return repairMissingArrayClose(repaired);
package/src/tui/index.ts CHANGED
@@ -37,6 +37,10 @@ async function main() {
37
37
  const app = new TuiApp(initialTab);
38
38
 
39
39
  process.on("uncaughtException", async (err) => {
40
+ const { isPlaywrightAlreadyClosedError } = await import("../services/playwright.ts");
41
+ if (isPlaywrightAlreadyClosedError(err)) {
42
+ return;
43
+ }
40
44
  try {
41
45
  await app.stop();
42
46
  } catch {}
@@ -45,6 +49,10 @@ async function main() {
45
49
  });
46
50
 
47
51
  process.on("unhandledRejection", async (err) => {
52
+ const { isPlaywrightAlreadyClosedError } = await import("../services/playwright.ts");
53
+ if (isPlaywrightAlreadyClosedError(err)) {
54
+ return;
55
+ }
48
56
  try {
49
57
  await app.stop();
50
58
  } catch {}