@ttmg/cli 0.3.5-beta.1 → 0.3.6-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/CHANGELOG.md +4 -1
  2. package/dist/index.js +140 -237
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +2 -2
  5. package/dist/public/assets/baseForm-CiVp-bI-.js +10 -0
  6. package/dist/public/assets/baseForm-CiVp-bI-.js.br +0 -0
  7. package/dist/public/assets/baseForm-DzWBZ1nI.css +1 -0
  8. package/dist/public/assets/baseForm-DzWBZ1nI.css.br +0 -0
  9. package/dist/public/assets/index-BFPQPvSA.css +1 -0
  10. package/dist/public/assets/index-B_Ivowka.js +1 -0
  11. package/dist/public/assets/index-B_Ivowka.js.br +0 -0
  12. package/dist/public/assets/index-BedicqfR.css +1 -0
  13. package/dist/public/assets/{index-EpYlOZ81.js → index-BexDbE8c.js} +1 -1
  14. package/dist/public/assets/index-BhOuEHVF.js +1 -0
  15. package/dist/public/assets/index-BhOuEHVF.js.br +0 -0
  16. package/dist/public/assets/index-Bkv8C1YM.js +1 -0
  17. package/dist/public/assets/index-Bkv8C1YM.js.br +0 -0
  18. package/dist/public/assets/index-BtJZs04X.js +1 -0
  19. package/dist/public/assets/index-C7C5ulLg.css +1 -0
  20. package/dist/public/assets/index-CRWaaDVs.js +14 -0
  21. package/dist/public/assets/index-CRWaaDVs.js.br +0 -0
  22. package/dist/public/assets/index-CoSJHl5r.js +1 -0
  23. package/dist/public/assets/index-CsuNwmbg.js +1 -0
  24. package/dist/public/assets/index-CsuNwmbg.js.br +0 -0
  25. package/dist/public/assets/index-D-FtjFjD.js +1 -0
  26. package/dist/public/assets/index-DOuHeHYY.js +1 -0
  27. package/dist/public/assets/index-DhmPFuxl.css +1 -0
  28. package/dist/public/assets/index-Dxp0kSQH.js +1 -0
  29. package/dist/public/assets/index-EPgyQeeR.js +1 -0
  30. package/dist/public/assets/index-SRmdMrn7.js +1 -0
  31. package/dist/public/assets/index-UihZn1LL.css +1 -0
  32. package/dist/public/assets/index-UihZn1LL.css.br +0 -0
  33. package/dist/public/assets/index-X0E7Y6e7.js +1 -0
  34. package/dist/public/assets/{index-D7wHfGqp.js → index-f98Kwcg1.js} +1 -1
  35. package/dist/public/assets/index-llUyinRO.js +1 -0
  36. package/dist/public/assets/isPlainObject-Cb2zGMtI.js +1 -0
  37. package/dist/public/assets/times-B65MF4Rf.js +1 -0
  38. package/dist/public/index.html +2 -2
  39. package/package.json +2 -2
  40. package/dist/public/assets/index-BRMID64m.js +0 -1
  41. package/dist/public/assets/index-Ba0pzb2a.js +0 -1
  42. package/dist/public/assets/index-Ba0pzb2a.js.br +0 -0
  43. package/dist/public/assets/index-BgPufU68.js +0 -1
  44. package/dist/public/assets/index-Bup0y3Y0.js +0 -1
  45. package/dist/public/assets/index-BvQYQ3nw.js +0 -23
  46. package/dist/public/assets/index-BvQYQ3nw.js.br +0 -0
  47. package/dist/public/assets/index-CUbWSY4M.js +0 -1
  48. package/dist/public/assets/index-DH6jmQlu.js +0 -1
  49. package/dist/public/assets/index-DNiiCmLA.js +0 -1
  50. package/dist/public/assets/index-DNiiCmLA.js.br +0 -0
  51. package/dist/public/assets/index-D_5oU4mJ.css +0 -1
  52. package/dist/public/assets/index-D_5oU4mJ.css.br +0 -0
  53. package/dist/public/assets/index-HAU2X1j9.js +0 -1
  54. package/dist/public/assets/index-HAU2X1j9.js.br +0 -0
  55. package/dist/public/assets/index-xb5uiTXk.js +0 -1
package/dist/index.js CHANGED
@@ -38,7 +38,6 @@ var FormData$1 = require('form-data');
38
38
  var ttmgPack = require('ttmg-pack');
39
39
  var expressStaticGzip = require('express-static-gzip');
40
40
  var fileUpload = require('express-fileupload');
41
- var async_hooks = require('async_hooks');
42
41
  var fs$1 = require('node:fs');
43
42
  var path$1 = require('node:path');
44
43
  var zlib = require('zlib');
@@ -6533,10 +6532,25 @@ function getAxiosProxyConfig() {
6533
6532
  }
6534
6533
  return {};
6535
6534
  }
