@ttmg/cli 0.3.2-beta.1 → 0.3.2-beta.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.
package/dist/index.js CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
+ var os = require('os');
5
+ var path = require('path');
6
+ var fs = require('fs');
4
7
  var commander = require('commander');
5
8
  var inquirer = require('inquirer');
6
- var fs = require('fs');
7
9
  var jsdom = require('jsdom');
8
10
  var prettier = require('prettier');
9
11
  var chalk = require('chalk');
10
12
  var express = require('express');
11
- var path = require('path');
12
13
  var cheerio = require('cheerio');
13
- var os = require('os');
14
14
  var worker_threads = require('worker_threads');
15
15
  var axios = require('axios');
16
16
  var qs = require('qs');
@@ -24,6 +24,7 @@ var got = require('got');
24
24
  var FormData$1 = require('form-data');
25
25
  var stream = require('stream');
26
26
  var ttmgPack = require('ttmg-pack');
27
+ var boxen = require('boxen');
27
28
  var http = require('http');
28
29
  var fs$1 = require('node:fs');
29
30
  var path$1 = require('node:path');
@@ -49,9 +50,9 @@ function _interopNamespaceDefault(e) {
49
50
  return Object.freeze(n);
50
51
  }
51
52
 
52
- var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
53
- var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
54
53
  var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
54
+ var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
55
+ var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
55
56
  var glob__namespace = /*#__PURE__*/_interopNamespaceDefault(glob);
56
57
 
57
58
  const CONFIG_FILE_NAME = 'minigame.config.json';
@@ -254,7 +255,7 @@ async function checkUpdate() {
254
255
  });
255
256
  }
256
257
 
