@playcraft/devkit 1.0.31-beta.11 → 1.0.31-beta.14
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/cli/bin/playable-scripts.js +6 -53
- package/cli/commands/build.js +32 -241
- package/cli/commands/builds.js +2 -13
- package/cli/commands/dev.js +1 -22
- package/cli/commands/pack.js +40 -320
- package/cli/commands/vite-dev.js +1 -7
- package/core/artifacts/emit-fonts.test.js +1 -0
- package/core/artifacts/emit.js +4 -98
- package/core/artifacts/fflate.js +1 -31
- package/core/artifacts/zip.js +1 -39
- package/core/batch-build.js +147 -1261
- package/core/constants.js +2 -20
- package/core/cos-uploader.js +23 -289
- package/core/engines/cocos/adapter-vfs-path.test.js +1 -0
- package/core/engines/cocos/clean-cache.js +5 -179
- package/core/engines/cocos/clean-cache.test.js +1 -75
- package/core/engines/cocos/cli-build.js +2 -116
- package/core/engines/cocos/cli.js +11 -38
- package/core/engines/cocos/constants.js +1 -21
- package/core/engines/cocos/creator-cli.js +1 -108
- package/core/engines/cocos/dev-server.js +4 -412
- package/core/engines/cocos/fs.js +1 -105
- package/core/engines/cocos/injects/3x/init.js +19 -438
- package/core/engines/cocos/injects/3x/main.js +2 -52
- package/core/engines/cocos/injects/libs/pako.js +1 -2
- package/core/engines/cocos/mcp-refresh.js +2 -76
- package/core/engines/cocos/merge-inline.test.js +1 -0
- package/core/engines/cocos/merge.js +9 -148
- package/core/engines/cocos/omit-playable-weight.js +10 -0
- package/core/engines/cocos/omit-playable-weight.test.js +2 -0
- package/core/engines/cocos/pack.js +1 -187
- package/core/engines/cocos/preview-cache.js +2 -48
- package/core/engines/cocos/preview-cache.test.js +1 -32
- package/core/engines/cocos/preview-concat.js +6 -189
- package/core/engines/cocos/preview-concat.test.js +1 -73
- package/core/engines/cocos/preview-json-hook.js +1 -200
- package/core/engines/cocos/preview-json-pack.js +3 -376
- package/core/engines/cocos/preview-json-pack.test.js +2 -226
- package/core/engines/cocos/preview-proxy.js +1 -132
- package/core/engines/cocos/rebundle-preview.js +2 -54
- package/core/engines/cocos/strip-social-share.js +3 -115
- package/core/engines/cocos/theme-assets.js +2 -161
- package/core/engines/cocos/theme-levels.js +1 -0
- package/core/engines/cocos/writable-cli.js +2 -248
- package/core/engines/cocos/writable-cli.test.js +1 -112
- package/core/engines/web/index.js +1 -20
- package/core/engines/web/vite.dev.js +17 -322
- package/core/engines/web/webpack.build.js +37 -522
- package/core/engines/web/webpack.common.js +11 -177
- package/core/engines/web/webpack.dev.js +6 -88
- package/core/index.js +7 -101
- package/core/injectors/apply.js +1 -94
- package/core/injectors/check-channel-matrix.js +2 -130
- package/core/injectors/spec.js +10 -217
- package/core/loaders/gltf-loader.js +28 -74
- package/core/options.js +16 -353
- package/core/plugins/AdikteevInjectorPlugin.js +4 -26
- package/core/plugins/BigoAdsInjectorPlugin.js +4 -21
- package/core/plugins/DAPIInjectorPlugin.js +2 -25
- package/core/plugins/DebuggerInjectionPlugin.js +3 -31
- package/core/plugins/ExitAPIInjectorPlugin.js +3 -56
- package/core/plugins/FflateCompressionPlugin.js +160 -307
- package/core/plugins/FflateCompressionPlugin.test.js +13 -0
- package/core/plugins/FontInjectionWebpackPlugin.js +4 -46
- package/core/plugins/LiftoffInjectorPlugin.js +4 -26
- package/core/plugins/MRAIDInjectorPlugin.js +2 -24
- package/core/plugins/MintegralInjectorPlugin.js +2 -25
- package/core/plugins/PangleInjectorPlugin.js +2 -24
- package/core/plugins/PlaycraftOrientationInjectorPlugin.js +3 -29
- package/core/plugins/SnapchatInjectorPlugin.js +4 -26
- package/core/plugins/SocialMediaInjectorPlugin.js +7 -119
- package/core/plugins/TikTokInjectorPlugin.js +2 -24
- package/core/plugins/UnityInjectorPlugin.js +8 -37
- package/core/plugins/ZipPlugin.js +20 -154
- package/core/plugins/socialMediaVitePlugin.js +2 -108
- package/core/utils/buildDefines.js +2 -30
- package/core/utils/buildTemplateString.js +5 -39
- package/core/utils/date.js +1 -16
- package/core/utils/fontRegistry.js +13 -81
- package/core/utils/fontResolver.js +37 -335
- package/core/utils/generateAdikteevHtmlWebpackPluginConfig.js +8 -42
- package/core/utils/generateBigabidHtmlWebpackPluginConfig.js +3 -30
- package/core/utils/generateInMobiHtmlWebpackPluginConfig.js +7 -43
- package/core/utils/getPlaycraftOrientationSuffix.js +2 -9
- package/core/utils/injectSDKPlugins.js +13 -68
- package/core/utils/logOptions.js +5 -46
- package/core/utils/mergeOptions.js +2 -21
- package/core/utils/obfuscateLevels.js +14 -0
- package/core/utils/obfuscateLevels.test.js +10 -0
- package/core/utils/parseArgvOptions.js +5 -125
- package/core/utils/resolveChannelFold2Zip.js +3 -15
- package/core/utils/validateThemeData.js +26 -227
- package/core/validators/pre-build-checker.js +25 -287
- package/core/validators/tracking-validator.js +40 -441
- package/core/validators/tracking-validator.test.js +2 -84
- package/core/vite.dev.js +1 -1
- package/core/webpack.build.js +1 -1
- package/core/webpack.common.js +1 -1
- package/core/webpack.dev.js +1 -1
- package/package.json +2 -3
- package/README.md +0 -262
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";/**
|
|
2
2
|
* 根据 AD_NETWORK 和 AD_PROTOCOL 注入对应的渠道 SDK 脚本插件
|
|
3
3
|
* 此函数被 webpack.dev.js 和 webpack.build.js 共用
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { ExitAPIInjectorPlugin } = require('../plugins/ExitAPIInjectorPlugin.js');
|
|
7
|
-
const { DAPIInjectorPlugin } = require('../plugins/DAPIInjectorPlugin.js');
|
|
8
|
-
const { PangleInjectorPlugin } = require('../plugins/PangleInjectorPlugin.js');
|
|
9
|
-
const { TikTokInjectorPlugin } = require('../plugins/TikTokInjectorPlugin.js');
|
|
10
|
-
const { MintegralInjectorPlugin } = require('../plugins/MintegralInjectorPlugin.js');
|
|
11
|
-
const { MRAIDInjectorPlugin } = require('../plugins/MRAIDInjectorPlugin.js');
|
|
12
|
-
const { BigoAdsInjectorPlugin } = require('../plugins/BigoAdsInjectorPlugin.js');
|
|
13
|
-
const { LiftoffInjectorPlugin } = require('../plugins/LiftoffInjectorPlugin.js');
|
|
14
|
-
const { SnapchatInjectorPlugin } = require('../plugins/SnapchatInjectorPlugin.js');
|
|
15
|
-
const { AdikteevInjectorPlugin } = require('../plugins/AdikteevInjectorPlugin.js');
|
|
16
|
-
const { UnityInjectorPlugin } = require('../plugins/UnityInjectorPlugin.js');
|
|
17
|
-
const { SocialMediaInjectorPlugin } = require('../plugins/SocialMediaInjectorPlugin.js');
|
|
18
|
-
|
|
19
|
-
/**
|
|
4
|
+
*/const{ExitAPIInjectorPlugin}=require("../plugins/ExitAPIInjectorPlugin.js");const{DAPIInjectorPlugin}=require("../plugins/DAPIInjectorPlugin.js");const{PangleInjectorPlugin}=require("../plugins/PangleInjectorPlugin.js");const{TikTokInjectorPlugin}=require("../plugins/TikTokInjectorPlugin.js");const{MintegralInjectorPlugin}=require("../plugins/MintegralInjectorPlugin.js");const{MRAIDInjectorPlugin}=require("../plugins/MRAIDInjectorPlugin.js");const{BigoAdsInjectorPlugin}=require("../plugins/BigoAdsInjectorPlugin.js");const{LiftoffInjectorPlugin}=require("../plugins/LiftoffInjectorPlugin.js");const{SnapchatInjectorPlugin}=require("../plugins/SnapchatInjectorPlugin.js");const{AdikteevInjectorPlugin}=require("../plugins/AdikteevInjectorPlugin.js");const{UnityInjectorPlugin}=require("../plugins/UnityInjectorPlugin.js");const{SocialMediaInjectorPlugin}=require("../plugins/SocialMediaInjectorPlugin.js");/**
|
|
20
5
|
* 注入渠道 SDK 插件到 webpack 配置中
|
|
21
6
|
* @param {import('webpack').Configuration} webpackConfig - webpack 配置对象
|
|
22
7
|
* @param {Object} options - 配置选项
|
|
@@ -27,54 +12,14 @@ const { SocialMediaInjectorPlugin } = require('../plugins/SocialMediaInjectorPlu
|
|
|
27
12
|
* @param {string} [options.themeName] - 当前主题名
|
|
28
13
|
* @param {object} [options.themeConfig] - builds.config.js 中的 themes 配置
|
|
29
14
|
* @param {object} [options.mergedData] - 预合并的主题数据(可选)
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
webpackConfig.plugins.push(new MRAIDInjectorPlugin());
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// 渠道特定注入
|
|
46
|
-
if (adNetwork === 'google') {
|
|
47
|
-
webpackConfig.plugins.push(new ExitAPIInjectorPlugin(playcraftOrientationValue));
|
|
48
|
-
} else if (adNetwork === 'unity') {
|
|
49
|
-
// Unity Ads 使用专门的 UnityInjectorPlugin
|
|
50
|
-
webpackConfig.plugins.push(new UnityInjectorPlugin());
|
|
51
|
-
} else if (adNetwork === 'pangle') {
|
|
52
|
-
webpackConfig.plugins.push(new PangleInjectorPlugin());
|
|
53
|
-
} else if (adNetwork === 'tiktok') {
|
|
54
|
-
webpackConfig.plugins.push(new TikTokInjectorPlugin());
|
|
55
|
-
} else if (adNetwork === 'mintegral') {
|
|
56
|
-
webpackConfig.plugins.push(new MintegralInjectorPlugin());
|
|
57
|
-
} else if (adNetwork === 'bigoads') {
|
|
58
|
-
// BigoAds 在 dev 模式下注入模拟配置
|
|
59
|
-
webpackConfig.plugins.push(new BigoAdsInjectorPlugin());
|
|
60
|
-
} else if (adNetwork === 'liftoff') {
|
|
61
|
-
webpackConfig.plugins.push(new LiftoffInjectorPlugin());
|
|
62
|
-
} else if (adNetwork === 'snapchat') {
|
|
63
|
-
// Snapchat 注入 ScPlayableAd SDK
|
|
64
|
-
webpackConfig.plugins.push(new SnapchatInjectorPlugin());
|
|
65
|
-
} else if (adNetwork === 'adikteev') {
|
|
66
|
-
// Adikteev 注入 MRAID mock 和占位符变量
|
|
67
|
-
webpackConfig.plugins.push(new AdikteevInjectorPlugin());
|
|
68
|
-
} else if (adNetwork === 'social_media') {
|
|
69
|
-
// social_media 渠道:注入 OG / Twitter meta 标签,让 Facebook / LinkedIn 爬取时
|
|
70
|
-
// 能拿到正确的标题/描述/预览图。注意 Telegram / Slack / Discord 也读 OG meta
|
|
71
|
-
webpackConfig.plugins.push(new SocialMediaInjectorPlugin({
|
|
72
|
-
projectRoot,
|
|
73
|
-
themeName,
|
|
74
|
-
themeConfig,
|
|
75
|
-
mergedData,
|
|
76
|
-
}));
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
exports.injectSDKPlugins = injectSDKPlugins;
|
|
15
|
+
*/function injectSDKPlugins(webpackConfig,options){const{network:adNetwork,protocol:adProtocol,playcraftOrientationValue,projectRoot,themeName,themeConfig,mergedData}=options;// 协议层注入
|
|
16
|
+
if("dapi"===adProtocol){webpackConfig.plugins.push(new DAPIInjectorPlugin)}else if("mraid"===adProtocol){// ironsource / remerge:HTML 内必须带 <script src="mraid.js">
|
|
17
|
+
// Unity 使用专门的 UnityInjectorPlugin(在渠道特定注入中处理)
|
|
18
|
+
if(adNetwork==="ironsource"||adNetwork==="remerge"){webpackConfig.plugins.push(new MRAIDInjectorPlugin)}}// 渠道特定注入
|
|
19
|
+
if(adNetwork==="google"){webpackConfig.plugins.push(new ExitAPIInjectorPlugin(playcraftOrientationValue))}else if(adNetwork==="unity"){// Unity Ads 使用专门的 UnityInjectorPlugin
|
|
20
|
+
webpackConfig.plugins.push(new UnityInjectorPlugin)}else if(adNetwork==="pangle"){webpackConfig.plugins.push(new PangleInjectorPlugin)}else if(adNetwork==="tiktok"){webpackConfig.plugins.push(new TikTokInjectorPlugin)}else if(adNetwork==="mintegral"){webpackConfig.plugins.push(new MintegralInjectorPlugin)}else if(adNetwork==="bigoads"){// BigoAds 在 dev 模式下注入模拟配置
|
|
21
|
+
webpackConfig.plugins.push(new BigoAdsInjectorPlugin)}else if(adNetwork==="liftoff"){webpackConfig.plugins.push(new LiftoffInjectorPlugin)}else if(adNetwork==="snapchat"){// Snapchat 注入 ScPlayableAd SDK
|
|
22
|
+
webpackConfig.plugins.push(new SnapchatInjectorPlugin)}else if(adNetwork==="adikteev"){// Adikteev 注入 MRAID mock 和占位符变量
|
|
23
|
+
webpackConfig.plugins.push(new AdikteevInjectorPlugin)}else if(adNetwork==="social_media"){// social_media 渠道:注入 OG / Twitter meta 标签,让 Facebook / LinkedIn 爬取时
|
|
24
|
+
// 能拿到正确的标题/描述/预览图。注意 Telegram / Slack / Discord 也读 OG meta
|
|
25
|
+
webpackConfig.plugins.push(new SocialMediaInjectorPlugin({projectRoot,themeName,themeConfig,mergedData}))}}exports.injectSDKPlugins=injectSDKPlugins;
|
package/core/utils/logOptions.js
CHANGED
|
@@ -1,47 +1,6 @@
|
|
|
1
|
-
var prettyjson
|
|
2
|
-
|
|
3
|
-
/**
|
|
1
|
+
"use strict";var prettyjson=require("prettyjson");/**
|
|
4
2
|
* Log provided options into console output
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (process.env.NODE_ENV === 'production') {
|
|
10
|
-
isProduction = true;
|
|
11
|
-
delete logOptions.port;
|
|
12
|
-
delete logOptions.open;
|
|
13
|
-
} else if (process.env.NODE_ENV === 'development') {
|
|
14
|
-
delete logOptions.outDir;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (Object.keys(logOptions.compilation).length === 0 || !isProduction) delete logOptions.compilation;
|
|
18
|
-
if (Object.keys(logOptions.adNetworkNames).length === 0 || !isProduction) delete logOptions.adNetworkNames;
|
|
19
|
-
if (Object.keys(logOptions.defines).length === 0) delete logOptions.defines;
|
|
20
|
-
if (logOptions.zip === false || !isProduction) delete logOptions.zip;
|
|
21
|
-
if (logOptions.tsConfig === 'tsconfig.json') delete logOptions.tsConfig;
|
|
22
|
-
if (logOptions.jsConfig === 'jsconfig.json') delete logOptions.jsConfig;
|
|
23
|
-
if (logOptions.buildConfig === 'build.json') delete logOptions.buildConfig;
|
|
24
|
-
if (logOptions.language === 'en') delete logOptions.language;
|
|
25
|
-
// playcraftOrientation/playcraftOrientationChannel 为默认值时不显示,避免日志噪音
|
|
26
|
-
if (Array.isArray(logOptions.playcraftOrientation) && logOptions.playcraftOrientation.length === 1 && logOptions.playcraftOrientation[0] === 'both') {
|
|
27
|
-
delete logOptions.playcraftOrientation;
|
|
28
|
-
}
|
|
29
|
-
if (Array.isArray(logOptions.playcraftOrientationChannel) && logOptions.playcraftOrientationChannel.length === 0) {
|
|
30
|
-
delete logOptions.playcraftOrientationChannel;
|
|
31
|
-
}
|
|
32
|
-
if (!logOptions.playcraftOrientationValue || logOptions.playcraftOrientationValue === 'both') {
|
|
33
|
-
delete logOptions.playcraftOrientationValue;
|
|
34
|
-
}
|
|
35
|
-
// 在 dev 模式下,如果 network 为默认值 preview 则不显示
|
|
36
|
-
if (!isProduction && logOptions.network === 'preview') delete logOptions.network;
|
|
37
|
-
// 在 dev 模式下,如果 protocol 为默认值 none 则不显示
|
|
38
|
-
if (!isProduction && logOptions.protocol === 'none') delete logOptions.protocol;
|
|
39
|
-
delete logOptions.filename;
|
|
40
|
-
delete logOptions.app;
|
|
41
|
-
delete logOptions.name;
|
|
42
|
-
delete logOptions.googlePlayUrl;
|
|
43
|
-
delete logOptions.appStoreUrl;
|
|
44
|
-
if (logOptions.obfuscateLevel === 2) delete logOptions.obfuscateLevel;
|
|
45
|
-
|
|
46
|
-
console.log(prettyjson.render(logOptions, {}, 2));
|
|
47
|
-
};
|
|
3
|
+
*/exports.logOptions=function logOptions(options){let logOptions={mode:process.env.NODE_ENV,...options};let isProduction=false;if(process.env.NODE_ENV==="production"){isProduction=true;delete logOptions.port;delete logOptions.open}else if(process.env.NODE_ENV==="development"){delete logOptions.outDir}if(Object.keys(logOptions.compilation).length===0||!isProduction)delete logOptions.compilation;if(Object.keys(logOptions.adNetworkNames).length===0||!isProduction)delete logOptions.adNetworkNames;if(Object.keys(logOptions.defines).length===0)delete logOptions.defines;if(logOptions.zip===false||!isProduction)delete logOptions.zip;if(logOptions.tsConfig==="tsconfig.json")delete logOptions.tsConfig;if(logOptions.jsConfig==="jsconfig.json")delete logOptions.jsConfig;if(logOptions.buildConfig==="build.json")delete logOptions.buildConfig;if(logOptions.language==="en")delete logOptions.language;// playcraftOrientation/playcraftOrientationChannel 为默认值时不显示,避免日志噪音
|
|
4
|
+
if(Array.isArray(logOptions.playcraftOrientation)&&logOptions.playcraftOrientation.length===1&&logOptions.playcraftOrientation[0]==="both"){delete logOptions.playcraftOrientation}if(Array.isArray(logOptions.playcraftOrientationChannel)&&logOptions.playcraftOrientationChannel.length===0){delete logOptions.playcraftOrientationChannel}if(!logOptions.playcraftOrientationValue||logOptions.playcraftOrientationValue==="both"){delete logOptions.playcraftOrientationValue}// 在 dev 模式下,如果 network 为默认值 preview 则不显示
|
|
5
|
+
if(!isProduction&&logOptions.network==="preview")delete logOptions.network;// 在 dev 模式下,如果 protocol 为默认值 none 则不显示
|
|
6
|
+
if(!isProduction&&logOptions.protocol==="none")delete logOptions.protocol;delete logOptions.filename;delete logOptions.app;delete logOptions.name;delete logOptions.googlePlayUrl;delete logOptions.appStoreUrl;if(logOptions.obfuscateLevel===2)delete logOptions.obfuscateLevel;console.log(prettyjson.render(logOptions,{},2))};
|
|
@@ -1,25 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";/**
|
|
2
2
|
* Merges two option objects with deep merge for 'defines' and 'build' properties
|
|
3
3
|
* @param {import('../index').CLIOptions} options1 - First options object
|
|
4
4
|
* @param {Partial<import('../index').CLIOptions>} [options2] - Second options object
|
|
5
5
|
* @returns {import('../index').CLIOptions} Merged options object with combined defines and build properties
|
|
6
|
-
*/
|
|
7
|
-
exports.mergeOptions = function mergeOptions(options1, options2) {
|
|
8
|
-
if (!options1) return {};
|
|
9
|
-
if (!options2) return options1;
|
|
10
|
-
|
|
11
|
-
const defines = Object.assign({}, options1.defines, options2.defines);
|
|
12
|
-
const build = Object.assign({}, options1.build, options2.build);
|
|
13
|
-
const compilation = Object.assign({}, options1.compilation, options2.compilation);
|
|
14
|
-
const adNetworkNames = Object.assign({}, options1.adNetworkNames, options2.adNetworkNames);
|
|
15
|
-
const cocos = Object.assign({}, options1.cocos, options2.cocos);
|
|
16
|
-
const options = Object.assign({}, options1, options2);
|
|
17
|
-
|
|
18
|
-
options.defines = defines;
|
|
19
|
-
options.compilation = compilation;
|
|
20
|
-
options.adNetworkNames = adNetworkNames;
|
|
21
|
-
options.build = build;
|
|
22
|
-
options.cocos = cocos;
|
|
23
|
-
|
|
24
|
-
return options;
|
|
25
|
-
};
|
|
6
|
+
*/exports.mergeOptions=function mergeOptions(options1,options2){if(!options1)return{};if(!options2)return options1;const defines=Object.assign({},options1.defines,options2.defines);const build=Object.assign({},options1.build,options2.build);const compilation=Object.assign({},options1.compilation,options2.compilation);const adNetworkNames=Object.assign({},options1.adNetworkNames,options2.adNetworkNames);const cocos=Object.assign({},options1.cocos,options2.cocos);const options=Object.assign({},options1,options2);options.defines=defines;options.compilation=compilation;options.adNetworkNames=adNetworkNames;options.build=build;options.cocos=cocos;return options};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";/**
|
|
2
|
+
* Same ladder as the Phaser webpack build:
|
|
3
|
+
* 0 none, 1 terser, 2 basic obfuscator, 3 + dead code, 4 maximum.
|
|
4
|
+
* Cocos applies this only to business bundles (assets/main/index.js).
|
|
5
|
+
* Order matches webpack: obfuscator loader, then Terser minimizer.
|
|
6
|
+
*/const LEVEL_NAMES=["none","terser-only","basic","dead-code","maximum"];function obfuscateLevelName(level){const n=Number(level)||0;return LEVEL_NAMES[n]||LEVEL_NAMES[0]}function obfuscatorOptionsForLevel(level){const n=Number(level)||0;if(n<2)return null;const options={target:"browser",sourceMap:false,selfDefending:false,renameProperties:false,disableConsoleOutput:true,splitStrings:false,unicodeEscapeSequence:false};if(n===2){Object.assign(options,{controlFlowFlattening:true,controlFlowFlatteningThreshold:0.75,deadCodeInjection:false,stringArray:true,stringArrayThreshold:0.75,stringArrayEncoding:["base64"],stringArrayIndexShift:true,stringArrayRotate:true,stringArrayShuffle:true,stringArrayWrappersCount:2,stringArrayWrappersChainedCalls:true,stringArrayWrappersType:"function",stringArrayCallsTransform:true,stringArrayCallsTransformThreshold:0.75,transformObjectKeys:true,identifierNamesGenerator:"hexadecimal"})}else if(n===3){Object.assign(options,{controlFlowFlattening:true,controlFlowFlatteningThreshold:0.75,deadCodeInjection:true,deadCodeInjectionThreshold:0.4,stringArray:true,stringArrayThreshold:0.75,stringArrayEncoding:["base64"],stringArrayIndexShift:true,stringArrayRotate:true,stringArrayShuffle:true,stringArrayWrappersCount:2,stringArrayWrappersChainedCalls:true,stringArrayWrappersType:"function",stringArrayCallsTransform:true,stringArrayCallsTransformThreshold:0.75,transformObjectKeys:true,identifierNamesGenerator:"hexadecimal"})}else{Object.assign(options,{controlFlowFlattening:true,controlFlowFlatteningThreshold:1,deadCodeInjection:true,deadCodeInjectionThreshold:0.5,stringArray:true,stringArrayThreshold:1,stringArrayEncoding:["rc4"],stringArrayIndexShift:true,stringArrayRotate:true,stringArrayShuffle:true,stringArrayWrappersCount:3,stringArrayWrappersChainedCalls:true,stringArrayWrappersType:"function",stringArrayCallsTransform:true,stringArrayCallsTransformThreshold:1,transformObjectKeys:true,identifierNamesGenerator:"hexadecimal",splitStrings:true,splitStringsChunkLength:5,unicodeEscapeSequence:true})}return options}/**
|
|
7
|
+
* Cocos obfuscates one already-minified main bundle, not per-source files.
|
|
8
|
+
* Phaser's level 4 (RC4 + control-flow 1 + splitStrings) does not finish on that file.
|
|
9
|
+
* Keep stringArrayThreshold at 1 so literals are covered, and drop the options that hang.
|
|
10
|
+
*/function obfuscatorOptionsForCocos(level){const options=obfuscatorOptionsForLevel(level);if(!options||Number(level)<4)return options;return{...options,stringArrayEncoding:["base64"],stringArrayThreshold:1,controlFlowFlattening:true,controlFlowFlatteningThreshold:0.75,deadCodeInjection:true,deadCodeInjectionThreshold:0.4,stringArrayWrappersCount:2,stringArrayCallsTransformThreshold:0.75,splitStrings:false,unicodeEscapeSequence:false}}function terserOptions(){return{safari10:true,mangle:{reserved:["$"],toplevel:true},compress:{drop_console:true,arrows:false,drop_debugger:true,unused:true,dead_code:true,passes:3,inline:3,collapse_vars:true,reduce_vars:true,hoist_vars:true,hoist_funs:true,sequences:20,properties:true,conditionals:true,comparisons:true,booleans:true,loops:true,if_return:true,join_vars:true,negate_iife:true,side_effects:true,switches:true,typeofs:true,unsafe:false,keep_fargs:false},output:{comments:false,quote_style:3,beautify:false,wrap_iife:true,ecma:2015},toplevel:true,keep_classnames:false,keep_fnames:false}}/**
|
|
11
|
+
* Creator web-mobile gameplay bundle. Engine (`cocos-js`, `assets/internal`)
|
|
12
|
+
* and the resources asset table stay as Creator emitted them.
|
|
13
|
+
* @param {string} objKey path inside the web-mobile folder
|
|
14
|
+
*/function isCocosBusinessScript(objKey){const key=String(objKey||"").replace(/\\/g,"/").replace(/^\//,"");return /^assets\/main\/index(?:\.[^/]+)?\.js$/.test(key)}async function applyObfuscation(code,level){const n=Number(level)||0;if(n<=0||typeof code!=="string"||!code)return code;let out=code;const obf=obfuscatorOptionsForCocos(n);if(obf){if(n>=4){console.log("[cocos] level 4 on the main bundle uses base64 string arrays; RC4 and full control-flow do not finish")}const JavaScriptObfuscator=require("javascript-obfuscator");out=JavaScriptObfuscator.obfuscate(out,obf).getObfuscatedCode()}if(n>=1){const{minify}=require("terser");const result=await minify(out,terserOptions());if(!result||!result.code){throw new Error(`terser produced empty output at obfuscate level ${n}`)}out=result.code}return out}module.exports={LEVEL_NAMES,obfuscateLevelName,obfuscatorOptionsForLevel,obfuscatorOptionsForCocos,terserOptions,isCocosBusinessScript,applyObfuscation};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";const{describe,it}=require("node:test");const assert=require("node:assert/strict");const vm=require("vm");const{isCocosBusinessScript,applyObfuscation,obfuscatorOptionsForLevel,obfuscatorOptionsForCocos}=require("./obfuscateLevels.js");const SAMPLE=`
|
|
2
|
+
System.register("chunks:///_virtual/Demo.js", ["./rollupPluginModLoBabelHelpers.js", "cc"], function (exports) {
|
|
3
|
+
return {
|
|
4
|
+
setters: [function () {}, function () {}],
|
|
5
|
+
execute: function () {
|
|
6
|
+
exports("findPath", function (start, goal) { return start + goal; });
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
});
|
|
10
|
+
`;function loadRegisters(code){const registered=[];const context=vm.createContext({System:{register(name,deps,factory){const ns=factory(function(){});registered.push({name:String(name),deps:Array.from(deps,dep=>String(dep)),keys:ns&&typeof ns==="object"?Object.keys(ns).map(String).sort():[]})}},console});vm.runInContext(code,context,{timeout:5000});return registered}describe("isCocosBusinessScript",()=>{it("matches the main bundle only",()=>{assert.equal(isCocosBusinessScript("assets/main/index.js"),true);assert.equal(isCocosBusinessScript("assets/main/index.abc123.js"),true);assert.equal(isCocosBusinessScript("assets/internal/index.js"),false);assert.equal(isCocosBusinessScript("assets/resources/index.js"),false);assert.equal(isCocosBusinessScript("cocos-js/cc.js"),false)})});describe("applyObfuscation",()=>{it("keeps System.register setters and execute at every level",async()=>{const original=loadRegisters(SAMPLE);assert.deepEqual(original[0].keys,["execute","setters"]);for(const level of[1,2,3,4]){const out=await applyObfuscation(SAMPLE,level);assert.equal(typeof out,"string");assert.ok(out.length>0,`level ${level} empty`);const registered=loadRegisters(out);assert.equal(registered.length,1,`level ${level} register count`);assert.deepEqual(registered[0].keys,["execute","setters"],`level ${level} keys`);assert.deepEqual(registered[0].deps,original[0].deps,`level ${level} deps`)}});it("level 0 and 1 do not enable the obfuscator",()=>{assert.equal(obfuscatorOptionsForLevel(0),null);assert.equal(obfuscatorOptionsForLevel(1),null);assert.equal(obfuscatorOptionsForLevel(2).stringArray,true);assert.equal(obfuscatorOptionsForLevel(3).deadCodeInjection,true);assert.equal(obfuscatorOptionsForLevel(4).stringArrayEncoding[0],"rc4");assert.equal(obfuscatorOptionsForCocos(4).stringArrayEncoding[0],"base64");assert.equal(obfuscatorOptionsForCocos(4).stringArrayThreshold,1);assert.equal(obfuscatorOptionsForCocos(4).splitStrings,false)})});
|
|
@@ -1,128 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
const allowedAdNetworks = [
|
|
3
|
-
'preview',
|
|
4
|
-
'applovin',
|
|
5
|
-
'unity',
|
|
6
|
-
'google',
|
|
7
|
-
'ironsource',
|
|
8
|
-
'facebook',
|
|
9
|
-
'moloco',
|
|
10
|
-
'adcolony',
|
|
11
|
-
'mintegral',
|
|
12
|
-
'vungle',
|
|
13
|
-
'tapjoy',
|
|
14
|
-
'snapchat',
|
|
15
|
-
'tiktok',
|
|
16
|
-
'appreciate',
|
|
17
|
-
'chartboost',
|
|
18
|
-
'pangle',
|
|
19
|
-
'mytarget',
|
|
20
|
-
'liftoff',
|
|
21
|
-
'smadex',
|
|
22
|
-
'adikteev',
|
|
23
|
-
'bigabid',
|
|
24
|
-
'inmobi',
|
|
25
|
-
'bigoads',
|
|
26
|
-
'remerge',
|
|
27
|
-
'social_media'
|
|
28
|
-
];
|
|
29
|
-
/** @type {AD_PROTOCOL[]} List of supported advertising protocols */
|
|
30
|
-
const allowedAdProtocols = ['none', 'mraid', 'dapi'];
|
|
31
|
-
|
|
32
|
-
/** @type {AD_NETWORK[]} List of advertising partners that support MRAID protocol */
|
|
33
|
-
const mraidPartners = [
|
|
34
|
-
'ironsource',
|
|
35
|
-
'applovin',
|
|
36
|
-
'unity',
|
|
37
|
-
'appreciate',
|
|
38
|
-
'chartboost',
|
|
39
|
-
'mytarget',
|
|
40
|
-
'liftoff',
|
|
41
|
-
'adcolony',
|
|
42
|
-
'adikteev',
|
|
43
|
-
'bigabid',
|
|
44
|
-
'inmobi',
|
|
45
|
-
'remerge'
|
|
46
|
-
];
|
|
47
|
-
|
|
48
|
-
/** @type {LANGUAGE[]} */
|
|
49
|
-
const allowedLanguages = ['auto', 'en', 'es', 'zh', 'hi', 'ar', 'fr', 'de', 'ja', 'pt'];
|
|
50
|
-
|
|
51
|
-
/** @type {('both'|'landscape'|'portrait')[]} playcraftOrientation 允许的横竖屏方向版本取值 */
|
|
52
|
-
const allowedPlaycraftOrientations = ['both', 'landscape', 'portrait'];
|
|
53
|
-
|
|
54
|
-
/** @type {('phaser'|'threejs'|'cocos')[]} */
|
|
55
|
-
const allowedEngines = ['phaser', 'threejs', 'cocos'];
|
|
56
|
-
|
|
57
|
-
const WEB_ENGINES = ['phaser', 'threejs'];
|
|
58
|
-
|
|
59
|
-
function isWebEngine(engine) {
|
|
60
|
-
return !engine || WEB_ENGINES.includes(engine);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
1
|
+
"use strict";/** @type {string[]} List of supported advertising networks */const allowedAdNetworks=["preview","applovin","unity","google","ironsource","facebook","moloco","adcolony","mintegral","vungle","tapjoy","snapchat","tiktok","appreciate","chartboost","pangle","mytarget","liftoff","smadex","adikteev","bigabid","inmobi","bigoads","remerge","social_media"];/** @type {AD_PROTOCOL[]} List of supported advertising protocols */const allowedAdProtocols=["none","mraid","dapi"];/** @type {AD_NETWORK[]} List of advertising partners that support MRAID protocol */const mraidPartners=["ironsource","applovin","unity","appreciate","chartboost","mytarget","liftoff","adcolony","adikteev","bigabid","inmobi","remerge"];/** @type {LANGUAGE[]} */const allowedLanguages=["auto","en","es","zh","hi","ar","fr","de","ja","pt"];/** @type {('both'|'landscape'|'portrait')[]} playcraftOrientation 允许的横竖屏方向版本取值 */const allowedPlaycraftOrientations=["both","landscape","portrait"];/** @type {('phaser'|'threejs'|'cocos')[]} */const allowedEngines=["phaser","threejs","cocos"];const WEB_ENGINES=["phaser","threejs"];function isWebEngine(engine){return!engine||WEB_ENGINES.includes(engine)}/**
|
|
64
2
|
* Parses command line arguments based on provided options configuration
|
|
65
3
|
* @param {import('../index').CLIOptionConfig[]} posiibleOptions - Array of possible options to parse
|
|
66
4
|
* @returns {Record<string, any>} Parsed options object with values from command line arguments
|
|
67
|
-
*/
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const cliExplicitKeys = new Set();
|
|
72
|
-
|
|
73
|
-
for (let possibleOption of posiibleOptions) {
|
|
74
|
-
if (possibleOption.defaultValue !== undefined)
|
|
75
|
-
argvOptions[possibleOption.alias || possibleOption.name] = possibleOption.defaultValue;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
let adNetwork = null;
|
|
79
|
-
|
|
80
|
-
for (let i = 2; i < process.argv.length; i++) {
|
|
81
|
-
let key = process.argv[i];
|
|
82
|
-
let inlineValue = null;
|
|
83
|
-
|
|
84
|
-
// 支持 --key=value 格式
|
|
85
|
-
if (key.includes('=')) {
|
|
86
|
-
const eqIndex = key.indexOf('=');
|
|
87
|
-
inlineValue = key.slice(eqIndex + 1);
|
|
88
|
-
key = key.slice(0, eqIndex);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const allowedOption = posiibleOptions.find((e) => '--' + e.name === key);
|
|
92
|
-
|
|
93
|
-
if (allowedOption) {
|
|
94
|
-
let value = true;
|
|
95
|
-
if (allowedOption.hasValue) {
|
|
96
|
-
// 优先使用内联值(--key=value),否则使用下一个参数
|
|
97
|
-
value = inlineValue !== null ? inlineValue : process.argv[++i];
|
|
98
|
-
if (allowedOption.parser) value = allowedOption.parser(value);
|
|
99
|
-
}
|
|
100
|
-
const optionKey = allowedOption.alias || allowedOption.name;
|
|
101
|
-
argvOptions[optionKey] = value;
|
|
102
|
-
cliExplicitKeys.add(optionKey);
|
|
103
|
-
} else if (!adNetwork) adNetwork = key;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (posiibleOptions.find((e) => e.name === 'network')) {
|
|
107
|
-
if (adNetwork && allowedAdNetworks.includes(adNetwork)) {
|
|
108
|
-
argvOptions['network'] = adNetwork;
|
|
109
|
-
}
|
|
110
|
-
if (posiibleOptions.find((e) => e.name === 'protocol')) {
|
|
111
|
-
if (mraidPartners.includes(argvOptions['network']) && argvOptions['protocol'] === 'none') {
|
|
112
|
-
argvOptions['protocol'] = 'mraid';
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
argvOptions._cliExplicitKeys = cliExplicitKeys;
|
|
118
|
-
return argvOptions;
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
exports.allowedAdNetworks = allowedAdNetworks;
|
|
122
|
-
exports.allowedAdProtocols = allowedAdProtocols;
|
|
123
|
-
exports.mraidPartners = mraidPartners;
|
|
124
|
-
exports.allowedLanguages = allowedLanguages;
|
|
125
|
-
exports.allowedPlaycraftOrientations = allowedPlaycraftOrientations;
|
|
126
|
-
exports.allowedEngines = allowedEngines;
|
|
127
|
-
exports.WEB_ENGINES = WEB_ENGINES;
|
|
128
|
-
exports.isWebEngine = isWebEngine;
|
|
5
|
+
*/exports.parseArgvOptions=function parseArgvOptions(posiibleOptions){const argvOptions={};// Track which options were explicitly set via CLI args
|
|
6
|
+
const cliExplicitKeys=new Set;for(let possibleOption of posiibleOptions){if(possibleOption.defaultValue!==undefined)argvOptions[possibleOption.alias||possibleOption.name]=possibleOption.defaultValue}let adNetwork=null;for(let i=2;i<process.argv.length;i++){let key=process.argv[i];let inlineValue=null;// 支持 --key=value 格式
|
|
7
|
+
if(key.includes("=")){const eqIndex=key.indexOf("=");inlineValue=key.slice(eqIndex+1);key=key.slice(0,eqIndex)}const allowedOption=posiibleOptions.find(e=>"--"+e.name===key);if(allowedOption){let value=true;if(allowedOption.hasValue){// 优先使用内联值(--key=value),否则使用下一个参数
|
|
8
|
+
value=inlineValue!==null?inlineValue:process.argv[++i];if(allowedOption.parser)value=allowedOption.parser(value)}const optionKey=allowedOption.alias||allowedOption.name;argvOptions[optionKey]=value;cliExplicitKeys.add(optionKey)}else if(!adNetwork)adNetwork=key}if(posiibleOptions.find(e=>e.name==="network")){if(adNetwork&&allowedAdNetworks.includes(adNetwork)){argvOptions["network"]=adNetwork}if(posiibleOptions.find(e=>e.name==="protocol")){if(mraidPartners.includes(argvOptions["network"])&&argvOptions["protocol"]==="none"){argvOptions["protocol"]="mraid"}}}argvOptions._cliExplicitKeys=cliExplicitKeys;return argvOptions};exports.allowedAdNetworks=allowedAdNetworks;exports.allowedAdProtocols=allowedAdProtocols;exports.mraidPartners=mraidPartners;exports.allowedLanguages=allowedLanguages;exports.allowedPlaycraftOrientations=allowedPlaycraftOrientations;exports.allowedEngines=allowedEngines;exports.WEB_ENGINES=WEB_ENGINES;exports.isWebEngine=isWebEngine;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";/**
|
|
2
2
|
* 解析 isChannelFold2Zip 相关标志
|
|
3
3
|
*
|
|
4
4
|
* isChannelFold2Zip:所有渠道(排除 preview)输出 dist/渠道名称.zip
|
|
@@ -10,17 +10,5 @@
|
|
|
10
10
|
* @param {string} params.adNetwork - 当前渠道名称
|
|
11
11
|
* @param {boolean} params.isZipOutput - 当前渠道是否本身就走 ZIP 输出流程
|
|
12
12
|
* @returns {{ isChannelFold2Zip: boolean, isZipOutputFinal: boolean }}
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const isChannelFold2Zip = !!(isChannelFold2ZipOption && adNetwork !== 'preview');
|
|
16
|
-
// 非 ZIP 渠道启用 isChannelFold2Zip 时,需要强制走 ZIP 输出流程
|
|
17
|
-
const isZipOutputFinal = isZipOutput || isChannelFold2Zip;
|
|
18
|
-
|
|
19
|
-
if (isChannelFold2Zip) {
|
|
20
|
-
console.log(`✅ isChannelFold2Zip enabled: output will be dist/${adNetwork}.zip`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return { isChannelFold2Zip, isZipOutputFinal };
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
exports.resolveChannelFold2Zip = resolveChannelFold2Zip;
|
|
13
|
+
*/function resolveChannelFold2Zip({isChannelFold2ZipOption,adNetwork,isZipOutput}){const isChannelFold2Zip=!!(isChannelFold2ZipOption&&adNetwork!=="preview");// 非 ZIP 渠道启用 isChannelFold2Zip 时,需要强制走 ZIP 输出流程
|
|
14
|
+
const isZipOutputFinal=isZipOutput||isChannelFold2Zip;if(isChannelFold2Zip){console.log(`✅ isChannelFold2Zip enabled: output will be dist/${adNetwork}.zip`)}return{isChannelFold2Zip,isZipOutputFinal}}exports.resolveChannelFold2Zip=resolveChannelFold2Zip;
|