6536
- async function request$1({ url, method, data, headers, params, }) {
6535
+ async function request({ url, method, data, headers, params, }) {
6537
6536
  const config = getTTMGRC();
6538
6537
  const cookie = config?.cookie;
6539
6538
  const proxyConfig = getAxiosProxyConfig();
6539
+ // 打印请求信息
6540
+ console.log('\n========== API Request ==========');
6541
+ console.log('URL:', url);
6542
+ console.log('Method:', method);
6543
+ console.log('Headers:', JSON.stringify({
6544
+ Cookie: cookie,
6545
+ ...(headers || {}),
6546
+ }, null, 2));
6547
+ if (params) {
6548
+ console.log('Query Params:', JSON.stringify(params, null, 2));
6549
+ }
6550
+ if (data) {
6551
+ console.log('Request Body:', JSON.stringify(data, null, 2));
6552
+ }
6553
+ console.log('=================================\n');
6540
6554
  try {
6541
6555
  const res = await axios({
6542
6556
  url,
@@ -6573,20 +6587,7 @@ async function request$1({ url, method, data, headers, params, }) {
6573
6587
  };
6574
6588
  }
6575
6589
  }
6576
- /** wasm/archive 大文件下载超时(毫秒),防止无限卡住 */
6577
- const DOWNLOAD_TIMEOUT_MS = 10 * 60 * 1000; // 10 分钟
6578
- function formatBytes(n) {
6579
- if (n >= 1024 * 1024)
6580
- return `${(n / 1024 / 1024).toFixed(2)}MB`;
6581
- if (n >= 1024)
6582
- return `${(n / 1024).toFixed(2)}KB`;
6583
- return `${n}B`;
6584
- }
6585
- async function download$1(url, filePath, headers) {
6586
- const t0 = Date.now();
6587
- const baseName = filePath.split(/[/\\]/).pop() ?? filePath;
6588
- const urlShort = url.length > 120 ? url.slice(0, 100) + '...' + url.slice(-20) : url;
6589
- console.log(`[download] start out=${baseName} url=${urlShort}`);
6590
+ async function download(url, filePath) {
6590
6591
  // 清理旧文件
6591
6592
  if (fs.existsSync(filePath)) {
6592
6593
  try {
@@ -6598,88 +6599,40 @@ async function download$1(url, filePath, headers) {
6598
6599
  try {
6599
6600
  const res = await axios.get(url, {
6600
6601
  responseType: 'stream',
6602
+ // 让非 2xx 进入 catch
6601
6603
  validateStatus: s => s >= 200 && s < 300,
6602
- headers: headers || {},
6603
- timeout: DOWNLOAD_TIMEOUT_MS,
6604
6604
  ...proxyConfig,
6605
6605
  });
6606
- const contentLength = res.headers['content-length'];
6607
- const expectedSize = contentLength ? parseInt(contentLength, 10) : null;
6608
- console.log(`[download] response ok out=${baseName} content-length=${expectedSize != null ? formatBytes(expectedSize) : 'unknown'} elapsed=${Date.now() - t0}ms`);
6609
- // 流写入 + 超时保护,防止 pipe 卡死
6610
- const pipePromise = new Promise((resolve, reject) => {
6606
+ // 关键:把“流事件”封装为 Promise,并 await 它
6607
+ await new Promise((resolve, reject) => {
6611
6608
  const writer = fs.createWriteStream(filePath);
6612
- let settled = false;
6613
- let receivedBytes = 0;
6614
- let lastLogBytes = 0;
6615
- const LOG_INTERVAL = 1024 * 1024; // 每 1MB 打一次日志
6616
- const settle = (fn) => {
6617
- if (settled)
6618
- return;
6619
- settled = true;
6620
- fn();
6621
- };
6622
6609
  const onError = (e) => {
6623
6610
  cleanup();
6624
- console.error(`[download] stream error out=${baseName} received=${formatBytes(receivedBytes)} err=`, e);
6625
- settle(() => {
6626
- try {
6627
- if (fs.existsSync(filePath))
6628
- fs.unlinkSync(filePath);
6629
- }
6630
- catch { }
6631
- reject(e);
6632
- });
6611
+ try {
6612
+ if (fs.existsSync(filePath))
6613
+ fs.unlinkSync(filePath);
6614
+ }
6615
+ catch { }
6616
+ reject(e);
6633
6617
  };
6634
6618
  const onClose = () => {
6635
6619
  cleanup();
6636
- const elapsed = Date.now() - t0;
6637
- const speed = elapsed > 0 ? (receivedBytes / 1024 / elapsed).toFixed(1) : '?';
6638
- console.log(`[download] pipe done out=${baseName} size=${formatBytes(receivedBytes)} elapsed=${elapsed}ms speed=${speed}KB/s`);
6639
- settle(resolve);
6620
+ resolve();
6640
6621
  };
6641
6622
  const cleanup = () => {
6642
- res.data.off('data', onData);
6643
6623
  writer.off('error', onError);
6644
6624
  writer.off('close', onClose);
6645
6625
  res.data.off('error', onError);
6646
- if (timeoutId)
6647
- clearTimeout(timeoutId);
6648
6626
  };
6649
- const onData = (chunk) => {
6650
- receivedBytes += Buffer.isBuffer(chunk) ? chunk.length : Buffer.byteLength(chunk);
6651
- if (receivedBytes - lastLogBytes >= LOG_INTERVAL) {
6652
- lastLogBytes = receivedBytes;
6653
- const elapsed = Date.now() - t0;
6654
- const speed = elapsed > 0 ? (receivedBytes / 1024 / elapsed).toFixed(1) : '?';
6655
- console.log(`[download] progress out=${baseName} received=${formatBytes(receivedBytes)} elapsed=${elapsed}ms speed=${speed}KB/s`);
6656
- }
6657
- };
6658
- const timeoutId = setTimeout(() => {
6659
- cleanup();
6660
- console.error(`[download] timeout out=${baseName} received=${formatBytes(receivedBytes)} expected=${expectedSize != null ? formatBytes(expectedSize) : 'unknown'}`);
6661
- settle(() => {
6662
- try {
6663
- if (fs.existsSync(filePath))
6664
- fs.unlinkSync(filePath);
6665
- }
6666
- catch { }
6667
- res.data?.destroy();
6668
- reject(new Error(`下载超时(${DOWNLOAD_TIMEOUT_MS / 60000} 分钟),请检查网络后重试`));
6669
- });
6670
- }, DOWNLOAD_TIMEOUT_MS);
6671
- res.data.on('data', onData);
6672
6627
  res.data.on('error', onError);
6673
6628
  writer.on('error', onError);
6674
6629
  writer.on('close', onClose);
6675
6630
  res.data.pipe(writer);
6676
6631
  });
6677
- await pipePromise;
6632
+ // 成功
6678
6633
  return { ok: true };
6679
6634
  }
6680
6635
  catch (err) {
6681
- const elapsed = Date.now() - t0;
6682
- console.error(`[download] failed out=${baseName} elapsed=${elapsed}ms err=`, err);
6683
6636
  // 403 等受控处理
6684
6637
  if (isAxiosError(err) && err.response?.status === 403) {
6685
6638
  // 不抛出,让上层自行决定
@@ -6695,7 +6648,7 @@ function isAxiosError(e) {
6695
6648
 
6696
6649
  async function fetchGameInfo(clientKey) {
6697
6650
  // 访问 V4 接口
6698
- const response = await request$1({
6651
+ const response = await request({
6699
6652
  url: `https://developers.tiktok.com/tiktok/v4/devportal/mini_game/devtool/info`,
6700
6653
  method: 'GET',
6701
6654
  params: {
@@ -6752,7 +6705,7 @@ async function uploadGameToPlatform({ data, name, clientKey, note = '--', appId,
6752
6705
  formData.append('file', new Blob([data], { type: 'application/zip' }), sanitized);
6753
6706
  formData.append('client_key', clientKey);
6754
6707
  formData.append('note', note);
6755
- const response = await request$1({
6708
+ const response = await request({
6756
6709
  method: 'POST',
6757
6710
  url: 'https://developers.tiktok.com/tiktok/v4/devportal/mini_game/devtool/upload',
6758
6711
  data: formData,
@@ -6904,9 +6857,9 @@ const messages = {
6904
6857
  'login.error.withCode': 'Login failed: {message}, error_code: {code}',
6905
6858
  'login.error.withMessage': 'Login failed: {message}',
6906
6859
  'login.error.noUserId': 'Login failed. No user_id in response.',
6907
- 'login.warning.proxyIssue': 'The response does not look like the login API (e.g. proxy returned "Connection established" instead of forwarding the real response).\n\nThe API is not reachable from mainland without proxy. Please ensure your proxy correctly forwards HTTPS to developers.tiktok.com: try another proxy node, or configure the CLI internal proxy using `ttmg config set proxy socks5://...`.\n\nProxy troubleshooting doc:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
6860
+ 'login.warning.proxyIssue': 'Login failed. Please refer to the proxy setup doc:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
6908
6861
  'login.error.connectService': 'Failed to connect to login service',
6909
- 'login.error.networkBlocked': "Network connection failed. This is usually caused by advanced proxy settings (e.g., fake-ip mode) or incorrect terminal proxy environment variables.\n\nWe strongly recommend turning off global proxy mode and configuring the CLI internal proxy using:\n ttmg config set proxy socks5://127.0.0.1:<your_socks_port>\n\nFor detailed solutions, please refer to the proxy troubleshooting doc:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg",
6862
+ 'login.error.networkBlocked': 'Network connection failed. Please refer to the proxy setup doc:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
6910
6863
  'logout.spinner.loggingOut': 'Logging out...',
6911
6864
  'logout.success': 'Logged out successfully!',
6912
6865
  'logout.fail': 'Logout failed: {error}',
@@ -7035,9 +6988,9 @@ const messages = {
7035
6988
  'login.error.withCode': '登录失败:{message},错误码:{code}',
7036
6989
  'login.error.withMessage': '登录失败:{message}',
7037
6990
  'login.error.noUserId': '登录失败,响应中未返回 user_id。',
7038
- 'login.warning.proxyIssue': '当前响应看起来不是登录接口返回(例如代理返回了 "Connection established",而不是转发真实响应)。\n\n该接口在大陆网络通常需要代理。请确认代理可正确转发 developers.tiktok.com 的 HTTPS 请求:尝试切换节点,或者使用 `ttmg config set proxy socks5://...` 配置 CLI 内置代理。\n\n代理排查文档:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
6991
+ 'login.warning.proxyIssue': '登录失败,请参考代理设置文档:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
7039
6992
  'login.error.connectService': '连接登录服务失败',
7040
- 'login.error.networkBlocked': '网络连接失败。这通常是由于代理软件的高级设置(如 fake-ip 模式)或终端残留了错误的代理环境变量导致的。\n\n我们强烈建议你关闭全局代理,并为 CLI 配置内置 SOCKS5 代理:\n ttmg config set proxy socks5://127.0.0.1:<你的socks端口>\n\n详细排查方案请参考最新代理设置文档:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
6993
+ 'login.error.networkBlocked': '网络连接失败,请参考代理设置文档:\nhttps://bytedance.larkoffice.com/wiki/PeIawT4M4ia9R8kYyLMcjwHknOg',
7041
6994
  'logout.spinner.loggingOut': '正在退出登录...',
7042
6995
  'logout.success': '退出登录成功!',
7043
6996
  'logout.fail': '退出登录失败:{error}',
@@ -8404,13 +8357,15 @@ function getLocalIPs() {
8404
8357
  }
8405
8358
  // 去重(同名+同地址)
8406
8359
  const unique = dedupe(results);
8407
- // 稳定排序:无线优先 or 有线优先按需定。这里有线优先,再无线,再其他。
8360
+ // 稳定排序:优先无线,再有线,再其他。
8361
+ // 说明:扫码调试场景下,手机通常在 Wi-Fi,优先选择无线网卡的 IP 更不容易踩到
8362
+ // “有线网段不可达/企业网络隔离”的坑。
8408
8363
  unique.sort((a, b) => {
8409
8364
  const rank = (n) => {
8410
8365
  const lower = n.toLowerCase();
8411
- if (WIRED_KEYWORDS.some(k => lower.includes(k)))
8412
- return 0;
8413
8366
  if (WIRELESS_KEYWORDS.some(k => lower.includes(k)))
8367
+ return 0;
8368
+ if (WIRED_KEYWORDS.some(k => lower.includes(k)))
8414
8369
  return 1;
8415
8370
  return 2;
8416
8371
  };
@@ -8451,6 +8406,11 @@ function getLocalIPs() {
8451
8406
  }
8452
8407
 
8453
8408
  function getLocalIP() {
8409
+ // 优先使用 getLocalIPs 的过滤 + 排序结果(更适合扫码调试场景)
8410
+ const preferred = getLocalIPs()[0];
8411
+ if (preferred) {
8412
+ return preferred;
8413
+ }
8454
8414
  const networkInterfaces = os.networkInterfaces();
8455
8415
  for (const interfaceName in networkInterfaces) {
8456
8416
  const interfaceInfo = networkInterfaces[interfaceName];
@@ -8462,6 +8422,8 @@ function getLocalIP() {
8462
8422
  }
8463
8423
  }
8464
8424
  }
8425
+ // 极端场景:无可用 IPv4(例如仅有回环/无网络)。避免返回 undefined 破坏 schema。
8426
+ return '127.0.0.1';
8465
8427
  }
8466
8428
 
8467
8429
  async function init() {
@@ -8742,34 +8704,8 @@ async function listen(app, options) {
8742
8704
  return { server, port, url, version };
8743
8705
  }
8744
8706
 
8745
- const asyncLocalStorage = new async_hooks.AsyncLocalStorage();
8746
- /** 在请求作用域内运行,供 middleware 调用 */
8747
- function runWithRequest(req, fn) {
8748
- return asyncLocalStorage.run({ req }, fn);
8749
- }
8750
- /** Express 中间件:将 req 注入 AsyncLocalStorage,供 api.request/download 内部读取 ppeHeaders */
8751
- function requestContextMiddleware(req, res, next) {
8752
- runWithRequest(req, () => next());
8753
- }
8754
- /** 从当前请求中提取 x-use-ppe、x-tt-env,仅当浏览器有传时才返回 */
8755
- function getPpeHeaders() {
8756
- const store = asyncLocalStorage.getStore();
8757
- if (!store?.req?.headers)
8758
- return {};
8759
- const h = store.req.headers;
8760
- const result = {};
8761
- const v1 = h['x-use-ppe'];
8762
- const v2 = h['x-tt-env'];
8763
- if (typeof v1 === 'string')
8764
- result['x-use-ppe'] = v1;
8765
- if (typeof v2 === 'string')
8766
- result['x-tt-env'] = v2;
8767
- return result;
8768
- }
8769
-
8770
8707
  function setupMiddlewares(app, options) {
8771
8708
  const { publicPath, outputDir } = options;
8772
- app.use(requestContextMiddleware);
8773
8709
  app.use(fileUpload());
8774
8710
  app.use(expressStaticGzip(publicPath, {
8775
8711
  enableBrotli: true,
@@ -8971,8 +8907,6 @@ const UNITY_WASM_SPLIT_CONFIG_FIELD_SCHEME = {
8971
8907
  IOS_CODE_FILE_MD5: `$IOS_CODE_FILE_MD5`,
8972
8908
  ANDROID_CODE_FILE_MD5: `$ANDROID_CODE_FILE_MD5`,
8973
8909
  ANDROID_SUB_CODE_FILE_MD5: `$SUB_CODE_FILE_MD5`,
8974
- ARCHIVE_CODE_FILE_MD5: `$ARCHIVE_CODE_FILE_MD5`,
8975
- enableArchiveMode: `"$ENABLEARCHIVEMODE"`,
8976
8910
  WASMSPLITVERSION: `"$WASMSPLITVERSION"`,
8977
8911
  ENABLEWASMSPLIT: `"$ENABLEWASMSPLIT"`,
8978
8912
  IOS_SUB_JS_FILE_CONFIG: `"$IOS_SUB_JS_FILE_CONFIG"`,
@@ -8992,11 +8926,9 @@ const WASM_SPLIT_SUBPACKAGE_CONFIG = {
8992
8926
  name: 'wasmcode1-android',
8993
8927
  root: 'wasmcode1-android/',
8994
8928
  },
8995
- archive: {
8996
- name: 'wasmcode-archive',
8997
- root: 'wasmcode-archive/',
8929
+ ios: {
8930
+ root: 'wasmcode-ios/',
8998
8931
  },
8999
- /** iOS 与 archive 互斥:有 archive 时 iOS URL 为空,反之亦然 */
9000
8932
  iosMain: {
9001
8933
  name: 'wasmcode-ios',
9002
8934
  root: 'wasmcode-ios/',
@@ -9007,7 +8939,6 @@ const WASM_SPLIT_SUBPACKAGE_CONFIG = {
9007
8939
  },
9008
8940
  };
9009
8941
  const WASM_FILENAME_SUFFIX = '.webgl.wasm.code.unityweb.wasm';
9010
- const WASM_ARCHIVE_FILENAME_SUFFIX = '.webgl.wasm.code.unityweb.bin';
9011
8942
  const BR_SUFFIX = '.br';
9012
8943
  // 输出 JSON 格式
9013
8944
  const JSON_INDENT = 2;
@@ -9017,21 +8948,6 @@ const CONCURRENCY_LIMIT = 2;
9017
8948
  const DOWNLOAD_RETRY = 3;
9018
8949
  const WASM_SPLIT_CONFIG_FILE_NAME = 'webgl-wasm-split.js';
9019
8950
 
9020
- /**
9021
- * Unity 模块统一的 HTTP 请求封装
9022
- * DEV_HEADERS 与 ppeHeaders(从当前请求 AsyncLocalStorage 读取)的合并逻辑集中在此处
9023
- */
9024
- const request = (opts) => {
9025
- const ppeHeaders = getPpeHeaders();
9026
- const headers = { ...DEV_HEADERS, ...ppeHeaders, ...opts.headers };
9027
- return request$1({ ...opts, headers });
9028
- };
9029
- const download = (url, filePath) => {
9030
- const ppeHeaders = getPpeHeaders();
9031
- const headers = ppeHeaders && Object.keys(ppeHeaders).length > 0 ? ppeHeaders : undefined;
9032
- return download$1(url, filePath, headers);
9033
- };
9034
-
9035
8951
  // prepare.ts
9036
8952
  // 若你的 request 是 axios:你可以添加 maxBodyLength/ maxContentLength 等参数
9037
8953
  // 若是 got:可直接传 form 实例
@@ -9082,9 +8998,16 @@ async function startPrepare(params) {
9082
8998
  return request({
9083
8999
  url: `${BASE_URL}/api/stark_wasm/v4/post/prepare`,
9084
9000
  method: 'POST',
9085
- headers: formHeaders,
9086
- params: { client_key: params.client_key, with_ios: true },
9001
+ headers: {
9002
+ ...DEV_HEADERS,
9003
+ ...formHeaders, // 包含正确的 multipart/form-data; boundary=...
9004
+ },
9005
+ params: {
9006
+ client_key: params.client_key,
9007
+ with_ios: true,
9008
+ },
9087
9009
  data: form,
9010
+ // 若 request 基于 axios,建议加上以下两项以支持大文件:
9088
9011
  });
9089
9012
  }
9090
9013
 
@@ -9170,6 +9093,7 @@ async function downloadPrepared(data) {
9170
9093
  const res = await request({
9171
9094
  url: `${BASE_URL}/api/stark_wasm/v4/post/download_prepared`,
9172
9095
  method: 'POST',
9096
+ headers: DEV_HEADERS,
9173
9097
  data,
9174
9098
  });
9175
9099
  wsServer.sendUnitySplitStatus({
@@ -9191,6 +9115,9 @@ async function downloadPrepared(data) {
9191
9115
  url: downloadUrl,
9192
9116
  });
9193
9117
  await download(downloadUrl, tempWasmPath);
9118
+ /**
9119
+ * 下载完成后需要进行 br 并替换 codePath 对应的文件后再返回成功
9120
+ */
9194
9121
  fs$1.copyFileSync(tempWasmPath, willReplaceWasmPath);
9195
9122
  wsServer.sendUnitySplitStatus({
9196
9123
  status: 'download_prepared_wasm_done',
@@ -9267,7 +9194,11 @@ async function getCollectedFuncIds({ client_key, wasm_md5, }) {
9267
9194
  return request({
9268
9195
  url: `${BASE_URL}/api/stark_wasm/v4/get/collectedfuncids`,
9269
9196
  method: 'GET',
9270
- params: { client_key, wasm_md5 },
9197
+ headers: DEV_HEADERS,
9198
+ params: {
9199
+ client_key,
9200
+ wasm_md5,
9201
+ },
9271
9202
  });
9272
9203
  }
9273
9204
 
@@ -9275,7 +9206,11 @@ async function setCollect({ client_key, wasm_md5, }) {
9275
9206
  return request({
9276
9207
  url: `${BASE_URL}/api/stark_wasm/v4/post/set_collecting`,
9277
9208
  method: 'POST',
9278
- data: { client_key, wasm_md5 },
9209
+ data: {
9210
+ client_key,
9211
+ wasm_md5,
9212
+ },
9213
+ headers: DEV_HEADERS,
9279
9214
  });
9280
9215
  }
9281
9216
 
@@ -9283,15 +9218,26 @@ async function getCollecttingInfo({ client_key, wasm_md5, }) {
9283
9218
  return request({
9284
9219
  url: `${BASE_URL}/api/stark_wasm/v4/get/funccollect`,
9285
9220
  method: 'GET',
9286
- params: { client_key, wasm_md5 },
9221
+ headers: DEV_HEADERS,
9222
+ params: {
9223
+ client_key,
9224
+ wasm_md5,
9225
+ },
9287
9226
  });
9288
9227
  }
9289
9228
 
9229
+ // /api/stark_wasm/v4/post/split
9290
9230
  async function startSplit({ client_key, wasm_md5, }) {
9291
9231
  return request({
9292
9232
  url: `${BASE_URL}/api/stark_wasm/v4/post/split`,
9293
9233
  method: 'POST',
9294
- data: { client_key, wasm_md5 },
9234
+ headers: {
9235
+ ...DEV_HEADERS,
9236
+ },
9237
+ data: {
9238
+ client_key,
9239
+ wasm_md5,
9240
+ },
9295
9241
  });
9296
9242
  }
9297
9243
 
@@ -9461,8 +9407,7 @@ function pLimit(concurrency) {
9461
9407
  return generator;
9462
9408
  }
9463
9409
 
9464
- /** iOS 与 archive 互斥,二者只会存在其一 */
9465
- function updateSubpackageConfigSync(options) {
9410
+ function updateSubpackageConfigSync() {
9466
9411
  const gameJsonPath = path__namespace.join(process.cwd(), SUBPACKAGE_CONFIG_FILE_NAME);
9467
9412
  const raw = fs__namespace.readFileSync(gameJsonPath, 'utf-8');
9468
9413
  const gameJson = JSON.parse(raw);
@@ -9475,17 +9420,11 @@ function updateSubpackageConfigSync(options) {
9475
9420
  const filtered = subpackages.filter(s => s.name !== WASM_SPLIT_SUBPACKAGE_CONFIG.origin.name);
9476
9421
  /**
9477
9422
  * 基于 SUBPACKAGE_CONFIG_FILE_NAME 更新 subpackages
9478
- * iOS 与 archive 互斥:有 archive 加 archive,否则有 iOS 加 iosMain+iosSub
9479
9423
  */
9480
9424
  filtered.push(WASM_SPLIT_SUBPACKAGE_CONFIG.androidMain);
9481
9425
  filtered.push(WASM_SPLIT_SUBPACKAGE_CONFIG.androidSub);
9482
- if (options?.hasArchive) {
9483
- filtered.push(WASM_SPLIT_SUBPACKAGE_CONFIG.archive);
9484
- }
9485
- else if (options?.hasIos) {
9486
- filtered.push(WASM_SPLIT_SUBPACKAGE_CONFIG.iosMain);
9487
- filtered.push(WASM_SPLIT_SUBPACKAGE_CONFIG.iosSub);
9488
- }
9426
+ filtered.push(WASM_SPLIT_SUBPACKAGE_CONFIG.iosMain);
9427
+ filtered.push(WASM_SPLIT_SUBPACKAGE_CONFIG.iosSub);
9489
9428
  // 合并去重:存在则更新 root,不存在则新增
9490
9429
  const map = new Map(filtered.map(s => [s.name, s]));
9491
9430
  gameJson[fieldName] = Array.from(map.values());
@@ -9537,28 +9476,12 @@ async function downloadSplited(context) {
9537
9476
  ensureDirSync(splitTempDir);
9538
9477
  const mainAndroidDir = path.join(splitTempDir, WASM_SPLIT_SUBPACKAGE_CONFIG.androidMain.root);
9539
9478
  const subAndroidDir = path.join(splitTempDir, WASM_SPLIT_SUBPACKAGE_CONFIG.androidSub.root);
9540
- /** iOS archive 互斥:有 archive 时 iOS URL 为空,反之亦然 */
9541
- const hasArchive = Boolean(context.archive_wasm_download_url);
9542
- const hasIos = !hasArchive && Boolean(context.main_wasm_h5_download_url);
9543
- const archiveDir = hasArchive
9544
- ? path.join(splitTempDir, WASM_SPLIT_SUBPACKAGE_CONFIG.archive.root)
9545
- : null;
9546
- const mainIosDir = hasIos
9547
- ? path.join(splitTempDir, WASM_SPLIT_SUBPACKAGE_CONFIG.iosMain.root)
9548
- : null;
9549
- const subIosDir = hasIos
9550
- ? path.join(splitTempDir, WASM_SPLIT_SUBPACKAGE_CONFIG.iosSub.root)
9551
- : null;
9552
- const dirsToEnsure = [
9553
- mainAndroidDir,
9554
- subAndroidDir,
9555
- ...(archiveDir ? [archiveDir] : []),
9556
- ...(mainIosDir ? [mainIosDir] : []),
9557
- ...(subIosDir ? [subIosDir] : []),
9558
- ];
9559
- dirsToEnsure.forEach(ensureDirSync);
9479
+ const mainIosDir = path.join(splitTempDir, WASM_SPLIT_SUBPACKAGE_CONFIG.iosMain.root);
9480
+ const subIosDir = path.join(splitTempDir, WASM_SPLIT_SUBPACKAGE_CONFIG.iosSub.root);
9481
+ [mainAndroidDir, subAndroidDir, mainIosDir, subIosDir].forEach(ensureDirSync);
9560
9482
  const mainAndroidWasmCodeTempPath = path.join(mainAndroidDir, `${context.main_wasm_md5}${WASM_FILENAME_SUFFIX}`);
9561
9483
  const subAndroidWasmCodeTempPath = path.join(subAndroidDir, `${context.sub_wasm_md5}${WASM_FILENAME_SUFFIX}`);
9484
+ const mainIosWasmCodeTempPath = path.join(mainIosDir, `${context.main_wasm_h5_md5}${WASM_FILENAME_SUFFIX}`);
9562
9485
  const limit = pLimit(CONCURRENCY_LIMIT);
9563
9486
  try {
9564
9487
  console.log('downloadWasmSplit', context);
@@ -9569,6 +9492,7 @@ async function downloadSplited(context) {
9569
9492
  wsServer.sendUnitySplitStatus({
9570
9493
  status: 'start_download_android_sub_wasm_code',
9571
9494
  });
9495
+ wsServer.sendUnitySplitStatus({ status: 'start_download_ios_main_wasm' });
9572
9496
  /**
9573
9497
  * 需要做个保护,只有 有 URL 时才下载
9574
9498
  */
@@ -9590,41 +9514,28 @@ async function downloadSplited(context) {
9590
9514
  url: context.sub_wasm_download_url,
9591
9515
  out: subAndroidWasmCodeTempPath,
9592
9516
  })),
9593
- ...(hasArchive && archiveDir && context.wasm_archive_md5
9594
- ? [
9595
- limit(() => downloadAndCompress({
9596
- startDownloadStatus: 'start_download_archive_wasm',
9597
- downloadDoneStatus: 'download_archive_wasm_done',
9598
- url: context.archive_wasm_download_url,
9599
- out: path.join(archiveDir, `${context.wasm_archive_md5}${WASM_ARCHIVE_FILENAME_SUFFIX}`),
9600
- })),
9601
- ]
9602
- : []),
9603
- // iOS 子包(与 archive 互斥,仅当 hasIos 时下载)
9604
- ...(hasIos && mainIosDir && subIosDir
9605
- ? [
9606
- limit(() => downloadAndCompress({
9607
- startDownloadStatus: 'start_download_ios_main_wasm',
9608
- downloadDoneStatus: 'download_ios_main_wasm_done',
9609
- startCompressStatus: 'start_compress_ios_main_wasm',
9610
- compressDoneStatus: 'compress_ios_main_wasm_done',
9611
- url: context.main_wasm_h5_download_url,
9612
- out: path.join(mainIosDir, `${context.main_wasm_h5_md5}${WASM_FILENAME_SUFFIX}`),
9613
- })),
9614
- limit(() => downloadAndCompress({
9615
- startDownloadStatus: 'start_download_ios_range_json',
9616
- downloadDoneStatus: 'download_ios_range_json_done',
9617
- url: context.sub_js_range_download_url,
9618
- out: path.join(subIosDir, 'func_bytes_range.json'),
9619
- })),
9620
- limit(() => downloadAndCompress({
9621
- startDownloadStatus: 'start_download_ios_js_data_br',
9622
- downloadDoneStatus: 'download_ios_js_data_br_done',
9623
- url: context.sub_js_data_download_url,
9624
- out: path.join(subIosDir, 'subjs.data'),
9625
- })),
9626
- ]
9627
- : []),
9517
+ limit(() => downloadAndCompress({
9518
+ startDownloadStatus: 'start_download_ios_main_wasm',
9519
+ downloadDoneStatus: 'download_ios_main_wasm_done',
9520
+ startCompressStatus: 'start_compress_ios_main_wasm',
9521
+ compressDoneStatus: 'compress_ios_main_wasm_done',
9522
+ url: context.main_wasm_h5_download_url,
9523
+ out: mainIosWasmCodeTempPath,
9524
+ })),
9525
+ // 下载 ios sub js range json
9526
+ limit(() => downloadAndCompress({
9527
+ startDownloadStatus: 'start_download_ios_range_json',
9528
+ downloadDoneStatus: 'download_ios_range_json_done',
9529
+ url: context.sub_js_range_download_url,
9530
+ out: path.join(subIosDir, 'func_bytes_range.json'),
9531
+ })),
9532
+ // 下载 ios sub js data br
9533
+ limit(() => downloadAndCompress({
9534
+ startDownloadStatus: 'start_download_ios_js_data_br',
9535
+ downloadDoneStatus: 'download_ios_js_data_br_done',
9536
+ url: context.sub_js_data_download_url,
9537
+ out: path.join(subIosDir, 'subjs.data'),
9538
+ })),
9628
9539
  ]);
9629
9540
  // 复制 split/* 到项目根目录(递归、覆盖)——避免 EISDIR
9630
9541
  console.log('copy splitTempDir to root start');
@@ -9642,35 +9553,25 @@ async function downloadSplited(context) {
9642
9553
  console.log('copy splitTempDir to root end');
9643
9554
  // 更新分包配置(幂等)
9644
9555
  console.log('updateSubpackageConfigSync start');
9645
- updateSubpackageConfigSync({
9646
- hasArchive,
9647
- hasIos,
9648
- });
9556
+ updateSubpackageConfigSync();
9649
9557
  console.log('updateSubpackageConfigSync end');
9650
9558
  // 更新 wasm split 配置(保持原始状态文案)
9651
9559
  console.log('updateWasmSplitConfig start');
9652
9560
  wsServer.sendUnitySplitStatus({ status: 'start_update_wasm_split_config' });
9653
- const wasmSplitConfigFields = {
9561
+ updateWasmSplitConfig({
9654
9562
  ENABLEWASMCOLLECT: true,
9655
9563
  ORIGINALWASMMD5: `${context.original_wasm_md5}`,
9656
9564
  WASMTABLESIZE: context.table_size,
9657
9565
  GLOBALVARLIST: JSON.stringify(context.global_var_list ?? []),
9566
+ SUBJSURL: `${context.sub_js_download_url}`,
9567
+ IOS_CODE_FILE_MD5: `${context.main_wasm_h5_md5}`,
9658
9568
  ANDROID_CODE_FILE_MD5: `${context.main_wasm_md5}`,
9659
9569
  ANDROID_SUB_CODE_FILE_MD5: `${context.sub_wasm_md5}`,
9660
9570
  WASMSPLITVERSION: `${context.version}`,
9571
+ USINGWASMH5: Boolean(context.main_wasm_h5_md5),
9661
9572
  ENABLEWASMSPLIT: true,
9662
- };
9663
- // iOS 与 archive 互斥:走 iOS 时写入 iOS 相关字段,走 archive 时写入 archive 相关字段
9664
- if (hasIos) {
9665
- wasmSplitConfigFields.IOS_CODE_FILE_MD5 = `${context.main_wasm_h5_md5}`;
9666
- wasmSplitConfigFields.USINGWASMH5 = true;
9667
- wasmSplitConfigFields.SUBJSURL = `${context.sub_js_download_url ?? ''}`;
9668
- }
9669
- if (hasArchive && context.wasm_archive_md5) {
9670
- wasmSplitConfigFields.ARCHIVE_CODE_FILE_MD5 = `${context.wasm_archive_md5}`;
9671
- wasmSplitConfigFields.enableArchiveMode = true;
9672
- }
9673
- updateWasmSplitConfig(wasmSplitConfigFields);
9573
+ // IOS_SUB_JS_FILE_CONFIG: JSON.stringify(context.merged_js ?? {}),
9574
+ });
9674
9575
  wsServer.sendUnitySplitStatus({ status: 'update_wasm_split_config_done' });
9675
9576
  console.log('updateWasmSplitConfig end');
9676
9577
  return {
@@ -9713,6 +9614,7 @@ async function getSplitResult({ client_key, wasm_md5, wasm_path, }) {
9713
9614
  return request({
9714
9615
  url: `${BASE_URL}/api/stark_wasm/v4/post/download`,
9715
9616
  method: 'POST',
9617
+ headers: { ...DEV_HEADERS },
9716
9618
  data: { client_key, wasm_md5, wasm_path },
9717
9619
  });
9718
9620
  }
@@ -9758,7 +9660,13 @@ async function resetWasmSplit(data) {
9758
9660
  const res = await request({
9759
9661
  url: `${BASE_URL}/api/stark_wasm/v4/post/reset`,
9760
9662
  method: 'POST',
9761
- data: { client_key: data.clientkey, wasm_md5: data.wasmMd5 },
9663
+ headers: {
9664
+ ...DEV_HEADERS,
9665
+ },
9666
+ data: {
9667
+ client_key: data.clientkey,
9668
+ wasm_md5: data.wasmMd5,
9669
+ },
9762
9670
  });
9763
9671
  /**
9764
9672
  * 把— __TTMG_TEMP__/wasmcode/ 目录下的所有文件恢复到原本的位置,进行重置
@@ -9810,17 +9718,9 @@ async function resetWasmSplit(data) {
9810
9718
  if (fs.existsSync(androidSubpackageSubDir)) {
9811
9719
  fs.rmSync(androidSubpackageSubDir, { recursive: true });
9812
9720
  }
9813
- const archiveSubpackageDir = path.join(process.cwd(), WASM_SPLIT_SUBPACKAGE_CONFIG.archive.root);
9814
- if (fs.existsSync(archiveSubpackageDir)) {
9815
- fs.rmSync(archiveSubpackageDir, { recursive: true });
9816
- }
9817
- const iosMainDir = path.join(process.cwd(), WASM_SPLIT_SUBPACKAGE_CONFIG.iosMain.root);
9818
- if (fs.existsSync(iosMainDir)) {
9819
- fs.rmSync(iosMainDir, { recursive: true });
9820
- }
9821
- const iosSubDir = path.join(process.cwd(), WASM_SPLIT_SUBPACKAGE_CONFIG.iosSub.root);
9822
- if (fs.existsSync(iosSubDir)) {
9823
- fs.rmSync(iosSubDir, { recursive: true });
9721
+ const iosSubpackageDir = path.join(process.cwd(), WASM_SPLIT_SUBPACKAGE_CONFIG.ios.root);
9722
+ if (fs.existsSync(iosSubpackageDir)) {
9723
+ fs.rmSync(iosSubpackageDir, { recursive: true });
9824
9724
  }
9825
9725
  return res;
9826
9726
  }
@@ -9861,6 +9761,7 @@ const getTaskStatus = (params) => {
9861
9761
  return request({
9862
9762
  url: `${BASE_URL}/api/stark_wasm/v4/get/status`,
9863
9763
  method: 'GET',
9764
+ headers: DEV_HEADERS,
9864
9765
  params,
9865
9766
  });
9866
9767
  };
@@ -9869,6 +9770,7 @@ const getTaskInfo = async (params) => {
9869
9770
  return request({
9870
9771
  url: `${BASE_URL}/api/stark_wasm/v4/get/taskinfo`,
9871
9772
  method: 'GET',
9773
+ headers: DEV_HEADERS,
9872
9774
  params,
9873
9775
  });
9874
9776
  };
@@ -10085,12 +9987,13 @@ const gameWasmSplitDownloadResultRoute = {
10085
9987
  }
10086
9988
  else {
10087
9989
  const splitResult = (response.data?.result || {});
10088
- // iOS 与 archive 互斥:有 archive 时校验 archive 字段,否则校验 iOS 字段
10089
- const hasArchive = typeof splitResult.archive_wasm_download_url === 'string' && String(splitResult.archive_wasm_download_url).trim() !== '';
10090
9990
  const requiredDownloadFields = [
10091
9991
  'main_wasm_download_url',
10092
- 'sub_wasm_download_url',
10093
- ...(hasArchive ? ['archive_wasm_download_url'] : ['main_wasm_h5_download_url']),
9992
+ 'main_wasm_h5_download_url',
9993
+ // 'sub_wasm_download_url',
9994
+ // 'sub_js_download_url',
9995
+ // 'sub_js_data_download_url',
9996
+ // 'sub_js_range_download_url',
10094
9997
  ];
10095
9998
  const missingFields = requiredDownloadFields.filter(field => {
10096
9999
  const value = splitResult[field];
@@ -10764,7 +10667,7 @@ async function upload({ clientKey, note = '--', dir, }) {
10764
10667
  }
10765
10668
  }
10766
10669
 
10767
- var version = "0.3.5-beta.1";
10670
+ var version = "0.3.6-beta.1";
10768
10671
  var pkg = {
10769
10672
  version: version};
10770
10673