257
- const CONFIG_PATH = path.join(os.homedir(), '.ttmgrc');
258
+ const CONFIG_PATH = process.env.TTMGRC_PATH || path.join(os.homedir(), '.ttmgrc');
258
259
  const getTTMGRC = () => {
259
260
  // only check one time
260
261
  if (!fs.existsSync(CONFIG_PATH)) {
@@ -281,7 +282,15 @@ const params = {
281
282
  sdk_version: '2.1.6-tiktok',
282
283
  };
283
284
  const prompt = inquirer.createPromptModule();
284
- async function login() {
285
+ async function login(options) {
286
+ const verbose = options?.verbose === true;
287
+ const log = (msg, data) => {
288
+ if (!verbose)
289
+ return;
290
+ console.log(chalk.gray('[ttmg login]'), msg, data !== undefined ? data : '');
291
+ };
292
+ if (verbose)
293
+ log('Verbose logging enabled');
285
294
  console.log(chalk.yellowBright('⚠️ Note: Please login with your TikTok Developer Platform account.'));
286
295
  // 增加对邮箱密码的校验
287
296
  const { email, password } = await prompt([
@@ -318,6 +327,8 @@ async function login() {
318
327
  },
319
328
  ]);
320
329
  const url = LOGIN_TT4D + '?' + new URLSearchParams(params);
330
+ log('Request URL', url);
331
+ log('Request params', { ...params, email: email.replace(/(.{2}).*(@.*)/, '$1***$2') });
321
332
  const headers = {
322
333
  'Content-Type': 'application/x-www-form-urlencoded',
323
334
  Accept: '*/*',
@@ -339,20 +350,25 @@ async function login() {
339
350
  fixed_mix_mode: '1',
340
351
  });
341
352
  try {
353
+ log('Sending POST request...');
342
354
  const response = await axios.post(url, data, {
343
355
  headers,
344
356
  maxRedirects: 20,
345
357
  timeout: 30000,
346
358
  });
359
+ log('Response status', response.status);
360
+ log('Response data', response?.data);
347
361
  if (!response?.data?.data?.user_id) {
348
362
  const errCode = response.data?.data?.error_code;
349
363
  const errMsg = response.data?.data?.description;
350
364
  if (errCode || errMsg) {
365
+ log('Login failed (api)', { errCode, errMsg, fullData: response?.data });
351
366
  spinner$1.fail(chalk.red(`login failed: ${errMsg}${errCode ? `, error_code: ${errCode}` : ''}`));
352
367
  }
353
368
  else {
369
+ log('Login failed (no user_id)', { fullResponse: response?.data });
354
370
  spinner$1.fail(chalk.red(`login failed`));
355
- console.log(response.data);
371
+ log('Login failed', { fullResponse: response });
356
372
  }
357
373
  spinner$1.stop();
358
374
  process.exit(1);
@@ -363,12 +379,14 @@ async function login() {
363
379
  user_id: response?.data?.data?.user_id,
364
380
  cookie: response?.headers['set-cookie'].join('; '),
365
381
  };
382
+ log('Login success', { user_id: data.user_id, email: data.email });
366
383
  setTTMGRC(data);
367
384
  spinner$1.succeed(chalk.bold.green('login successfully!'));
368
385
  process.exit(0);
369
386
  }
370
387
  }
371
388
  catch (error) {
389
+ log('Request error', error instanceof Error ? { message: error.message, name: error.name, stack: error.stack } : error);
372
390
  // 1. Error Title: Red and bold
373
391
  spinner$1.fail(chalk.red.bold('Failed to connect to login service'));
374
392
  // 2. Description: Normal text with bold keywords
@@ -380,6 +398,25 @@ async function login() {
380
398
  }
381
399
  }
382
400
 
401
+ async function setup(options) {
402
+ const inputLang = options?.lang;
403
+ const normalizedLang = inputLang === 'en-US' || inputLang === 'zh-CN' ? inputLang : null;
404
+ const lang = normalizedLang ??
405
+ (await inquirer.createPromptModule()([
406
+ {
407
+ type: 'list',
408
+ name: 'lang',
409
+ message: 'Select language your prefer',
410
+ choices: [
411
+ { name: 'English (en-US)', value: 'en-US' },
412
+ { name: '简体中文 (zh-CN)', value: 'zh-CN' },
413
+ ],
414
+ default: 'en-US',
415
+ },
416
+ ])).lang;
417
+ setTTMGRC({ lang });
418
+ }
419
+
383
420
  // ppe_dev_tool
384
421
  async function request({ url, method, data, headers, params, }) {
385
422
  const config = getTTMGRC();
@@ -475,115 +512,62 @@ function isAxiosError(e) {
475
512
  }
476
513
 
477
514
  async function fetchGameInfo(clientKey) {
478
- if (clientKey?.startsWith('sb')) {
479
- return await fetchGameInfoV3(clientKey);
515
+ // 访问 V4 接口
516
+ const response = await request({
517
+ url: `https://developers.tiktok.com/tiktok/v4/devportal/mini_game/devtool/info`,
518
+ method: 'GET',
519
+ params: {
520
+ client_key: clientKey,
521
+ },
522
+ });
523
+ if (!response?.data) {
524
+ return {
525
+ error: {
526
+ errorCode: response?.error?.StatusCode,
527
+ errorMsg: response?.error?.StatusMessage,
528
+ clientKey: clientKey,
529
+ },
530
+ data: null,
531
+ };
480
532
  }
481
533
  else {
482
- return await fetchGameInfoV4(clientKey);
483
- }
484
- async function fetchGameInfoV3(clientKey) {
485
- const response = await request({
486
- url: `https://developers.tiktok.com/tiktok/v3/devportal/minigame/devtool/sandbox/get`,
487
- // url: `https://developers.tiktok.com/tiktok/v3/devportal/minigame/info`,
488
- method: 'GET',
489
- params: {
490
- client_key: clientKey,
491
- // version_type: 1,
534
+ return {
535
+ error: null,
536
+ data: {
537
+ app_id: response?.data?.mini_game_id,
538
+ name: response?.data?.mini_game_name,
539
+ description: response?.data?.description,
540
+ client_key: response?.data?.client_key,
541
+ request_allowed_domains: response?.data?.trusted_domains,
542
+ display_icon_url: response?.data?.icon_url,
543
+ privacy_policy_link: response?.data?.privacy_policy,
544
+ terms_of_service_link: response?.data?.terms_of_service,
492
545
  },
493
- });
494
- const gameInfo = response?.data?.mini_game;
495
- if (!gameInfo) {
496
- return {
497
- error: {
498
- errorCode: response?.error?.StatusCode,
499
- errorMsg: response?.error?.StatusMessage,
500
- clientKey: clientKey,
501
- client_key: clientKey,
502
- },
503
- data: null,
504
- };
505
- }
506
- else {
507
- return {
508
- error: null,
509
- data: {
510
- ...gameInfo,
511
- },
512
- };
513
- }
514
- }
515
- async function fetchGameInfoV4(clientKey) {
516
- // 访问 V4 接口
517
- const response = await request({
518
- url: `https://developers.tiktok.com/tiktok/v4/devportal/mini_game/devtool/info`,
519
- method: 'GET',
520
- params: {
521
- client_key: clientKey,
522
- // version_type: 1,
523
- }
524
- // headers: {
525
- // 'x-use-ppe': '1',
526
- // 'x-tt-env': 'ppe_mg_revamp',
527
- // },
528
- });
529
- if (!response?.data) {
530
- return {
531
- error: {
532
- errorCode: response?.error?.StatusCode,
533
- errorMsg: response?.error?.StatusMessage,
534
- clientKey: clientKey,
535
- },
536
- data: null,
537
- };
538
- }
539
- else {
540
- return {
541
- error: null,
542
- data: {
543
- app_id: response?.data?.mini_game_id,
544
- name: response?.data?.mini_game_name,
545
- description: response?.data?.description,
546
- client_key: response?.data?.client_key,
547
- request_allowed_domains: response?.data?.trusted_domains,
548
- display_icon_url: response?.data?.icon_url,
549
- privacy_policy_link: response?.data?.privacy_policy,
550
- terms_of_service_link: response?.data?.terms_of_service,
551
- },
552
- };
553
- }
546
+ };
554
547
  }
555
548
  }
556
549
 
557
- async function uploadGameToPlatform({ data, name, clientKey, note = '--', appId, sandboxId, }) {
550
+ async function uploadGameToPlatform({ data, name, clientKey, note = '--', appId, }) {
551
+ if (!appId) {
552
+ return {
553
+ data: null,
554
+ error: {
555
+ message:
556
+ // 可能是登录过期也可能是没有权限导致无法通过 Client key 查询到 appid,请检查网络和登录状态,确保 clientKey 正确。
557
+ 'Upload failed: please check your network and login status, ensure clientKey is correct.',
558
+ },
559
+ };
560
+ }
558
561
  /**
559
562
  * 修复文件名中的非法字符
560
563
  */
561
564
  const fixFilename = (s) => Buffer.from(s, 'latin1').toString('utf8');
562
565
  const safeName = fixFilename(name);
563
- const sanitized = safeName.replace(/[<>:"/\\|?*\u0000-\u001F]/g, '_').slice(0, 255);
564
- if (clientKey?.startsWith('sb')) {
565
- return uploadGameToPlatformV3({
566
- data,
567
- name: sanitized,
568
- clientKey,
569
- note,
570
- appId,
571
- sandboxId,
572
- });
573
- }
574
- else {
575
- return uploadGameToPlatformV4({
576
- data,
577
- name: sanitized,
578
- clientKey,
579
- note,
580
- appId,
581
- });
582
- }
583
- }
584
- async function uploadGameToPlatformV4({ data, name, clientKey, note = '--', appId, }) {
566
+ const sanitized = safeName
567
+ .replace(/[<>:"/\\|?*\u0000-\u001F]/g, '_')
568
+ .slice(0, 255);
585
569
  const formData = new FormData();
586
- formData.append('file', new Blob([data], { type: 'application/zip' }), name);
570
+ formData.append('file', new Blob([data], { type: 'application/zip' }), sanitized);
587
571
  formData.append('client_key', clientKey);
588
572
  formData.append('note', note);
589
573
  const response = await request({
@@ -591,61 +575,31 @@ async function uploadGameToPlatformV4({ data, name, clientKey, note = '--', appI
591
575
  url: 'https://developers.tiktok.com/tiktok/v4/devportal/mini_game/devtool/upload',
592
576
  data: formData,
593
577
  headers: {
594
- // 'x-use-ppe': '1',
595
- // 'x-tt-env': 'ppe_mg_revamp',
596
578
  // @ts-ignore
597
579
  'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
598
580
  },
599
581
  });
600
- const detail = `https://developers.tiktok.com/portal/game/${appId}/code-version`;
601
- return {
602
- data: {
603
- ...response?.data,
604
- detail,
605
- client_key: clientKey,
606
- },
607
- error: response?.error,
608
- };
609
- }
610
- async function uploadGameToPlatformV3({ data, name, clientKey, note = '--', sandboxId, appId, }) {
611
- const formData = new FormData();
612
- formData.append('file', new Blob([data], { type: 'application/zip' }), name);
613
- formData.append('client_key', clientKey);
614
- formData.append('note', note);
615
- const response = await request({
616
- method: 'POST',
617
- url: 'https://developers.tiktok.com/tiktok/v3/devportal/minigame/devtool/upload',
618
- data: formData,
619
- headers: {
620
- // 'x-use-ppe': '1',
621
- // 'x-tt-env': 'ppe_dev_tool',
622
- // @ts-ignore
623
- 'Content-Type': `multipart/form-data; boundary=${formData._boundary}`,
624
- },
625
- });
626
- if (response?.data?.asset_id) {
627
- const detail = `https://developers.tiktok.com/mini-game/${appId}/sandbox/${sandboxId}/code-assets`;
628
- return {
629
- data: {
630
- ...response?.data,
631
- detail,
632
- client_key: clientKey,
633
- },
634
- error: null,
635
- };
636
- }
637
- else {
582
+ if (!response?.data?.asset_id) {
638
583
  const fileValidationError = response?.data?.file_validation_error?.join(', ');
639
- // 报错
640
584
  return {
641
585
  data: null,
642
586
  error: {
643
- StatusMessage: fileValidationError ||
587
+ message: fileValidationError ||
644
588
  response?.error?.StatusMessage ||
645
589
  'Upload failed, please try again',
646
590
  },
647
591
  };
648
592
  }
593
+ else {
594
+ return {
595
+ data: {
596
+ ...response?.data,
597
+ detail: `https://developers.tiktok.com/portal/game/${appId}/code-version`,
598
+ client_key: clientKey,
599
+ },
600
+ error: response?.error,
601
+ };
602
+ }
649
603
  }
650
604
 
651
605
  function getCurrentUser() {
@@ -664,6 +618,23 @@ function ensureDirSync(dirPath) {
664
618
  }
665
619
  }
666
620
 
621
+ var index = /*#__PURE__*/Object.freeze({
622
+ __proto__: null,
623
+ checkUpdate: checkUpdate,
624
+ download: download,
625
+ ensureDirSync: ensureDirSync,
626
+ fetchGameInfo: fetchGameInfo,
627
+ getCurrentUser: getCurrentUser,
628
+ getLocalIP: getLocalIP,
629
+ getTTMGRC: getTTMGRC,
630
+ login: login,
631
+ openUrl: openUrl,
632
+ request: request,
633
+ setTTMGRC: setTTMGRC,
634
+ setup: setup,
635
+ uploadGameToPlatform: uploadGameToPlatform
636
+ });
637
+
667
638
  const bareToRelativePlugin = {
668
639
  name: 'bare-to-relative',
669
640
  setup(build) {
@@ -1040,7 +1011,7 @@ const NATIVE_GAME_ENTRY_FILES = [
1040
1011
  'game.json',
1041
1012
  'project.config.json',
1042
1013
  ];
1043
- const SUBAPCKAGE_FILED_NAMES = ['subpackages', 'subPackages'];
1014
+ const SUBPACKAGE_FIELD_NAMES = ['subpackages', 'subPackages'];
1044
1015
  const SUBPACKAGE_CONFIG_FILE_NAME = 'game.json';
1045
1016
 
1046
1017
  // store.ts
@@ -1085,7 +1056,6 @@ const store = Store.getInstance({
1085
1056
  clientWsHost: '',
1086
1057
  clientKey: '',
1087
1058
  appId: '',
1088
- sandboxId: '',
1089
1059
  nodeServerPort: DEV_PORT,
1090
1060
  nodeWsPort: DEV_WS_PORT,
1091
1061
  packages: {},
@@ -1326,6 +1296,10 @@ async function compile(context) {
1326
1296
  isSuccess: false,
1327
1297
  });
1328
1298
  console.log(chalk.red.bold(errorMsg));
1299
+ // 非 watch 模式下,校验失败直接退出进程
1300
+ if (context?.mode !== 'watch') {
1301
+ process.exit(1);
1302
+ }
1329
1303
  }
1330
1304
  else {
1331
1305
  store.setState({
@@ -1789,21 +1763,6 @@ async function init() {
1789
1763
  }
1790
1764
  }
1791
1765
 
1792
- /**
1793
- * 检查当前目录是否为 Mini Game 项目的入口目录
1794
- */
1795
- function checkEntry() {
1796
- const entryFiles = NATIVE_GAME_ENTRY_FILES.map(file => path.join(process.cwd(), file));
1797
- const foundEntryFile = entryFiles.find(file => fs.existsSync(file));
1798
- if (!foundEntryFile) {
1799
- /**
1800
- * 如果当前目录下没有任何一个入口文件,提示用户检查当前目录是否为 Mini Game 项目的入口目录,需要提醒开发者进入到游戏项目根目录进行调试
1801
- */
1802
- console.error(chalk.red.bold(`Current directory is not a Mini Game project entry directory, please enter the game project root directory for debugging`));
1803
- process.exit(1);
1804
- }
1805
- }
1806
-
1807
1766
  function getDevToolVersion() {
1808
1767
  try {
1809
1768
  return JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8')).version;
@@ -1876,6 +1835,92 @@ const zipCwdToBuffer = (customIgnores = []) => {
1876
1835
  });
1877
1836
  };
1878
1837
 
1838
+ /**
1839
+ * 检查当前目录是否为 Mini Game 项目的入口目录
1840
+ */
1841
+ function isWorkspace() {
1842
+ const entryFiles = NATIVE_GAME_ENTRY_FILES.map(file => path.join(process.cwd(), file));
1843
+ const foundEntryFile = entryFiles.find(file => fs.existsSync(file));
1844
+ if (!foundEntryFile) {
1845
+ return false;
1846
+ }
1847
+ else {
1848
+ return true;
1849
+ }
1850
+ }
1851
+
1852
+ async function check() {
1853
+ const boxenFn = boxen.default ??
1854
+ boxen;
1855
+ const printBox = (type, message) => {
1856
+ const borderColor = 'red' ;
1857
+ const log = console.error ;
1858
+ log(boxenFn(chalk.white(message), {
1859
+ title: type,
1860
+ titleAlignment: 'left',
1861
+ borderStyle: 'round',
1862
+ borderColor,
1863
+ padding: 1,
1864
+ }));
1865
+ };
1866
+ // if (!isLogin()) {
1867
+ // printBox(
1868
+ // 'Warning',
1869
+ // `You are not logged in, please login first, run ttmg login to login with your TikTok Dev Portal account, then try again`,
1870
+ // );
1871
+ // process.exit(1);
1872
+ // }
1873
+ if (!isWorkspace()) {
1874
+ printBox('Error', `Current directory is not a Mini Game project entry directory, please enter the game project root directory for debugging`);
1875
+ process.exit(1);
1876
+ }
1877
+ // const checkResult = await checkPkgs({
1878
+ // entry: process.cwd(),
1879
+ // output: process.cwd(),
1880
+ // dev: {
1881
+ // enable: true,
1882
+ // enableSourcemap: false,
1883
+ // enableLog: false,
1884
+ // },
1885
+ // build: {
1886
+ // enableOdr: false,
1887
+ // enableAPICheck: true,
1888
+ // ...PKG_SIZE_LIMIT,
1889
+ // },
1890
+ // });
1891
+ // const errorResults = checkResult.filter(
1892
+ // item => !item.passed && item.level === 'error',
1893
+ // );
1894
+ // const warningResults = checkResult.filter(
1895
+ // item => !item.passed && item.level === 'warning',
1896
+ // );
1897
+ // if (warningResults.length > 0) {
1898
+ // const warningText = warningResults.map(item => item.msg).join('\n');
1899
+ // console.warn(
1900
+ // boxenFn(chalk.white(warningText), {
1901
+ // title: 'Warning',
1902
+ // titleAlignment: 'left',
1903
+ // borderStyle: 'round',
1904
+ // borderColor: 'yellow',
1905
+ // padding: 1,
1906
+ // }),
1907
+ // );
1908
+ // }
1909
+ // if (errorResults.length > 0) {
1910
+ // const errorText = errorResults.map(item => item.msg).join('\n');
1911
+ // console.error(
1912
+ // boxenFn(chalk.white(errorText), {
1913
+ // title: 'Error',
1914
+ // titleAlignment: 'left',
1915
+ // borderStyle: 'round',
1916
+ // borderColor: 'red',
1917
+ // padding: 1,
1918
+ // }),
1919
+ // );
1920
+ // process.exit(1);
1921
+ // }
1922
+ }
1923
+
1879
1924
  const BASE_URL = 'https://developers.tiktok.com';
1880
1925
  const DEV_HEADERS = {
1881
1926
  // 'x-use-ppe': '1',
@@ -2400,8 +2445,8 @@ function updateSubpackageConfigSync() {
2400
2445
  const gameJsonPath = path__namespace.join(process.cwd(), SUBPACKAGE_CONFIG_FILE_NAME);
2401
2446
  const raw = fs__namespace.readFileSync(gameJsonPath, 'utf-8');
2402
2447
  const gameJson = JSON.parse(raw);
2403
- const fieldName = SUBAPCKAGE_FILED_NAMES.find(k => k in gameJson) ??
2404
- SUBAPCKAGE_FILED_NAMES[0];
2448
+ const fieldName = SUBPACKAGE_FIELD_NAMES.find(k => k in gameJson) ??
2449
+ SUBPACKAGE_FIELD_NAMES[0];
2405
2450
  if (!gameJson[fieldName])
2406
2451
  gameJson[fieldName] = [];
2407
2452
  const subpackages = gameJson[fieldName];
@@ -2813,7 +2858,6 @@ async function start() {
2813
2858
  const { error, data: gameInfo } = await fetchGameInfo(clientKey);
2814
2859
  store.setState({
2815
2860
  appId: gameInfo?.app_id,
2816
- sandboxId: gameInfo?.sandbox_info?.sandbox_id,
2817
2861
  });
2818
2862
  if (error) {
2819
2863
  res.send({ error, data: null });
@@ -2825,68 +2869,23 @@ async function start() {
2825
2869
  });
2826
2870
  app.get('/game/check', async (req, res) => {
2827
2871
  const checkResult = await ttmgPack.checkPkgs({
2828
- entryDir: process.cwd(),
2829
- config: {
2830
- entry: process.cwd(),
2831
- output: outputDir,
2832
- dev: {
2833
- enable: true,
2834
- port: store.getState().nodeServerPort,
2835
- host: 'localhost',
2836
- enableSourcemap: false,
2837
- enableLog: false,
2838
- },
2839
- build: {
2840
- enableOdr: false,
2841
- enableAPICheck: true,
2842
- ...PKG_SIZE_LIMIT,
2843
- },
2872
+ entry: process.cwd(),
2873
+ output: outputDir,
2874
+ dev: {
2875
+ enable: true,
2876
+ port: store.getState().nodeServerPort,
2877
+ host: 'localhost',
2878
+ enableSourcemap: false,
2879
+ enableLog: false,
2880
+ },
2881
+ build: {
2882
+ enableOdr: false,
2883
+ enableAPICheck: true,
2884
+ ...PKG_SIZE_LIMIT,
2844
2885
  },
2845
2886
  });
2846
2887
  res.send({ code: successCode, data: checkResult });
2847
2888
  });
2848
- /**
2849
- * @description 上传游戏代码到服务器
2850
- */
2851
- // app.post('/game/upload', async (req, res) => {
2852
- // /**
2853
- // * 我要新版本不做开发者选择,直接当前 cwd 作为 entryDir,压缩成 game.zip 进行上传
2854
- // */
2855
- // const fileKeys = Object.keys(req.files);
2856
- // const uploadedFile = req.files[fileKeys[0]];
2857
- // if (!uploadedFile) {
2858
- // res.status(400).send({ code: errorCode, data: 'No file uploaded' }); // 使用正确的 HTTP 状态码
2859
- // return;
2860
- // }
2861
- // try {
2862
- // // 通过 header 获取 desc
2863
- // const desc = req.headers['ttmg-game-desc'];
2864
- // // 需要做 decodeURIComponent 处理
2865
- // const decodedDesc = decodeURIComponent(desc || '--');
2866
- // // 直接传递需要的信息
2867
- // const { data, error } = await uploadGameToPlatform({
2868
- // data: uploadedFile.data, // 这是 Buffer
2869
- // name: uploadedFile.name, // 这是文件名
2870
- // clientKey: getClientKey().clientKey,
2871
- // note: decodedDesc,
2872
- // appId: store.getState().appId,
2873
- // sandboxId: store.getState().sandboxId,
2874
- // });
2875
- // if (error) {
2876
- // res.send({ code: errorCode, error });
2877
- // } else {
2878
- // res.send({ code: successCode, data });
2879
- // }
2880
- // } catch (error) {
2881
- // // 错误处理可以更具体
2882
- // let errorMessage = 'An unknown error occurred.';
2883
- // if (error instanceof Error) {
2884
- // errorMessage = error.message;
2885
- // }
2886
- // // 打印详细错误到服务器日志,方便排查
2887
- // res.status(500).send({ code: errorCode, data: errorMessage }); // 使用正确的 HTTP 状态码
2888
- // }
2889
- // });
2890
2889
  app.post('/game/upload', async (req, res) => {
2891
2890
  try {
2892
2891
  console.log(`正在打包当前目录: ${process.cwd()} ...`);
@@ -2902,7 +2901,6 @@ async function start() {
2902
2901
  clientKey: getClientKey().clientKey,
2903
2902
  note: decodedDesc,
2904
2903
  appId: store.getState().appId,
2905
- sandboxId: store.getState().sandboxId,
2906
2904
  });
2907
2905
  if (error) {
2908
2906
  res.send({ code: errorCode, error });
@@ -3184,29 +3182,7 @@ async function start() {
3184
3182
  }
3185
3183
  });
3186
3184
  /**
3187
- *
3188
- 高鹏
3189
- 抄一下码下面的话
3190
- 我试试这个咋样看[看]闵行的是好吃的
3191
- 可以
3192
- 下周大哥来 让他别整一群的 就咱们几个吃个串挺好
3193
- 哪个unity筹备群拉你了哈
3194
-
3195
- 新知识 30% 等于部分用户
3196
- 0.3.1-unity.6
3197
- {
3198
- "code": 0,
3199
- "data": {
3200
- "isSuccess": true
3201
- },
3202
- "msg": "download success",
3203
- "ctx":
3204
- }
3205
- 发现个小问题
3206
- wasmcode1-ios 下面下载缺了一个func_bytes_range.json 以及subjs.data.br 多了一个 br 后缀
3207
- ​​​
3208
- Shift + Enter 换行
3209
-
3185
+ * @description 下载分包产物后,查询并返回下载结果
3210
3186
  */
3211
3187
  app.post('/game/wasm-split-download-result', async (req, res) => {
3212
3188
  const { clientKey, codeMd5, codePath } = req.body;
@@ -3353,7 +3329,7 @@ async function start() {
3353
3329
  }
3354
3330
 
3355
3331
  async function dev() {
3356
- checkEntry();
3332
+ await check();
3357
3333
  await init();
3358
3334
  await start();
3359
3335
  await compile();
@@ -3361,7 +3337,7 @@ async function dev() {
3361
3337
  watch();
3362
3338
  }
3363
3339
 
3364
- var version = "0.3.2-beta.1";
3340
+ var version = "0.3.2-beta.3";
3365
3341
  var pkg = {
3366
3342
  version: version};
3367
3343
 
@@ -3375,8 +3351,16 @@ program
3375
3351
  program
3376
3352
  .command('login')
3377
3353
  .description('User Dev Portal Account to Login')
3378
- .action(async () => {
3379
- await login();
3354
+ .option('--verbose', 'Print verbose logs for debugging')
3355
+ .action(async (cmd) => {
3356
+ await login({ verbose: cmd.verbose });
3357
+ });
3358
+ program
3359
+ .command('setup')
3360
+ .description('Initialize ttmg environment')
3361
+ .option('--lang <lang>', 'Language: en-US | zh-CN')
3362
+ .action(async (cmd) => {
3363
+ await setup({ lang: cmd.lang });
3380
3364
  });
3381
3365
  program
3382
3366
  .option('--h5', 'H5 Mini Game')
@@ -3399,6 +3383,12 @@ program
3399
3383
  .command('dev')
3400
3384
  .description('Open browser dev environment')
3401
3385
  .action(async () => {
3386
+ const { getCurrentUser } = await Promise.resolve().then(function () { return index; });
3387
+ const user = getCurrentUser();
3388
+ if (!user) {
3389
+ console.log('\n❌ 请先登录 TikTok 账号,执行命令: ttmg login\n');
3390
+ process.exit(1);
3391
+ }
3402
3392
  const options = program.opts();
3403
3393
  if (options.h5) {
3404
3394
  await dev$1();