jimeng-cli 0.3.1 → 0.3.3

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.
@@ -5627,6 +5627,17 @@ var import_mime = __toESM(require("mime"), 1);
5627
5627
  var import_axios = __toESM(require("axios"), 1);
5628
5628
  var import_uuid = require("uuid");
5629
5629
  var import_date_fns = require("date-fns");
5630
+ var CRC32_TABLE = (() => {
5631
+ const table = [];
5632
+ for (let i = 0; i < 256; i++) {
5633
+ let crc = i;
5634
+ for (let j = 0; j < 8; j++) {
5635
+ crc = crc & 1 ? 3988292384 ^ crc >>> 1 : crc >>> 1;
5636
+ }
5637
+ table[i] = crc;
5638
+ }
5639
+ return table;
5640
+ })();
5630
5641
  var util = {
5631
5642
  uuid: (separator = true) => separator ? (0, import_uuid.v4)() : (0, import_uuid.v4)().replace(/-/g, ""),
5632
5643
  getDateString(format = "yyyy-MM-dd", date = /* @__PURE__ */ new Date()) {
@@ -5672,22 +5683,18 @@ var util = {
5672
5683
  * @returns CRC32 十六进制字符串
5673
5684
  */
5674
5685
  calculateCRC32(buffer) {
5675
- const crcTable = [];
5676
- for (let i = 0; i < 256; i++) {
5677
- let crc2 = i;
5678
- for (let j = 0; j < 8; j++) {
5679
- crc2 = crc2 & 1 ? 3988292384 ^ crc2 >>> 1 : crc2 >>> 1;
5680
- }
5681
- crcTable[i] = crc2;
5682
- }
5683
5686
  let crc = 0 ^ -1;
5684
5687
  const bytes = buffer instanceof ArrayBuffer ? new Uint8Array(buffer) : new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
5685
5688
  for (let i = 0; i < bytes.length; i++) {
5686
- crc = crc >>> 8 ^ crcTable[(crc ^ bytes[i]) & 255];
5689
+ crc = crc >>> 8 ^ CRC32_TABLE[(crc ^ bytes[i]) & 255];
5687
5690
  }
5688
5691
  return ((crc ^ -1) >>> 0).toString(16).padStart(8, "0");
5689
5692
  }
5690
5693
  };
5694
+ function maskToken(token) {
5695
+ if (token.length <= 10) return "***";
5696
+ return `${token.slice(0, 4)}...${token.slice(-4)}`;
5697
+ }
5691
5698
  var util_default = util;
5692
5699
 
5693
5700
  // src/lib/logger.ts
@@ -5967,6 +5974,8 @@ var JimengErrorHandler = class {
5967
5974
  throw new APIException(exceptions_default.API_IMAGE_GENERATION_FAILED, `[\u751F\u6210\u5931\u8D25]: ${errmsg}`);
5968
5975
  case "5002":
5969
5976
  throw new APIException(exceptions_default.API_VIDEO_GENERATION_FAILED, `[\u89C6\u9891\u751F\u6210\u5931\u8D25]: ${errmsg}`);
5977
+ case "34010105":
5978
+ throw new APIException(exceptions_default.API_REQUEST_FAILED, `[\u767B\u5F55\u9A8C\u8BC1\u5931\u8D25]: ${errmsg} (\u9519\u8BEF\u7801: ${ret})`);
5970
5979
  default:
5971
5980
  throw new APIException(exceptions_default.API_REQUEST_FAILED, `[${operation}\u5931\u8D25]: ${errmsg} (\u9519\u8BEF\u7801: ${ret})`);
5972
5981
  }
@@ -5996,16 +6005,18 @@ var JimengErrorHandler = class {
5996
6005
  * 处理轮询超时错误
5997
6006
  * @returns 如果有部分结果,返回 void 而不抛出异常
5998
6007
  */
5999
- static handlePollingTimeout(pollCount, maxPollCount, elapsedTime, status, itemCount, historyId) {
6000
- const message = `\u8F6E\u8BE2\u8D85\u65F6: \u5DF2\u8F6E\u8BE2 ${pollCount} \u6B21\uFF0C\u8017\u65F6 ${elapsedTime} \u79D2\uFF0C\u6700\u7EC8\u72B6\u6001: ${status}\uFF0C\u56FE\u7247\u6570\u91CF: ${itemCount}`;
6008
+ static handlePollingTimeout(pollCount, maxPollCount, elapsedTime, status, itemCount, historyId, type = "image") {
6009
+ const typeText = type === "image" ? "\u56FE\u7247" : "\u89C6\u9891";
6010
+ const message = `\u8F6E\u8BE2\u8D85\u65F6: \u5DF2\u8F6E\u8BE2 ${pollCount} \u6B21\uFF0C\u8017\u65F6 ${elapsedTime} \u79D2\uFF0C\u6700\u7EC8\u72B6\u6001: ${status}\uFF0C${typeText}\u6570\u91CF: ${itemCount}`;
6001
6011
  logger_default.warn(message + (historyId ? `\uFF0C\u5386\u53F2ID: ${historyId}` : ""));
6002
6012
  if (itemCount === 0) {
6013
+ const exception = type === "image" ? exceptions_default.API_IMAGE_GENERATION_FAILED : exceptions_default.API_VIDEO_GENERATION_FAILED;
6003
6014
  throw new APIException(
6004
- exceptions_default.API_IMAGE_GENERATION_FAILED,
6005
- `\u751F\u6210\u8D85\u65F6\u4E14\u65E0\u7ED3\u679C\uFF0C\u72B6\u6001\u7801: ${status}${historyId ? `\uFF0C\u5386\u53F2ID: ${historyId}` : ""}`
6015
+ exception,
6016
+ `${typeText}\u751F\u6210\u8D85\u65F6\u4E14\u65E0\u7ED3\u679C\uFF0C\u72B6\u6001\u7801: ${status}${historyId ? `\uFF0C\u5386\u53F2ID: ${historyId}` : ""}`
6006
6017
  );
6007
6018
  }
6008
- logger_default.info(`\u8F6E\u8BE2\u8D85\u65F6\u4F46\u5DF2\u83B7\u5F97 ${itemCount} \u5F20\u56FE\u7247\uFF0C\u5C06\u8FD4\u56DE\u73B0\u6709\u7ED3\u679C`);
6019
+ logger_default.info(`\u8F6E\u8BE2\u8D85\u65F6\u4F46\u5DF2\u83B7\u5F97 ${itemCount} \u4E2A${typeText}\uFF0C\u5C06\u8FD4\u56DE\u73B0\u6709\u7ED3\u679C`);
6009
6020
  }
6010
6021
  /**
6011
6022
  * 处理生成失败错误
@@ -6070,12 +6081,11 @@ var BASE_URL_IMAGEX_US = "https://imagex16-normal-us-ttp.capcutapi.us";
6070
6081
  var BASE_URL_DREAMINA_HK = "https://mweb-api-sg.capcut.com";
6071
6082
  var BASE_URL_IMAGEX_HK = "https://imagex-normal-sg.capcutapi.com";
6072
6083
  var WEB_VERSION = "7.5.0";
6073
- var DA_VERSION = "3.3.8";
6084
+ var DA_VERSION = "3.3.12";
6074
6085
 
6075
6086
  // src/api/consts/common.ts
6076
6087
  var BASE_URL_CN = "https://jimeng.jianying.com";
6077
6088
  var BASE_URL_US_COMMERCE = "https://commerce.us.capcut.com";
6078
- var BASE_URL_HK_COMMERCE = "https://commerce-api-sg.capcut.com";
6079
6089
  var DEFAULT_ASSISTANT_ID_CN = 513695;
6080
6090
  var DEFAULT_ASSISTANT_ID_US = 513641;
6081
6091
  var DEFAULT_ASSISTANT_ID_HK = 513641;
@@ -6091,9 +6101,9 @@ var VERSION_CODE = "8.4.0";
6091
6101
  var DEFAULT_IMAGE_MODEL = "jimeng-4.5";
6092
6102
  var DEFAULT_IMAGE_MODEL_US = "jimeng-4.5";
6093
6103
  var DEFAULT_VIDEO_MODEL = "jimeng-video-3.5-pro";
6094
- var DRAFT_VERSION = "3.3.8";
6104
+ var DRAFT_VERSION = "3.3.12";
6095
6105
  var DRAFT_MIN_VERSION = "3.0.2";
6096
- var DRAFT_VERSION_OMNI = "3.3.9";
6106
+ var DRAFT_VERSION_OMNI = "3.3.12";
6097
6107
  var OMNI_BENEFIT_TYPE = "dreamina_video_seedance_20_video_add";
6098
6108
  var OMNI_BENEFIT_TYPE_FAST = "dreamina_seedance_20_fast_with_video";
6099
6109
  var IMAGE_MODEL_MAP = {
@@ -6109,6 +6119,8 @@ var IMAGE_MODEL_MAP = {
6109
6119
  "jimeng-lab": "high_aes_general_v50_lab"
6110
6120
  };
6111
6121
  var IMAGE_MODEL_MAP_US = {
6122
+ "jimeng-5.0": "high_aes_general_v50",
6123
+ "jimeng-4.6": "high_aes_general_v42",
6112
6124
  "jimeng-4.5": "high_aes_general_v40l",
6113
6125
  "jimeng-4.1": "high_aes_general_v41",
6114
6126
  "jimeng-4.0": "high_aes_general_v40",
@@ -6122,6 +6134,7 @@ var IMAGE_MODEL_MAP_ASIA = {
6122
6134
  "jimeng-4.5": "high_aes_general_v40l",
6123
6135
  "jimeng-4.1": "high_aes_general_v41",
6124
6136
  "jimeng-4.0": "high_aes_general_v40",
6137
+ "jimeng-3.1": "high_aes_general_v30l_art:general_v3.0_18b",
6125
6138
  "jimeng-3.0": "high_aes_general_v30l:general_v3.0_18b",
6126
6139
  "nanobanana": "external_model_gemini_flash_image_v25",
6127
6140
  "nanobananapro": "dreamina_image_lib_1"
@@ -6139,10 +6152,14 @@ var VIDEO_MODEL_MAP = {
6139
6152
  "jimeng-video-2.0-pro": "dreamina_ic_generate_video_model_vgfm1.0"
6140
6153
  };
6141
6154
  var VIDEO_MODEL_MAP_US = {
6155
+ "jimeng-video-seedance-2.0": "dreamina_seedance_40_pro",
6156
+ "jimeng-video-seedance-2.0-fast": "dreamina_seedance_40",
6142
6157
  "jimeng-video-3.5-pro": "dreamina_ic_generate_video_model_vgfm_3.5_pro",
6143
6158
  "jimeng-video-3.0": "dreamina_ic_generate_video_model_vgfm_3.0"
6144
6159
  };
6145
6160
  var VIDEO_MODEL_MAP_ASIA = {
6161
+ "jimeng-video-seedance-2.0": "dreamina_seedance_40_pro",
6162
+ "jimeng-video-seedance-2.0-fast": "dreamina_seedance_40",
6146
6163
  "jimeng-video-veo3": "dreamina_veo3_generate_video",
6147
6164
  "jimeng-video-veo3.1": "dreamina_veo3.1_generate_video",
6148
6165
  "jimeng-video-sora2": "dreamina_sora2_generate_video",
@@ -6222,6 +6239,7 @@ var RESOLUTION_OPTIONS_NANOBANANAPRO_4K = {
6222
6239
  var DEVICE_ID = Math.random() * 1e18 + 7e18;
6223
6240
  var WEB_ID = Math.random() * 1e18 + 7e18;
6224
6241
  var USER_ID = util_default.uuid(false);
6242
+ var INTERNATIONAL_FRONTEND_ORIGIN = "https://dreamina.capcut.com";
6225
6243
  var FAKE_HEADERS = {
6226
6244
  Accept: "application/json, text/plain, */*",
6227
6245
  "Accept-Encoding": "gzip, deflate, br, zstd",
@@ -6345,8 +6363,7 @@ function parseProxyFromToken(rawToken) {
6345
6363
  return { token, proxyUrl };
6346
6364
  }
6347
6365
  function getRefererByRegion(regionInfo, cnPath) {
6348
- const { isInternational } = regionInfo;
6349
- return isInternational ? "https://dreamina.capcut.com/" : `https://jimeng.jianying.com${cnPath}`;
6366
+ return regionInfo.isInternational ? `${INTERNATIONAL_FRONTEND_ORIGIN}/` : `${BASE_URL_CN}${cnPath}`;
6350
6367
  }
6351
6368
  function getAssistantId(regionInfo) {
6352
6369
  if (regionInfo.isUS) return DEFAULT_ASSISTANT_ID_US;
@@ -6377,12 +6394,14 @@ function generateCookie(refreshToken) {
6377
6394
  }
6378
6395
  async function getCredit(refreshToken, regionInfo) {
6379
6396
  const referer = getRefererByRegion(regionInfo, "/ai-tool/image/generate");
6397
+ const origin = regionInfo.isInternational ? INTERNATIONAL_FRONTEND_ORIGIN : void 0;
6380
6398
  const {
6381
6399
  credit: { gift_credit, purchase_credit, vip_credit }
6382
6400
  } = await request("POST", "/commerce/v1/benefits/user_credit", refreshToken, regionInfo, {
6383
6401
  data: {},
6384
6402
  headers: {
6385
- Referer: referer
6403
+ Referer: referer,
6404
+ ...origin ? { Origin: origin } : {}
6386
6405
  },
6387
6406
  noDefaultParams: true
6388
6407
  });
@@ -6399,13 +6418,15 @@ async function getCredit(refreshToken, regionInfo) {
6399
6418
  async function receiveCredit(refreshToken, regionInfo) {
6400
6419
  logger_default.info("\u6B63\u5728\u5C1D\u8BD5\u6536\u53D6\u4ECA\u65E5\u79EF\u5206...");
6401
6420
  const referer = getRefererByRegion(regionInfo, "/ai-tool/home");
6421
+ const origin = regionInfo.isInternational ? INTERNATIONAL_FRONTEND_ORIGIN : void 0;
6402
6422
  const timeZone = regionInfo.isUS ? "America/New_York" : regionInfo.isHK ? "Asia/Hong_Kong" : regionInfo.isJP ? "Asia/Tokyo" : regionInfo.isSG ? "Asia/Singapore" : "Asia/Shanghai";
6403
6423
  const { receive_quota } = await request("POST", "/commerce/v1/benefits/credit_receive", refreshToken, regionInfo, {
6404
6424
  data: {
6405
6425
  time_zone: timeZone
6406
6426
  },
6407
6427
  headers: {
6408
- Referer: referer
6428
+ Referer: referer,
6429
+ ...origin ? { Origin: origin } : {}
6409
6430
  }
6410
6431
  });
6411
6432
  logger_default.info(`\u4ECA\u65E5${receive_quota}\u79EF\u5206\u6536\u53D6\u6210\u529F`);
@@ -6433,7 +6454,7 @@ async function request(method, uri, refreshToken, regionInfo, options = {}) {
6433
6454
  region = REGION_US;
6434
6455
  } else if (isHK || isJP || isSG) {
6435
6456
  if (uri.startsWith("/commerce/")) {
6436
- baseUrl = BASE_URL_HK_COMMERCE;
6457
+ baseUrl = BASE_URL_US_COMMERCE;
6437
6458
  } else {
6438
6459
  baseUrl = BASE_URL_DREAMINA_HK;
6439
6460
  }
@@ -6513,7 +6534,8 @@ async function request(method, uri, refreshToken, regionInfo, options = {}) {
6513
6534
  });
6514
6535
  logger_default.info(`\u54CD\u5E94\u72B6\u6001: ${response.status} ${response.statusText}`);
6515
6536
  if (options.responseType == "stream") return response;
6516
- const responseDataSummary = JSON.stringify(response.data).substring(0, 500) + (JSON.stringify(response.data).length > 500 ? "..." : "");
6537
+ const responseJson = JSON.stringify(response.data);
6538
+ const responseDataSummary = responseJson.substring(0, 500) + (responseJson.length > 500 ? "..." : "");
6517
6539
  logger_default.info(`\u54CD\u5E94\u6570\u636E\u6458\u8981: ${responseDataSummary}`);
6518
6540
  if (response.status >= 400) {
6519
6541
  logger_default.warn(`HTTP\u9519\u8BEF: ${response.status} ${response.statusText}`);
@@ -6604,6 +6626,9 @@ function checkResult(result) {
6604
6626
  }
6605
6627
  async function getTokenLiveStatus(refreshToken, regionInfo) {
6606
6628
  try {
6629
+ if (regionInfo.isInternational) {
6630
+ return await checkInternationalTokenLive(refreshToken, regionInfo);
6631
+ }
6607
6632
  const result = await request(
6608
6633
  "POST",
6609
6634
  "/passport/account/info/v2",
@@ -6622,6 +6647,258 @@ async function getTokenLiveStatus(refreshToken, regionInfo) {
6622
6647
  return false;
6623
6648
  }
6624
6649
  }
6650
+ async function checkInternationalTokenLive(refreshToken, regionInfo) {
6651
+ const aid = getAssistantId(regionInfo);
6652
+ const countryCode = regionInfo.isUS ? "us" : regionInfo.isJP ? "jp" : regionInfo.isHK ? "hk" : "sg";
6653
+ const cookie = generateCookie(refreshToken);
6654
+ try {
6655
+ const response = await import_axios2.default.get(
6656
+ `${INTERNATIONAL_FRONTEND_ORIGIN}/passport/web/account/info/`,
6657
+ {
6658
+ params: {
6659
+ aid,
6660
+ account_sdk_source: "web",
6661
+ sdk_version: "2.1.10-tiktok",
6662
+ language: countryCode === "jp" ? "ja" : "en"
6663
+ },
6664
+ headers: {
6665
+ ...FAKE_HEADERS,
6666
+ Cookie: cookie,
6667
+ Referer: `${INTERNATIONAL_FRONTEND_ORIGIN}/ai-tool/home/`,
6668
+ Origin: INTERNATIONAL_FRONTEND_ORIGIN,
6669
+ Appid: String(aid),
6670
+ "store-country-code": countryCode,
6671
+ "store-country-code-src": "uid"
6672
+ },
6673
+ timeout: 15e3
6674
+ }
6675
+ );
6676
+ const data = response.data;
6677
+ if (data && typeof data === "object") {
6678
+ const obj = data;
6679
+ if (obj.user_id || obj.email || obj.data) {
6680
+ return true;
6681
+ }
6682
+ }
6683
+ return false;
6684
+ } catch {
6685
+ return false;
6686
+ }
6687
+ }
6688
+
6689
+ // src/api/controllers/models.ts
6690
+ var CACHE_TTL_MS = 10 * 60 * 1e3;
6691
+ var FALLBACK_TOKEN = "test_token";
6692
+ var modelCache = /* @__PURE__ */ new Map();
6693
+ function mapVideoDescription(id) {
6694
+ if (id.includes("veo3.1")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B veo3.1";
6695
+ if (id.includes("veo3")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B veo3";
6696
+ if (id.includes("sora2")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B sora2";
6697
+ if (id.includes("seedance-2.0-fast")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B seedance 2.0-fast";
6698
+ if (id.includes("seedance-2.0")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B seedance 2.0";
6699
+ if (id.includes("3.5-pro")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 3.5 \u4E13\u4E1A\u7248";
6700
+ if (id.includes("3.0-fast")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 3.0 \u6781\u901F\u7248";
6701
+ if (id.includes("3.0-pro")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 3.0 \u4E13\u4E1A\u7248";
6702
+ if (id.includes("3.0")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 3.0";
6703
+ if (id.includes("2.0-pro")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 2.0 \u4E13\u4E1A\u7248";
6704
+ if (id.includes("2.0")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 2.0";
6705
+ return void 0;
6706
+ }
6707
+ function mapImageDescription(id) {
6708
+ if (id.includes("5.0")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 5.0";
6709
+ if (id.includes("4.6")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 4.6";
6710
+ if (id.includes("4.5")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 4.5";
6711
+ if (id.includes("4.1")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 4.1";
6712
+ if (id.includes("4.0")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 4.0";
6713
+ if (id.includes("3.1")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 3.1";
6714
+ if (id.includes("3.0")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 3.0";
6715
+ return `\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B ${id}`;
6716
+ }
6717
+ function buildModelItem(modelId, meta) {
6718
+ var _a;
6719
+ const modelType = modelId.startsWith("jimeng-video-") ? "video" : "image";
6720
+ const item = {
6721
+ id: modelId,
6722
+ object: "model",
6723
+ owned_by: "jimeng-cli",
6724
+ model_type: modelType
6725
+ };
6726
+ if (meta == null ? void 0 : meta.reqKey) item.model_req_key = meta.reqKey;
6727
+ if (meta == null ? void 0 : meta.modelName) item.model_name = meta.modelName;
6728
+ if ((_a = meta == null ? void 0 : meta.capabilities) == null ? void 0 : _a.length) item.capabilities = Array.from(new Set(meta.capabilities)).sort();
6729
+ if ((meta == null ? void 0 : meta.params) && Object.keys(meta.params).length > 0) item.params = meta.params;
6730
+ if (meta == null ? void 0 : meta.modelTip) {
6731
+ item.description = meta.modelTip;
6732
+ } else if (modelType === "video") {
6733
+ item.description = mapVideoDescription(modelId);
6734
+ } else {
6735
+ item.description = mapImageDescription(modelId);
6736
+ }
6737
+ return item;
6738
+ }
6739
+ function parseFirstToken(authorization) {
6740
+ var _a;
6741
+ if (!authorization || !/^Bearer\s+/i.test(authorization)) return void 0;
6742
+ const raw = authorization.replace(/^Bearer\s+/i, "").trim();
6743
+ if (!raw) return void 0;
6744
+ const first = (_a = raw.split(",")[0]) == null ? void 0 : _a.trim();
6745
+ return first || void 0;
6746
+ }
6747
+ function resolveToken(authorization) {
6748
+ const fromAuth = parseFirstToken(authorization);
6749
+ if (fromAuth) return fromAuth;
6750
+ const fromPool = session_pool_default.getAllTokens({ onlyEnabled: true, preferLive: true })[0];
6751
+ return fromPool || void 0;
6752
+ }
6753
+ function getRegionalMaps(region) {
6754
+ if (region === "us") return [IMAGE_MODEL_MAP_US, VIDEO_MODEL_MAP_US];
6755
+ if (region === "hk" || region === "jp" || region === "sg") return [IMAGE_MODEL_MAP_ASIA, VIDEO_MODEL_MAP_ASIA];
6756
+ if (region === "cn") return [IMAGE_MODEL_MAP, VIDEO_MODEL_MAP];
6757
+ return [IMAGE_MODEL_MAP, IMAGE_MODEL_MAP_US, IMAGE_MODEL_MAP_ASIA, VIDEO_MODEL_MAP, VIDEO_MODEL_MAP_US, VIDEO_MODEL_MAP_ASIA];
6758
+ }
6759
+ function resolveRegion(authorization, xRegion) {
6760
+ var _a;
6761
+ const token = resolveToken(authorization);
6762
+ const parsedXRegion = parseRegionCode(xRegion);
6763
+ if (parsedXRegion) return parsedXRegion;
6764
+ if (token) {
6765
+ assertTokenWithoutRegionPrefix(token);
6766
+ const normalizedToken = parseProxyFromToken(token).token;
6767
+ const poolRegion = (_a = session_pool_default.getTokenEntry(normalizedToken)) == null ? void 0 : _a.region;
6768
+ if (poolRegion) return poolRegion;
6769
+ throw new Error("\u7F3A\u5C11 region\u3002token \u672A\u5728 pool \u4E2D\u6CE8\u518C\u65F6\uFF0C/v1/models \u9700\u8981\u63D0\u4F9B\u8BF7\u6C42\u5934 X-Region");
6770
+ }
6771
+ return "cn";
6772
+ }
6773
+ var reverseMapCache = /* @__PURE__ */ new Map();
6774
+ function buildReverseMap(region) {
6775
+ const cached = reverseMapCache.get(region);
6776
+ if (cached) return cached;
6777
+ const reverse = {};
6778
+ for (const map of getRegionalMaps(region)) {
6779
+ for (const [modelId, upstreamKey] of Object.entries(map)) {
6780
+ reverse[upstreamKey] = modelId;
6781
+ }
6782
+ }
6783
+ reverseMapCache.set(region, reverse);
6784
+ return reverse;
6785
+ }
6786
+ function buildFallbackModels(region) {
6787
+ const maps = getRegionalMaps(region);
6788
+ const modelIds = Array.from(new Set(maps.flatMap((item) => Object.keys(item)))).sort();
6789
+ return modelIds.map((id) => buildModelItem(id));
6790
+ }
6791
+ function makeCacheKey(region) {
6792
+ return `models|${region}`;
6793
+ }
6794
+ function resolveFetchToken(token) {
6795
+ if (!token) return FALLBACK_TOKEN;
6796
+ const normalizedToken = parseProxyFromToken(token).token;
6797
+ assertTokenWithoutRegionPrefix(normalizedToken);
6798
+ return normalizedToken;
6799
+ }
6800
+ function extractValidOptions(item) {
6801
+ return (Array.isArray(item.options) ? item.options : []).filter(
6802
+ (opt) => !!opt && typeof opt === "object" && typeof opt.key === "string" && opt.key.length > 0
6803
+ );
6804
+ }
6805
+ function extractCapabilities(item) {
6806
+ const features = Array.isArray(item.feats) ? item.feats.filter((f) => typeof f === "string" && f.length > 0) : [];
6807
+ const optionKeys = extractValidOptions(item).map((o) => o.key);
6808
+ return Array.from(/* @__PURE__ */ new Set([...features, ...optionKeys]));
6809
+ }
6810
+ function extractEnumParams(item) {
6811
+ const params = {};
6812
+ for (const o of extractValidOptions(item)) {
6813
+ const ev = o.enum_val;
6814
+ if (!ev) continue;
6815
+ const sv = ev.string_value;
6816
+ const iv = ev.int_value;
6817
+ const vals = sv || iv;
6818
+ if (vals && vals.length > 0) {
6819
+ params[o.key] = vals;
6820
+ }
6821
+ }
6822
+ const rm = item.resolution_map;
6823
+ if (rm && typeof rm === "object") {
6824
+ params["resolution"] = Object.keys(rm).map(String);
6825
+ }
6826
+ const steps = item.sample_steps;
6827
+ if (steps && typeof steps === "object") {
6828
+ params["steps"] = [steps.min_steps, steps.max_steps];
6829
+ }
6830
+ return params;
6831
+ }
6832
+ function toUpstreamMeta(item) {
6833
+ const reqKey = item == null ? void 0 : item.model_req_key;
6834
+ if (typeof reqKey !== "string" || reqKey.length === 0) return void 0;
6835
+ return {
6836
+ reqKey,
6837
+ modelName: typeof (item == null ? void 0 : item.model_name) === "string" ? item.model_name : void 0,
6838
+ modelTip: typeof (item == null ? void 0 : item.model_tip) === "string" ? item.model_tip : void 0,
6839
+ capabilities: extractCapabilities(item),
6840
+ params: extractEnumParams(item)
6841
+ };
6842
+ }
6843
+ async function fetchConfigModelReqKeys(token, region) {
6844
+ const regionInfo = buildRegionInfo(region);
6845
+ const [imageConfig, videoConfig] = await Promise.all([
6846
+ request("post", "/mweb/v1/get_common_config", token, regionInfo, {
6847
+ data: {},
6848
+ params: { needCache: true, needRefresh: false }
6849
+ }),
6850
+ request("post", "/mweb/v1/video_generate/get_common_config", token, regionInfo, {
6851
+ data: { scene: "generate_video", params: {} }
6852
+ })
6853
+ ]);
6854
+ const toList = (config) => Array.isArray(config == null ? void 0 : config.model_list) ? config.model_list.map(toUpstreamMeta).filter((m) => Boolean(m)) : [];
6855
+ return { imageModels: toList(imageConfig), videoModels: toList(videoConfig) };
6856
+ }
6857
+ async function getLiveModels(authorization, xRegion) {
6858
+ const region = resolveRegion(authorization, xRegion);
6859
+ const token = resolveToken(authorization);
6860
+ const effectiveToken = resolveFetchToken(token);
6861
+ const cacheKey = makeCacheKey(region);
6862
+ const cached = modelCache.get(cacheKey);
6863
+ if (cached && cached.expiresAt > Date.now()) {
6864
+ return { source: cached.source, data: cached.data };
6865
+ }
6866
+ try {
6867
+ const reverseMap = buildReverseMap(region);
6868
+ const { imageModels, videoModels } = await fetchConfigModelReqKeys(effectiveToken, region);
6869
+ const upstreamModels = [...imageModels, ...videoModels];
6870
+ const metaByModelId = /* @__PURE__ */ new Map();
6871
+ const mapped = upstreamModels.map((model) => {
6872
+ const modelId = reverseMap[model.reqKey];
6873
+ if (modelId && !metaByModelId.has(modelId)) {
6874
+ metaByModelId.set(modelId, model);
6875
+ }
6876
+ return modelId;
6877
+ }).filter((item) => typeof item === "string" && item.length > 0);
6878
+ const modelIds = Array.from(new Set(mapped)).sort();
6879
+ if (modelIds.length === 0) {
6880
+ throw new Error("model_req_key resolved but none matched local reverse map");
6881
+ }
6882
+ const data = modelIds.map((id) => buildModelItem(id, metaByModelId.get(id)));
6883
+ modelCache.set(cacheKey, {
6884
+ expiresAt: Date.now() + CACHE_TTL_MS,
6885
+ source: "upstream",
6886
+ data
6887
+ });
6888
+ return { source: "upstream", data };
6889
+ } catch {
6890
+ const data = buildFallbackModels(region);
6891
+ modelCache.set(cacheKey, {
6892
+ expiresAt: Date.now() + CACHE_TTL_MS,
6893
+ source: "fallback",
6894
+ data
6895
+ });
6896
+ return { source: "fallback", data };
6897
+ }
6898
+ }
6899
+ async function refreshAllTokenModels() {
6900
+ return session_pool_default.refreshAllDynamicCapabilities();
6901
+ }
6625
6902
 
6626
6903
  // src/lib/session-pool.ts
6627
6904
  function sample(arr) {
@@ -6672,10 +6949,14 @@ var TokenPool = class {
6672
6949
  );
6673
6950
  }
6674
6951
  getSummary() {
6675
- const entries = this.getEntries(false);
6676
- const enabledCount = entries.filter((item) => item.enabled).length;
6677
- const liveCount = entries.filter((item) => item.enabled && item.live === true).length;
6678
- const missingRegionCount = entries.filter((item) => !item.region).length;
6952
+ let enabledCount = 0;
6953
+ let liveCount = 0;
6954
+ let missingRegionCount = 0;
6955
+ for (const item of this.entryMap.values()) {
6956
+ if (item.enabled) enabledCount++;
6957
+ if (item.enabled && item.live === true) liveCount++;
6958
+ if (!item.region) missingRegionCount++;
6959
+ }
6679
6960
  return {
6680
6961
  enabled: this.enabled,
6681
6962
  filePath: this.filePath,
@@ -6684,19 +6965,19 @@ var TokenPool = class {
6684
6965
  fetchCreditOnCheck: this.fetchCreditOnCheck,
6685
6966
  autoDisableEnabled: this.autoDisableEnabled,
6686
6967
  autoDisableFailures: this.autoDisableFailures,
6687
- total: entries.length,
6968
+ total: this.entryMap.size,
6688
6969
  enabledCount,
6689
6970
  liveCount,
6690
6971
  missingRegionCount,
6691
6972
  lastHealthCheckAt: this.lastHealthCheckAt || null
6692
6973
  };
6693
6974
  }
6694
- getEntries(maskToken2 = true) {
6975
+ getEntries(shouldMask = true) {
6695
6976
  const items = Array.from(this.entryMap.values()).map((item) => ({ ...item }));
6696
- if (!maskToken2) return items;
6977
+ if (!shouldMask) return items;
6697
6978
  return items.map((item) => ({
6698
6979
  ...item,
6699
- token: this.maskToken(item.token)
6980
+ token: maskToken(item.token)
6700
6981
  }));
6701
6982
  }
6702
6983
  getAllTokens(options = {}) {
@@ -6767,7 +7048,7 @@ var TokenPool = class {
6767
7048
  token: null,
6768
7049
  region: null,
6769
7050
  error: "prefixed_token_not_supported",
6770
- reason: `token ${this.maskToken(prefixedCandidate.token)} \u4F7F\u7528\u4E86\u5DF2\u5E9F\u5F03\u7684 region \u524D\u7F00`
7051
+ reason: `token ${maskToken(prefixedCandidate.token)} \u4F7F\u7528\u4E86\u5DF2\u5E9F\u5F03\u7684 region \u524D\u7F00`
6771
7052
  };
6772
7053
  }
6773
7054
  const regionLockedCandidates = validCandidates.filter(
@@ -6873,8 +7154,8 @@ var TokenPool = class {
6873
7154
  async refreshDynamicCapabilitiesForToken(token) {
6874
7155
  if (!this.enabled) throw new Error("Token pool disabled");
6875
7156
  const item = this.entryMap.get(token);
6876
- if (!item) throw new Error(`Token not found in pool: ${this.maskToken(token)}`);
6877
- if (!item.region) throw new Error(`Token ${this.maskToken(token)} has no region`);
7157
+ if (!item) throw new Error(`Token not found in pool: ${maskToken(token)}`);
7158
+ if (!item.region) throw new Error(`Token ${maskToken(token)} has no region`);
6878
7159
  const regionInfo = buildRegionInfo(item.region);
6879
7160
  const capabilities = await this.fetchDynamicCapabilities(token, regionInfo);
6880
7161
  item.dynamicCapabilities = { ...capabilities, updatedAt: Date.now() };
@@ -6886,39 +7167,41 @@ var TokenPool = class {
6886
7167
  * Returns a per-token result summary.
6887
7168
  */
6888
7169
  async refreshAllDynamicCapabilities() {
6889
- var _a, _b;
6890
7170
  if (!this.enabled) return [];
6891
7171
  const entries = this.getEntries(false).filter(
6892
7172
  (item) => item.enabled && item.live !== false && Boolean(item.region)
6893
7173
  );
6894
- const results = [];
6895
- for (const entry of entries) {
6896
- try {
6897
- const regionInfo = buildRegionInfo(entry.region);
6898
- const capabilities = await this.fetchDynamicCapabilities(entry.token, regionInfo);
6899
- const current = this.entryMap.get(entry.token);
6900
- if (current) {
6901
- current.dynamicCapabilities = { ...capabilities, updatedAt: Date.now() };
6902
- }
6903
- results.push({
6904
- token: this.maskToken(entry.token),
6905
- region: entry.region,
6906
- imageModels: ((_a = capabilities.imageModels) == null ? void 0 : _a.length) ?? 0,
6907
- videoModels: ((_b = capabilities.videoModels) == null ? void 0 : _b.length) ?? 0,
6908
- capabilityTags: capabilities.capabilityTags ?? []
6909
- });
6910
- } catch (err) {
6911
- results.push({
6912
- token: this.maskToken(entry.token),
6913
- region: entry.region,
6914
- imageModels: 0,
6915
- videoModels: 0,
6916
- capabilityTags: [],
6917
- error: (err == null ? void 0 : err.message) || String(err)
6918
- });
6919
- }
6920
- }
6921
- if (entries.length > 0) await this.persistToDisk();
7174
+ if (entries.length === 0) return [];
7175
+ const results = await Promise.all(
7176
+ entries.map(async (entry) => {
7177
+ var _a, _b;
7178
+ try {
7179
+ const regionInfo = buildRegionInfo(entry.region);
7180
+ const capabilities = await this.fetchDynamicCapabilities(entry.token, regionInfo);
7181
+ const current = this.entryMap.get(entry.token);
7182
+ if (current) {
7183
+ current.dynamicCapabilities = { ...capabilities, updatedAt: Date.now() };
7184
+ }
7185
+ return {
7186
+ token: maskToken(entry.token),
7187
+ region: entry.region,
7188
+ imageModels: ((_a = capabilities.imageModels) == null ? void 0 : _a.length) ?? 0,
7189
+ videoModels: ((_b = capabilities.videoModels) == null ? void 0 : _b.length) ?? 0,
7190
+ capabilityTags: capabilities.capabilityTags ?? []
7191
+ };
7192
+ } catch (err) {
7193
+ return {
7194
+ token: maskToken(entry.token),
7195
+ region: entry.region,
7196
+ imageModels: 0,
7197
+ videoModels: 0,
7198
+ capabilityTags: [],
7199
+ error: err instanceof Error ? err.message : String(err)
7200
+ };
7201
+ }
7202
+ })
7203
+ );
7204
+ await this.persistToDisk();
6922
7205
  return results;
6923
7206
  }
6924
7207
  async runHealthCheck() {
@@ -7039,14 +7322,10 @@ var TokenPool = class {
7039
7322
  await import_fs_extra4.default.ensureDir(import_path4.default.dirname(this.filePath));
7040
7323
  const payload = {
7041
7324
  updatedAt: Date.now(),
7042
- tokens: this.getEntries(false)
7325
+ tokens: Array.from(this.entryMap.values())
7043
7326
  };
7044
7327
  await import_fs_extra4.default.writeJson(this.filePath, payload, { spaces: 2 });
7045
7328
  }
7046
- maskToken(token) {
7047
- if (token.length <= 10) return "***";
7048
- return `${token.slice(0, 4)}...${token.slice(-4)}`;
7049
- }
7050
7329
  parseAuthorizationTokens(authorization) {
7051
7330
  if (typeof authorization !== "string" || authorization.trim().length === 0) {
7052
7331
  return { tokens: [], error: null };
@@ -7075,7 +7354,7 @@ var TokenPool = class {
7075
7354
  if (!token) continue;
7076
7355
  const parsedRegion = parseRegionCode(item.region || defaultRegion);
7077
7356
  if (!parsedRegion) {
7078
- throw new Error(`token ${this.maskToken(token)} \u7F3A\u5C11\u6709\u6548 region\uFF08\u4EC5\u652F\u6301 cn/us/hk/jp/sg\uFF09`);
7357
+ throw new Error(`token ${maskToken(token)} \u7F3A\u5C11\u6709\u6548 region\uFF08\u4EC5\u652F\u6301 cn/us/hk/jp/sg\uFF09`);
7079
7358
  }
7080
7359
  normalized.push({
7081
7360
  token,
@@ -7183,40 +7462,22 @@ var TokenPool = class {
7183
7462
  }
7184
7463
  async fetchDynamicCapabilities(token, regionInfo) {
7185
7464
  const regionCode = regionInfo.isUS ? "us" : regionInfo.isHK ? "hk" : regionInfo.isJP ? "jp" : regionInfo.isSG ? "sg" : "cn";
7186
- const reverseMap = this.getReverseModelMapByRegion(regionCode);
7187
- const imageConfig = await request("post", "/mweb/v1/get_common_config", token, regionInfo, {
7188
- data: {},
7189
- params: { needCache: true, needRefresh: false }
7190
- });
7191
- const videoConfig = await request("post", "/mweb/v1/video_generate/get_common_config", token, regionInfo, {
7192
- data: { scene: "generate_video", params: {} }
7193
- });
7194
- const imageReqKeys = Array.isArray(imageConfig == null ? void 0 : imageConfig.model_list) ? imageConfig.model_list.map((item) => typeof (item == null ? void 0 : item.model_req_key) === "string" ? item.model_req_key : "").filter(Boolean) : [];
7195
- const videoReqKeys = Array.isArray(videoConfig == null ? void 0 : videoConfig.model_list) ? videoConfig.model_list.map((item) => typeof (item == null ? void 0 : item.model_req_key) === "string" ? item.model_req_key : "").filter(Boolean) : [];
7196
- const imageModels = imageReqKeys.map((key) => reverseMap[key]).filter(Boolean);
7197
- const videoModels = videoReqKeys.map((key) => reverseMap[key]).filter(Boolean);
7465
+ const reverseMap = buildReverseMap(regionCode);
7466
+ const { imageModels, videoModels } = await fetchConfigModelReqKeys(token, regionCode);
7467
+ const imageIds = imageModels.map((m) => reverseMap[m.reqKey]).filter(Boolean);
7468
+ const videoIds = videoModels.map((m) => reverseMap[m.reqKey]).filter(Boolean);
7198
7469
  const capabilityTags = /* @__PURE__ */ new Set();
7199
- for (const model of videoModels) {
7470
+ for (const model of videoIds) {
7200
7471
  if (model.includes("seedance_40")) capabilityTags.add("omni_reference");
7201
7472
  if (model.includes("veo3")) capabilityTags.add("veo3");
7202
7473
  if (model.includes("sora2")) capabilityTags.add("sora2");
7203
7474
  }
7204
7475
  return {
7205
- imageModels: imageModels.length ? Array.from(new Set(imageModels)) : void 0,
7206
- videoModels: videoModels.length ? Array.from(new Set(videoModels)) : void 0,
7476
+ imageModels: imageIds.length ? Array.from(new Set(imageIds)) : void 0,
7477
+ videoModels: videoIds.length ? Array.from(new Set(videoIds)) : void 0,
7207
7478
  capabilityTags: capabilityTags.size ? Array.from(capabilityTags) : void 0
7208
7479
  };
7209
7480
  }
7210
- getReverseModelMapByRegion(region) {
7211
- const maps = region === "us" ? [IMAGE_MODEL_MAP_US, VIDEO_MODEL_MAP_US] : region === "hk" || region === "jp" || region === "sg" ? [IMAGE_MODEL_MAP_ASIA, VIDEO_MODEL_MAP_ASIA] : [IMAGE_MODEL_MAP, VIDEO_MODEL_MAP];
7212
- const reverse = {};
7213
- for (const map of maps) {
7214
- for (const [modelId, reqKey] of Object.entries(map)) {
7215
- reverse[reqKey] = modelId;
7216
- }
7217
- }
7218
- return reverse;
7219
- }
7220
7481
  };
7221
7482
  var session_pool_default = new TokenPool();
7222
7483
 
@@ -7225,11 +7486,6 @@ var import_node_fs = require("fs");
7225
7486
  var import_node_path = __toESM(require("path"), 1);
7226
7487
  var import_promises2 = require("fs/promises");
7227
7488
  var import_minimist2 = __toESM(require("minimist"), 1);
7228
- function maskToken(token) {
7229
- const n = token.length;
7230
- if (n <= 10) return "***";
7231
- return `${token.slice(0, 4)}...${token.slice(-4)}`;
7232
- }
7233
7489
  function formatUnixMs(value) {
7234
7490
  if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return "-";
7235
7491
  return new Date(value).toISOString();
@@ -7242,14 +7498,14 @@ function printTokenEntriesTable(items) {
7242
7498
  console.log("token region enabled live lastCredit lastCheckedAt failures");
7243
7499
  for (const item of items) {
7244
7500
  if (!item || typeof item !== "object") continue;
7245
- const entry = item;
7246
- const token = typeof entry.token === "string" ? entry.token : "-";
7247
- const region = typeof entry.region === "string" ? entry.region : "-";
7248
- const enabled = typeof entry.enabled === "boolean" ? String(entry.enabled) : "-";
7249
- const live = typeof entry.live === "boolean" ? String(entry.live) : "-";
7250
- const lastCredit = typeof entry.lastCredit === "number" ? String(entry.lastCredit) : "-";
7251
- const lastCheckedAt = formatUnixMs(entry.lastCheckedAt);
7252
- const failures = typeof entry.consecutiveFailures === "number" ? String(entry.consecutiveFailures) : "-";
7501
+ const e = item;
7502
+ const token = typeof e.token === "string" ? e.token : "-";
7503
+ const region = typeof e.region === "string" ? e.region : "-";
7504
+ const enabled = typeof e.enabled === "boolean" ? String(e.enabled) : "-";
7505
+ const live = typeof e.live === "boolean" ? String(e.live) : "-";
7506
+ const lastCredit = typeof e.lastCredit === "number" ? String(e.lastCredit) : "-";
7507
+ const lastCheckedAt = formatUnixMs(e.lastCheckedAt);
7508
+ const failures = typeof e.consecutiveFailures === "number" ? String(e.consecutiveFailures) : "-";
7253
7509
  console.log(`${token} ${region} ${enabled} ${live} ${lastCredit} ${lastCheckedAt} ${failures}`);
7254
7510
  }
7255
7511
  }
@@ -7288,6 +7544,30 @@ ${usage}`);
7288
7544
  }
7289
7545
  return deduped;
7290
7546
  }
7547
+ function resolveTokenRegionPairs(explicitTokens, regionCode, deps, opts) {
7548
+ if (explicitTokens.length > 0) {
7549
+ return explicitTokens.map((token) => {
7550
+ var _a;
7551
+ const entryRegion = (_a = session_pool_default.getTokenEntry(token)) == null ? void 0 : _a.region;
7552
+ const finalRegion = regionCode || entryRegion;
7553
+ if (!finalRegion) {
7554
+ deps.fail(`Missing region for token ${maskToken(token)}. Provide --region or register token in token-pool.`);
7555
+ }
7556
+ return { token, region: finalRegion };
7557
+ });
7558
+ }
7559
+ const requireLive = (opts == null ? void 0 : opts.requireLive) ?? true;
7560
+ const entries = session_pool_default.getEntries(false).filter((item) => {
7561
+ if (!item.enabled || !item.region) return false;
7562
+ if (requireLive && item.live === false) return false;
7563
+ if (regionCode && item.region !== regionCode) return false;
7564
+ return true;
7565
+ });
7566
+ if (entries.length === 0) {
7567
+ deps.fail("No token available. Provide --token or configure token-pool.");
7568
+ }
7569
+ return entries.map((item) => ({ token: item.token, region: item.region }));
7570
+ }
7291
7571
  function createTokenSubcommands(deps) {
7292
7572
  const handleTokenCheck = async (argv) => {
7293
7573
  const args = (0, import_minimist2.default)(argv, {
@@ -7299,74 +7579,67 @@ function createTokenSubcommands(deps) {
7299
7579
  console.log(usage);
7300
7580
  return;
7301
7581
  }
7302
- const region = deps.getRegionWithDefault(args);
7303
- const regionCode = deps.parseRegionOrFail(region);
7304
- if (!regionCode) {
7305
- deps.fail("Missing region. Use --region cn/us/hk/jp/sg.");
7306
- }
7307
- const tokens = await collectTokensFromArgs(args, usage, deps, true);
7582
+ const explicitRegion = deps.getSingleString(args, "region");
7583
+ const regionCode = explicitRegion ? deps.parseRegionOrFail(explicitRegion) : void 0;
7584
+ await deps.ensureTokenPoolReady();
7585
+ const explicitTokens = await collectTokensFromArgs(args, usage, deps, false);
7586
+ const pairs = resolveTokenRegionPairs(explicitTokens, regionCode, deps, { requireLive: false });
7308
7587
  if (!args.json) {
7309
- console.log(`Checking ${tokens.length} token(s)`);
7588
+ console.log(`Checking ${pairs.length} token(s)`);
7310
7589
  }
7311
- await deps.ensureTokenPoolReady();
7312
- let invalid = 0;
7313
- let requestErrors = 0;
7314
- const results = [];
7315
- for (const token of tokens) {
7316
- const masked = maskToken(token);
7317
- try {
7318
- const live = await getTokenLiveStatus(token, buildRegionInfo(regionCode));
7319
- await session_pool_default.syncTokenCheckResult(token, live);
7320
- if (live === true) {
7321
- if (!args.json) console.log(`[OK] ${masked} live=true`);
7322
- } else {
7323
- invalid += 1;
7324
- if (!args.json) console.log(`[FAIL] ${masked} live=false`);
7590
+ const results = await Promise.all(
7591
+ pairs.map(async ({ token, region }) => {
7592
+ const masked = maskToken(token);
7593
+ try {
7594
+ const live = await getTokenLiveStatus(token, buildRegionInfo(region));
7595
+ await session_pool_default.syncTokenCheckResult(token, live);
7596
+ if (live) {
7597
+ if (!args.json) console.log(`[OK] ${masked} (${region}) live=true`);
7598
+ return { token_masked: masked, region, live: true };
7599
+ } else {
7600
+ if (!args.json) console.log(`[FAIL] ${masked} (${region}) live=false`);
7601
+ return { token_masked: masked, region, live: false };
7602
+ }
7603
+ } catch (error) {
7604
+ const message = error instanceof Error ? error.message : String(error);
7605
+ if (!args.json) console.log(`[ERROR] ${masked} (${region}) ${message}`);
7606
+ return { token_masked: masked, region, error: message };
7325
7607
  }
7326
- results.push({ token_masked: masked, live: live === true });
7327
- } catch (error) {
7328
- requestErrors += 1;
7329
- const message = error instanceof Error ? error.message : String(error);
7330
- if (!args.json) console.log(`[ERROR] ${masked} ${message}`);
7331
- results.push({ token_masked: masked, error: message });
7332
- }
7333
- }
7608
+ })
7609
+ );
7610
+ const invalid = results.filter((r) => r.live === false).length;
7611
+ const requestErrors = results.filter((r) => r.error).length;
7334
7612
  if (args.json) {
7335
7613
  deps.printCommandJson("token.check", results, {
7336
- total: tokens.length,
7614
+ total: pairs.length,
7337
7615
  invalid,
7338
7616
  request_errors: requestErrors
7339
7617
  });
7340
7618
  } else {
7341
- console.log(`Summary: total=${tokens.length} invalid=${invalid} request_errors=${requestErrors}`);
7619
+ console.log(`Summary: total=${pairs.length} invalid=${invalid} request_errors=${requestErrors}`);
7342
7620
  }
7343
7621
  if (requestErrors > 0) process.exit(3);
7344
7622
  if (invalid > 0) process.exit(2);
7345
7623
  };
7346
7624
  const handleTokenList = async (argv) => {
7347
- const args = (0, import_minimist2.default)(argv, {
7348
- boolean: ["help", "json"]
7349
- });
7350
- const usage = deps.getUsage("list");
7625
+ const args = (0, import_minimist2.default)(argv, { boolean: ["help", "json"] });
7351
7626
  if (args.help) {
7352
- console.log(usage);
7627
+ console.log(deps.getUsage("list"));
7353
7628
  return;
7354
7629
  }
7355
7630
  await deps.ensureTokenPoolReady();
7356
- const normalized = buildTokenPoolSnapshot();
7631
+ const snapshot = buildTokenPoolSnapshot();
7357
7632
  if (args.json) {
7358
- deps.printCommandJson("token.list", normalized);
7633
+ deps.printCommandJson("token.list", snapshot);
7359
7634
  return;
7360
7635
  }
7361
- const body = normalized && typeof normalized === "object" ? normalized : {};
7362
- const summary = body.summary;
7363
- if (summary && typeof summary === "object") {
7636
+ const body = snapshot && typeof snapshot === "object" ? snapshot : {};
7637
+ if (body.summary && typeof body.summary === "object") {
7364
7638
  console.log("Summary:");
7365
- deps.printJson(summary);
7639
+ deps.printJson(body.summary);
7366
7640
  }
7367
- const items = Array.isArray(body.items) ? body.items : [];
7368
7641
  console.log("Entries:");
7369
- printTokenEntriesTable(items);
7642
+ printTokenEntriesTable(Array.isArray(body.items) ? body.items : []);
7370
7643
  };
7371
7644
  const handleTokenPointsOrReceive = async (argv, action) => {
7372
7645
  const args = (0, import_minimist2.default)(argv, {
@@ -7378,47 +7651,42 @@ function createTokenSubcommands(deps) {
7378
7651
  console.log(usage);
7379
7652
  return;
7380
7653
  }
7381
- const region = deps.getRegionWithDefault(args);
7382
- const regionCode = deps.parseRegionOrFail(region);
7654
+ const regionArg = deps.getSingleString(args, "region");
7655
+ const regionCode = regionArg ? deps.parseRegionOrFail(regionArg) : void 0;
7383
7656
  await deps.ensureTokenPoolReady();
7384
- const tokens = await collectTokensFromArgs(args, usage, deps, false);
7385
- const resolvedTokens = tokens.length > 0 ? tokens.map((token) => {
7386
- var _a;
7387
- const entryRegion = (_a = session_pool_default.getTokenEntry(token)) == null ? void 0 : _a.region;
7388
- const finalRegion = regionCode || entryRegion;
7389
- if (!finalRegion) {
7390
- deps.fail(`Missing region for token ${maskToken(token)}. Provide --region or register token region in token-pool.`);
7657
+ const explicitTokens = await collectTokensFromArgs(args, usage, deps, false);
7658
+ const pairs = resolveTokenRegionPairs(explicitTokens, regionCode, deps);
7659
+ const toErrorResult = (token, region, error) => ({
7660
+ token_masked: maskToken(token),
7661
+ region,
7662
+ error: error instanceof Error ? error.message : String(error)
7663
+ });
7664
+ const fetchPoints = async ({ token, region }) => {
7665
+ try {
7666
+ return { token_masked: maskToken(token), region, points: await getCredit(token, buildRegionInfo(region)) };
7667
+ } catch (error) {
7668
+ return toErrorResult(token, region, error);
7391
7669
  }
7392
- return { token, region: finalRegion };
7393
- }) : session_pool_default.getEntries(false).filter((item) => item.enabled && item.live !== false && item.region).filter((item) => regionCode ? item.region === regionCode : true).map((item) => ({ token: item.token, region: item.region }));
7394
- if (resolvedTokens.length === 0) {
7395
- deps.fail("No token available. Provide --token or configure token-pool.");
7396
- }
7397
- const payload = action === "points" ? await Promise.all(
7398
- resolvedTokens.map(async (item) => ({
7399
- token: item.token,
7400
- points: await getCredit(item.token, buildRegionInfo(item.region))
7401
- }))
7402
- ) : await Promise.all(
7403
- resolvedTokens.map(async (item) => {
7404
- const currentCredit = await getCredit(item.token, buildRegionInfo(item.region));
7405
- if (currentCredit.totalCredit <= 0) {
7406
- try {
7407
- await receiveCredit(item.token, buildRegionInfo(item.region));
7408
- const updatedCredit = await getCredit(item.token, buildRegionInfo(item.region));
7409
- return { token: item.token, credits: updatedCredit, received: true };
7410
- } catch (error) {
7411
- return {
7412
- token: item.token,
7413
- credits: currentCredit,
7414
- received: false,
7415
- error: (error == null ? void 0 : error.message) || String(error)
7416
- };
7417
- }
7670
+ };
7671
+ const processReceive = async ({ token, region }) => {
7672
+ const regionInfo = buildRegionInfo(region);
7673
+ try {
7674
+ const currentCredit = await getCredit(token, regionInfo);
7675
+ if (currentCredit.totalCredit > 0) {
7676
+ return { token_masked: maskToken(token), region, credits: currentCredit, received: false };
7418
7677
  }
7419
- return { token: item.token, credits: currentCredit, received: false };
7420
- })
7421
- );
7678
+ try {
7679
+ await receiveCredit(token, regionInfo);
7680
+ const updatedCredit = await getCredit(token, regionInfo);
7681
+ return { token_masked: maskToken(token), region, credits: updatedCredit, received: true };
7682
+ } catch (error) {
7683
+ return { token_masked: maskToken(token), region, credits: currentCredit, received: false, ...toErrorResult(token, region, error) };
7684
+ }
7685
+ } catch (error) {
7686
+ return toErrorResult(token, region, error);
7687
+ }
7688
+ };
7689
+ const payload = action === "points" ? await Promise.all(pairs.map(fetchPoints)) : await Promise.all(pairs.map(processReceive));
7422
7690
  if (args.json) {
7423
7691
  deps.printCommandJson(`token.${action}`, payload);
7424
7692
  return;
@@ -7435,28 +7703,32 @@ function createTokenSubcommands(deps) {
7435
7703
  console.log(usage);
7436
7704
  return;
7437
7705
  }
7438
- const region = deps.getRegionWithDefault(args);
7439
7706
  await deps.ensureTokenPoolReady();
7440
7707
  const tokens = await collectTokensFromArgs(args, usage, deps, true);
7441
- const regionCode = deps.parseRegionOrFail(region);
7442
- const payload = action === "add" ? {
7443
- ...await session_pool_default.addTokens(tokens, { defaultRegion: regionCode || void 0 }),
7444
- summary: session_pool_default.getSummary()
7445
- } : {
7446
- ...await session_pool_default.removeTokens(tokens),
7447
- summary: session_pool_default.getSummary()
7448
- };
7708
+ let payload;
7709
+ let jsonMeta;
7710
+ if (action === "add") {
7711
+ const region = deps.getRegionWithDefault(args);
7712
+ const regionCode = deps.parseRegionOrFail(region);
7713
+ payload = {
7714
+ ...await session_pool_default.addTokens(tokens, { defaultRegion: regionCode || void 0 }),
7715
+ summary: session_pool_default.getSummary()
7716
+ };
7717
+ jsonMeta = { region };
7718
+ } else {
7719
+ payload = {
7720
+ ...await session_pool_default.removeTokens(tokens),
7721
+ summary: session_pool_default.getSummary()
7722
+ };
7723
+ }
7449
7724
  if (args.json) {
7450
- deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload), { region });
7725
+ deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload), jsonMeta);
7451
7726
  return;
7452
7727
  }
7453
7728
  deps.printJson(deps.unwrapBody(payload));
7454
7729
  };
7455
7730
  const handleTokenEnableOrDisable = async (argv, action) => {
7456
- const args = (0, import_minimist2.default)(argv, {
7457
- string: ["token"],
7458
- boolean: ["help", "json"]
7459
- });
7731
+ const args = (0, import_minimist2.default)(argv, { string: ["token"], boolean: ["help", "json"] });
7460
7732
  const usage = deps.getUsage(action);
7461
7733
  if (args.help) {
7462
7734
  console.log(usage);
@@ -7478,353 +7750,156 @@ function createTokenSubcommands(deps) {
7478
7750
  deps.printJson(deps.unwrapBody(payload));
7479
7751
  };
7480
7752
  const handleTokenPool = async (argv) => {
7481
- const args = (0, import_minimist2.default)(argv, {
7482
- boolean: ["help", "json"]
7483
- });
7484
- const usage = deps.getUsage("pool");
7485
- if (args.help) {
7486
- console.log(usage);
7487
- return;
7488
- }
7489
- await deps.ensureTokenPoolReady();
7490
- const normalized = buildTokenPoolSnapshot();
7491
- if (args.json) {
7492
- deps.printCommandJson("token.pool", normalized);
7493
- return;
7494
- }
7495
- const body = normalized && typeof normalized === "object" ? normalized : {};
7496
- console.log("Summary:");
7497
- deps.printJson(body.summary ?? {});
7498
- console.log("Entries:");
7499
- printTokenEntriesTable(Array.isArray(body.items) ? body.items : []);
7500
- };
7501
- const handleTokenPoolCheckOrReload = async (argv, action) => {
7502
- const args = (0, import_minimist2.default)(argv, {
7503
- boolean: ["help", "json"]
7504
- });
7505
- const usage = deps.getUsage(action);
7753
+ const args = (0, import_minimist2.default)(argv, { boolean: ["help", "json"] });
7506
7754
  if (args.help) {
7507
- console.log(usage);
7755
+ console.log(deps.getUsage("pool"));
7508
7756
  return;
7509
7757
  }
7510
7758
  await deps.ensureTokenPoolReady();
7511
- const payload = action === "pool-check" ? {
7512
- ...await session_pool_default.runHealthCheck(),
7513
- summary: session_pool_default.getSummary()
7514
- } : (await session_pool_default.reloadFromDisk(), {
7515
- reloaded: true,
7516
- summary: session_pool_default.getSummary(),
7517
- items: buildTokenPoolSnapshot().items
7518
- });
7519
- if (args.json) {
7520
- deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload));
7521
- return;
7522
- }
7523
- deps.printJson(deps.unwrapBody(payload));
7524
- };
7525
- return [
7526
- {
7527
- name: "list",
7528
- description: "List token pool entries",
7529
- usageLine: " jimeng token list [options]",
7530
- options: [deps.jsonOption, deps.helpOption],
7531
- handler: handleTokenList
7532
- },
7533
- {
7534
- name: "check",
7535
- description: "Validate tokens directly",
7536
- usageLine: " jimeng token check --token <token> [--token <token> ...] [options]",
7537
- options: [
7538
- " --token <token> Token, can be repeated",
7539
- " --token-file <path> Read tokens from file (one per line, # for comments)",
7540
- " --region <region> X-Region, default cn (cn/us/hk/jp/sg)",
7541
- deps.jsonOption,
7542
- deps.helpOption
7543
- ],
7544
- handler: handleTokenCheck
7545
- },
7546
- {
7547
- name: "points",
7548
- description: "Query token points directly",
7549
- usageLine: " jimeng token points [options]",
7550
- options: [
7551
- " --token <token> Token, can be repeated",
7552
- " --token-file <path> Read tokens from file (one per line, # for comments)",
7553
- " --region <region> Filter tokens by X-Region, default cn (cn/us/hk/jp/sg)",
7554
- deps.jsonOption,
7555
- deps.helpOption
7556
- ],
7557
- handler: async (argv) => handleTokenPointsOrReceive(argv, "points")
7558
- },
7559
- {
7560
- name: "receive",
7561
- description: "Receive token credits directly",
7562
- usageLine: " jimeng token receive [options]",
7563
- options: [
7564
- " --token <token> Token, can be repeated",
7565
- " --token-file <path> Read tokens from file (one per line, # for comments)",
7566
- " --region <region> Filter tokens by X-Region, default cn (cn/us/hk/jp/sg)",
7567
- deps.jsonOption,
7568
- deps.helpOption
7569
- ],
7570
- handler: async (argv) => handleTokenPointsOrReceive(argv, "receive")
7571
- },
7572
- {
7573
- name: "add",
7574
- description: "Add token(s) into token-pool",
7575
- usageLine: " jimeng token add --token <token> [--token <token> ...] [options]",
7576
- options: [
7577
- " --token <token> Token, can be repeated",
7578
- " --token-file <path> Read tokens from file (one per line, # for comments)",
7579
- " --region <region> Region for add, default cn (cn/us/hk/jp/sg)",
7580
- deps.jsonOption,
7581
- deps.helpOption
7582
- ],
7583
- handler: async (argv) => handleTokenAddOrRemove(argv, "add")
7584
- },
7585
- {
7586
- name: "remove",
7587
- description: "Remove token(s) from token-pool",
7588
- usageLine: " jimeng token remove --token <token> [--token <token> ...] [options]",
7589
- options: [
7590
- " --token <token> Token, can be repeated",
7591
- " --token-file <path> Read tokens from file (one per line, # for comments)",
7592
- deps.jsonOption,
7593
- deps.helpOption
7594
- ],
7595
- handler: async (argv) => handleTokenAddOrRemove(argv, "remove")
7596
- },
7597
- {
7598
- name: "enable",
7599
- description: "Enable one token in token-pool",
7600
- usageLine: " jimeng token enable --token <token> [options]",
7601
- options: [" --token <token> Required, a single token", deps.jsonOption, deps.helpOption],
7602
- handler: async (argv) => handleTokenEnableOrDisable(argv, "enable")
7603
- },
7604
- {
7605
- name: "disable",
7606
- description: "Disable one token in token-pool",
7607
- usageLine: " jimeng token disable --token <token> [options]",
7608
- options: [" --token <token> Required, a single token", deps.jsonOption, deps.helpOption],
7609
- handler: async (argv) => handleTokenEnableOrDisable(argv, "disable")
7610
- },
7611
- {
7612
- name: "pool",
7613
- description: "Show token-pool summary and entries",
7614
- usageLine: " jimeng token pool [options]",
7615
- options: [deps.jsonOption, deps.helpOption],
7616
- handler: handleTokenPool
7617
- },
7618
- {
7619
- name: "pool-check",
7620
- description: "Trigger token-pool health check",
7621
- usageLine: " jimeng token pool-check [options]",
7622
- options: [deps.jsonOption, deps.helpOption],
7623
- handler: async (argv) => handleTokenPoolCheckOrReload(argv, "pool-check")
7624
- },
7625
- {
7626
- name: "pool-reload",
7627
- description: "Reload token-pool from disk",
7628
- usageLine: " jimeng token pool-reload [options]",
7629
- options: [deps.jsonOption, deps.helpOption],
7630
- handler: async (argv) => handleTokenPoolCheckOrReload(argv, "pool-reload")
7631
- }
7632
- ];
7633
- }
7634
-
7635
- // src/cli/query-commands.ts
7636
- var import_minimist3 = __toESM(require("minimist"), 1);
7637
-
7638
- // src/api/controllers/models.ts
7639
- var CACHE_TTL_MS = 10 * 60 * 1e3;
7640
- var FALLBACK_TOKEN = "test_token";
7641
- var modelCache = /* @__PURE__ */ new Map();
7642
- function mapVideoDescription(id) {
7643
- if (id.includes("veo3.1")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B veo3.1";
7644
- if (id.includes("veo3")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B veo3";
7645
- if (id.includes("sora2")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B sora2";
7646
- if (id.includes("seedance-2.0-fast")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B seedance 2.0-fast";
7647
- if (id.includes("seedance-2.0")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B seedance 2.0";
7648
- if (id.includes("3.5-pro")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 3.5 \u4E13\u4E1A\u7248";
7649
- if (id.includes("3.0-fast")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 3.0 \u6781\u901F\u7248";
7650
- if (id.includes("3.0-pro")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 3.0 \u4E13\u4E1A\u7248";
7651
- if (id.includes("3.0")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 3.0";
7652
- if (id.includes("2.0-pro")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 2.0 \u4E13\u4E1A\u7248";
7653
- if (id.includes("2.0")) return "\u5373\u68A6AI\u89C6\u9891\u751F\u6210\u6A21\u578B 2.0";
7654
- return void 0;
7655
- }
7656
- function mapImageDescription(id) {
7657
- if (id.includes("5.0")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 5.0";
7658
- if (id.includes("4.6")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 4.6";
7659
- if (id.includes("4.5")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 4.5";
7660
- if (id.includes("4.1")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 4.1";
7661
- if (id.includes("4.0")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 4.0";
7662
- if (id.includes("3.1")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 3.1";
7663
- if (id.includes("3.0")) return "\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B 3.0";
7664
- return `\u5373\u68A6AI\u56FE\u50CF\u6A21\u578B ${id}`;
7665
- }
7666
- function buildModelItem(modelId, meta) {
7667
- var _a;
7668
- const modelType = modelId.startsWith("jimeng-video-") ? "video" : "image";
7669
- const item = {
7670
- id: modelId,
7671
- object: "model",
7672
- owned_by: "jimeng-cli",
7673
- model_type: modelType
7674
- };
7675
- if (meta == null ? void 0 : meta.reqKey) item.model_req_key = meta.reqKey;
7676
- if (meta == null ? void 0 : meta.modelName) item.model_name = meta.modelName;
7677
- if ((_a = meta == null ? void 0 : meta.capabilities) == null ? void 0 : _a.length) item.capabilities = Array.from(new Set(meta.capabilities)).sort();
7678
- if (meta == null ? void 0 : meta.modelTip) {
7679
- item.description = meta.modelTip;
7680
- } else if (modelType === "video") {
7681
- item.description = mapVideoDescription(modelId);
7682
- } else {
7683
- item.description = mapImageDescription(modelId);
7684
- }
7685
- return item;
7686
- }
7687
- function parseFirstToken(authorization) {
7688
- var _a;
7689
- if (!authorization || !/^Bearer\s+/i.test(authorization)) return void 0;
7690
- const raw = authorization.replace(/^Bearer\s+/i, "").trim();
7691
- if (!raw) return void 0;
7692
- const first = (_a = raw.split(",")[0]) == null ? void 0 : _a.trim();
7693
- return first || void 0;
7694
- }
7695
- function resolveToken(authorization) {
7696
- const fromAuth = parseFirstToken(authorization);
7697
- if (fromAuth) return fromAuth;
7698
- const fromPool = session_pool_default.getAllTokens({ onlyEnabled: true, preferLive: true })[0];
7699
- return fromPool || void 0;
7700
- }
7701
- function getRegionalMaps(region) {
7702
- if (region === "us") return [IMAGE_MODEL_MAP_US, VIDEO_MODEL_MAP_US];
7703
- if (region === "hk" || region === "jp" || region === "sg") return [IMAGE_MODEL_MAP_ASIA, VIDEO_MODEL_MAP_ASIA];
7704
- if (region === "cn") return [IMAGE_MODEL_MAP, VIDEO_MODEL_MAP];
7705
- return [IMAGE_MODEL_MAP, IMAGE_MODEL_MAP_US, IMAGE_MODEL_MAP_ASIA, VIDEO_MODEL_MAP, VIDEO_MODEL_MAP_US, VIDEO_MODEL_MAP_ASIA];
7706
- }
7707
- function resolveRegion(authorization, xRegion) {
7708
- var _a;
7709
- const token = resolveToken(authorization);
7710
- const parsedXRegion = parseRegionCode(xRegion);
7711
- if (parsedXRegion) return parsedXRegion;
7712
- if (token) {
7713
- assertTokenWithoutRegionPrefix(token);
7714
- const normalizedToken = parseProxyFromToken(token).token;
7715
- const poolRegion = (_a = session_pool_default.getTokenEntry(normalizedToken)) == null ? void 0 : _a.region;
7716
- if (poolRegion) return poolRegion;
7717
- throw new Error("\u7F3A\u5C11 region\u3002token \u672A\u5728 pool \u4E2D\u6CE8\u518C\u65F6\uFF0C/v1/models \u9700\u8981\u63D0\u4F9B\u8BF7\u6C42\u5934 X-Region");
7718
- }
7719
- return "cn";
7720
- }
7721
- function buildReverseMap(region) {
7722
- const reverse = {};
7723
- for (const map of getRegionalMaps(region)) {
7724
- for (const [modelId, upstreamKey] of Object.entries(map)) {
7725
- reverse[upstreamKey] = modelId;
7726
- }
7727
- }
7728
- return reverse;
7729
- }
7730
- function buildFallbackModels(region) {
7731
- const maps = getRegionalMaps(region);
7732
- const modelIds = Array.from(new Set(maps.flatMap((item) => Object.keys(item)))).sort();
7733
- return modelIds.map((id) => buildModelItem(id));
7734
- }
7735
- function makeCacheKey(region) {
7736
- return `models|${region}`;
7737
- }
7738
- function resolveFetchToken(token) {
7739
- if (!token) return FALLBACK_TOKEN;
7740
- const normalizedToken = parseProxyFromToken(token).token;
7741
- assertTokenWithoutRegionPrefix(normalizedToken);
7742
- return normalizedToken;
7743
- }
7744
- function extractCapabilities(item) {
7745
- const features = Array.isArray(item.feats) ? item.feats.filter((feature) => typeof feature === "string" && feature.length > 0) : [];
7746
- const options = Array.isArray(item.options) ? item.options.map(
7747
- (option) => option && typeof option === "object" && typeof option.key === "string" ? option.key : void 0
7748
- ).filter((key) => typeof key === "string" && key.length > 0) : [];
7749
- return Array.from(/* @__PURE__ */ new Set([...features, ...options]));
7750
- }
7751
- async function fetchConfigModelReqKeys(token, region) {
7752
- const regionInfo = buildRegionInfo(region);
7753
- const imageConfig = await request("post", "/mweb/v1/get_common_config", token, regionInfo, {
7754
- data: {},
7755
- params: { needCache: true, needRefresh: false }
7756
- });
7757
- const videoConfig = await request("post", "/mweb/v1/video_generate/get_common_config", token, regionInfo, {
7758
- data: { scene: "generate_video", params: {} }
7759
- });
7760
- const imageModels = Array.isArray(imageConfig == null ? void 0 : imageConfig.model_list) ? imageConfig.model_list.map((item) => {
7761
- const reqKey = item == null ? void 0 : item.model_req_key;
7762
- if (typeof reqKey !== "string" || reqKey.length === 0) return void 0;
7763
- return {
7764
- reqKey,
7765
- modelName: typeof (item == null ? void 0 : item.model_name) === "string" ? item.model_name : void 0,
7766
- modelTip: typeof (item == null ? void 0 : item.model_tip) === "string" ? item.model_tip : void 0,
7767
- capabilities: extractCapabilities(item)
7768
- };
7769
- }).filter((item) => Boolean(item)) : [];
7770
- const videoModels = Array.isArray(videoConfig == null ? void 0 : videoConfig.model_list) ? videoConfig.model_list.map((item) => {
7771
- const reqKey = item == null ? void 0 : item.model_req_key;
7772
- if (typeof reqKey !== "string" || reqKey.length === 0) return void 0;
7773
- return {
7774
- reqKey,
7775
- modelName: typeof (item == null ? void 0 : item.model_name) === "string" ? item.model_name : void 0,
7776
- modelTip: typeof (item == null ? void 0 : item.model_tip) === "string" ? item.model_tip : void 0,
7777
- capabilities: extractCapabilities(item)
7778
- };
7779
- }).filter((item) => Boolean(item)) : [];
7780
- return { imageModels, videoModels };
7781
- }
7782
- async function getLiveModels(authorization, xRegion) {
7783
- const region = resolveRegion(authorization, xRegion);
7784
- const token = resolveToken(authorization);
7785
- const effectiveToken = resolveFetchToken(token);
7786
- const cacheKey = makeCacheKey(region);
7787
- const cached = modelCache.get(cacheKey);
7788
- if (cached && cached.expiresAt > Date.now()) {
7789
- return { source: cached.source, data: cached.data };
7790
- }
7791
- try {
7792
- const reverseMap = buildReverseMap(region);
7793
- const { imageModels, videoModels } = await fetchConfigModelReqKeys(effectiveToken, region);
7794
- const upstreamModels = [...imageModels, ...videoModels];
7795
- const metaByModelId = /* @__PURE__ */ new Map();
7796
- const mapped = upstreamModels.map((model) => {
7797
- const modelId = reverseMap[model.reqKey];
7798
- if (modelId && !metaByModelId.has(modelId)) {
7799
- metaByModelId.set(modelId, model);
7800
- }
7801
- return modelId;
7802
- }).filter((item) => typeof item === "string" && item.length > 0);
7803
- const modelIds = Array.from(new Set(mapped)).sort();
7804
- if (modelIds.length === 0) {
7805
- throw new Error("model_req_key resolved but none matched local reverse map");
7759
+ const snapshot = buildTokenPoolSnapshot();
7760
+ if (args.json) {
7761
+ deps.printCommandJson("token.pool", snapshot);
7762
+ return;
7806
7763
  }
7807
- const data = modelIds.map((id) => buildModelItem(id, metaByModelId.get(id)));
7808
- modelCache.set(cacheKey, {
7809
- expiresAt: Date.now() + CACHE_TTL_MS,
7810
- source: "upstream",
7811
- data
7812
- });
7813
- return { source: "upstream", data };
7814
- } catch {
7815
- const data = buildFallbackModels(region);
7816
- modelCache.set(cacheKey, {
7817
- expiresAt: Date.now() + CACHE_TTL_MS,
7818
- source: "fallback",
7819
- data
7820
- });
7821
- return { source: "fallback", data };
7822
- }
7823
- }
7824
- async function refreshAllTokenModels() {
7825
- return session_pool_default.refreshAllDynamicCapabilities();
7764
+ const body = snapshot && typeof snapshot === "object" ? snapshot : {};
7765
+ console.log("Summary:");
7766
+ deps.printJson(body.summary ?? {});
7767
+ console.log("Entries:");
7768
+ printTokenEntriesTable(Array.isArray(body.items) ? body.items : []);
7769
+ };
7770
+ const handleTokenPoolCheckOrReload = async (argv, action) => {
7771
+ const args = (0, import_minimist2.default)(argv, { boolean: ["help", "json"] });
7772
+ if (args.help) {
7773
+ console.log(deps.getUsage(action));
7774
+ return;
7775
+ }
7776
+ await deps.ensureTokenPoolReady();
7777
+ let payload;
7778
+ if (action === "pool-check") {
7779
+ payload = { ...await session_pool_default.runHealthCheck(), summary: session_pool_default.getSummary() };
7780
+ } else {
7781
+ session_pool_default.reloadFromDisk();
7782
+ payload = { reloaded: true, summary: session_pool_default.getSummary(), items: buildTokenPoolSnapshot().items };
7783
+ }
7784
+ if (args.json) {
7785
+ deps.printCommandJson(`token.${action}`, deps.unwrapBody(payload));
7786
+ return;
7787
+ }
7788
+ deps.printJson(deps.unwrapBody(payload));
7789
+ };
7790
+ return [
7791
+ {
7792
+ name: "list",
7793
+ description: "List token pool entries",
7794
+ usageLine: " jimeng token list [options]",
7795
+ options: [deps.jsonOption, deps.helpOption],
7796
+ handler: handleTokenList
7797
+ },
7798
+ {
7799
+ name: "check",
7800
+ description: "Validate tokens",
7801
+ usageLine: " jimeng token check [options]",
7802
+ options: [
7803
+ " --token <token> Token, can be repeated (default: all enabled tokens)",
7804
+ " --token-file <path> Read tokens from file (one per line, # for comments)",
7805
+ " --region <region> Override region (default: token's registered region)",
7806
+ deps.jsonOption,
7807
+ deps.helpOption
7808
+ ],
7809
+ handler: handleTokenCheck
7810
+ },
7811
+ {
7812
+ name: "points",
7813
+ description: "Query token points",
7814
+ usageLine: " jimeng token points [options]",
7815
+ options: [
7816
+ " --token <token> Token, can be repeated",
7817
+ " --token-file <path> Read tokens from file (one per line, # for comments)",
7818
+ " --region <region> Filter tokens by region (cn/us/hk/jp/sg)",
7819
+ deps.jsonOption,
7820
+ deps.helpOption
7821
+ ],
7822
+ handler: async (argv) => handleTokenPointsOrReceive(argv, "points")
7823
+ },
7824
+ {
7825
+ name: "receive",
7826
+ description: "Receive token credits",
7827
+ usageLine: " jimeng token receive [options]",
7828
+ options: [
7829
+ " --token <token> Token, can be repeated",
7830
+ " --token-file <path> Read tokens from file (one per line, # for comments)",
7831
+ " --region <region> Filter tokens by region (cn/us/hk/jp/sg)",
7832
+ deps.jsonOption,
7833
+ deps.helpOption
7834
+ ],
7835
+ handler: async (argv) => handleTokenPointsOrReceive(argv, "receive")
7836
+ },
7837
+ {
7838
+ name: "add",
7839
+ description: "Add token(s) into token-pool",
7840
+ usageLine: " jimeng token add --token <token> [--token <token> ...] [options]",
7841
+ options: [
7842
+ " --token <token> Token, can be repeated",
7843
+ " --token-file <path> Read tokens from file (one per line, # for comments)",
7844
+ " --region <region> Region for add, default cn (cn/us/hk/jp/sg)",
7845
+ deps.jsonOption,
7846
+ deps.helpOption
7847
+ ],
7848
+ handler: async (argv) => handleTokenAddOrRemove(argv, "add")
7849
+ },
7850
+ {
7851
+ name: "remove",
7852
+ description: "Remove token(s) from token-pool",
7853
+ usageLine: " jimeng token remove --token <token> [--token <token> ...] [options]",
7854
+ options: [
7855
+ " --token <token> Token, can be repeated",
7856
+ " --token-file <path> Read tokens from file (one per line, # for comments)",
7857
+ deps.jsonOption,
7858
+ deps.helpOption
7859
+ ],
7860
+ handler: async (argv) => handleTokenAddOrRemove(argv, "remove")
7861
+ },
7862
+ {
7863
+ name: "enable",
7864
+ description: "Enable one token in token-pool",
7865
+ usageLine: " jimeng token enable --token <token> [options]",
7866
+ options: [" --token <token> Required, a single token", deps.jsonOption, deps.helpOption],
7867
+ handler: async (argv) => handleTokenEnableOrDisable(argv, "enable")
7868
+ },
7869
+ {
7870
+ name: "disable",
7871
+ description: "Disable one token in token-pool",
7872
+ usageLine: " jimeng token disable --token <token> [options]",
7873
+ options: [" --token <token> Required, a single token", deps.jsonOption, deps.helpOption],
7874
+ handler: async (argv) => handleTokenEnableOrDisable(argv, "disable")
7875
+ },
7876
+ {
7877
+ name: "pool",
7878
+ description: "Show token-pool summary and entries",
7879
+ usageLine: " jimeng token pool [options]",
7880
+ options: [deps.jsonOption, deps.helpOption],
7881
+ handler: handleTokenPool
7882
+ },
7883
+ {
7884
+ name: "pool-check",
7885
+ description: "Trigger token-pool health check",
7886
+ usageLine: " jimeng token pool-check [options]",
7887
+ options: [deps.jsonOption, deps.helpOption],
7888
+ handler: async (argv) => handleTokenPoolCheckOrReload(argv, "pool-check")
7889
+ },
7890
+ {
7891
+ name: "pool-reload",
7892
+ description: "Reload token-pool from disk",
7893
+ usageLine: " jimeng token pool-reload [options]",
7894
+ options: [deps.jsonOption, deps.helpOption],
7895
+ handler: async (argv) => handleTokenPoolCheckOrReload(argv, "pool-reload")
7896
+ }
7897
+ ];
7826
7898
  }
7827
7899
 
7900
+ // src/cli/query-commands.ts
7901
+ var import_minimist3 = __toESM(require("minimist"), 1);
7902
+
7828
7903
  // src/lib/smart-poller.ts
7829
7904
  var SmartPoller = class {
7830
7905
  pollCount = 0;
@@ -7851,7 +7926,7 @@ var SmartPoller = class {
7851
7926
  /**
7852
7927
  * 根据状态码计算智能轮询间隔
7853
7928
  */
7854
- getSmartInterval(status, itemCount) {
7929
+ getSmartInterval(status, _itemCount) {
7855
7930
  const baseInterval = this.options.pollInterval;
7856
7931
  switch (status) {
7857
7932
  case 20:
@@ -7888,9 +7963,6 @@ var SmartPoller = class {
7888
7963
  if (status === 30) {
7889
7964
  return { shouldExit: true, reason: "\u4EFB\u52A1\u5931\u8D25" };
7890
7965
  }
7891
- if (itemCount >= this.options.expectedItemCount && (status === 10 || status === 50)) {
7892
- return { shouldExit: true, reason: `\u5DF2\u83B7\u5F97\u5B8C\u6574\u7ED3\u679C\u96C6(${itemCount}/${this.options.expectedItemCount})` };
7893
- }
7894
7966
  if (this.pollCount >= this.options.maxPollCount) {
7895
7967
  return { shouldExit: true, reason: "\u8F6E\u8BE2\u6B21\u6570\u8D85\u9650" };
7896
7968
  }
@@ -7907,6 +7979,7 @@ var SmartPoller = class {
7907
7979
  logger_default.info(`\u5F00\u59CB\u667A\u80FD\u8F6E\u8BE2: historyId=${historyId || "N/A"}, \u6700\u5927\u8F6E\u8BE2\u6B21\u6570=${this.options.maxPollCount}, \u671F\u671B\u7ED3\u679C\u6570=${this.options.expectedItemCount}`);
7908
7980
  let lastData;
7909
7981
  let lastStatus = { status: 20, itemCount: 0 };
7982
+ let exitReason = "";
7910
7983
  while (true) {
7911
7984
  this.pollCount++;
7912
7985
  const elapsedTime = Math.round((Date.now() - this.startTime) / 1e3);
@@ -7920,6 +7993,7 @@ var SmartPoller = class {
7920
7993
  }
7921
7994
  const { shouldExit, reason } = this.shouldExitPolling(status);
7922
7995
  if (shouldExit) {
7996
+ exitReason = reason;
7923
7997
  logger_default.info(`\u9000\u51FA\u8F6E\u8BE2: ${reason}, \u6700\u7EC8${this.options.type === "image" ? "\u56FE\u7247" : "\u89C6\u9891"}\u6570\u91CF=${status.itemCount}`);
7924
7998
  if (status.status === 30) {
7925
7999
  handleGenerationFailure(status.status, status.failCode, historyId, this.options.type, status.itemCount);
@@ -7931,7 +8005,8 @@ var SmartPoller = class {
7931
8005
  elapsedTime,
7932
8006
  status.status,
7933
8007
  status.itemCount,
7934
- historyId
8008
+ historyId,
8009
+ this.options.type
7935
8010
  );
7936
8011
  }
7937
8012
  break;
@@ -7975,7 +8050,7 @@ var SmartPoller = class {
7975
8050
  itemCount: lastStatus.itemCount,
7976
8051
  elapsedTime: finalElapsedTime,
7977
8052
  pollCount: this.pollCount,
7978
- exitReason: this.shouldExitPolling(lastStatus).reason
8053
+ exitReason
7979
8054
  };
7980
8055
  logger_default.info(`${this.options.type === "image" ? "\u56FE\u50CF" : "\u89C6\u9891"}\u751F\u6210\u5B8C\u6210: \u6210\u529F\u751F\u6210 ${lastStatus.itemCount} \u4E2A\u7ED3\u679C\uFF0C\u603B\u8017\u65F6 ${finalElapsedTime} \u79D2\uFF0C\u6700\u7EC8\u72B6\u6001: ${this.getStatusName(lastStatus.status)}`);
7981
8056
  return { result, data: lastData };
@@ -8021,17 +8096,20 @@ function extractImageUrls(itemList) {
8021
8096
  return itemList.map((item, index) => extractImageUrl(item, index)).filter((url) => url !== null);
8022
8097
  }
8023
8098
  function extractVideoUrl(item) {
8024
- var _a, _b, _c, _d, _e, _f;
8025
- if ((_c = (_b = (_a = item == null ? void 0 : item.video) == null ? void 0 : _a.transcoded_video) == null ? void 0 : _b.origin) == null ? void 0 : _c.video_url) {
8099
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
8100
+ if ((_c = (_b = (_a = item == null ? void 0 : item.common_attr) == null ? void 0 : _a.transcoded_video) == null ? void 0 : _b.origin) == null ? void 0 : _c.video_url) {
8101
+ return item.common_attr.transcoded_video.origin.video_url;
8102
+ }
8103
+ if ((_f = (_e = (_d = item == null ? void 0 : item.video) == null ? void 0 : _d.transcoded_video) == null ? void 0 : _e.origin) == null ? void 0 : _f.video_url) {
8026
8104
  return item.video.transcoded_video.origin.video_url;
8027
8105
  }
8028
- if ((_d = item == null ? void 0 : item.video) == null ? void 0 : _d.play_url) {
8106
+ if ((_g = item == null ? void 0 : item.video) == null ? void 0 : _g.play_url) {
8029
8107
  return item.video.play_url;
8030
8108
  }
8031
- if ((_e = item == null ? void 0 : item.video) == null ? void 0 : _e.download_url) {
8109
+ if ((_h = item == null ? void 0 : item.video) == null ? void 0 : _h.download_url) {
8032
8110
  return item.video.download_url;
8033
8111
  }
8034
- if ((_f = item == null ? void 0 : item.video) == null ? void 0 : _f.url) {
8112
+ if ((_i = item == null ? void 0 : item.video) == null ? void 0 : _i.url) {
8035
8113
  return item.video.url;
8036
8114
  }
8037
8115
  return null;
@@ -8061,20 +8139,15 @@ async function fetchHighQualityVideoUrl(itemId, refreshToken, regionInfo) {
8061
8139
  return videoUrl;
8062
8140
  }
8063
8141
  }
8064
- const hqUrlMatch = responseStr.match(/https:\/\/v[0-9]+-dreamnia\.jimeng\.com\/[^"\s\\]+/);
8065
- if (hqUrlMatch && hqUrlMatch[0]) {
8066
- logger_default.info(`\u6B63\u5219\u63D0\u53D6\u5230\u9AD8\u8D28\u91CF\u89C6\u9891URL (dreamnia): ${hqUrlMatch[0]}`);
8067
- return hqUrlMatch[0];
8068
- }
8069
- const jimengUrlMatch = responseStr.match(/https:\/\/v[0-9]+-[^"\\]*\.jimeng\.com\/[^"\s\\]+/);
8070
- if (jimengUrlMatch && jimengUrlMatch[0]) {
8071
- logger_default.info(`\u6B63\u5219\u63D0\u53D6\u5230jimeng\u89C6\u9891URL: ${jimengUrlMatch[0]}`);
8072
- return jimengUrlMatch[0];
8142
+ const cdnUrlMatch = responseStr.match(/https:\/\/v[0-9]+-[^"\\]*\.(jimeng|capcut|dreamina)\.com\/[^"\s\\]+/);
8143
+ if (cdnUrlMatch && cdnUrlMatch[0]) {
8144
+ logger_default.info(`\u6B63\u5219\u63D0\u53D6\u5230\u89C6\u9891URL: ${cdnUrlMatch[0]}`);
8145
+ return cdnUrlMatch[0];
8073
8146
  }
8074
- const anyVideoUrlMatch = responseStr.match(/https:\/\/v[0-9]+-[^"\\]*\.(vlabvod|jimeng)\.com\/[^"\s\\]+/);
8075
- if (anyVideoUrlMatch && anyVideoUrlMatch[0]) {
8076
- logger_default.info(`\u4ECEget_local_item_list\u63D0\u53D6\u5230\u89C6\u9891URL: ${anyVideoUrlMatch[0]}`);
8077
- return anyVideoUrlMatch[0];
8147
+ const vlabUrlMatch = responseStr.match(/https:\/\/v[0-9]+-[^"\\]*\.vlabvod\.com\/[^"\s\\]+/);
8148
+ if (vlabUrlMatch && vlabUrlMatch[0]) {
8149
+ logger_default.info(`\u6B63\u5219\u63D0\u53D6\u5230\u89C6\u9891URL: ${vlabUrlMatch[0]}`);
8150
+ return vlabUrlMatch[0];
8078
8151
  }
8079
8152
  logger_default.warn(`\u672A\u80FD\u4ECEget_local_item_list\u54CD\u5E94\u4E2D\u63D0\u53D6\u5230\u89C6\u9891URL`);
8080
8153
  return null;
@@ -8327,11 +8400,71 @@ function printTaskInfo(task, deps) {
8327
8400
  deps.printJson(task.data);
8328
8401
  }
8329
8402
  }
8403
+ function outputTaskResult(command, normalized, isJson, deps) {
8404
+ const taskInfo = collectTaskInfo(normalized, deps);
8405
+ if (!taskInfo) {
8406
+ const body = deps.unwrapBody(normalized);
8407
+ if (isJson) deps.printCommandJson(command, body);
8408
+ else deps.printJson(body);
8409
+ return;
8410
+ }
8411
+ if (isJson) deps.printCommandJson(command, taskInfo);
8412
+ else printTaskInfo(taskInfo, deps);
8413
+ }
8414
+ function resolveSingleQueryToken(explicitToken, explicitRegion, deps) {
8415
+ var _a;
8416
+ const regionCode = explicitRegion ? deps.parseRegionOrFail(explicitRegion) : void 0;
8417
+ if (explicitToken) {
8418
+ const poolRegion = (_a = session_pool_default.getTokenEntry(explicitToken)) == null ? void 0 : _a.region;
8419
+ const region = regionCode || poolRegion;
8420
+ if (!region) {
8421
+ deps.fail("Missing region for token. Provide --region or register token in token-pool.");
8422
+ }
8423
+ return { token: explicitToken, region };
8424
+ }
8425
+ if (!regionCode) {
8426
+ const entry = session_pool_default.getEntries(false).find(
8427
+ (item) => item.enabled && item.live !== false && item.region
8428
+ );
8429
+ if (!entry) {
8430
+ deps.fail("No token available. Provide --token, --region, or --all.");
8431
+ }
8432
+ return { token: entry.token, region: entry.region };
8433
+ }
8434
+ return { token: void 0, region: regionCode };
8435
+ }
8436
+ function printModelIds(models) {
8437
+ for (const item of models) {
8438
+ if (!item || typeof item !== "object") continue;
8439
+ const id = item.id;
8440
+ if (typeof id === "string" && id.length > 0) console.log(id);
8441
+ }
8442
+ }
8443
+ function printModelVerbose(models) {
8444
+ for (const item of models) {
8445
+ if (!item || typeof item !== "object") continue;
8446
+ const m = item;
8447
+ const id = typeof m.id === "string" ? m.id : "";
8448
+ if (!id) continue;
8449
+ const type = typeof m.model_type === "string" ? m.model_type : "-";
8450
+ const desc = typeof m.description === "string" ? m.description : "-";
8451
+ const caps = Array.isArray(m.capabilities) ? m.capabilities.filter((c) => typeof c === "string").join(",") : "-";
8452
+ console.log(`${id} [${type}] ${desc}`);
8453
+ console.log(` capabilities: ${caps}`);
8454
+ const params = m.params;
8455
+ if (params && typeof params === "object") {
8456
+ for (const [key, vals] of Object.entries(params)) {
8457
+ if (Array.isArray(vals)) {
8458
+ console.log(` ${key}: ${vals.join(", ")}`);
8459
+ }
8460
+ }
8461
+ }
8462
+ console.log("");
8463
+ }
8464
+ }
8330
8465
  function createQueryCommandHandlers(deps) {
8331
8466
  const handleModelsRefresh = async (argv) => {
8332
- const args = (0, import_minimist3.default)(argv, {
8333
- boolean: ["help", "json"]
8334
- });
8467
+ const args = (0, import_minimist3.default)(argv, { boolean: ["help", "json"] });
8335
8468
  if (args.help) {
8336
8469
  console.log(deps.usageModelsRefresh());
8337
8470
  return;
@@ -8359,48 +8492,72 @@ function createQueryCommandHandlers(deps) {
8359
8492
  const handleModelsList = async (argv) => {
8360
8493
  const args = (0, import_minimist3.default)(argv, {
8361
8494
  string: ["region", "token"],
8362
- boolean: ["help", "json", "verbose"]
8495
+ boolean: ["help", "json", "verbose", "all"]
8363
8496
  });
8364
8497
  if (args.help) {
8365
8498
  console.log(deps.usageModelsList());
8366
8499
  return;
8367
8500
  }
8368
- const region = deps.getRegionWithDefault(args);
8369
- const parsedRegion = deps.parseRegionOrFail(region);
8370
- const token = deps.getSingleString(args, "token");
8501
+ const isJson = Boolean(args.json);
8502
+ const isVerbose = Boolean(args.verbose);
8503
+ const explicitRegion = deps.getSingleString(args, "region");
8504
+ const explicitToken = deps.getSingleString(args, "token");
8371
8505
  await deps.ensureTokenPoolReady();
8372
- const auth = token ? `Bearer ${token}` : void 0;
8373
- const direct = await getLiveModels(auth, parsedRegion || region);
8374
- const normalized = { object: "list", data: direct.data };
8375
- if (args.json) {
8376
- deps.printCommandJson("models.list", normalized, { region: region || null });
8506
+ if (args.all) {
8507
+ const entries = session_pool_default.getEntries(false).filter(
8508
+ (item) => item.enabled && item.live !== false && item.region
8509
+ );
8510
+ if (entries.length === 0) {
8511
+ deps.fail("No enabled+live tokens with region found in pool.");
8512
+ }
8513
+ const results = await Promise.all(
8514
+ entries.map(async (entry) => {
8515
+ const masked = maskToken(entry.token);
8516
+ try {
8517
+ const direct2 = await getLiveModels(`Bearer ${entry.token}`, entry.region);
8518
+ return {
8519
+ token: masked,
8520
+ region: entry.region,
8521
+ source: direct2.source,
8522
+ models: isVerbose ? direct2.data : direct2.data.map((m) => m.id)
8523
+ };
8524
+ } catch (error) {
8525
+ return { token: masked, region: entry.region, error: error instanceof Error ? error.message : String(error) };
8526
+ }
8527
+ })
8528
+ );
8529
+ if (isJson) {
8530
+ deps.printCommandJson("models.list", results);
8531
+ return;
8532
+ }
8533
+ for (const r of results) {
8534
+ console.log(`[${r.region}] ${r.token}`);
8535
+ if (r.error) {
8536
+ console.log(` error: ${r.error}`);
8537
+ } else if (isVerbose) {
8538
+ printModelVerbose(r.models);
8539
+ } else {
8540
+ for (const id of r.models) console.log(` ${id}`);
8541
+ }
8542
+ console.log("");
8543
+ }
8377
8544
  return;
8378
8545
  }
8379
- const data = normalized && typeof normalized === "object" && Array.isArray(normalized.data) ? normalized.data : [];
8380
- if (data.length === 0) {
8381
- deps.fail(`No models found in response: ${JSON.stringify(normalized)}`);
8382
- }
8383
- if (args.verbose) {
8384
- console.log("id type desc capabilities");
8385
- for (const item of data) {
8386
- if (!item || typeof item !== "object") continue;
8387
- const model = item;
8388
- const id = typeof model.id === "string" ? model.id : "";
8389
- if (!id) continue;
8390
- const modelType = typeof model.model_type === "string" ? model.model_type : "-";
8391
- const description = typeof model.description === "string" ? model.description : "-";
8392
- const capabilities = Array.isArray(model.capabilities) ? model.capabilities.filter((cap) => typeof cap === "string").join(",") : "-";
8393
- console.log(`${id} type=${modelType} desc=${description} capabilities=${capabilities}`);
8394
- }
8546
+ const { token, region } = resolveSingleQueryToken(explicitToken, explicitRegion, deps);
8547
+ const direct = await getLiveModels(token ? `Bearer ${token}` : void 0, region);
8548
+ const models = direct.data;
8549
+ if (isJson) {
8550
+ deps.printCommandJson("models.list", { object: "list", data: models }, {
8551
+ region: region || null,
8552
+ token: token ? `${token.slice(0, 4)}...` : null
8553
+ });
8395
8554
  return;
8396
8555
  }
8397
- for (const item of data) {
8398
- if (!item || typeof item !== "object") continue;
8399
- const id = item.id;
8400
- if (typeof id === "string" && id.length > 0) {
8401
- console.log(id);
8402
- }
8556
+ if (models.length === 0) {
8557
+ deps.fail("No models found.");
8403
8558
  }
8559
+ if (isVerbose) printModelVerbose(models);
8560
+ else printModelIds(models);
8404
8561
  };
8405
8562
  const handleTaskGet = async (argv) => {
8406
8563
  const args = (0, import_minimist3.default)(argv, {
@@ -8417,42 +8574,13 @@ function createQueryCommandHandlers(deps) {
8417
8574
  ${deps.usageTaskGet()}`);
8418
8575
  const type = parseTaskTypeOrFail(deps.getSingleString(args, "type"), deps);
8419
8576
  const responseFormat = parseResponseFormatOrFail(deps.getSingleString(args, "response-format"), deps);
8420
- const token = deps.getSingleString(args, "token");
8421
- const region = deps.getRegionWithDefault(args);
8422
- const isJson = Boolean(args.json);
8423
- const pick = await deps.pickDirectTokenForTask(token, region);
8424
- const normalized = await getTaskResponse(
8425
- taskId,
8426
- pick.token,
8427
- buildRegionInfo(pick.region),
8428
- {
8429
- type,
8430
- responseFormat
8431
- }
8432
- );
8433
- const taskInfo = collectTaskInfo(normalized, deps);
8434
- if (!taskInfo) {
8435
- if (isJson) {
8436
- deps.printCommandJson("task.get", deps.unwrapBody(normalized));
8437
- } else {
8438
- deps.printJson(deps.unwrapBody(normalized));
8439
- }
8440
- return;
8441
- }
8442
- if (isJson) deps.printCommandJson("task.get", taskInfo);
8443
- else printTaskInfo(taskInfo, deps);
8577
+ const pick = await deps.pickDirectTokenForTask(deps.getSingleString(args, "token"), deps.getSingleString(args, "region"));
8578
+ const normalized = await getTaskResponse(taskId, pick.token, buildRegionInfo(pick.region), { type, responseFormat });
8579
+ outputTaskResult("task.get", normalized, Boolean(args.json), deps);
8444
8580
  };
8445
8581
  const handleTaskWait = async (argv) => {
8446
8582
  const args = (0, import_minimist3.default)(argv, {
8447
- string: [
8448
- "token",
8449
- "region",
8450
- "task-id",
8451
- "type",
8452
- "response-format",
8453
- "wait-timeout-seconds",
8454
- "poll-interval-ms"
8455
- ],
8583
+ string: ["token", "region", "task-id", "type", "response-format", "wait-timeout-seconds", "poll-interval-ms"],
8456
8584
  boolean: ["help", "json"]
8457
8585
  });
8458
8586
  if (args.help) {
@@ -8463,41 +8591,18 @@ ${deps.usageTaskGet()}`);
8463
8591
  if (!taskId) deps.fail(`Missing required --task-id.
8464
8592
 
8465
8593
  ${deps.usageTaskWait()}`);
8466
- const token = deps.getSingleString(args, "token");
8467
- const region = deps.getRegionWithDefault(args);
8468
- const isJson = Boolean(args.json);
8469
- const body = {};
8470
8594
  const type = parseTaskTypeOrFail(deps.getSingleString(args, "type"), deps);
8471
8595
  const responseFormat = parseResponseFormatOrFail(deps.getSingleString(args, "response-format"), deps);
8472
- if (type) body.type = type;
8473
- body.response_format = responseFormat;
8474
8596
  const waitTimeoutSeconds = parsePositiveNumberOption(args, "wait-timeout-seconds", deps);
8475
- if (waitTimeoutSeconds !== void 0) body.wait_timeout_seconds = waitTimeoutSeconds;
8476
8597
  const pollIntervalMs = parsePositiveNumberOption(args, "poll-interval-ms", deps);
8477
- if (pollIntervalMs !== void 0) body.poll_interval_ms = pollIntervalMs;
8478
- const pick = await deps.pickDirectTokenForTask(token, region);
8479
- const normalized = await waitForTaskResponse(
8480
- taskId,
8481
- pick.token,
8482
- buildRegionInfo(pick.region),
8483
- {
8484
- type,
8485
- responseFormat,
8486
- waitTimeoutSeconds: typeof body.wait_timeout_seconds === "number" ? body.wait_timeout_seconds : void 0,
8487
- pollIntervalMs: typeof body.poll_interval_ms === "number" ? body.poll_interval_ms : void 0
8488
- }
8489
- );
8490
- const taskInfo = collectTaskInfo(normalized, deps);
8491
- if (!taskInfo) {
8492
- if (isJson) {
8493
- deps.printCommandJson("task.wait", deps.unwrapBody(normalized));
8494
- } else {
8495
- deps.printJson(deps.unwrapBody(normalized));
8496
- }
8497
- return;
8498
- }
8499
- if (isJson) deps.printCommandJson("task.wait", taskInfo);
8500
- else printTaskInfo(taskInfo, deps);
8598
+ const pick = await deps.pickDirectTokenForTask(deps.getSingleString(args, "token"), deps.getSingleString(args, "region"));
8599
+ const normalized = await waitForTaskResponse(taskId, pick.token, buildRegionInfo(pick.region), {
8600
+ type,
8601
+ responseFormat,
8602
+ waitTimeoutSeconds,
8603
+ pollIntervalMs
8604
+ });
8605
+ outputTaskResult("task.wait", normalized, Boolean(args.json), deps);
8501
8606
  };
8502
8607
  const handleTaskList = async (argv) => {
8503
8608
  const args = (0, import_minimist3.default)(argv, {
@@ -8508,24 +8613,18 @@ ${deps.usageTaskWait()}`);
8508
8613
  console.log(deps.usageTaskList());
8509
8614
  return;
8510
8615
  }
8511
- const token = deps.getSingleString(args, "token");
8512
- const region = deps.getRegionWithDefault(args);
8513
8616
  const type = deps.getSingleString(args, "type");
8514
- const countRaw = deps.getSingleString(args, "count");
8515
- const count = countRaw ? Number(countRaw) : 20;
8516
- const isJson = Boolean(args.json);
8517
8617
  if (type && type !== "image" && type !== "video" && type !== "all") {
8518
8618
  deps.fail(`Invalid --type: ${type}. Use image, video, or all.`);
8519
8619
  }
8520
- const pick = await deps.pickDirectTokenForTask(token, region);
8521
- const result = await getAssetList(
8522
- pick.token,
8523
- buildRegionInfo(pick.region),
8524
- {
8525
- count: Number.isFinite(count) && count > 0 ? count : 20,
8526
- type
8527
- }
8528
- );
8620
+ const countRaw = deps.getSingleString(args, "count");
8621
+ const count = countRaw ? Number(countRaw) : 20;
8622
+ const isJson = Boolean(args.json);
8623
+ const pick = await deps.pickDirectTokenForTask(deps.getSingleString(args, "token"), deps.getSingleString(args, "region"));
8624
+ const result = await getAssetList(pick.token, buildRegionInfo(pick.region), {
8625
+ count: Number.isFinite(count) && count > 0 ? count : 20,
8626
+ type
8627
+ });
8529
8628
  if (isJson) {
8530
8629
  deps.printCommandJson("task.list", {
8531
8630
  has_more: result.hasMore,
@@ -8544,9 +8643,7 @@ ${deps.usageTaskWait()}`);
8544
8643
  const modelShort = item.modelName || item.modelReqKey || "-";
8545
8644
  const promptShort = item.prompt.length > 50 ? item.prompt.slice(0, 50) + "..." : item.prompt;
8546
8645
  console.log(`${item.id} ${typeLabel} ${statusLabel.padEnd(4)} ${time} ${modelShort.padEnd(20)} ${promptShort}`);
8547
- if (item.imageUrl) {
8548
- console.log(` ${item.imageUrl}`);
8549
- }
8646
+ if (item.imageUrl) console.log(` ${item.imageUrl}`);
8550
8647
  }
8551
8648
  };
8552
8649
  return {
@@ -8556,12 +8653,12 @@ ${deps.usageTaskWait()}`);
8556
8653
  handleTaskWait,
8557
8654
  handleTaskList,
8558
8655
  printTaskInfo: (task) => {
8559
- const normalized = collectTaskInfo(task, deps);
8560
- if (!normalized) {
8656
+ const info = collectTaskInfo(task, deps);
8657
+ if (!info) {
8561
8658
  deps.printJson(task);
8562
8659
  return;
8563
8660
  }
8564
- printTaskInfo(normalized, deps);
8661
+ printTaskInfo(info, deps);
8565
8662
  }
8566
8663
  };
8567
8664
  }
@@ -8782,7 +8879,7 @@ async function uploadImageBuffer(imageBuffer, refreshToken, regionInfo) {
8782
8879
  "Authorization": auth,
8783
8880
  "Connection": "keep-alive",
8784
8881
  "Content-CRC32": crc32,
8785
- "Content-Disposition": 'attachment; filename="undefined"',
8882
+ "Content-Disposition": 'attachment; filename="upload.bin"',
8786
8883
  "Content-Type": "application/octet-stream",
8787
8884
  "Origin": origin,
8788
8885
  "Referer": RegionUtils.getRefererPath(regionInfo),
@@ -9282,7 +9379,7 @@ async function generateImageComposition(_model, prompt, images, {
9282
9379
  abilityName: "byte_edit",
9283
9380
  strength: sampleStrength,
9284
9381
  source: {
9285
- imageUrl: `blob:https://dreamina.capcut.com/${util_default.uuid()}`
9382
+ imageUrl: `blob:${INTERNATIONAL_FRONTEND_ORIGIN}/${util_default.uuid()}`
9286
9383
  }
9287
9384
  }));
9288
9385
  const metricsExtra = buildMetricsExtra({
@@ -9317,7 +9414,7 @@ async function generateImageComposition(_model, prompt, images, {
9317
9414
  draftContent,
9318
9415
  metricsExtra
9319
9416
  });
9320
- const imageReferer = regionInfo.isCN ? "https://jimeng.jianying.com/ai-tool/generate?type=image" : "https://dreamina.capcut.com/ai-tool/generate?type=image";
9417
+ const imageReferer = regionInfo.isCN ? `${BASE_URL_CN}/ai-tool/generate?type=image` : `${INTERNATIONAL_FRONTEND_ORIGIN}/ai-tool/generate?type=image`;
9321
9418
  const { aigc_data } = await request(
9322
9419
  "post",
9323
9420
  "/mweb/v1/aigc_draft/generate",
@@ -9481,7 +9578,7 @@ async function generateImagesInternal(_model, prompt, {
9481
9578
  draftContent,
9482
9579
  metricsExtra
9483
9580
  });
9484
- const imageReferer = regionInfo.isCN ? "https://jimeng.jianying.com/ai-tool/generate?type=image" : "https://dreamina.capcut.com/ai-tool/generate?type=image";
9581
+ const imageReferer = regionInfo.isCN ? `${BASE_URL_CN}/ai-tool/generate?type=image` : `${INTERNATIONAL_FRONTEND_ORIGIN}/ai-tool/generate?type=image`;
9485
9582
  const { aigc_data } = await request(
9486
9583
  "post",
9487
9584
  "/mweb/v1/aigc_draft/generate",
@@ -9603,7 +9700,7 @@ async function generateJimeng4xMultiImages(_model, prompt, {
9603
9700
  draftContent,
9604
9701
  metricsExtra
9605
9702
  });
9606
- const imageReferer = regionInfo.isCN ? "https://jimeng.jianying.com/ai-tool/generate?type=image" : "https://dreamina.capcut.com/ai-tool/generate?type=image";
9703
+ const imageReferer = regionInfo.isCN ? `${BASE_URL_CN}/ai-tool/generate?type=image` : `${INTERNATIONAL_FRONTEND_ORIGIN}/ai-tool/generate?type=image`;
9607
9704
  const { aigc_data } = await request(
9608
9705
  "post",
9609
9706
  "/mweb/v1/aigc_draft/generate",
@@ -9775,7 +9872,7 @@ async function upscaleImage(_model, image, {
9775
9872
  draftContent,
9776
9873
  metricsExtra
9777
9874
  });
9778
- const imageReferer = regionInfo.isCN ? "https://jimeng.jianying.com/ai-tool/generate?type=image" : "https://dreamina.capcut.com/ai-tool/generate?type=image";
9875
+ const imageReferer = regionInfo.isCN ? `${BASE_URL_CN}/ai-tool/generate?type=image` : `${INTERNATIONAL_FRONTEND_ORIGIN}/ai-tool/generate?type=image`;
9779
9876
  const { aigc_data } = await request(
9780
9877
  "post",
9781
9878
  "/mweb/v1/aigc_draft/generate",
@@ -10730,7 +10827,8 @@ async function generateVideo(_model, prompt, {
10730
10827
  isDefaultSeed: 1,
10731
10828
  originSubmitId,
10732
10829
  isRegenerate: false,
10733
- enterFrom: "click",
10830
+ enterFrom: "use_bgimage_prompt",
10831
+ position: "page_bottom_box",
10734
10832
  functionMode: flFunctionMode,
10735
10833
  sceneOptions: JSON.stringify([sceneOption])
10736
10834
  });
@@ -10824,7 +10922,7 @@ async function generateVideo(_model, prompt, {
10824
10922
  }
10825
10923
  };
10826
10924
  }
10827
- const videoReferer = regionInfo.isCN ? "https://jimeng.jianying.com/ai-tool/generate?type=video" : "https://dreamina.capcut.com/ai-tool/generate?type=video";
10925
+ const videoReferer = regionInfo.isCN ? `${BASE_URL_CN}/ai-tool/generate?type=video` : `${INTERNATIONAL_FRONTEND_ORIGIN}/ai-tool/generate?type=video`;
10828
10926
  const { aigc_data } = await request(
10829
10927
  "post",
10830
10928
  "/mweb/v1/aigc_draft/generate",
@@ -10855,7 +10953,7 @@ async function generateVideo(_model, prompt, {
10855
10953
  timeoutSeconds: pollerOptions.timeoutSeconds
10856
10954
  });
10857
10955
  const { result: pollingResult, data: finalHistoryData } = await poller.poll(async () => {
10858
- var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2;
10956
+ var _a2, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l, _m, _n, _o;
10859
10957
  pollAttempts++;
10860
10958
  const result = await request("post", "/mweb/v1/get_history_by_ids", refreshToken, regionInfo, {
10861
10959
  data: {
@@ -10880,7 +10978,7 @@ async function generateVideo(_model, prompt, {
10880
10978
  const currentItemList = historyData.item_list || [];
10881
10979
  const finishTime = ((_a2 = historyData.task) == null ? void 0 : _a2.finish_time) || 0;
10882
10980
  if (currentItemList.length > 0) {
10883
- const tempVideoUrl = ((_e2 = (_d2 = (_c2 = (_b2 = currentItemList[0]) == null ? void 0 : _b2.video) == null ? void 0 : _c2.transcoded_video) == null ? void 0 : _d2.origin) == null ? void 0 : _e2.video_url) || ((_g2 = (_f2 = currentItemList[0]) == null ? void 0 : _f2.video) == null ? void 0 : _g2.play_url) || ((_i2 = (_h2 = currentItemList[0]) == null ? void 0 : _h2.video) == null ? void 0 : _i2.download_url) || ((_k2 = (_j2 = currentItemList[0]) == null ? void 0 : _j2.video) == null ? void 0 : _k2.url);
10981
+ const tempVideoUrl = ((_e2 = (_d2 = (_c2 = (_b2 = currentItemList[0]) == null ? void 0 : _b2.common_attr) == null ? void 0 : _c2.transcoded_video) == null ? void 0 : _d2.origin) == null ? void 0 : _e2.video_url) || ((_i2 = (_h2 = (_g2 = (_f2 = currentItemList[0]) == null ? void 0 : _f2.video) == null ? void 0 : _g2.transcoded_video) == null ? void 0 : _h2.origin) == null ? void 0 : _i2.video_url) || ((_k2 = (_j2 = currentItemList[0]) == null ? void 0 : _j2.video) == null ? void 0 : _k2.play_url) || ((_m = (_l = currentItemList[0]) == null ? void 0 : _l.video) == null ? void 0 : _m.download_url) || ((_o = (_n = currentItemList[0]) == null ? void 0 : _n.video) == null ? void 0 : _o.url);
10884
10982
  if (tempVideoUrl) {
10885
10983
  logger_default.info(`\u68C0\u6D4B\u5230\u89C6\u9891URL: ${tempVideoUrl}`);
10886
10984
  }
@@ -11143,7 +11241,19 @@ function applyWaitOptionsToBody(body, args, deps, includeWaitFlag = true) {
11143
11241
  return wait;
11144
11242
  }
11145
11243
  async function downloadBinary(url, deps) {
11146
- const response = await fetch(url);
11244
+ const controller = new AbortController();
11245
+ const timeout = setTimeout(() => controller.abort(), 12e4);
11246
+ let response;
11247
+ try {
11248
+ response = await fetch(url, { signal: controller.signal });
11249
+ } catch (err) {
11250
+ clearTimeout(timeout);
11251
+ if (err.name === "AbortError") {
11252
+ deps.fail(`Download timed out after 120s: ${url}`);
11253
+ }
11254
+ throw err;
11255
+ }
11256
+ clearTimeout(timeout);
11147
11257
  if (!response.ok) {
11148
11258
  deps.fail(`Download failed (${response.status}): ${url}`);
11149
11259
  }
@@ -11212,6 +11322,9 @@ function createMediaCommandHandlers(deps) {
11212
11322
  if (!Number.isFinite(parsed)) {
11213
11323
  deps.fail(`Invalid --sample-strength: ${sampleStrengthRaw}`);
11214
11324
  }
11325
+ if (parsed < 0 || parsed > 1) {
11326
+ deps.fail(`Invalid --sample-strength: ${sampleStrengthRaw} (must be between 0 and 1)`);
11327
+ }
11215
11328
  body.sample_strength = parsed;
11216
11329
  }
11217
11330
  const pick = await deps.pickDirectTokenForGeneration(
@@ -11528,12 +11641,15 @@ var import_node_child_process = require("child_process");
11528
11641
  var import_node_fs3 = require("fs");
11529
11642
  var import_node_path4 = __toESM(require("path"), 1);
11530
11643
  var import_node_os = __toESM(require("os"), 1);
11531
- var import_node_url = require("url");
11532
11644
  var import_minimist5 = __toESM(require("minimist"), 1);
11533
11645
  var import_meta = {};
11534
- var __filename = (0, import_node_url.fileURLToPath)(import_meta.url);
11535
- var __dirname = import_node_path4.default.dirname(__filename);
11536
- var LOGIN_SCRIPT = import_node_path4.default.join(__dirname, "..", "..", "scripts", "jimeng_login_helper.py");
11646
+ var LOGIN_SCRIPT = import_node_path4.default.join(
11647
+ import_node_path4.default.dirname(new URL(import_meta.url).pathname),
11648
+ "..",
11649
+ "..",
11650
+ "scripts",
11651
+ "jimeng_login_helper.py"
11652
+ );
11537
11653
  function createLoginCommandHandler(deps) {
11538
11654
  return async (argv) => {
11539
11655
  const args = (0, import_minimist5.default)(argv, {
@@ -11737,10 +11853,20 @@ function usageRoot() {
11737
11853
  }
11738
11854
  function usageModelsList() {
11739
11855
  return buildUsageText(" jimeng models list [options]", [
11740
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
11856
+ " --token <token> Query with specific token",
11857
+ " --region <region> Query with specific region (cn/us/hk/jp/sg)",
11858
+ " --all Query all tokens in pool, grouped by token/region",
11741
11859
  " --verbose Print rich model fields",
11742
11860
  " --json Print full JSON response",
11743
11861
  HELP_OPTION
11862
+ ], [
11863
+ {
11864
+ title: "Notes:",
11865
+ lines: [
11866
+ " Without --token, --region, or --all, uses the first available token in pool.",
11867
+ " With --all, queries every enabled+live token and groups results by token/region."
11868
+ ]
11869
+ }
11744
11870
  ]);
11745
11871
  }
11746
11872
  function usageModelsRefresh() {
@@ -11900,7 +12026,7 @@ function usageVideoGenerate() {
11900
12026
  function usageTaskGet() {
11901
12027
  return buildUsageText(" jimeng task get --task-id <id> [options]", [
11902
12028
  " --token <token> Optional, override token-pool selection",
11903
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
12029
+ " --region <region> Filter token by region (cn/us/hk/jp/sg)",
11904
12030
  " --task-id <id> Required history/task id",
11905
12031
  " --type <type> Optional image or video",
11906
12032
  " --response-format <fmt> Optional url or b64_json",
@@ -11911,7 +12037,7 @@ function usageTaskGet() {
11911
12037
  function usageTaskWait() {
11912
12038
  return buildUsageText(" jimeng task wait --task-id <id> [options]", [
11913
12039
  " --token <token> Optional, override token-pool selection",
11914
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
12040
+ " --region <region> Filter token by region (cn/us/hk/jp/sg)",
11915
12041
  " --task-id <id> Required history/task id",
11916
12042
  " --type <type> Optional image or video",
11917
12043
  " --response-format <fmt> Optional url or b64_json",
@@ -11924,7 +12050,7 @@ function usageTaskWait() {
11924
12050
  function usageTaskList() {
11925
12051
  return buildUsageText(" jimeng task list [options]", [
11926
12052
  " --token <token> Optional, override token-pool selection",
11927
- " --region <region> X-Region header, default cn (cn/us/hk/jp/sg)",
12053
+ " --region <region> Filter token by region (cn/us/hk/jp/sg)",
11928
12054
  " --type <type> Filter by type: image, video, or all (default all)",
11929
12055
  " --count <num> Number of items per page (default 20)",
11930
12056
  JSON_OPTION,
@@ -12069,7 +12195,6 @@ var queryHandlers = createQueryCommandHandlers({
12069
12195
  usageTaskWait,
12070
12196
  usageTaskList,
12071
12197
  getSingleString,
12072
- getRegionWithDefault,
12073
12198
  parseRegionOrFail,
12074
12199
  ensureTokenPoolReady,
12075
12200
  pickDirectTokenForTask,