qwenproxy-cli 1.2.10 → 1.3.1

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.
@@ -341,21 +341,22 @@ async function getSTSToken(
341
341
  filesize: number,
342
342
  filetype: string,
343
343
  headers: Record<string, string>,
344
+ accountId?: string,
344
345
  ): Promise<STSResponse["data"]> {
345
- const response = await fetch(
346
- qwenUrl("/api/v2/files/getstsToken"),
347
- {
346
+ const doFetch = (reqHeaders: Record<string, string>) =>
347
+ fetch(qwenUrl("/api/v2/files/getstsToken"), {
348
348
  method: "POST",
349
349
  headers: buildQwenRequestHeaders({
350
- cookie: headers.cookie,
351
- userAgent: headers["user-agent"],
352
- bxUa: headers["bx-ua"],
353
- bxUmidtoken: headers["bx-umidtoken"],
354
- bxV: headers["bx-v"],
350
+ cookie: reqHeaders.cookie,
351
+ userAgent: reqHeaders["user-agent"],
352
+ bxUa: reqHeaders["bx-ua"],
353
+ bxUmidtoken: reqHeaders["bx-umidtoken"],
354
+ bxV: reqHeaders["bx-v"],
355
355
  }),
356
356
  body: JSON.stringify({ filename, filesize: String(filesize), filetype }),
357
- },
358
- );
357
+ });
358
+
359
+ let response = await doFetch(headers);
359
360
 
360
361
  if (!response.ok) {
361
362
  const errorText = await response.text().catch(() => "");
@@ -364,8 +365,43 @@ async function getSTSToken(
364
365
  );
365
366
  }
366
367
 
367
- const data = await response.json();
368
- if (!data.success || !data.data) {
368
+ let data = await response.json().catch(() => null);
369
+ const is401 =
370
+ data?.success === false &&
371
+ (data?.data?.code === "Unauthorized" ||
372
+ (typeof data?.data?.details === "string" &&
373
+ data.data.details.includes("401")));
374
+
375
+ if (is401) {
376
+ try {
377
+ const { refreshHeaders } = await import("../services/playwright.ts");
378
+ const { getBasicHeaders } = await import("../services/auth-playwright.ts");
379
+ const { loadAccounts } = await import("../core/accounts.ts");
380
+ const resolvedId = accountId ?? loadAccounts()[0]?.id;
381
+ if (resolvedId) {
382
+ console.warn(
383
+ `[Upload] STS token 401 — refreshing session with re-auth and retrying...`,
384
+ );
385
+ await refreshHeaders(resolvedId, undefined, true);
386
+ const fresh = await getBasicHeaders(resolvedId);
387
+ headers.cookie = fresh.cookie;
388
+ headers["user-agent"] = fresh.userAgent;
389
+ headers["bx-v"] = fresh.bxV;
390
+ if (fresh.bxUa) headers["bx-ua"] = fresh.bxUa;
391
+ if (fresh.bxUmidtoken) headers["bx-umidtoken"] = fresh.bxUmidtoken;
392
+ response = await doFetch(headers);
393
+ if (response.ok) {
394
+ data = await response.json().catch(() => null);
395
+ }
396
+ }
397
+ } catch (refreshErr) {
398
+ console.warn(
399
+ `[Upload] Re-auth for STS token failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`,
400
+ );
401
+ }
402
+ }
403
+
404
+ if (!data?.success || !data?.data) {
369
405
  throw new Error(
370
406
  `STS token invalid: ${JSON.stringify(data).substring(0, 200)}`,
371
407
  );
@@ -617,6 +653,7 @@ export async function processImagesForQwen(
617
653
  file_url?: { url: string };
618
654
  }>,
619
655
  headers: Record<string, string>,
656
+ accountId?: string,
620
657
  ): Promise<{ text: string; files: QwenFileEntry[] }> {
621
658
  const textParts: string[] = [];
622
659
  const files: QwenFileEntry[] = [];
@@ -654,6 +691,7 @@ export async function processImagesForQwen(
654
691
  fileSize,
655
692
  typeInfo.qwenFileType,
656
693
  headers,
694
+ accountId,
657
695
  );
658
696
  fileUrl = await uploadToOSS(remoteMedia.buffer, stsData, filename);
659
697
  fileId = stsData.file_id;
@@ -686,6 +724,7 @@ export async function processImagesForQwen(
686
724
  fileSize,
687
725
  typeInfo.qwenFileType,
688
726
  headers,
727
+ accountId,
689
728
  );
690
729
  fileUrl = await uploadToOSS(buffer, stsData, filename);
691
730
  fileId = stsData.file_id;
@@ -94,36 +94,13 @@ export async function getBasicHeaders(accountId?: string): Promise<{
94
94
  return getPlaywrightBasicHeaders(resolvedAccountId);
95
95
  }
96
96
 
97
- export function isTokenExpiringSoon(
98
- cookie: string,
99
- minutesBeforeExpiry = 5,
100
- ): boolean {
101
- const tokenMatch = cookie.match(/token=([^;]+)/);
102
- if (!tokenMatch) return false;
103
-
104
- try {
105
- const token = decodeURIComponent(tokenMatch[1]);
106
- const segments = token.split(".");
107
- // Some Qwen deployments use opaque cookies. Treating those as expired
108
- // forces expensive header capture on every personalization request.
109
- if (segments.length !== 3 || !segments[1]) return false;
110
-
111
- const payloadJson = Buffer.from(segments[1], "base64url").toString("utf-8");
112
- const payload = JSON.parse(payloadJson);
113
- const exp = payload.exp;
114
- if (typeof exp !== "number" || !Number.isFinite(exp)) return false;
115
-
116
- const nowSec = Math.floor(Date.now() / 1000);
117
- const thresholdSec = minutesBeforeExpiry * 60;
118
- return exp - nowSec < thresholdSec;
119
- } catch {
120
- return false;
121
- }
122
- }
97
+ import { parseJwtExpiry, isTokenExpiringSoon } from "../utils/jwt.ts";
98
+ export { parseJwtExpiry, isTokenExpiringSoon };
123
99
 
124
100
  export async function getQwenHeaders(
125
101
  forceNew = false,
126
102
  accountId?: string,
103
+ forceReauth = false,
127
104
  ): Promise<HeaderResult> {
128
105
  if (isAuthMockEnabled()) {
129
106
  const basic = await getBasicHeaders(accountId);
@@ -150,8 +127,8 @@ export async function getQwenHeaders(
150
127
 
151
128
  await ensurePlaywrightInitialized(resolvedAccountId);
152
129
 
153
- if (forceNew) {
154
- await refreshHeaders(resolvedAccountId);
130
+ if (forceNew || forceReauth) {
131
+ await refreshHeaders(resolvedAccountId, config.timeouts.headers, forceReauth);
155
132
  }
156
133
 
157
134
  const basic = await getPlaywrightBasicHeaders(resolvedAccountId);