@leonxin/meetgames 0.1.18 → 0.1.20
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/README.md +16 -6
- package/dist/android/detect.d.ts +6 -1
- package/dist/android/detect.d.ts.map +1 -1
- package/dist/android/detect.js +41 -17
- package/dist/android/detect.js.map +1 -1
- package/dist/android/gradle.d.ts.map +1 -1
- package/dist/android/gradle.js +8 -1
- package/dist/android/gradle.js.map +1 -1
- package/dist/android/meetSdkRemoteGradle.d.ts +1 -0
- package/dist/android/meetSdkRemoteGradle.d.ts.map +1 -1
- package/dist/android/meetSdkRemoteGradle.js +44 -21
- package/dist/android/meetSdkRemoteGradle.js.map +1 -1
- package/dist/cache.d.ts +16 -0
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +21 -0
- package/dist/cache.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +52 -23
- package/dist/cli.js.map +1 -1
- package/dist/config/meetSdkDefaultConfig.d.ts +7 -11
- package/dist/config/meetSdkDefaultConfig.d.ts.map +1 -1
- package/dist/config/meetSdkDefaultConfig.js +216 -53
- package/dist/config/meetSdkDefaultConfig.js.map +1 -1
- package/dist/config/meetSdkIosConfig.d.ts +4 -5
- package/dist/config/meetSdkIosConfig.d.ts.map +1 -1
- package/dist/config/meetSdkIosConfig.js +19 -19
- package/dist/config/meetSdkIosConfig.js.map +1 -1
- package/dist/contracts/types.d.ts +18 -0
- package/dist/contracts/types.d.ts.map +1 -1
- package/dist/core/doctor.d.ts.map +1 -1
- package/dist/core/doctor.js +18 -1
- package/dist/core/doctor.js.map +1 -1
- package/dist/core/platform.js +1 -1
- package/dist/core/platform.js.map +1 -1
- package/dist/core/previewPatches.d.ts +2 -2
- package/dist/core/previewPatches.d.ts.map +1 -1
- package/dist/core/previewPatches.js +3 -3
- package/dist/core/previewPatches.js.map +1 -1
- package/dist/core/workspace.d.ts.map +1 -1
- package/dist/core/workspace.js +3 -1
- package/dist/core/workspace.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +12 -7
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/service.d.ts +6 -0
- package/dist/mcp/service.d.ts.map +1 -1
- package/dist/mcp/service.js +17 -9
- package/dist/mcp/service.js.map +1 -1
- package/dist/ops/handlers.d.ts.map +1 -1
- package/dist/ops/handlers.js +25 -3
- package/dist/ops/handlers.js.map +1 -1
- package/dist/remote/sdkHomeDownload.d.ts +4 -5
- package/dist/remote/sdkHomeDownload.d.ts.map +1 -1
- package/dist/remote/sdkHomeDownload.js +38 -12
- package/dist/remote/sdkHomeDownload.js.map +1 -1
- package/docs/API.md +13 -13
- package/docs/CLI.md +27 -13
- package/docs/INTEGRATION.md +7 -6
- package/package.json +1 -1
- package/src/android/detect.ts +47 -17
- package/src/android/gradle.ts +16 -1
- package/src/android/meetSdkRemoteGradle.ts +50 -22
- package/src/cache.ts +37 -0
- package/src/cli.ts +51 -21
- package/src/config/meetSdkDefaultConfig.ts +243 -59
- package/src/config/meetSdkIosConfig.ts +17 -21
- package/src/contracts/types.ts +21 -0
- package/src/core/doctor.ts +17 -1
- package/src/core/platform.ts +1 -1
- package/src/core/previewPatches.ts +3 -3
- package/src/core/workspace.ts +3 -1
- package/src/index.ts +5 -3
- package/src/mcp/server.ts +12 -7
- package/src/mcp/service.ts +30 -10
- package/src/ops/handlers.ts +27 -3
- package/src/remote/sdkHomeDownload.ts +48 -16
- package/config/meetsdk-android.json +0 -171
- package/config/meetsdk-ios.json +0 -15
- package/tests/assemble.test.ts +0 -12
- package/tests/doctor.test.ts +0 -131
- package/tests/downloadGoogleServicesJson.test.ts +0 -47
- package/tests/fetch-remote.test.ts +0 -23
- package/tests/fetchConfigOverrides.test.ts +0 -28
- package/tests/fetchConfigWrite.test.ts +0 -54
- package/tests/fixtures-hosts.test.ts +0 -78
- package/tests/gradle.test.ts +0 -33
- package/tests/integration-json.test.ts +0 -29
- package/tests/ios.codeUtils.test.ts +0 -23
- package/tests/ios.sdkBundle.test.ts +0 -21
- package/tests/loadManifest.test.ts +0 -15
- package/tests/manifest-xml.test.ts +0 -30
- package/tests/mcp.e2e.ts +0 -214
- package/tests/mcp.service.test.ts +0 -53
- package/tests/meetSdkRemoteConfig.test.ts +0 -482
- package/tests/meetSdkRemoteGradle.test.ts +0 -414
- package/tests/pipeline.android.test.ts +0 -149
- package/tests/pipeline.integration-json.test.ts +0 -58
- package/tests/pipeline.ios.test.ts +0 -609
- package/tests/pipeline.preview.patch.test.ts +0 -85
- package/tests/platformSelection.test.ts +0 -77
- package/tests/sdkHomeDownload.test.ts +0 -275
- package/tests/sdkVersionConfig.test.ts +0 -131
- package/tests/topsdk.test.ts +0 -53
- package/tests/topsdkDownloadSdkConfig.test.ts +0 -81
- package/tests/topsdkFeatureModules.test.ts +0 -116
package/src/android/detect.ts
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
-
import type { AndroidDetectOptions, AndroidDetectResult } from "../contracts/types.js";
|
|
3
|
+
import type { AndroidDetectOptions, AndroidDetectResult, AndroidSdkModuleResult } from "../contracts/types.js";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
export const DEFAULT_ANDROID_SDK_MODULE_NAME = "unityLibrary";
|
|
6
|
+
|
|
7
|
+
export function parseIncludes(settingsContent: string): string[] {
|
|
6
8
|
const includes: string[] = [];
|
|
7
|
-
const includeRegex =
|
|
9
|
+
const includeRegex = /\binclude\b\s*(?:\(([^)\n]+)\)|([^\n]+))/g;
|
|
8
10
|
let match = includeRegex.exec(settingsContent);
|
|
9
11
|
while (match) {
|
|
10
|
-
const raw = match[1];
|
|
12
|
+
const raw = match[1] ?? match[2] ?? "";
|
|
11
13
|
const parts = raw
|
|
12
14
|
.split(",")
|
|
13
15
|
.map((x) => x.trim())
|
|
@@ -28,7 +30,7 @@ function isApplicationModule(buildGradleContent: string): boolean {
|
|
|
28
30
|
return applyPlugin || pluginsBlock || pluginAlias || (hasAndroidBlock && hasApplicationId);
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
function moduleNameToDir(projectRoot: string, moduleName: string): string {
|
|
33
|
+
export function moduleNameToDir(projectRoot: string, moduleName: string): string {
|
|
32
34
|
const normalized = moduleName.startsWith(":") ? moduleName.slice(1) : moduleName;
|
|
33
35
|
const relative = normalized.replace(/:/g, "/");
|
|
34
36
|
return path.join(projectRoot, relative);
|
|
@@ -38,7 +40,7 @@ function defaultManifestPath(moduleDir: string): string {
|
|
|
38
40
|
return path.join(moduleDir, "src", "main", "AndroidManifest.xml");
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
function normalizeModuleSelector(value: string): string {
|
|
43
|
+
export function normalizeModuleSelector(value: string): string {
|
|
42
44
|
const trimmed = value.trim().replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
|
|
43
45
|
if (!trimmed) return "";
|
|
44
46
|
const asGradlePath = trimmed.replace(/\//g, ":");
|
|
@@ -59,18 +61,10 @@ function successResult(projectRoot: string, moduleName: string, moduleDir: strin
|
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
export function detectAndroid(projectRoot: string, options: AndroidDetectOptions = {}): AndroidDetectResult {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
let settingsContent = "";
|
|
65
|
-
if (fs.existsSync(settingsGradle)) {
|
|
66
|
-
settingsContent = fs.readFileSync(settingsGradle, "utf8");
|
|
67
|
-
} else if (fs.existsSync(settingsGradleKts)) {
|
|
68
|
-
settingsContent = fs.readFileSync(settingsGradleKts, "utf8");
|
|
69
|
-
} else {
|
|
70
|
-
return { ok: false, error: "settings.gradle / settings.gradle.kts not found in project root" };
|
|
71
|
-
}
|
|
64
|
+
const settings = readAndroidSettings(projectRoot);
|
|
65
|
+
if (!settings) return { ok: false, error: "settings.gradle / settings.gradle.kts not found in project root" };
|
|
72
66
|
|
|
73
|
-
const modules = parseIncludes(
|
|
67
|
+
const modules = parseIncludes(settings.content);
|
|
74
68
|
if (!modules.length) {
|
|
75
69
|
return { ok: false, error: "no modules found in settings.gradle" };
|
|
76
70
|
}
|
|
@@ -114,6 +108,42 @@ export function detectAndroid(projectRoot: string, options: AndroidDetectOptions
|
|
|
114
108
|
return successResult(projectRoot, moduleName, moduleDir);
|
|
115
109
|
}
|
|
116
110
|
|
|
111
|
+
function readAndroidSettings(projectRoot: string): { path: string; content: string } | null {
|
|
112
|
+
const settingsGradle = path.join(projectRoot, "settings.gradle");
|
|
113
|
+
const settingsGradleKts = path.join(projectRoot, "settings.gradle.kts");
|
|
114
|
+
if (fs.existsSync(settingsGradle)) {
|
|
115
|
+
return { path: settingsGradle, content: fs.readFileSync(settingsGradle, "utf8") };
|
|
116
|
+
}
|
|
117
|
+
if (fs.existsSync(settingsGradleKts)) {
|
|
118
|
+
return { path: settingsGradleKts, content: fs.readFileSync(settingsGradleKts, "utf8") };
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function resolveAndroidSdkModule(
|
|
124
|
+
projectRoot: string,
|
|
125
|
+
moduleName = DEFAULT_ANDROID_SDK_MODULE_NAME
|
|
126
|
+
): AndroidSdkModuleResult {
|
|
127
|
+
const settings = readAndroidSettings(projectRoot);
|
|
128
|
+
if (!settings) return { ok: false, error: "settings.gradle / settings.gradle.kts not found in project root" };
|
|
129
|
+
const modules = parseIncludes(settings.content);
|
|
130
|
+
if (!modules.length) return { ok: false, error: "no modules found in settings.gradle" };
|
|
131
|
+
|
|
132
|
+
const requested = normalizeModuleSelector(moduleName);
|
|
133
|
+
const selected = modules.find((x) => normalizeModuleSelector(x) === requested);
|
|
134
|
+
if (!selected) {
|
|
135
|
+
return {
|
|
136
|
+
ok: false,
|
|
137
|
+
error: `ANDROID_SDK_MODULE_NOT_FOUND: ${requested}; available modules: ${modules.join(", ")}`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
ok: true,
|
|
142
|
+
moduleName: normalizeModuleSelector(selected),
|
|
143
|
+
moduleDir: moduleNameToDir(projectRoot, selected),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
117
147
|
/** Relative path from project root to the detected application module directory (e.g. `app`, `launcher`). */
|
|
118
148
|
export function applicationModuleRelPath(
|
|
119
149
|
projectRoot: string,
|
package/src/android/gradle.ts
CHANGED
|
@@ -79,13 +79,28 @@ export function updateRootBuildGradleRepositories(
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
const snippet = buildRepoSnippet(urls || []);
|
|
82
|
-
|
|
82
|
+
let updated = replaceOrInsertManaged(
|
|
83
83
|
content,
|
|
84
84
|
repositoriesBlock,
|
|
85
85
|
START_REPO_MARKER,
|
|
86
86
|
END_REPO_MARKER,
|
|
87
87
|
snippet
|
|
88
88
|
);
|
|
89
|
+
|
|
90
|
+
const buildscript = findBlockRange(updated, "buildscript");
|
|
91
|
+
if (buildscript) {
|
|
92
|
+
const buildscriptRepositoriesBlock = findBlockRange(updated, "repositories", buildscript.start);
|
|
93
|
+
if (buildscriptRepositoriesBlock && buildscriptRepositoriesBlock.end <= buildscript.end) {
|
|
94
|
+
updated = replaceOrInsertManaged(
|
|
95
|
+
updated,
|
|
96
|
+
buildscriptRepositoriesBlock,
|
|
97
|
+
START_REPO_MARKER,
|
|
98
|
+
END_REPO_MARKER,
|
|
99
|
+
snippet
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
89
104
|
if (updated === content) warnings.push("root build.gradle repositories unchanged");
|
|
90
105
|
return { ok: true, content: updated, changed: updated !== content, warnings };
|
|
91
106
|
}
|
|
@@ -180,7 +180,7 @@ export type ModuleGradlePluginStyle = "plugins-dsl" | "apply-plugin";
|
|
|
180
180
|
* Module uses `plugins { }` for the Android application plugin (no `apply plugin: com.android.application`).
|
|
181
181
|
*/
|
|
182
182
|
export function detectModuleGradlePluginStyle(content: string): ModuleGradlePluginStyle {
|
|
183
|
-
if (/apply\s+plugin:\s*['"]com\.android\.application['"]/m.test(content)) {
|
|
183
|
+
if (/apply\s+plugin:\s*['"]com\.android\.(?:application|library)['"]/m.test(content)) {
|
|
184
184
|
return "apply-plugin";
|
|
185
185
|
}
|
|
186
186
|
const pluginsBlock = findBlockRange(content, "plugins");
|
|
@@ -191,8 +191,9 @@ export function detectModuleGradlePluginStyle(content: string): ModuleGradlePlug
|
|
|
191
191
|
const blockText = content.slice(pluginsBlock.openBrace + 1, pluginsBlock.end);
|
|
192
192
|
if (
|
|
193
193
|
/alias\s*\(\s*libs\.plugins\.android\.application\s*\)/.test(blockText) ||
|
|
194
|
-
|
|
195
|
-
/\bid\s
|
|
194
|
+
/alias\s*\(\s*libs\.plugins\.android\.library\s*\)/.test(blockText) ||
|
|
195
|
+
/\bid\s+['"]com\.android\.(?:application|library)['"]/.test(blockText) ||
|
|
196
|
+
/\bid\s*\(\s*['"]com\.android\.(?:application|library)['"]\s*\)/.test(blockText)
|
|
196
197
|
) {
|
|
197
198
|
return "plugins-dsl";
|
|
198
199
|
}
|
|
@@ -525,6 +526,14 @@ function ensureBuildscriptBlock(content: string): string {
|
|
|
525
526
|
return `buildscript {\n repositories {\n }\n dependencies {\n }\n}\n\n${content}`;
|
|
526
527
|
}
|
|
527
528
|
|
|
529
|
+
function uniqueStrings(values: readonly string[]): string[] {
|
|
530
|
+
const out: string[] = [];
|
|
531
|
+
for (const value of values) {
|
|
532
|
+
if (!out.includes(value)) out.push(value);
|
|
533
|
+
}
|
|
534
|
+
return out;
|
|
535
|
+
}
|
|
536
|
+
|
|
528
537
|
export function updateRootBuildGradleMeetSdkRemote(
|
|
529
538
|
content: string,
|
|
530
539
|
params:
|
|
@@ -574,7 +583,13 @@ export function updateRootBuildGradleMeetSdkRemote(
|
|
|
574
583
|
current = removePluginsDslLinesByIds(current, new Set(stripPluginsDslIds));
|
|
575
584
|
current = stripManagedBlocks(current, TOPSDK_PLUGIN_AUTO_START, TOPSDK_PLUGIN_AUTO_END);
|
|
576
585
|
}
|
|
577
|
-
|
|
586
|
+
const hasExistingBuildscript = Boolean(findBlockRange(current, "buildscript"));
|
|
587
|
+
const mergedBuildscriptRepositoriesToApply = uniqueStrings([
|
|
588
|
+
...buildscriptRepositories,
|
|
589
|
+
...(hasExistingBuildscript || buildscriptRepositories.length > 0 || buildscriptClasspaths.length > 0 ? repositories : []),
|
|
590
|
+
]);
|
|
591
|
+
|
|
592
|
+
if (mergedBuildscriptRepositoriesToApply.length > 0 || buildscriptClasspaths.length > 0) {
|
|
578
593
|
current = ensureBuildscriptBlock(current);
|
|
579
594
|
const buildscript = findBlockRange(current, "buildscript");
|
|
580
595
|
if (!buildscript) return { ok: false, error: "buildscript block not found in root build.gradle" };
|
|
@@ -583,7 +598,7 @@ export function updateRootBuildGradleMeetSdkRemote(
|
|
|
583
598
|
return { ok: false, error: "repositories block under buildscript not found" };
|
|
584
599
|
}
|
|
585
600
|
const buildscriptReposText = current.slice(repositoriesBlock.openBrace + 1, repositoriesBlock.end);
|
|
586
|
-
const mergedBuildscriptRepos = mergeRepositoriesInBlock(buildscriptReposText,
|
|
601
|
+
const mergedBuildscriptRepos = mergeRepositoriesInBlock(buildscriptReposText, mergedBuildscriptRepositoriesToApply);
|
|
587
602
|
current =
|
|
588
603
|
current.slice(0, repositoriesBlock.openBrace + 1) +
|
|
589
604
|
mergedBuildscriptRepos +
|
|
@@ -880,8 +895,25 @@ export type MeetSdkModulePluginConfig = {
|
|
|
880
895
|
style: ModuleGradlePluginStyle;
|
|
881
896
|
applyPlugins?: readonly string[];
|
|
882
897
|
pluginsDsl?: readonly MeetSdkGradlePluginDslSpec[];
|
|
898
|
+
writeApplicationId?: boolean;
|
|
883
899
|
};
|
|
884
900
|
|
|
901
|
+
function findAndroidDefaultConfigBlocks(
|
|
902
|
+
content: string
|
|
903
|
+
): { androidBlock: { start: number; openBrace: number; end: number }; defaultConfigBlock: { start: number; openBrace: number; end: number } } | null {
|
|
904
|
+
let searchFrom = 0;
|
|
905
|
+
while (searchFrom < content.length) {
|
|
906
|
+
const androidBlock = findBlockRange(content, "android", searchFrom);
|
|
907
|
+
if (!androidBlock) return null;
|
|
908
|
+
const defaultConfigBlock = findBlockRange(content, "defaultConfig", androidBlock.start);
|
|
909
|
+
if (defaultConfigBlock && defaultConfigBlock.end <= androidBlock.end) {
|
|
910
|
+
return { androidBlock, defaultConfigBlock };
|
|
911
|
+
}
|
|
912
|
+
searchFrom = androidBlock.end + 1;
|
|
913
|
+
}
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
916
|
+
|
|
885
917
|
export function updateModuleBuildGradleMeetSdkRemote(
|
|
886
918
|
content: string,
|
|
887
919
|
config: MeetSdkRemoteConfig,
|
|
@@ -896,6 +928,7 @@ export function updateModuleBuildGradleMeetSdkRemote(
|
|
|
896
928
|
style: detectModuleGradlePluginStyle(content),
|
|
897
929
|
applyPlugins: Array.isArray(plugins) ? plugins : [],
|
|
898
930
|
pluginsDsl: [],
|
|
931
|
+
writeApplicationId: true,
|
|
899
932
|
};
|
|
900
933
|
}
|
|
901
934
|
const withPlugins =
|
|
@@ -905,35 +938,30 @@ export function updateModuleBuildGradleMeetSdkRemote(
|
|
|
905
938
|
? mergeApplyPluginsInContent(content, pluginConfig.applyPlugins!)
|
|
906
939
|
: content;
|
|
907
940
|
|
|
908
|
-
const
|
|
909
|
-
if (!
|
|
910
|
-
return { ok: false, error: "android block not found in module build.gradle" };
|
|
911
|
-
}
|
|
912
|
-
const defaultConfigBlock = findBlockRange(withPlugins, "defaultConfig", androidBlock.start);
|
|
913
|
-
if (!defaultConfigBlock || defaultConfigBlock.end > androidBlock.end) {
|
|
941
|
+
const blocks = findAndroidDefaultConfigBlocks(withPlugins);
|
|
942
|
+
if (!blocks) {
|
|
914
943
|
return { ok: false, error: "defaultConfig block not found under android" };
|
|
915
944
|
}
|
|
916
|
-
const withApplicationId =
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
if (!refreshedDefaultConfigBlock || refreshedDefaultConfigBlock.end > refreshedAndroidBlock.end) {
|
|
945
|
+
const withApplicationId =
|
|
946
|
+
pluginConfig.writeApplicationId === false
|
|
947
|
+
? withPlugins
|
|
948
|
+
: updateDefaultConfigApplicationId(withPlugins, blocks.defaultConfigBlock, config.packageName);
|
|
949
|
+
const refreshedBlocks = findAndroidDefaultConfigBlocks(withApplicationId);
|
|
950
|
+
if (!refreshedBlocks) {
|
|
923
951
|
return { ok: false, error: "defaultConfig block not found under android" };
|
|
924
952
|
}
|
|
925
953
|
const defaultConfigText = withApplicationId.slice(
|
|
926
|
-
|
|
927
|
-
|
|
954
|
+
refreshedBlocks.defaultConfigBlock.openBrace + 1,
|
|
955
|
+
refreshedBlocks.defaultConfigBlock.end
|
|
928
956
|
);
|
|
929
957
|
const mergedDefaultConfigText = mergeResValuesInDefaultConfigBlock(
|
|
930
958
|
defaultConfigText,
|
|
931
959
|
buildResValuesSnippet(config)
|
|
932
960
|
);
|
|
933
961
|
const withResValues =
|
|
934
|
-
withApplicationId.slice(0,
|
|
962
|
+
withApplicationId.slice(0, refreshedBlocks.defaultConfigBlock.openBrace + 1) +
|
|
935
963
|
mergedDefaultConfigText +
|
|
936
|
-
withApplicationId.slice(
|
|
964
|
+
withApplicationId.slice(refreshedBlocks.defaultConfigBlock.end);
|
|
937
965
|
|
|
938
966
|
const dependenciesBlock = findBlockRange(withResValues, "dependencies");
|
|
939
967
|
if (!dependenciesBlock) {
|
package/src/cache.ts
CHANGED
|
@@ -5,11 +5,17 @@ import path from "node:path";
|
|
|
5
5
|
import { MEETSDK_REMOTE_CONFIG_FILENAME } from "./config/meetSdkRemoteConfig.js";
|
|
6
6
|
|
|
7
7
|
export const MEET_SDK_TOOL_CACHE_ROOT = path.join(os.homedir(), ".cache", "meet-sdk-tool");
|
|
8
|
+
export const MEETSDK_ANDROID_CONFIG_FILENAME = "meetsdk-android.json";
|
|
9
|
+
export const MEETSDK_IOS_CONFIG_FILENAME = "meetsdk-ios.json";
|
|
8
10
|
|
|
9
11
|
function iosSdkZipFileName(version: string): string {
|
|
10
12
|
return `topSDK-ios--V${version}.zip`;
|
|
11
13
|
}
|
|
12
14
|
|
|
15
|
+
function androidSdkZipFileName(version: string): string {
|
|
16
|
+
return `topSDK-android-V${version}.zip`;
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
function safeSegment(value: string): string {
|
|
14
20
|
const cleaned = value.trim().replace(/[^a-zA-Z0-9._-]+/g, "_").replace(/^_+|_+$/g, "");
|
|
15
21
|
return cleaned || "unknown";
|
|
@@ -52,6 +58,14 @@ export function resolveRemoteConfigCachePath(params: {
|
|
|
52
58
|
);
|
|
53
59
|
}
|
|
54
60
|
|
|
61
|
+
export function resolveMeetSdkAndroidConfigCachePath(cacheRoot = MEET_SDK_TOOL_CACHE_ROOT): string {
|
|
62
|
+
return path.join(cacheRoot, "configs", "sdk-home", MEETSDK_ANDROID_CONFIG_FILENAME);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function resolveMeetSdkIosConfigCachePath(cacheRoot = MEET_SDK_TOOL_CACHE_ROOT): string {
|
|
66
|
+
return path.join(cacheRoot, "configs", "sdk-home", MEETSDK_IOS_CONFIG_FILENAME);
|
|
67
|
+
}
|
|
68
|
+
|
|
55
69
|
export function writeRemoteConfigCache(params: {
|
|
56
70
|
env: string;
|
|
57
71
|
appId: string;
|
|
@@ -110,6 +124,29 @@ export function resolveIosSdkCacheLayout(params: {
|
|
|
110
124
|
};
|
|
111
125
|
}
|
|
112
126
|
|
|
127
|
+
export function resolveAndroidSdkCacheLayout(params: {
|
|
128
|
+
version: string;
|
|
129
|
+
packageType: string;
|
|
130
|
+
plugins: readonly string[];
|
|
131
|
+
cacheRoot?: string;
|
|
132
|
+
}): { baseDir: string; zipPath: string; extractDir: string; metadataPath: string; lockDir: string } {
|
|
133
|
+
const baseDir = path.join(
|
|
134
|
+
params.cacheRoot ?? MEET_SDK_TOOL_CACHE_ROOT,
|
|
135
|
+
"sdk",
|
|
136
|
+
"android",
|
|
137
|
+
safeSegment(params.packageType),
|
|
138
|
+
safeSegment(params.version),
|
|
139
|
+
pluginsHash(params.plugins)
|
|
140
|
+
);
|
|
141
|
+
return {
|
|
142
|
+
baseDir,
|
|
143
|
+
zipPath: path.join(baseDir, androidSdkZipFileName(params.version)),
|
|
144
|
+
extractDir: path.join(baseDir, "extracted"),
|
|
145
|
+
metadataPath: path.join(baseDir, "metadata.json"),
|
|
146
|
+
lockDir: path.join(baseDir, ".lock"),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
113
150
|
export function writeIosSdkCacheMetadata(params: {
|
|
114
151
|
metadataPath: string;
|
|
115
152
|
version: string;
|
package/src/cli.ts
CHANGED
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
defaultSdkHomeApiBaseUrl,
|
|
17
17
|
downloadIosSdkToBundled,
|
|
18
18
|
DEFAULT_IOS_SDK_PACKAGE_TYPE,
|
|
19
|
-
resolveIosSdkDownloadPluginsFromRemoteConfig,
|
|
20
19
|
} from "./remote/sdkHomeDownload.js";
|
|
21
20
|
import type { Manifest } from "./contracts/types.js";
|
|
22
21
|
import {
|
|
@@ -63,6 +62,7 @@ interface Parsed {
|
|
|
63
62
|
topsdkChannelType: string;
|
|
64
63
|
topsdkPackageName: string;
|
|
65
64
|
appTarget: string;
|
|
65
|
+
sdkModuleName: string;
|
|
66
66
|
sdkHomeApiBaseUrl: string;
|
|
67
67
|
iosSdkPackageType: string;
|
|
68
68
|
}
|
|
@@ -72,11 +72,11 @@ function printHelp(): void {
|
|
|
72
72
|
meetgames — Android-first integration CLI (TypeScript)
|
|
73
73
|
|
|
74
74
|
Usage:
|
|
75
|
-
meetgames integrate [--project-root <path>] [--app-id ID] [--channel-type TYPE] [--env prod|pre|test] [--app-target <target>] [--dry-run] [--verbose] [--patch-file <path>]
|
|
75
|
+
meetgames integrate [--project-root <path>] [--app-id ID] [--channel-type TYPE] [--env prod|pre|test] [--app-target <target>] [--sdk-module <module>] [--dry-run] [--verbose] [--patch-file <path>]
|
|
76
76
|
meetgames fetch-config [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] [--project-root <path>] [--verbose]
|
|
77
|
-
meetgames download-ios-sdk [--package-type native|unity|cocos] [--sdk-api-base-url URL] [--verbose]
|
|
78
|
-
meetgames setup [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] [--project-root <path>] [--app-target <target>] [--
|
|
79
|
-
meetgames doctor [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] --project-root <path> [--app-target <target>] [--verbose]
|
|
77
|
+
meetgames download-ios-sdk [--project-root <path>] [--app-id ID] [--channel-type TYPE] [--env prod|pre|test] [--package-type native|unity|cocos] [--sdk-api-base-url URL] [--verbose]
|
|
78
|
+
meetgames setup [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] [--project-root <path>] [--app-target <target>] [--sdk-module <module>] [--dry-run] [--verbose]
|
|
79
|
+
meetgames doctor [--app-id ID] [--app-secret SECRET] [--channel-type TYPE] [--env prod|pre|test] --project-root <path> [--app-target <target>] [--sdk-module <module>] [--verbose]
|
|
80
80
|
|
|
81
81
|
Notes:
|
|
82
82
|
- Source code is TypeScript only; published bin runs compiled output under dist/.
|
|
@@ -87,8 +87,8 @@ Notes:
|
|
|
87
87
|
- doctor first fetches downloadSDKConfig to the cache, then validates the detected platform integration.
|
|
88
88
|
- integrate uses recipes/integrate-default.yaml, filtered to the detected platform before execution.
|
|
89
89
|
- iOS SDK is read from ${MEET_SDK_TOOL_CACHE_ROOT}/sdk/ios/.
|
|
90
|
-
- Android integrate/doctor reads
|
|
91
|
-
- download-ios-sdk calls sdk-home getDownLoadUrl
|
|
90
|
+
- Android integrate/doctor reads latest SDK config from sdk-home and stores it under ${MEET_SDK_TOOL_CACHE_ROOT}/configs/sdk-home/.
|
|
91
|
+
- download-ios-sdk reads an iOS meetsdk-remote-config.json, derives sdk-home plugins from it, then calls sdk-home getDownLoadUrl and extracts the iOS SDK under ${MEET_SDK_TOOL_CACHE_ROOT}/sdk/ios/.
|
|
92
92
|
- fetch-config requires --app-secret (or TOPSDK_APP_SECRET) to sign downloadSDKConfig; appSecret is never read from meetsdk-remote-config.json.
|
|
93
93
|
- When analytics.firebase is enabled, Android downloads google-services.json to the detected/selected app module; iOS downloads GoogleService-Info.plist next to Info.plist.
|
|
94
94
|
- fetch-config writes to ${MEET_SDK_TOOL_CACHE_ROOT}/configs/<env>/<appId>/<channelType>/meetsdk-remote-config.json.
|
|
@@ -98,22 +98,23 @@ Notes:
|
|
|
98
98
|
Options (global where noted):
|
|
99
99
|
--project-root Host project directory (default: cwd); for iOS it may point to the project root or directly to a .xcodeproj directory
|
|
100
100
|
--app-target App target to integrate/check: Android application Gradle module (e.g. :app or launcher) or iOS App target name
|
|
101
|
+
--sdk-module Android SDK integration Gradle module for resValue/dependencies (default: unityLibrary); must be included by settings.gradle/settings.gradle.kts
|
|
101
102
|
--app-id fetch-config/integrate/doctor cache selector; default TOPSDK_APP_ID
|
|
102
103
|
--app-secret fetch-config: required appSecret for downloadSDKConfig sign (or env TOPSDK_APP_SECRET)
|
|
103
104
|
--channel-type fetch-config/integrate/doctor cache selector; default TOPSDK_CHANNEL_TYPE
|
|
104
105
|
--env fetch-config: prod(正式服,默认)| pre | test(开发调试)
|
|
105
106
|
TOPSDK_API_BASE_URL fetch-config: 覆盖 API 根地址(如 http://localhost:18080/ 联调本机 console)
|
|
106
107
|
MEETGAMES_SDK_HOME_API_BASE_URL 覆盖 sdk-home API 根地址(默认 https://business-api.meetgames.com);用于 Android 最新版本查询和 iOS SDK 下载
|
|
107
|
-
--sdk-api-base-url sdk-home API 根地址;用于 Android 最新版本查询和 iOS SDK
|
|
108
|
+
--sdk-api-base-url sdk-home API 根地址;用于 Android 最新版本查询和 iOS SDK 下载(setup 不支持)
|
|
108
109
|
--package-type download-ios-sdk: native(默认)| unity | cocos
|
|
109
|
-
--dry-run integrate: compute changes
|
|
110
|
-
--report-file
|
|
111
|
-
--patch-file integrate: write unified diff to this path (works with --dry-run). If under <pkg>/
|
|
110
|
+
--dry-run integrate/setup: compute changes without writing host project files (setup still writes fetched config cache)
|
|
111
|
+
--report-file integrate: write JSON report to path
|
|
112
|
+
--patch-file integrate: write unified diff to this path (works with --dry-run). If under <pkg>/fixtures/expected-patches/, all existing files in that dir are removed first so only the latest patch remains.
|
|
112
113
|
--verbose Verbose logs and full patch preview
|
|
113
114
|
|
|
114
115
|
Subcommand notes:
|
|
115
116
|
- integrate defaults to writing files; use --dry-run for CI preview / diff-only.
|
|
116
|
-
- setup: step 1 always writes meetsdk-remote-config.json; step 2 honors --dry-run
|
|
117
|
+
- setup: step 1 always writes meetsdk-remote-config.json; step 2 honors --dry-run.
|
|
117
118
|
- fetch-config ignores --dry-run, --report-file, --patch-file (shared parser only).
|
|
118
119
|
`);
|
|
119
120
|
}
|
|
@@ -134,6 +135,7 @@ function parseArgv(argv: string[]): Parsed {
|
|
|
134
135
|
topsdkChannelType: "",
|
|
135
136
|
topsdkPackageName: "",
|
|
136
137
|
appTarget: "",
|
|
138
|
+
sdkModuleName: "",
|
|
137
139
|
sdkHomeApiBaseUrl: "",
|
|
138
140
|
iosSdkPackageType: "",
|
|
139
141
|
};
|
|
@@ -169,6 +171,12 @@ function parseArgv(argv: string[]): Parsed {
|
|
|
169
171
|
i += 1;
|
|
170
172
|
continue;
|
|
171
173
|
}
|
|
174
|
+
if (t === "--sdk-module") {
|
|
175
|
+
out.sdkModuleName = rest[i + 1] ?? "";
|
|
176
|
+
if (!out.sdkModuleName || out.sdkModuleName.startsWith("-")) fail("--sdk-module requires a module name", EXIT.INVALID_ARGS);
|
|
177
|
+
i += 1;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
172
180
|
if (t === "--sdk-api-base-url") {
|
|
173
181
|
out.sdkHomeApiBaseUrl = rest[i + 1] ?? "";
|
|
174
182
|
if (!out.sdkHomeApiBaseUrl || out.sdkHomeApiBaseUrl.startsWith("-")) {
|
|
@@ -232,6 +240,10 @@ function resolvedAppTarget(parsed: Parsed): string {
|
|
|
232
240
|
return parsed.appTarget;
|
|
233
241
|
}
|
|
234
242
|
|
|
243
|
+
function resolvedSdkModuleName(parsed: Parsed): string | undefined {
|
|
244
|
+
return parsed.sdkModuleName.trim() || undefined;
|
|
245
|
+
}
|
|
246
|
+
|
|
235
247
|
function cachedRemoteConfigPathFromArgs(parsed: Parsed): string {
|
|
236
248
|
const appId = parsed.topsdkAppId || process.env.TOPSDK_APP_ID || "";
|
|
237
249
|
const channelType = parsed.topsdkChannelType || process.env.TOPSDK_CHANNEL_TYPE || "";
|
|
@@ -246,6 +258,7 @@ function selectedPlatformContext(parsed: Parsed): {
|
|
|
246
258
|
} {
|
|
247
259
|
const ctx = buildWorkspaceContext(parsed.projectRoot, resolvePackageRoot(), {
|
|
248
260
|
appTarget: resolvedAppTarget(parsed),
|
|
261
|
+
sdkModuleName: resolvedSdkModuleName(parsed),
|
|
249
262
|
sdkHomeApiBaseUrl: parsed.sdkHomeApiBaseUrl || undefined,
|
|
250
263
|
remoteConfigPath: cachedRemoteConfigPathFromArgs(parsed) || undefined,
|
|
251
264
|
});
|
|
@@ -396,12 +409,20 @@ async function cmdSetup(parsed: Parsed): Promise<void> {
|
|
|
396
409
|
await cmdIntegrate(parsed);
|
|
397
410
|
}
|
|
398
411
|
|
|
399
|
-
function
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
412
|
+
function resolveIosDownloadRemoteConfigPath(parsed: Parsed, explicitPath?: string): string {
|
|
413
|
+
const candidates = [
|
|
414
|
+
explicitPath,
|
|
415
|
+
cachedRemoteConfigPathFromArgs(parsed),
|
|
416
|
+
path.join(parsed.projectRoot, MEETSDK_REMOTE_CONFIG_FILENAME),
|
|
417
|
+
]
|
|
418
|
+
.filter((p): p is string => Boolean(p))
|
|
419
|
+
.filter((p, i, arr) => arr.indexOf(p) === i);
|
|
420
|
+
const found = candidates.find((p) => fs.existsSync(p));
|
|
421
|
+
if (found) return found;
|
|
422
|
+
fail(
|
|
423
|
+
`download-ios-sdk requires an iOS ${MEETSDK_REMOTE_CONFIG_FILENAME}; checked: ${candidates.join(", ")}`,
|
|
424
|
+
EXIT.CONFIG_ERROR
|
|
425
|
+
);
|
|
405
426
|
}
|
|
406
427
|
|
|
407
428
|
async function cmdDownloadIosSdk(parsed: Parsed, remoteConfigPath?: string): Promise<void> {
|
|
@@ -411,15 +432,15 @@ async function cmdDownloadIosSdk(parsed: Parsed, remoteConfigPath?: string): Pro
|
|
|
411
432
|
if (!["native", "unity", "cocos"].includes(packageType)) {
|
|
412
433
|
fail(`invalid --package-type (use native, unity, or cocos): ${packageType}`, EXIT.INVALID_ARGS);
|
|
413
434
|
}
|
|
414
|
-
const
|
|
415
|
-
const plugins = configuredPlugins;
|
|
435
|
+
const configPath = resolveIosDownloadRemoteConfigPath(parsed, remoteConfigPath);
|
|
416
436
|
|
|
437
|
+
console.log(`[meetgames] download-ios-sdk: using remote config ${configPath}`);
|
|
417
438
|
console.log("[meetgames] download-ios-sdk: resolving sdk-home iOS SDK…");
|
|
418
439
|
let result;
|
|
419
440
|
try {
|
|
420
441
|
result = await downloadIosSdkToBundled(resolvePackageRoot(), {
|
|
421
442
|
baseUrl,
|
|
422
|
-
|
|
443
|
+
remoteConfigPath: configPath,
|
|
423
444
|
packageType,
|
|
424
445
|
});
|
|
425
446
|
} catch (e) {
|
|
@@ -462,7 +483,16 @@ export async function main(): Promise<void> {
|
|
|
462
483
|
if (parsed.appTarget && !["doctor", "setup", "integrate"].includes(parsed.command)) {
|
|
463
484
|
fail("--app-target is only supported by doctor, setup, and integrate", EXIT.INVALID_ARGS);
|
|
464
485
|
}
|
|
486
|
+
if (parsed.sdkModuleName && !["doctor", "setup", "integrate"].includes(parsed.command)) {
|
|
487
|
+
fail("--sdk-module is only supported by doctor, setup, and integrate", EXIT.INVALID_ARGS);
|
|
488
|
+
}
|
|
489
|
+
if (parsed.command === "setup") {
|
|
490
|
+
if (parsed.patchFile) fail("--patch-file is not supported by setup", EXIT.INVALID_ARGS);
|
|
491
|
+
if (parsed.reportFile) fail("--report-file is not supported by setup", EXIT.INVALID_ARGS);
|
|
492
|
+
if (parsed.sdkHomeApiBaseUrl) fail("--sdk-api-base-url is not supported by setup", EXIT.INVALID_ARGS);
|
|
493
|
+
}
|
|
465
494
|
resolvedAppTarget(parsed);
|
|
495
|
+
resolvedSdkModuleName(parsed);
|
|
466
496
|
|
|
467
497
|
switch (parsed.command) {
|
|
468
498
|
case "doctor":
|