@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/CHANGELOG.md +5 -0
- package/dist/index.js +243 -253
- package/dist/index.js.map +1 -1
- package/dist/package.json +4 -3
- package/dist/public/assets/index-BF340A10.js +67 -0
- package/dist/public/assets/index-BF340A10.js.br +0 -0
- package/dist/public/assets/index-C3n9EBdl.css +1 -0
- package/dist/public/assets/index-C3n9EBdl.css.br +0 -0
- package/dist/public/assets/index-CAUBU0xh.js +67 -0
- package/dist/public/assets/index-CAUBU0xh.js.br +0 -0
- package/dist/public/assets/index-TTMMHmbX.js +22 -0
- package/dist/public/assets/index-TTMMHmbX.js.br +0 -0
- package/dist/public/index.html +2 -2
- package/dist/scripts/build.js +10 -0
- package/dist/scripts/setup.js +30 -0
- package/package.json +4 -3
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
|
-
|
|
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
|
-
|
|
479
|
-
|
|
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
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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,
|
|
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
|
|
564
|
-
|
|
565
|
-
|
|
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' }),
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
2404
|
-
|
|
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
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
.
|
|
3379
|
-
|
|
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();
|